1*b3b94faaSDavid Teigland /* 2*b3b94faaSDavid Teigland * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 3*b3b94faaSDavid Teigland * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 4*b3b94faaSDavid Teigland * 5*b3b94faaSDavid Teigland * This copyrighted material is made available to anyone wishing to use, 6*b3b94faaSDavid Teigland * modify, copy, or redistribute it subject to the terms and conditions 7*b3b94faaSDavid Teigland * of the GNU General Public License v.2. 8*b3b94faaSDavid Teigland */ 9*b3b94faaSDavid Teigland 10*b3b94faaSDavid Teigland #include <linux/sched.h> 11*b3b94faaSDavid Teigland #include <linux/slab.h> 12*b3b94faaSDavid Teigland #include <linux/spinlock.h> 13*b3b94faaSDavid Teigland #include <linux/completion.h> 14*b3b94faaSDavid Teigland #include <linux/buffer_head.h> 15*b3b94faaSDavid Teigland #include <asm/semaphore.h> 16*b3b94faaSDavid Teigland 17*b3b94faaSDavid Teigland #include "gfs2.h" 18*b3b94faaSDavid Teigland #include "bmap.h" 19*b3b94faaSDavid Teigland #include "glock.h" 20*b3b94faaSDavid Teigland #include "log.h" 21*b3b94faaSDavid Teigland #include "lops.h" 22*b3b94faaSDavid Teigland #include "meta_io.h" 23*b3b94faaSDavid Teigland 24*b3b94faaSDavid Teigland #define PULL 1 25*b3b94faaSDavid Teigland 26*b3b94faaSDavid Teigland static inline int is_done(struct gfs2_sbd *sdp, atomic_t *a) 27*b3b94faaSDavid Teigland { 28*b3b94faaSDavid Teigland int done; 29*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 30*b3b94faaSDavid Teigland done = atomic_read(a) ? 0 : 1; 31*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 32*b3b94faaSDavid Teigland return done; 33*b3b94faaSDavid Teigland } 34*b3b94faaSDavid Teigland 35*b3b94faaSDavid Teigland static void do_lock_wait(struct gfs2_sbd *sdp, wait_queue_head_t *wq, 36*b3b94faaSDavid Teigland atomic_t *a) 37*b3b94faaSDavid Teigland { 38*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 39*b3b94faaSDavid Teigland wait_event(*wq, is_done(sdp, a)); 40*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 41*b3b94faaSDavid Teigland } 42*b3b94faaSDavid Teigland 43*b3b94faaSDavid Teigland static void lock_for_trans(struct gfs2_sbd *sdp) 44*b3b94faaSDavid Teigland { 45*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 46*b3b94faaSDavid Teigland do_lock_wait(sdp, &sdp->sd_log_trans_wq, &sdp->sd_log_flush_count); 47*b3b94faaSDavid Teigland atomic_inc(&sdp->sd_log_trans_count); 48*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 49*b3b94faaSDavid Teigland } 50*b3b94faaSDavid Teigland 51*b3b94faaSDavid Teigland static void unlock_from_trans(struct gfs2_sbd *sdp) 52*b3b94faaSDavid Teigland { 53*b3b94faaSDavid Teigland gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_trans_count)); 54*b3b94faaSDavid Teigland if (atomic_dec_and_test(&sdp->sd_log_trans_count)) 55*b3b94faaSDavid Teigland wake_up(&sdp->sd_log_flush_wq); 56*b3b94faaSDavid Teigland } 57*b3b94faaSDavid Teigland 58*b3b94faaSDavid Teigland void gfs2_lock_for_flush(struct gfs2_sbd *sdp) 59*b3b94faaSDavid Teigland { 60*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 61*b3b94faaSDavid Teigland atomic_inc(&sdp->sd_log_flush_count); 62*b3b94faaSDavid Teigland do_lock_wait(sdp, &sdp->sd_log_flush_wq, &sdp->sd_log_trans_count); 63*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 64*b3b94faaSDavid Teigland } 65*b3b94faaSDavid Teigland 66*b3b94faaSDavid Teigland void gfs2_unlock_from_flush(struct gfs2_sbd *sdp) 67*b3b94faaSDavid Teigland { 68*b3b94faaSDavid Teigland gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_flush_count)); 69*b3b94faaSDavid Teigland if (atomic_dec_and_test(&sdp->sd_log_flush_count)) 70*b3b94faaSDavid Teigland wake_up(&sdp->sd_log_trans_wq); 71*b3b94faaSDavid Teigland } 72*b3b94faaSDavid Teigland 73*b3b94faaSDavid Teigland /** 74*b3b94faaSDavid Teigland * gfs2_struct2blk - compute stuff 75*b3b94faaSDavid Teigland * @sdp: the filesystem 76*b3b94faaSDavid Teigland * @nstruct: the number of structures 77*b3b94faaSDavid Teigland * @ssize: the size of the structures 78*b3b94faaSDavid Teigland * 79*b3b94faaSDavid Teigland * Compute the number of log descriptor blocks needed to hold a certain number 80*b3b94faaSDavid Teigland * of structures of a certain size. 81*b3b94faaSDavid Teigland * 82*b3b94faaSDavid Teigland * Returns: the number of blocks needed (minimum is always 1) 83*b3b94faaSDavid Teigland */ 84*b3b94faaSDavid Teigland 85*b3b94faaSDavid Teigland unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, 86*b3b94faaSDavid Teigland unsigned int ssize) 87*b3b94faaSDavid Teigland { 88*b3b94faaSDavid Teigland unsigned int blks; 89*b3b94faaSDavid Teigland unsigned int first, second; 90*b3b94faaSDavid Teigland 91*b3b94faaSDavid Teigland blks = 1; 92*b3b94faaSDavid Teigland first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize; 93*b3b94faaSDavid Teigland 94*b3b94faaSDavid Teigland if (nstruct > first) { 95*b3b94faaSDavid Teigland second = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / ssize; 96*b3b94faaSDavid Teigland blks += DIV_RU(nstruct - first, second); 97*b3b94faaSDavid Teigland } 98*b3b94faaSDavid Teigland 99*b3b94faaSDavid Teigland return blks; 100*b3b94faaSDavid Teigland } 101*b3b94faaSDavid Teigland 102*b3b94faaSDavid Teigland void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) 103*b3b94faaSDavid Teigland { 104*b3b94faaSDavid Teigland struct list_head *head = &sdp->sd_ail1_list; 105*b3b94faaSDavid Teigland uint64_t sync_gen; 106*b3b94faaSDavid Teigland struct list_head *first, *tmp; 107*b3b94faaSDavid Teigland struct gfs2_ail *first_ai, *ai; 108*b3b94faaSDavid Teigland 109*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 110*b3b94faaSDavid Teigland if (list_empty(head)) { 111*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 112*b3b94faaSDavid Teigland return; 113*b3b94faaSDavid Teigland } 114*b3b94faaSDavid Teigland sync_gen = sdp->sd_ail_sync_gen++; 115*b3b94faaSDavid Teigland 116*b3b94faaSDavid Teigland first = head->prev; 117*b3b94faaSDavid Teigland first_ai = list_entry(first, struct gfs2_ail, ai_list); 118*b3b94faaSDavid Teigland first_ai->ai_sync_gen = sync_gen; 119*b3b94faaSDavid Teigland gfs2_ail1_start_one(sdp, first_ai); 120*b3b94faaSDavid Teigland 121*b3b94faaSDavid Teigland if (flags & DIO_ALL) 122*b3b94faaSDavid Teigland first = NULL; 123*b3b94faaSDavid Teigland 124*b3b94faaSDavid Teigland for (;;) { 125*b3b94faaSDavid Teigland if (first && 126*b3b94faaSDavid Teigland (head->prev != first || 127*b3b94faaSDavid Teigland gfs2_ail1_empty_one(sdp, first_ai, 0))) 128*b3b94faaSDavid Teigland break; 129*b3b94faaSDavid Teigland 130*b3b94faaSDavid Teigland for (tmp = head->prev; tmp != head; tmp = tmp->prev) { 131*b3b94faaSDavid Teigland ai = list_entry(tmp, struct gfs2_ail, ai_list); 132*b3b94faaSDavid Teigland if (ai->ai_sync_gen >= sync_gen) 133*b3b94faaSDavid Teigland continue; 134*b3b94faaSDavid Teigland ai->ai_sync_gen = sync_gen; 135*b3b94faaSDavid Teigland gfs2_ail1_start_one(sdp, ai); 136*b3b94faaSDavid Teigland break; 137*b3b94faaSDavid Teigland } 138*b3b94faaSDavid Teigland 139*b3b94faaSDavid Teigland if (tmp == head) 140*b3b94faaSDavid Teigland break; 141*b3b94faaSDavid Teigland } 142*b3b94faaSDavid Teigland 143*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 144*b3b94faaSDavid Teigland } 145*b3b94faaSDavid Teigland 146*b3b94faaSDavid Teigland int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) 147*b3b94faaSDavid Teigland { 148*b3b94faaSDavid Teigland struct gfs2_ail *ai, *s; 149*b3b94faaSDavid Teigland int ret; 150*b3b94faaSDavid Teigland 151*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 152*b3b94faaSDavid Teigland 153*b3b94faaSDavid Teigland list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { 154*b3b94faaSDavid Teigland if (gfs2_ail1_empty_one(sdp, ai, flags)) 155*b3b94faaSDavid Teigland list_move(&ai->ai_list, &sdp->sd_ail2_list); 156*b3b94faaSDavid Teigland else if (!(flags & DIO_ALL)) 157*b3b94faaSDavid Teigland break; 158*b3b94faaSDavid Teigland } 159*b3b94faaSDavid Teigland 160*b3b94faaSDavid Teigland ret = list_empty(&sdp->sd_ail1_list); 161*b3b94faaSDavid Teigland 162*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 163*b3b94faaSDavid Teigland 164*b3b94faaSDavid Teigland return ret; 165*b3b94faaSDavid Teigland } 166*b3b94faaSDavid Teigland 167*b3b94faaSDavid Teigland static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) 168*b3b94faaSDavid Teigland { 169*b3b94faaSDavid Teigland struct gfs2_ail *ai, *safe; 170*b3b94faaSDavid Teigland unsigned int old_tail = sdp->sd_log_tail; 171*b3b94faaSDavid Teigland int wrap = (new_tail < old_tail); 172*b3b94faaSDavid Teigland int a, b, rm; 173*b3b94faaSDavid Teigland 174*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 175*b3b94faaSDavid Teigland 176*b3b94faaSDavid Teigland list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) { 177*b3b94faaSDavid Teigland a = (old_tail <= ai->ai_first); 178*b3b94faaSDavid Teigland b = (ai->ai_first < new_tail); 179*b3b94faaSDavid Teigland rm = (wrap) ? (a || b) : (a && b); 180*b3b94faaSDavid Teigland if (!rm) 181*b3b94faaSDavid Teigland continue; 182*b3b94faaSDavid Teigland 183*b3b94faaSDavid Teigland gfs2_ail2_empty_one(sdp, ai); 184*b3b94faaSDavid Teigland list_del(&ai->ai_list); 185*b3b94faaSDavid Teigland gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list)); 186*b3b94faaSDavid Teigland gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list)); 187*b3b94faaSDavid Teigland kfree(ai); 188*b3b94faaSDavid Teigland } 189*b3b94faaSDavid Teigland 190*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 191*b3b94faaSDavid Teigland } 192*b3b94faaSDavid Teigland 193*b3b94faaSDavid Teigland /** 194*b3b94faaSDavid Teigland * gfs2_log_reserve - Make a log reservation 195*b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 196*b3b94faaSDavid Teigland * @blks: The number of blocks to reserve 197*b3b94faaSDavid Teigland * 198*b3b94faaSDavid Teigland * Returns: errno 199*b3b94faaSDavid Teigland */ 200*b3b94faaSDavid Teigland 201*b3b94faaSDavid Teigland int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) 202*b3b94faaSDavid Teigland { 203*b3b94faaSDavid Teigland LIST_HEAD(list); 204*b3b94faaSDavid Teigland unsigned int try = 0; 205*b3b94faaSDavid Teigland 206*b3b94faaSDavid Teigland if (gfs2_assert_warn(sdp, blks) || 207*b3b94faaSDavid Teigland gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks)) 208*b3b94faaSDavid Teigland return -EINVAL; 209*b3b94faaSDavid Teigland 210*b3b94faaSDavid Teigland for (;;) { 211*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 212*b3b94faaSDavid Teigland 213*b3b94faaSDavid Teigland if (list_empty(&list)) { 214*b3b94faaSDavid Teigland list_add_tail(&list, &sdp->sd_log_blks_list); 215*b3b94faaSDavid Teigland while (sdp->sd_log_blks_list.next != &list) { 216*b3b94faaSDavid Teigland DECLARE_WAITQUEUE(__wait_chan, current); 217*b3b94faaSDavid Teigland set_current_state(TASK_UNINTERRUPTIBLE); 218*b3b94faaSDavid Teigland add_wait_queue(&sdp->sd_log_blks_wait, 219*b3b94faaSDavid Teigland &__wait_chan); 220*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 221*b3b94faaSDavid Teigland schedule(); 222*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 223*b3b94faaSDavid Teigland remove_wait_queue(&sdp->sd_log_blks_wait, 224*b3b94faaSDavid Teigland &__wait_chan); 225*b3b94faaSDavid Teigland set_current_state(TASK_RUNNING); 226*b3b94faaSDavid Teigland } 227*b3b94faaSDavid Teigland } 228*b3b94faaSDavid Teigland 229*b3b94faaSDavid Teigland /* Never give away the last block so we can 230*b3b94faaSDavid Teigland always pull the tail if we need to. */ 231*b3b94faaSDavid Teigland if (sdp->sd_log_blks_free > blks) { 232*b3b94faaSDavid Teigland sdp->sd_log_blks_free -= blks; 233*b3b94faaSDavid Teigland list_del(&list); 234*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 235*b3b94faaSDavid Teigland wake_up(&sdp->sd_log_blks_wait); 236*b3b94faaSDavid Teigland break; 237*b3b94faaSDavid Teigland } 238*b3b94faaSDavid Teigland 239*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 240*b3b94faaSDavid Teigland 241*b3b94faaSDavid Teigland gfs2_ail1_empty(sdp, 0); 242*b3b94faaSDavid Teigland gfs2_log_flush(sdp); 243*b3b94faaSDavid Teigland 244*b3b94faaSDavid Teigland if (try++) 245*b3b94faaSDavid Teigland gfs2_ail1_start(sdp, 0); 246*b3b94faaSDavid Teigland } 247*b3b94faaSDavid Teigland 248*b3b94faaSDavid Teigland lock_for_trans(sdp); 249*b3b94faaSDavid Teigland 250*b3b94faaSDavid Teigland return 0; 251*b3b94faaSDavid Teigland } 252*b3b94faaSDavid Teigland 253*b3b94faaSDavid Teigland /** 254*b3b94faaSDavid Teigland * gfs2_log_release - Release a given number of log blocks 255*b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 256*b3b94faaSDavid Teigland * @blks: The number of blocks 257*b3b94faaSDavid Teigland * 258*b3b94faaSDavid Teigland */ 259*b3b94faaSDavid Teigland 260*b3b94faaSDavid Teigland void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) 261*b3b94faaSDavid Teigland { 262*b3b94faaSDavid Teigland unlock_from_trans(sdp); 263*b3b94faaSDavid Teigland 264*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 265*b3b94faaSDavid Teigland sdp->sd_log_blks_free += blks; 266*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 267*b3b94faaSDavid Teigland sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); 268*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 269*b3b94faaSDavid Teigland } 270*b3b94faaSDavid Teigland 271*b3b94faaSDavid Teigland static uint64_t log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) 272*b3b94faaSDavid Teigland { 273*b3b94faaSDavid Teigland int new = 0; 274*b3b94faaSDavid Teigland uint64_t dbn; 275*b3b94faaSDavid Teigland int error; 276*b3b94faaSDavid Teigland 277*b3b94faaSDavid Teigland error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, &new, &dbn, NULL); 278*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !error && dbn); 279*b3b94faaSDavid Teigland 280*b3b94faaSDavid Teigland return dbn; 281*b3b94faaSDavid Teigland } 282*b3b94faaSDavid Teigland 283*b3b94faaSDavid Teigland /** 284*b3b94faaSDavid Teigland * log_distance - Compute distance between two journal blocks 285*b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 286*b3b94faaSDavid Teigland * @newer: The most recent journal block of the pair 287*b3b94faaSDavid Teigland * @older: The older journal block of the pair 288*b3b94faaSDavid Teigland * 289*b3b94faaSDavid Teigland * Compute the distance (in the journal direction) between two 290*b3b94faaSDavid Teigland * blocks in the journal 291*b3b94faaSDavid Teigland * 292*b3b94faaSDavid Teigland * Returns: the distance in blocks 293*b3b94faaSDavid Teigland */ 294*b3b94faaSDavid Teigland 295*b3b94faaSDavid Teigland static inline unsigned int log_distance(struct gfs2_sbd *sdp, 296*b3b94faaSDavid Teigland unsigned int newer, 297*b3b94faaSDavid Teigland unsigned int older) 298*b3b94faaSDavid Teigland { 299*b3b94faaSDavid Teigland int dist; 300*b3b94faaSDavid Teigland 301*b3b94faaSDavid Teigland dist = newer - older; 302*b3b94faaSDavid Teigland if (dist < 0) 303*b3b94faaSDavid Teigland dist += sdp->sd_jdesc->jd_blocks; 304*b3b94faaSDavid Teigland 305*b3b94faaSDavid Teigland return dist; 306*b3b94faaSDavid Teigland } 307*b3b94faaSDavid Teigland 308*b3b94faaSDavid Teigland static unsigned int current_tail(struct gfs2_sbd *sdp) 309*b3b94faaSDavid Teigland { 310*b3b94faaSDavid Teigland struct gfs2_ail *ai; 311*b3b94faaSDavid Teigland unsigned int tail; 312*b3b94faaSDavid Teigland 313*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 314*b3b94faaSDavid Teigland 315*b3b94faaSDavid Teigland if (list_empty(&sdp->sd_ail1_list)) 316*b3b94faaSDavid Teigland tail = sdp->sd_log_head; 317*b3b94faaSDavid Teigland else { 318*b3b94faaSDavid Teigland ai = list_entry(sdp->sd_ail1_list.prev, 319*b3b94faaSDavid Teigland struct gfs2_ail, ai_list); 320*b3b94faaSDavid Teigland tail = ai->ai_first; 321*b3b94faaSDavid Teigland } 322*b3b94faaSDavid Teigland 323*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 324*b3b94faaSDavid Teigland 325*b3b94faaSDavid Teigland return tail; 326*b3b94faaSDavid Teigland } 327*b3b94faaSDavid Teigland 328*b3b94faaSDavid Teigland static inline void log_incr_head(struct gfs2_sbd *sdp) 329*b3b94faaSDavid Teigland { 330*b3b94faaSDavid Teigland if (sdp->sd_log_flush_head == sdp->sd_log_tail) 331*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 332*b3b94faaSDavid Teigland sdp->sd_log_flush_head == sdp->sd_log_head); 333*b3b94faaSDavid Teigland 334*b3b94faaSDavid Teigland if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { 335*b3b94faaSDavid Teigland sdp->sd_log_flush_head = 0; 336*b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 1; 337*b3b94faaSDavid Teigland } 338*b3b94faaSDavid Teigland } 339*b3b94faaSDavid Teigland 340*b3b94faaSDavid Teigland /** 341*b3b94faaSDavid Teigland * gfs2_log_get_buf - Get and initialize a buffer to use for log control data 342*b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 343*b3b94faaSDavid Teigland * 344*b3b94faaSDavid Teigland * Returns: the buffer_head 345*b3b94faaSDavid Teigland */ 346*b3b94faaSDavid Teigland 347*b3b94faaSDavid Teigland struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) 348*b3b94faaSDavid Teigland { 349*b3b94faaSDavid Teigland uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); 350*b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 351*b3b94faaSDavid Teigland struct buffer_head *bh; 352*b3b94faaSDavid Teigland 353*b3b94faaSDavid Teigland lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); 354*b3b94faaSDavid Teigland list_add(&lb->lb_list, &sdp->sd_log_flush_list); 355*b3b94faaSDavid Teigland 356*b3b94faaSDavid Teigland bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); 357*b3b94faaSDavid Teigland lock_buffer(bh); 358*b3b94faaSDavid Teigland memset(bh->b_data, 0, bh->b_size); 359*b3b94faaSDavid Teigland set_buffer_uptodate(bh); 360*b3b94faaSDavid Teigland clear_buffer_dirty(bh); 361*b3b94faaSDavid Teigland unlock_buffer(bh); 362*b3b94faaSDavid Teigland 363*b3b94faaSDavid Teigland log_incr_head(sdp); 364*b3b94faaSDavid Teigland 365*b3b94faaSDavid Teigland return bh; 366*b3b94faaSDavid Teigland } 367*b3b94faaSDavid Teigland 368*b3b94faaSDavid Teigland /** 369*b3b94faaSDavid Teigland * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log 370*b3b94faaSDavid Teigland * @sdp: the filesystem 371*b3b94faaSDavid Teigland * @data: the data the buffer_head should point to 372*b3b94faaSDavid Teigland * 373*b3b94faaSDavid Teigland * Returns: the log buffer descriptor 374*b3b94faaSDavid Teigland */ 375*b3b94faaSDavid Teigland 376*b3b94faaSDavid Teigland struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, 377*b3b94faaSDavid Teigland struct buffer_head *real) 378*b3b94faaSDavid Teigland { 379*b3b94faaSDavid Teigland uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); 380*b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 381*b3b94faaSDavid Teigland struct buffer_head *bh; 382*b3b94faaSDavid Teigland 383*b3b94faaSDavid Teigland lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_KERNEL | __GFP_NOFAIL); 384*b3b94faaSDavid Teigland list_add(&lb->lb_list, &sdp->sd_log_flush_list); 385*b3b94faaSDavid Teigland lb->lb_real = real; 386*b3b94faaSDavid Teigland 387*b3b94faaSDavid Teigland bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); 388*b3b94faaSDavid Teigland atomic_set(&bh->b_count, 1); 389*b3b94faaSDavid Teigland bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); 390*b3b94faaSDavid Teigland set_bh_page(bh, virt_to_page(real->b_data), 391*b3b94faaSDavid Teigland ((unsigned long)real->b_data) & (PAGE_SIZE - 1)); 392*b3b94faaSDavid Teigland bh->b_blocknr = blkno; 393*b3b94faaSDavid Teigland bh->b_size = sdp->sd_sb.sb_bsize; 394*b3b94faaSDavid Teigland bh->b_bdev = sdp->sd_vfs->s_bdev; 395*b3b94faaSDavid Teigland 396*b3b94faaSDavid Teigland log_incr_head(sdp); 397*b3b94faaSDavid Teigland 398*b3b94faaSDavid Teigland return bh; 399*b3b94faaSDavid Teigland } 400*b3b94faaSDavid Teigland 401*b3b94faaSDavid Teigland static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull) 402*b3b94faaSDavid Teigland { 403*b3b94faaSDavid Teigland unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); 404*b3b94faaSDavid Teigland 405*b3b94faaSDavid Teigland ail2_empty(sdp, new_tail); 406*b3b94faaSDavid Teigland 407*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 408*b3b94faaSDavid Teigland sdp->sd_log_blks_free += dist - ((pull) ? 1 : 0); 409*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 410*b3b94faaSDavid Teigland sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); 411*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 412*b3b94faaSDavid Teigland 413*b3b94faaSDavid Teigland sdp->sd_log_tail = new_tail; 414*b3b94faaSDavid Teigland } 415*b3b94faaSDavid Teigland 416*b3b94faaSDavid Teigland /** 417*b3b94faaSDavid Teigland * log_write_header - Get and initialize a journal header buffer 418*b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 419*b3b94faaSDavid Teigland * 420*b3b94faaSDavid Teigland * Returns: the initialized log buffer descriptor 421*b3b94faaSDavid Teigland */ 422*b3b94faaSDavid Teigland 423*b3b94faaSDavid Teigland static void log_write_header(struct gfs2_sbd *sdp, uint32_t flags, int pull) 424*b3b94faaSDavid Teigland { 425*b3b94faaSDavid Teigland uint64_t blkno = log_bmap(sdp, sdp->sd_log_flush_head); 426*b3b94faaSDavid Teigland struct buffer_head *bh; 427*b3b94faaSDavid Teigland struct gfs2_log_header *lh; 428*b3b94faaSDavid Teigland unsigned int tail; 429*b3b94faaSDavid Teigland uint32_t hash; 430*b3b94faaSDavid Teigland 431*b3b94faaSDavid Teigland atomic_inc(&sdp->sd_log_flush_ondisk); 432*b3b94faaSDavid Teigland 433*b3b94faaSDavid Teigland bh = sb_getblk(sdp->sd_vfs, blkno); 434*b3b94faaSDavid Teigland lock_buffer(bh); 435*b3b94faaSDavid Teigland memset(bh->b_data, 0, bh->b_size); 436*b3b94faaSDavid Teigland set_buffer_uptodate(bh); 437*b3b94faaSDavid Teigland clear_buffer_dirty(bh); 438*b3b94faaSDavid Teigland unlock_buffer(bh); 439*b3b94faaSDavid Teigland 440*b3b94faaSDavid Teigland gfs2_ail1_empty(sdp, 0); 441*b3b94faaSDavid Teigland tail = current_tail(sdp); 442*b3b94faaSDavid Teigland 443*b3b94faaSDavid Teigland lh = (struct gfs2_log_header *)bh->b_data; 444*b3b94faaSDavid Teigland memset(lh, 0, sizeof(struct gfs2_log_header)); 445*b3b94faaSDavid Teigland lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); 446*b3b94faaSDavid Teigland lh->lh_header.mh_type = cpu_to_be16(GFS2_METATYPE_LH); 447*b3b94faaSDavid Teigland lh->lh_header.mh_format = cpu_to_be16(GFS2_FORMAT_LH); 448*b3b94faaSDavid Teigland lh->lh_sequence = be64_to_cpu(sdp->sd_log_sequence++); 449*b3b94faaSDavid Teigland lh->lh_flags = be32_to_cpu(flags); 450*b3b94faaSDavid Teigland lh->lh_tail = be32_to_cpu(tail); 451*b3b94faaSDavid Teigland lh->lh_blkno = be32_to_cpu(sdp->sd_log_flush_head); 452*b3b94faaSDavid Teigland hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); 453*b3b94faaSDavid Teigland lh->lh_hash = cpu_to_be32(hash); 454*b3b94faaSDavid Teigland 455*b3b94faaSDavid Teigland set_buffer_dirty(bh); 456*b3b94faaSDavid Teigland if (sync_dirty_buffer(bh)) 457*b3b94faaSDavid Teigland gfs2_io_error_bh(sdp, bh); 458*b3b94faaSDavid Teigland brelse(bh); 459*b3b94faaSDavid Teigland 460*b3b94faaSDavid Teigland if (sdp->sd_log_tail != tail) 461*b3b94faaSDavid Teigland log_pull_tail(sdp, tail, pull); 462*b3b94faaSDavid Teigland else 463*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !pull); 464*b3b94faaSDavid Teigland 465*b3b94faaSDavid Teigland sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); 466*b3b94faaSDavid Teigland log_incr_head(sdp); 467*b3b94faaSDavid Teigland } 468*b3b94faaSDavid Teigland 469*b3b94faaSDavid Teigland static void log_flush_commit(struct gfs2_sbd *sdp) 470*b3b94faaSDavid Teigland { 471*b3b94faaSDavid Teigland struct list_head *head = &sdp->sd_log_flush_list; 472*b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 473*b3b94faaSDavid Teigland struct buffer_head *bh; 474*b3b94faaSDavid Teigland unsigned int d; 475*b3b94faaSDavid Teigland 476*b3b94faaSDavid Teigland d = log_distance(sdp, sdp->sd_log_flush_head, sdp->sd_log_head); 477*b3b94faaSDavid Teigland 478*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, d + 1 == sdp->sd_log_blks_reserved); 479*b3b94faaSDavid Teigland 480*b3b94faaSDavid Teigland while (!list_empty(head)) { 481*b3b94faaSDavid Teigland lb = list_entry(head->next, struct gfs2_log_buf, lb_list); 482*b3b94faaSDavid Teigland list_del(&lb->lb_list); 483*b3b94faaSDavid Teigland bh = lb->lb_bh; 484*b3b94faaSDavid Teigland 485*b3b94faaSDavid Teigland wait_on_buffer(bh); 486*b3b94faaSDavid Teigland if (!buffer_uptodate(bh)) 487*b3b94faaSDavid Teigland gfs2_io_error_bh(sdp, bh); 488*b3b94faaSDavid Teigland if (lb->lb_real) { 489*b3b94faaSDavid Teigland while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ 490*b3b94faaSDavid Teigland schedule(); 491*b3b94faaSDavid Teigland free_buffer_head(bh); 492*b3b94faaSDavid Teigland } else 493*b3b94faaSDavid Teigland brelse(bh); 494*b3b94faaSDavid Teigland kfree(lb); 495*b3b94faaSDavid Teigland } 496*b3b94faaSDavid Teigland 497*b3b94faaSDavid Teigland log_write_header(sdp, 0, 0); 498*b3b94faaSDavid Teigland } 499*b3b94faaSDavid Teigland 500*b3b94faaSDavid Teigland /** 501*b3b94faaSDavid Teigland * gfs2_log_flush_i - flush incore transaction(s) 502*b3b94faaSDavid Teigland * @sdp: the filesystem 503*b3b94faaSDavid Teigland * @gl: The glock structure to flush. If NULL, flush the whole incore log 504*b3b94faaSDavid Teigland * 505*b3b94faaSDavid Teigland */ 506*b3b94faaSDavid Teigland 507*b3b94faaSDavid Teigland void gfs2_log_flush_i(struct gfs2_sbd *sdp, struct gfs2_glock *gl) 508*b3b94faaSDavid Teigland { 509*b3b94faaSDavid Teigland struct gfs2_ail *ai; 510*b3b94faaSDavid Teigland 511*b3b94faaSDavid Teigland atomic_inc(&sdp->sd_log_flush_incore); 512*b3b94faaSDavid Teigland 513*b3b94faaSDavid Teigland ai = kzalloc(sizeof(struct gfs2_ail), GFP_KERNEL | __GFP_NOFAIL); 514*b3b94faaSDavid Teigland INIT_LIST_HEAD(&ai->ai_ail1_list); 515*b3b94faaSDavid Teigland INIT_LIST_HEAD(&ai->ai_ail2_list); 516*b3b94faaSDavid Teigland 517*b3b94faaSDavid Teigland gfs2_lock_for_flush(sdp); 518*b3b94faaSDavid Teigland down(&sdp->sd_log_flush_lock); 519*b3b94faaSDavid Teigland 520*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 521*b3b94faaSDavid Teigland sdp->sd_log_num_buf == sdp->sd_log_commited_buf); 522*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 523*b3b94faaSDavid Teigland sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); 524*b3b94faaSDavid Teigland 525*b3b94faaSDavid Teigland if (gl && list_empty(&gl->gl_le.le_list)) { 526*b3b94faaSDavid Teigland up(&sdp->sd_log_flush_lock); 527*b3b94faaSDavid Teigland gfs2_unlock_from_flush(sdp); 528*b3b94faaSDavid Teigland kfree(ai); 529*b3b94faaSDavid Teigland return; 530*b3b94faaSDavid Teigland } 531*b3b94faaSDavid Teigland 532*b3b94faaSDavid Teigland sdp->sd_log_flush_head = sdp->sd_log_head; 533*b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 0; 534*b3b94faaSDavid Teigland ai->ai_first = sdp->sd_log_flush_head; 535*b3b94faaSDavid Teigland 536*b3b94faaSDavid Teigland lops_before_commit(sdp); 537*b3b94faaSDavid Teigland if (!list_empty(&sdp->sd_log_flush_list)) 538*b3b94faaSDavid Teigland log_flush_commit(sdp); 539*b3b94faaSDavid Teigland else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle) 540*b3b94faaSDavid Teigland log_write_header(sdp, 0, PULL); 541*b3b94faaSDavid Teigland lops_after_commit(sdp, ai); 542*b3b94faaSDavid Teigland 543*b3b94faaSDavid Teigland sdp->sd_log_head = sdp->sd_log_flush_head; 544*b3b94faaSDavid Teigland if (sdp->sd_log_flush_wrapped) 545*b3b94faaSDavid Teigland sdp->sd_log_wraps++; 546*b3b94faaSDavid Teigland 547*b3b94faaSDavid Teigland sdp->sd_log_blks_reserved = 548*b3b94faaSDavid Teigland sdp->sd_log_commited_buf = 549*b3b94faaSDavid Teigland sdp->sd_log_commited_revoke = 0; 550*b3b94faaSDavid Teigland 551*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 552*b3b94faaSDavid Teigland if (!list_empty(&ai->ai_ail1_list)) { 553*b3b94faaSDavid Teigland list_add(&ai->ai_list, &sdp->sd_ail1_list); 554*b3b94faaSDavid Teigland ai = NULL; 555*b3b94faaSDavid Teigland } 556*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 557*b3b94faaSDavid Teigland 558*b3b94faaSDavid Teigland up(&sdp->sd_log_flush_lock); 559*b3b94faaSDavid Teigland sdp->sd_vfs->s_dirt = 0; 560*b3b94faaSDavid Teigland gfs2_unlock_from_flush(sdp); 561*b3b94faaSDavid Teigland 562*b3b94faaSDavid Teigland kfree(ai); 563*b3b94faaSDavid Teigland } 564*b3b94faaSDavid Teigland 565*b3b94faaSDavid Teigland static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 566*b3b94faaSDavid Teigland { 567*b3b94faaSDavid Teigland unsigned int reserved = 1; 568*b3b94faaSDavid Teigland unsigned int old; 569*b3b94faaSDavid Teigland 570*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 571*b3b94faaSDavid Teigland 572*b3b94faaSDavid Teigland sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm; 573*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0); 574*b3b94faaSDavid Teigland sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; 575*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); 576*b3b94faaSDavid Teigland 577*b3b94faaSDavid Teigland if (sdp->sd_log_commited_buf) 578*b3b94faaSDavid Teigland reserved += 1 + sdp->sd_log_commited_buf + sdp->sd_log_commited_buf/503; 579*b3b94faaSDavid Teigland if (sdp->sd_log_commited_revoke) 580*b3b94faaSDavid Teigland reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, 581*b3b94faaSDavid Teigland sizeof(uint64_t)); 582*b3b94faaSDavid Teigland 583*b3b94faaSDavid Teigland old = sdp->sd_log_blks_free; 584*b3b94faaSDavid Teigland sdp->sd_log_blks_free += tr->tr_reserved - 585*b3b94faaSDavid Teigland (reserved - sdp->sd_log_blks_reserved); 586*b3b94faaSDavid Teigland 587*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 588*b3b94faaSDavid Teigland sdp->sd_log_blks_free >= old); 589*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 590*b3b94faaSDavid Teigland sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); 591*b3b94faaSDavid Teigland 592*b3b94faaSDavid Teigland sdp->sd_log_blks_reserved = reserved; 593*b3b94faaSDavid Teigland 594*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 595*b3b94faaSDavid Teigland } 596*b3b94faaSDavid Teigland 597*b3b94faaSDavid Teigland /** 598*b3b94faaSDavid Teigland * gfs2_log_commit - Commit a transaction to the log 599*b3b94faaSDavid Teigland * @sdp: the filesystem 600*b3b94faaSDavid Teigland * @tr: the transaction 601*b3b94faaSDavid Teigland * 602*b3b94faaSDavid Teigland * Returns: errno 603*b3b94faaSDavid Teigland */ 604*b3b94faaSDavid Teigland 605*b3b94faaSDavid Teigland void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 606*b3b94faaSDavid Teigland { 607*b3b94faaSDavid Teigland log_refund(sdp, tr); 608*b3b94faaSDavid Teigland lops_incore_commit(sdp, tr); 609*b3b94faaSDavid Teigland 610*b3b94faaSDavid Teigland sdp->sd_vfs->s_dirt = 1; 611*b3b94faaSDavid Teigland unlock_from_trans(sdp); 612*b3b94faaSDavid Teigland 613*b3b94faaSDavid Teigland kfree(tr); 614*b3b94faaSDavid Teigland 615*b3b94faaSDavid Teigland gfs2_log_lock(sdp); 616*b3b94faaSDavid Teigland if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) { 617*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 618*b3b94faaSDavid Teigland gfs2_log_flush(sdp); 619*b3b94faaSDavid Teigland } else 620*b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 621*b3b94faaSDavid Teigland } 622*b3b94faaSDavid Teigland 623*b3b94faaSDavid Teigland /** 624*b3b94faaSDavid Teigland * gfs2_log_shutdown - write a shutdown header into a journal 625*b3b94faaSDavid Teigland * @sdp: the filesystem 626*b3b94faaSDavid Teigland * 627*b3b94faaSDavid Teigland */ 628*b3b94faaSDavid Teigland 629*b3b94faaSDavid Teigland void gfs2_log_shutdown(struct gfs2_sbd *sdp) 630*b3b94faaSDavid Teigland { 631*b3b94faaSDavid Teigland down(&sdp->sd_log_flush_lock); 632*b3b94faaSDavid Teigland 633*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !atomic_read(&sdp->sd_log_trans_count)); 634*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); 635*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); 636*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); 637*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); 638*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); 639*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); 640*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); 641*b3b94faaSDavid Teigland 642*b3b94faaSDavid Teigland sdp->sd_log_flush_head = sdp->sd_log_head; 643*b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 0; 644*b3b94faaSDavid Teigland 645*b3b94faaSDavid Teigland log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0); 646*b3b94faaSDavid Teigland 647*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free == 648*b3b94faaSDavid Teigland sdp->sd_jdesc->jd_blocks); 649*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, sdp->sd_log_head == sdp->sd_log_tail); 650*b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail2_list)); 651*b3b94faaSDavid Teigland 652*b3b94faaSDavid Teigland sdp->sd_log_head = sdp->sd_log_flush_head; 653*b3b94faaSDavid Teigland if (sdp->sd_log_flush_wrapped) 654*b3b94faaSDavid Teigland sdp->sd_log_wraps++; 655*b3b94faaSDavid Teigland sdp->sd_log_tail = sdp->sd_log_head; 656*b3b94faaSDavid Teigland 657*b3b94faaSDavid Teigland up(&sdp->sd_log_flush_lock); 658*b3b94faaSDavid Teigland } 659*b3b94faaSDavid Teigland 660