1b3b94faaSDavid Teigland /* 2b3b94faaSDavid Teigland * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 33a8a9a10SSteven Whitehouse * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 4b3b94faaSDavid Teigland * 5b3b94faaSDavid Teigland * This copyrighted material is made available to anyone wishing to use, 6b3b94faaSDavid Teigland * modify, copy, or redistribute it subject to the terms and conditions 7e9fc2aa0SSteven Whitehouse * of the GNU General Public License version 2. 8b3b94faaSDavid Teigland */ 9b3b94faaSDavid Teigland 10b3b94faaSDavid Teigland #include <linux/sched.h> 11b3b94faaSDavid Teigland #include <linux/slab.h> 12b3b94faaSDavid Teigland #include <linux/spinlock.h> 13b3b94faaSDavid Teigland #include <linux/completion.h> 14b3b94faaSDavid Teigland #include <linux/buffer_head.h> 155c676f6dSSteven Whitehouse #include <linux/gfs2_ondisk.h> 1671b86f56SSteven Whitehouse #include <linux/crc32.h> 177d308590SFabio Massimo Di Nitto #include <linux/lm_interface.h> 18a25311c8SSteven Whitehouse #include <linux/delay.h> 19b3b94faaSDavid Teigland 20b3b94faaSDavid Teigland #include "gfs2.h" 215c676f6dSSteven Whitehouse #include "incore.h" 22b3b94faaSDavid Teigland #include "bmap.h" 23b3b94faaSDavid Teigland #include "glock.h" 24b3b94faaSDavid Teigland #include "log.h" 25b3b94faaSDavid Teigland #include "lops.h" 26b3b94faaSDavid Teigland #include "meta_io.h" 275c676f6dSSteven Whitehouse #include "util.h" 2871b86f56SSteven Whitehouse #include "dir.h" 29b3b94faaSDavid Teigland 30b3b94faaSDavid Teigland #define PULL 1 31b3b94faaSDavid Teigland 32b3b94faaSDavid Teigland /** 33b3b94faaSDavid Teigland * gfs2_struct2blk - compute stuff 34b3b94faaSDavid Teigland * @sdp: the filesystem 35b3b94faaSDavid Teigland * @nstruct: the number of structures 36b3b94faaSDavid Teigland * @ssize: the size of the structures 37b3b94faaSDavid Teigland * 38b3b94faaSDavid Teigland * Compute the number of log descriptor blocks needed to hold a certain number 39b3b94faaSDavid Teigland * of structures of a certain size. 40b3b94faaSDavid Teigland * 41b3b94faaSDavid Teigland * Returns: the number of blocks needed (minimum is always 1) 42b3b94faaSDavid Teigland */ 43b3b94faaSDavid Teigland 44b3b94faaSDavid Teigland unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, 45b3b94faaSDavid Teigland unsigned int ssize) 46b3b94faaSDavid Teigland { 47b3b94faaSDavid Teigland unsigned int blks; 48b3b94faaSDavid Teigland unsigned int first, second; 49b3b94faaSDavid Teigland 50b3b94faaSDavid Teigland blks = 1; 51faa31ce8SSteven Whitehouse first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize; 52b3b94faaSDavid Teigland 53b3b94faaSDavid Teigland if (nstruct > first) { 54568f4c96SSteven Whitehouse second = (sdp->sd_sb.sb_bsize - 55568f4c96SSteven Whitehouse sizeof(struct gfs2_meta_header)) / ssize; 565c676f6dSSteven Whitehouse blks += DIV_ROUND_UP(nstruct - first, second); 57b3b94faaSDavid Teigland } 58b3b94faaSDavid Teigland 59b3b94faaSDavid Teigland return blks; 60b3b94faaSDavid Teigland } 61b3b94faaSDavid Teigland 62ddacfaf7SSteven Whitehouse /** 63ddacfaf7SSteven Whitehouse * gfs2_ail1_start_one - Start I/O on a part of the AIL 64ddacfaf7SSteven Whitehouse * @sdp: the filesystem 65ddacfaf7SSteven Whitehouse * @tr: the part of the AIL 66ddacfaf7SSteven Whitehouse * 67ddacfaf7SSteven Whitehouse */ 68ddacfaf7SSteven Whitehouse 69ddacfaf7SSteven Whitehouse static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) 70ddacfaf7SSteven Whitehouse { 71ddacfaf7SSteven Whitehouse struct gfs2_bufdata *bd, *s; 72ddacfaf7SSteven Whitehouse struct buffer_head *bh; 73ddacfaf7SSteven Whitehouse int retry; 74ddacfaf7SSteven Whitehouse 75ddacfaf7SSteven Whitehouse BUG_ON(!spin_is_locked(&sdp->sd_log_lock)); 76ddacfaf7SSteven Whitehouse 77ddacfaf7SSteven Whitehouse do { 78ddacfaf7SSteven Whitehouse retry = 0; 79ddacfaf7SSteven Whitehouse 80ddacfaf7SSteven Whitehouse list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, 81ddacfaf7SSteven Whitehouse bd_ail_st_list) { 82ddacfaf7SSteven Whitehouse bh = bd->bd_bh; 83ddacfaf7SSteven Whitehouse 84ddacfaf7SSteven Whitehouse gfs2_assert(sdp, bd->bd_ail == ai); 85ddacfaf7SSteven Whitehouse 868fb68595SRobert Peterson if (!bh){ 878fb68595SRobert Peterson list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); 888fb68595SRobert Peterson continue; 898fb68595SRobert Peterson } 908fb68595SRobert Peterson 91ddacfaf7SSteven Whitehouse if (!buffer_busy(bh)) { 92ddacfaf7SSteven Whitehouse if (!buffer_uptodate(bh)) { 93ddacfaf7SSteven Whitehouse gfs2_log_unlock(sdp); 94ddacfaf7SSteven Whitehouse gfs2_io_error_bh(sdp, bh); 95ddacfaf7SSteven Whitehouse gfs2_log_lock(sdp); 96ddacfaf7SSteven Whitehouse } 97ddacfaf7SSteven Whitehouse list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); 98ddacfaf7SSteven Whitehouse continue; 99ddacfaf7SSteven Whitehouse } 100ddacfaf7SSteven Whitehouse 101ddacfaf7SSteven Whitehouse if (!buffer_dirty(bh)) 102ddacfaf7SSteven Whitehouse continue; 103ddacfaf7SSteven Whitehouse 104ddacfaf7SSteven Whitehouse list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list); 105ddacfaf7SSteven Whitehouse 106ddacfaf7SSteven Whitehouse gfs2_log_unlock(sdp); 107ddacfaf7SSteven Whitehouse wait_on_buffer(bh); 108ddacfaf7SSteven Whitehouse ll_rw_block(WRITE, 1, &bh); 109ddacfaf7SSteven Whitehouse gfs2_log_lock(sdp); 110ddacfaf7SSteven Whitehouse 111ddacfaf7SSteven Whitehouse retry = 1; 112ddacfaf7SSteven Whitehouse break; 113ddacfaf7SSteven Whitehouse } 114ddacfaf7SSteven Whitehouse } while (retry); 115ddacfaf7SSteven Whitehouse } 116ddacfaf7SSteven Whitehouse 117ddacfaf7SSteven Whitehouse /** 118ddacfaf7SSteven Whitehouse * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced 119ddacfaf7SSteven Whitehouse * @sdp: the filesystem 120ddacfaf7SSteven Whitehouse * @ai: the AIL entry 121ddacfaf7SSteven Whitehouse * 122ddacfaf7SSteven Whitehouse */ 123ddacfaf7SSteven Whitehouse 124ddacfaf7SSteven Whitehouse static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags) 125ddacfaf7SSteven Whitehouse { 126ddacfaf7SSteven Whitehouse struct gfs2_bufdata *bd, *s; 127ddacfaf7SSteven Whitehouse struct buffer_head *bh; 128ddacfaf7SSteven Whitehouse 129ddacfaf7SSteven Whitehouse list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, 130ddacfaf7SSteven Whitehouse bd_ail_st_list) { 131ddacfaf7SSteven Whitehouse bh = bd->bd_bh; 132ddacfaf7SSteven Whitehouse 1338fb68595SRobert Peterson if (!bh){ 1348fb68595SRobert Peterson list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); 1358fb68595SRobert Peterson continue; 1368fb68595SRobert Peterson } 1378fb68595SRobert Peterson 138ddacfaf7SSteven Whitehouse gfs2_assert(sdp, bd->bd_ail == ai); 139ddacfaf7SSteven Whitehouse 140ddacfaf7SSteven Whitehouse if (buffer_busy(bh)) { 141ddacfaf7SSteven Whitehouse if (flags & DIO_ALL) 142ddacfaf7SSteven Whitehouse continue; 143ddacfaf7SSteven Whitehouse else 144ddacfaf7SSteven Whitehouse break; 145ddacfaf7SSteven Whitehouse } 146ddacfaf7SSteven Whitehouse 147ddacfaf7SSteven Whitehouse if (!buffer_uptodate(bh)) 148ddacfaf7SSteven Whitehouse gfs2_io_error_bh(sdp, bh); 149ddacfaf7SSteven Whitehouse 150ddacfaf7SSteven Whitehouse list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list); 151ddacfaf7SSteven Whitehouse } 152ddacfaf7SSteven Whitehouse 153ddacfaf7SSteven Whitehouse return list_empty(&ai->ai_ail1_list); 154ddacfaf7SSteven Whitehouse } 155ddacfaf7SSteven Whitehouse 156a25311c8SSteven Whitehouse static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags) 157b3b94faaSDavid Teigland { 158b3b94faaSDavid Teigland struct list_head *head = &sdp->sd_ail1_list; 159cd915493SSteven Whitehouse u64 sync_gen; 16074669416SSteven Whitehouse struct list_head *first; 16174669416SSteven Whitehouse struct gfs2_ail *first_ai, *ai, *tmp; 16274669416SSteven Whitehouse int done = 0; 163b3b94faaSDavid Teigland 164b3b94faaSDavid Teigland gfs2_log_lock(sdp); 165b3b94faaSDavid Teigland if (list_empty(head)) { 166b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 167b3b94faaSDavid Teigland return; 168b3b94faaSDavid Teigland } 169b3b94faaSDavid Teigland sync_gen = sdp->sd_ail_sync_gen++; 170b3b94faaSDavid Teigland 171b3b94faaSDavid Teigland first = head->prev; 172b3b94faaSDavid Teigland first_ai = list_entry(first, struct gfs2_ail, ai_list); 173b3b94faaSDavid Teigland first_ai->ai_sync_gen = sync_gen; 17474669416SSteven Whitehouse gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */ 175b3b94faaSDavid Teigland 176b3b94faaSDavid Teigland if (flags & DIO_ALL) 177b3b94faaSDavid Teigland first = NULL; 178b3b94faaSDavid Teigland 17974669416SSteven Whitehouse while(!done) { 180484adff8SSteven Whitehouse if (first && (head->prev != first || 181b3b94faaSDavid Teigland gfs2_ail1_empty_one(sdp, first_ai, 0))) 182b3b94faaSDavid Teigland break; 183b3b94faaSDavid Teigland 18474669416SSteven Whitehouse done = 1; 18574669416SSteven Whitehouse list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) { 186b3b94faaSDavid Teigland if (ai->ai_sync_gen >= sync_gen) 187b3b94faaSDavid Teigland continue; 188b3b94faaSDavid Teigland ai->ai_sync_gen = sync_gen; 18974669416SSteven Whitehouse gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */ 19074669416SSteven Whitehouse done = 0; 191b3b94faaSDavid Teigland break; 192b3b94faaSDavid Teigland } 193b3b94faaSDavid Teigland } 194b3b94faaSDavid Teigland 195b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 196b3b94faaSDavid Teigland } 197b3b94faaSDavid Teigland 198b3b94faaSDavid Teigland int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags) 199b3b94faaSDavid Teigland { 200b3b94faaSDavid Teigland struct gfs2_ail *ai, *s; 201b3b94faaSDavid Teigland int ret; 202b3b94faaSDavid Teigland 203b3b94faaSDavid Teigland gfs2_log_lock(sdp); 204b3b94faaSDavid Teigland 205b3b94faaSDavid Teigland list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) { 206b3b94faaSDavid Teigland if (gfs2_ail1_empty_one(sdp, ai, flags)) 207b3b94faaSDavid Teigland list_move(&ai->ai_list, &sdp->sd_ail2_list); 208b3b94faaSDavid Teigland else if (!(flags & DIO_ALL)) 209b3b94faaSDavid Teigland break; 210b3b94faaSDavid Teigland } 211b3b94faaSDavid Teigland 212b3b94faaSDavid Teigland ret = list_empty(&sdp->sd_ail1_list); 213b3b94faaSDavid Teigland 214b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 215b3b94faaSDavid Teigland 216b3b94faaSDavid Teigland return ret; 217b3b94faaSDavid Teigland } 218b3b94faaSDavid Teigland 219ddacfaf7SSteven Whitehouse 220ddacfaf7SSteven Whitehouse /** 221ddacfaf7SSteven Whitehouse * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced 222ddacfaf7SSteven Whitehouse * @sdp: the filesystem 223ddacfaf7SSteven Whitehouse * @ai: the AIL entry 224ddacfaf7SSteven Whitehouse * 225ddacfaf7SSteven Whitehouse */ 226ddacfaf7SSteven Whitehouse 227ddacfaf7SSteven Whitehouse static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai) 228ddacfaf7SSteven Whitehouse { 229ddacfaf7SSteven Whitehouse struct list_head *head = &ai->ai_ail2_list; 230ddacfaf7SSteven Whitehouse struct gfs2_bufdata *bd; 231ddacfaf7SSteven Whitehouse 232ddacfaf7SSteven Whitehouse while (!list_empty(head)) { 233ddacfaf7SSteven Whitehouse bd = list_entry(head->prev, struct gfs2_bufdata, 234ddacfaf7SSteven Whitehouse bd_ail_st_list); 235ddacfaf7SSteven Whitehouse gfs2_assert(sdp, bd->bd_ail == ai); 236ddacfaf7SSteven Whitehouse bd->bd_ail = NULL; 237ddacfaf7SSteven Whitehouse list_del(&bd->bd_ail_st_list); 238ddacfaf7SSteven Whitehouse list_del(&bd->bd_ail_gl_list); 239ddacfaf7SSteven Whitehouse atomic_dec(&bd->bd_gl->gl_ail_count); 2408fb68595SRobert Peterson if (bd->bd_bh) 241ddacfaf7SSteven Whitehouse brelse(bd->bd_bh); 2428fb68595SRobert Peterson else 2438fb68595SRobert Peterson kmem_cache_free(gfs2_bufdata_cachep, bd); 244ddacfaf7SSteven Whitehouse } 245ddacfaf7SSteven Whitehouse } 246ddacfaf7SSteven Whitehouse 247b3b94faaSDavid Teigland static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail) 248b3b94faaSDavid Teigland { 249b3b94faaSDavid Teigland struct gfs2_ail *ai, *safe; 250b3b94faaSDavid Teigland unsigned int old_tail = sdp->sd_log_tail; 251b3b94faaSDavid Teigland int wrap = (new_tail < old_tail); 252b3b94faaSDavid Teigland int a, b, rm; 253b3b94faaSDavid Teigland 254b3b94faaSDavid Teigland gfs2_log_lock(sdp); 255b3b94faaSDavid Teigland 256b3b94faaSDavid Teigland list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) { 257b3b94faaSDavid Teigland a = (old_tail <= ai->ai_first); 258b3b94faaSDavid Teigland b = (ai->ai_first < new_tail); 259b3b94faaSDavid Teigland rm = (wrap) ? (a || b) : (a && b); 260b3b94faaSDavid Teigland if (!rm) 261b3b94faaSDavid Teigland continue; 262b3b94faaSDavid Teigland 263b3b94faaSDavid Teigland gfs2_ail2_empty_one(sdp, ai); 264b3b94faaSDavid Teigland list_del(&ai->ai_list); 265b3b94faaSDavid Teigland gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list)); 266b3b94faaSDavid Teigland gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list)); 267b3b94faaSDavid Teigland kfree(ai); 268b3b94faaSDavid Teigland } 269b3b94faaSDavid Teigland 270b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 271b3b94faaSDavid Teigland } 272b3b94faaSDavid Teigland 273b3b94faaSDavid Teigland /** 274b3b94faaSDavid Teigland * gfs2_log_reserve - Make a log reservation 275b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 276b3b94faaSDavid Teigland * @blks: The number of blocks to reserve 277b3b94faaSDavid Teigland * 27889918647SSteven Whitehouse * Note that we never give out the last few blocks of the journal. Thats 2792332c443SRobert Peterson * due to the fact that there is a small number of header blocks 280b004157aSSteven Whitehouse * associated with each log flush. The exact number can't be known until 281b004157aSSteven Whitehouse * flush time, so we ensure that we have just enough free blocks at all 282b004157aSSteven Whitehouse * times to avoid running out during a log flush. 283b004157aSSteven Whitehouse * 284b3b94faaSDavid Teigland * Returns: errno 285b3b94faaSDavid Teigland */ 286b3b94faaSDavid Teigland 287b3b94faaSDavid Teigland int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) 288b3b94faaSDavid Teigland { 289b3b94faaSDavid Teigland unsigned int try = 0; 29089918647SSteven Whitehouse unsigned reserved_blks = 6 * (4096 / sdp->sd_vfs->s_blocksize); 291b3b94faaSDavid Teigland 292b3b94faaSDavid Teigland if (gfs2_assert_warn(sdp, blks) || 293b3b94faaSDavid Teigland gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks)) 294b3b94faaSDavid Teigland return -EINVAL; 295b3b94faaSDavid Teigland 29671b86f56SSteven Whitehouse mutex_lock(&sdp->sd_log_reserve_mutex); 297b3b94faaSDavid Teigland gfs2_log_lock(sdp); 29889918647SSteven Whitehouse while(sdp->sd_log_blks_free <= (blks + reserved_blks)) { 299b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 300b3b94faaSDavid Teigland gfs2_ail1_empty(sdp, 0); 301b09e593dSSteven Whitehouse gfs2_log_flush(sdp, NULL); 302b3b94faaSDavid Teigland 303b3b94faaSDavid Teigland if (try++) 304b3b94faaSDavid Teigland gfs2_ail1_start(sdp, 0); 305484adff8SSteven Whitehouse gfs2_log_lock(sdp); 306b3b94faaSDavid Teigland } 307484adff8SSteven Whitehouse sdp->sd_log_blks_free -= blks; 308484adff8SSteven Whitehouse gfs2_log_unlock(sdp); 309484adff8SSteven Whitehouse mutex_unlock(&sdp->sd_log_reserve_mutex); 310484adff8SSteven Whitehouse 311484adff8SSteven Whitehouse down_read(&sdp->sd_log_flush_lock); 312b3b94faaSDavid Teigland 313b3b94faaSDavid Teigland return 0; 314b3b94faaSDavid Teigland } 315b3b94faaSDavid Teigland 316b3b94faaSDavid Teigland /** 317b3b94faaSDavid Teigland * gfs2_log_release - Release a given number of log blocks 318b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 319b3b94faaSDavid Teigland * @blks: The number of blocks 320b3b94faaSDavid Teigland * 321b3b94faaSDavid Teigland */ 322b3b94faaSDavid Teigland 323b3b94faaSDavid Teigland void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) 324b3b94faaSDavid Teigland { 325b3b94faaSDavid Teigland 326b3b94faaSDavid Teigland gfs2_log_lock(sdp); 327b3b94faaSDavid Teigland sdp->sd_log_blks_free += blks; 328b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 329b3b94faaSDavid Teigland sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); 330b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 331ed386507SSteven Whitehouse up_read(&sdp->sd_log_flush_lock); 332b3b94faaSDavid Teigland } 333b3b94faaSDavid Teigland 334cd915493SSteven Whitehouse static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) 335b3b94faaSDavid Teigland { 33623591256SSteven Whitehouse struct inode *inode = sdp->sd_jdesc->jd_inode; 337b3b94faaSDavid Teigland int error; 33823591256SSteven Whitehouse struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; 339b3b94faaSDavid Teigland 34023591256SSteven Whitehouse bh_map.b_size = 1 << inode->i_blkbits; 34123591256SSteven Whitehouse error = gfs2_block_map(inode, lbn, 0, &bh_map); 3427a6bbacbSSteven Whitehouse if (error || !bh_map.b_blocknr) 343aed3255fSRyusuke Konishi printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, 344aed3255fSRyusuke Konishi (unsigned long long)bh_map.b_blocknr, lbn); 3457a6bbacbSSteven Whitehouse gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr); 346b3b94faaSDavid Teigland 3477a6bbacbSSteven Whitehouse return bh_map.b_blocknr; 348b3b94faaSDavid Teigland } 349b3b94faaSDavid Teigland 350b3b94faaSDavid Teigland /** 351b3b94faaSDavid Teigland * log_distance - Compute distance between two journal blocks 352b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 353b3b94faaSDavid Teigland * @newer: The most recent journal block of the pair 354b3b94faaSDavid Teigland * @older: The older journal block of the pair 355b3b94faaSDavid Teigland * 356b3b94faaSDavid Teigland * Compute the distance (in the journal direction) between two 357b3b94faaSDavid Teigland * blocks in the journal 358b3b94faaSDavid Teigland * 359b3b94faaSDavid Teigland * Returns: the distance in blocks 360b3b94faaSDavid Teigland */ 361b3b94faaSDavid Teigland 362faa31ce8SSteven Whitehouse static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer, 363b3b94faaSDavid Teigland unsigned int older) 364b3b94faaSDavid Teigland { 365b3b94faaSDavid Teigland int dist; 366b3b94faaSDavid Teigland 367b3b94faaSDavid Teigland dist = newer - older; 368b3b94faaSDavid Teigland if (dist < 0) 369b3b94faaSDavid Teigland dist += sdp->sd_jdesc->jd_blocks; 370b3b94faaSDavid Teigland 371b3b94faaSDavid Teigland return dist; 372b3b94faaSDavid Teigland } 373b3b94faaSDavid Teigland 3742332c443SRobert Peterson /** 3752332c443SRobert Peterson * calc_reserved - Calculate the number of blocks to reserve when 3762332c443SRobert Peterson * refunding a transaction's unused buffers. 3772332c443SRobert Peterson * @sdp: The GFS2 superblock 3782332c443SRobert Peterson * 3792332c443SRobert Peterson * This is complex. We need to reserve room for all our currently used 3802332c443SRobert Peterson * metadata buffers (e.g. normal file I/O rewriting file time stamps) and 3812332c443SRobert Peterson * all our journaled data buffers for journaled files (e.g. files in the 3822332c443SRobert Peterson * meta_fs like rindex, or files for which chattr +j was done.) 3832332c443SRobert Peterson * If we don't reserve enough space, gfs2_log_refund and gfs2_log_flush 3842332c443SRobert Peterson * will count it as free space (sd_log_blks_free) and corruption will follow. 3852332c443SRobert Peterson * 3862332c443SRobert Peterson * We can have metadata bufs and jdata bufs in the same journal. So each 3872332c443SRobert Peterson * type gets its own log header, for which we need to reserve a block. 3882332c443SRobert Peterson * In fact, each type has the potential for needing more than one header 3892332c443SRobert Peterson * in cases where we have more buffers than will fit on a journal page. 3902332c443SRobert Peterson * Metadata journal entries take up half the space of journaled buffer entries. 3912332c443SRobert Peterson * Thus, metadata entries have buf_limit (502) and journaled buffers have 3922332c443SRobert Peterson * databuf_limit (251) before they cause a wrap around. 3932332c443SRobert Peterson * 3942332c443SRobert Peterson * Also, we need to reserve blocks for revoke journal entries and one for an 3952332c443SRobert Peterson * overall header for the lot. 3962332c443SRobert Peterson * 3972332c443SRobert Peterson * Returns: the number of blocks reserved 3982332c443SRobert Peterson */ 3992332c443SRobert Peterson static unsigned int calc_reserved(struct gfs2_sbd *sdp) 4002332c443SRobert Peterson { 4012332c443SRobert Peterson unsigned int reserved = 0; 4022332c443SRobert Peterson unsigned int mbuf_limit, metabufhdrs_needed; 4032332c443SRobert Peterson unsigned int dbuf_limit, databufhdrs_needed; 4042332c443SRobert Peterson unsigned int revokes = 0; 4052332c443SRobert Peterson 4062332c443SRobert Peterson mbuf_limit = buf_limit(sdp); 4072332c443SRobert Peterson metabufhdrs_needed = (sdp->sd_log_commited_buf + 4082332c443SRobert Peterson (mbuf_limit - 1)) / mbuf_limit; 4092332c443SRobert Peterson dbuf_limit = databuf_limit(sdp); 4102332c443SRobert Peterson databufhdrs_needed = (sdp->sd_log_commited_databuf + 4112332c443SRobert Peterson (dbuf_limit - 1)) / dbuf_limit; 4122332c443SRobert Peterson 4132332c443SRobert Peterson if (sdp->sd_log_commited_revoke) 4142332c443SRobert Peterson revokes = gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke, 4152332c443SRobert Peterson sizeof(u64)); 4162332c443SRobert Peterson 4172332c443SRobert Peterson reserved = sdp->sd_log_commited_buf + metabufhdrs_needed + 4182332c443SRobert Peterson sdp->sd_log_commited_databuf + databufhdrs_needed + 4192332c443SRobert Peterson revokes; 4202332c443SRobert Peterson /* One for the overall header */ 4212332c443SRobert Peterson if (reserved) 4222332c443SRobert Peterson reserved++; 4232332c443SRobert Peterson return reserved; 4242332c443SRobert Peterson } 4252332c443SRobert Peterson 426b3b94faaSDavid Teigland static unsigned int current_tail(struct gfs2_sbd *sdp) 427b3b94faaSDavid Teigland { 428b3b94faaSDavid Teigland struct gfs2_ail *ai; 429b3b94faaSDavid Teigland unsigned int tail; 430b3b94faaSDavid Teigland 431b3b94faaSDavid Teigland gfs2_log_lock(sdp); 432b3b94faaSDavid Teigland 433faa31ce8SSteven Whitehouse if (list_empty(&sdp->sd_ail1_list)) { 434b3b94faaSDavid Teigland tail = sdp->sd_log_head; 435faa31ce8SSteven Whitehouse } else { 436faa31ce8SSteven Whitehouse ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list); 437b3b94faaSDavid Teigland tail = ai->ai_first; 438b3b94faaSDavid Teigland } 439b3b94faaSDavid Teigland 440b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 441b3b94faaSDavid Teigland 442b3b94faaSDavid Teigland return tail; 443b3b94faaSDavid Teigland } 444b3b94faaSDavid Teigland 445b3b94faaSDavid Teigland static inline void log_incr_head(struct gfs2_sbd *sdp) 446b3b94faaSDavid Teigland { 447b3b94faaSDavid Teigland if (sdp->sd_log_flush_head == sdp->sd_log_tail) 448faa31ce8SSteven Whitehouse gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head); 449b3b94faaSDavid Teigland 450b3b94faaSDavid Teigland if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { 451b3b94faaSDavid Teigland sdp->sd_log_flush_head = 0; 452b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 1; 453b3b94faaSDavid Teigland } 454b3b94faaSDavid Teigland } 455b3b94faaSDavid Teigland 456b3b94faaSDavid Teigland /** 457b3b94faaSDavid Teigland * gfs2_log_get_buf - Get and initialize a buffer to use for log control data 458b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 459b3b94faaSDavid Teigland * 460b3b94faaSDavid Teigland * Returns: the buffer_head 461b3b94faaSDavid Teigland */ 462b3b94faaSDavid Teigland 463b3b94faaSDavid Teigland struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) 464b3b94faaSDavid Teigland { 465cd915493SSteven Whitehouse u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); 466b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 467b3b94faaSDavid Teigland struct buffer_head *bh; 468b3b94faaSDavid Teigland 4694f3df041SSteven Whitehouse lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); 470b3b94faaSDavid Teigland list_add(&lb->lb_list, &sdp->sd_log_flush_list); 471b3b94faaSDavid Teigland 472b3b94faaSDavid Teigland bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno); 473b3b94faaSDavid Teigland lock_buffer(bh); 474b3b94faaSDavid Teigland memset(bh->b_data, 0, bh->b_size); 475b3b94faaSDavid Teigland set_buffer_uptodate(bh); 476b3b94faaSDavid Teigland clear_buffer_dirty(bh); 477b3b94faaSDavid Teigland unlock_buffer(bh); 478b3b94faaSDavid Teigland 479b3b94faaSDavid Teigland log_incr_head(sdp); 480b3b94faaSDavid Teigland 481b3b94faaSDavid Teigland return bh; 482b3b94faaSDavid Teigland } 483b3b94faaSDavid Teigland 484b3b94faaSDavid Teigland /** 485b3b94faaSDavid Teigland * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log 486b3b94faaSDavid Teigland * @sdp: the filesystem 487b3b94faaSDavid Teigland * @data: the data the buffer_head should point to 488b3b94faaSDavid Teigland * 489b3b94faaSDavid Teigland * Returns: the log buffer descriptor 490b3b94faaSDavid Teigland */ 491b3b94faaSDavid Teigland 492b3b94faaSDavid Teigland struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, 493b3b94faaSDavid Teigland struct buffer_head *real) 494b3b94faaSDavid Teigland { 495cd915493SSteven Whitehouse u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); 496b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 497b3b94faaSDavid Teigland struct buffer_head *bh; 498b3b94faaSDavid Teigland 4994f3df041SSteven Whitehouse lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL); 500b3b94faaSDavid Teigland list_add(&lb->lb_list, &sdp->sd_log_flush_list); 501b3b94faaSDavid Teigland lb->lb_real = real; 502b3b94faaSDavid Teigland 503b3b94faaSDavid Teigland bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); 504b3b94faaSDavid Teigland atomic_set(&bh->b_count, 1); 505b3b94faaSDavid Teigland bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate); 50618ec7d5cSSteven Whitehouse set_bh_page(bh, real->b_page, bh_offset(real)); 507b3b94faaSDavid Teigland bh->b_blocknr = blkno; 508b3b94faaSDavid Teigland bh->b_size = sdp->sd_sb.sb_bsize; 509b3b94faaSDavid Teigland bh->b_bdev = sdp->sd_vfs->s_bdev; 510b3b94faaSDavid Teigland 511b3b94faaSDavid Teigland log_incr_head(sdp); 512b3b94faaSDavid Teigland 513b3b94faaSDavid Teigland return bh; 514b3b94faaSDavid Teigland } 515b3b94faaSDavid Teigland 5162332c443SRobert Peterson static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) 517b3b94faaSDavid Teigland { 518b3b94faaSDavid Teigland unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); 519b3b94faaSDavid Teigland 520b3b94faaSDavid Teigland ail2_empty(sdp, new_tail); 521b3b94faaSDavid Teigland 522b3b94faaSDavid Teigland gfs2_log_lock(sdp); 5232332c443SRobert Peterson sdp->sd_log_blks_free += dist; 524faa31ce8SSteven Whitehouse gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks); 525b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 526b3b94faaSDavid Teigland 527b3b94faaSDavid Teigland sdp->sd_log_tail = new_tail; 528b3b94faaSDavid Teigland } 529b3b94faaSDavid Teigland 530b3b94faaSDavid Teigland /** 531b3b94faaSDavid Teigland * log_write_header - Get and initialize a journal header buffer 532b3b94faaSDavid Teigland * @sdp: The GFS2 superblock 533b3b94faaSDavid Teigland * 534b3b94faaSDavid Teigland * Returns: the initialized log buffer descriptor 535b3b94faaSDavid Teigland */ 536b3b94faaSDavid Teigland 537cd915493SSteven Whitehouse static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) 538b3b94faaSDavid Teigland { 539cd915493SSteven Whitehouse u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); 540b3b94faaSDavid Teigland struct buffer_head *bh; 541b3b94faaSDavid Teigland struct gfs2_log_header *lh; 542b3b94faaSDavid Teigland unsigned int tail; 543cd915493SSteven Whitehouse u32 hash; 544b3b94faaSDavid Teigland 545b3b94faaSDavid Teigland bh = sb_getblk(sdp->sd_vfs, blkno); 546b3b94faaSDavid Teigland lock_buffer(bh); 547b3b94faaSDavid Teigland memset(bh->b_data, 0, bh->b_size); 548b3b94faaSDavid Teigland set_buffer_uptodate(bh); 549b3b94faaSDavid Teigland clear_buffer_dirty(bh); 550b3b94faaSDavid Teigland unlock_buffer(bh); 551b3b94faaSDavid Teigland 552b3b94faaSDavid Teigland gfs2_ail1_empty(sdp, 0); 553b3b94faaSDavid Teigland tail = current_tail(sdp); 554b3b94faaSDavid Teigland 555b3b94faaSDavid Teigland lh = (struct gfs2_log_header *)bh->b_data; 556b3b94faaSDavid Teigland memset(lh, 0, sizeof(struct gfs2_log_header)); 557b3b94faaSDavid Teigland lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); 558e3167dedSSteven Whitehouse lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); 559e3167dedSSteven Whitehouse lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); 560e0f2bf78SSteven Whitehouse lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); 561e0f2bf78SSteven Whitehouse lh->lh_flags = cpu_to_be32(flags); 562e0f2bf78SSteven Whitehouse lh->lh_tail = cpu_to_be32(tail); 563e0f2bf78SSteven Whitehouse lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); 564b3b94faaSDavid Teigland hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); 565b3b94faaSDavid Teigland lh->lh_hash = cpu_to_be32(hash); 566b3b94faaSDavid Teigland 567b3b94faaSDavid Teigland set_buffer_dirty(bh); 568b3b94faaSDavid Teigland if (sync_dirty_buffer(bh)) 569b3b94faaSDavid Teigland gfs2_io_error_bh(sdp, bh); 570b3b94faaSDavid Teigland brelse(bh); 571b3b94faaSDavid Teigland 572b3b94faaSDavid Teigland if (sdp->sd_log_tail != tail) 5732332c443SRobert Peterson log_pull_tail(sdp, tail); 574b3b94faaSDavid Teigland else 575b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !pull); 576b3b94faaSDavid Teigland 577b3b94faaSDavid Teigland sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); 578b3b94faaSDavid Teigland log_incr_head(sdp); 579b3b94faaSDavid Teigland } 580b3b94faaSDavid Teigland 581b3b94faaSDavid Teigland static void log_flush_commit(struct gfs2_sbd *sdp) 582b3b94faaSDavid Teigland { 583b3b94faaSDavid Teigland struct list_head *head = &sdp->sd_log_flush_list; 584b3b94faaSDavid Teigland struct gfs2_log_buf *lb; 585b3b94faaSDavid Teigland struct buffer_head *bh; 586b3b94faaSDavid Teigland 587b3b94faaSDavid Teigland while (!list_empty(head)) { 588b3b94faaSDavid Teigland lb = list_entry(head->next, struct gfs2_log_buf, lb_list); 589b3b94faaSDavid Teigland list_del(&lb->lb_list); 590b3b94faaSDavid Teigland bh = lb->lb_bh; 591b3b94faaSDavid Teigland 592b3b94faaSDavid Teigland wait_on_buffer(bh); 593b3b94faaSDavid Teigland if (!buffer_uptodate(bh)) 594b3b94faaSDavid Teigland gfs2_io_error_bh(sdp, bh); 595b3b94faaSDavid Teigland if (lb->lb_real) { 596b3b94faaSDavid Teigland while (atomic_read(&bh->b_count) != 1) /* Grrrr... */ 597b3b94faaSDavid Teigland schedule(); 598b3b94faaSDavid Teigland free_buffer_head(bh); 599b3b94faaSDavid Teigland } else 600b3b94faaSDavid Teigland brelse(bh); 601b3b94faaSDavid Teigland kfree(lb); 602b3b94faaSDavid Teigland } 603b3b94faaSDavid Teigland 604b3b94faaSDavid Teigland log_write_header(sdp, 0, 0); 605b3b94faaSDavid Teigland } 606b3b94faaSDavid Teigland 607b3b94faaSDavid Teigland /** 608b09e593dSSteven Whitehouse * gfs2_log_flush - flush incore transaction(s) 609b3b94faaSDavid Teigland * @sdp: the filesystem 610b3b94faaSDavid Teigland * @gl: The glock structure to flush. If NULL, flush the whole incore log 611b3b94faaSDavid Teigland * 612b3b94faaSDavid Teigland */ 613b3b94faaSDavid Teigland 614b09e593dSSteven Whitehouse void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) 615b3b94faaSDavid Teigland { 616b3b94faaSDavid Teigland struct gfs2_ail *ai; 617b3b94faaSDavid Teigland 618484adff8SSteven Whitehouse down_write(&sdp->sd_log_flush_lock); 619f55ab26aSSteven Whitehouse 620f55ab26aSSteven Whitehouse if (gl) { 621f55ab26aSSteven Whitehouse gfs2_log_lock(sdp); 622f55ab26aSSteven Whitehouse if (list_empty(&gl->gl_le.le_list)) { 623f55ab26aSSteven Whitehouse gfs2_log_unlock(sdp); 624484adff8SSteven Whitehouse up_write(&sdp->sd_log_flush_lock); 625f55ab26aSSteven Whitehouse return; 626f55ab26aSSteven Whitehouse } 627f55ab26aSSteven Whitehouse gfs2_log_unlock(sdp); 628f55ab26aSSteven Whitehouse } 629f55ab26aSSteven Whitehouse 630b09e593dSSteven Whitehouse ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL); 631b09e593dSSteven Whitehouse INIT_LIST_HEAD(&ai->ai_ail1_list); 632b09e593dSSteven Whitehouse INIT_LIST_HEAD(&ai->ai_ail2_list); 633b3b94faaSDavid Teigland 6342332c443SRobert Peterson gfs2_assert_withdraw(sdp, 6352332c443SRobert Peterson sdp->sd_log_num_buf + sdp->sd_log_num_jdata == 6362332c443SRobert Peterson sdp->sd_log_commited_buf + 6372332c443SRobert Peterson sdp->sd_log_commited_databuf); 638b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, 639b3b94faaSDavid Teigland sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke); 640b3b94faaSDavid Teigland 641b3b94faaSDavid Teigland sdp->sd_log_flush_head = sdp->sd_log_head; 642b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 0; 643b3b94faaSDavid Teigland ai->ai_first = sdp->sd_log_flush_head; 644b3b94faaSDavid Teigland 645b3b94faaSDavid Teigland lops_before_commit(sdp); 646b3b94faaSDavid Teigland if (!list_empty(&sdp->sd_log_flush_list)) 647b3b94faaSDavid Teigland log_flush_commit(sdp); 6482332c443SRobert Peterson else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ 6492332c443SRobert Peterson gfs2_log_lock(sdp); 6502332c443SRobert Peterson sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */ 6512332c443SRobert Peterson gfs2_log_unlock(sdp); 652b3b94faaSDavid Teigland log_write_header(sdp, 0, PULL); 6532332c443SRobert Peterson } 654b3b94faaSDavid Teigland lops_after_commit(sdp, ai); 655fe1a698fSSteven Whitehouse 656fe1a698fSSteven Whitehouse gfs2_log_lock(sdp); 657b3b94faaSDavid Teigland sdp->sd_log_head = sdp->sd_log_flush_head; 658faa31ce8SSteven Whitehouse sdp->sd_log_blks_reserved = 0; 659faa31ce8SSteven Whitehouse sdp->sd_log_commited_buf = 0; 6602332c443SRobert Peterson sdp->sd_log_commited_databuf = 0; 661b3b94faaSDavid Teigland sdp->sd_log_commited_revoke = 0; 662b3b94faaSDavid Teigland 663b3b94faaSDavid Teigland if (!list_empty(&ai->ai_ail1_list)) { 664b3b94faaSDavid Teigland list_add(&ai->ai_list, &sdp->sd_ail1_list); 665b3b94faaSDavid Teigland ai = NULL; 666b3b94faaSDavid Teigland } 667b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 668b3b94faaSDavid Teigland 669b3b94faaSDavid Teigland sdp->sd_vfs->s_dirt = 0; 670484adff8SSteven Whitehouse up_write(&sdp->sd_log_flush_lock); 671b3b94faaSDavid Teigland 672b3b94faaSDavid Teigland kfree(ai); 673b3b94faaSDavid Teigland } 674b3b94faaSDavid Teigland 675b3b94faaSDavid Teigland static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 676b3b94faaSDavid Teigland { 6772332c443SRobert Peterson unsigned int reserved; 678b3b94faaSDavid Teigland unsigned int old; 679b3b94faaSDavid Teigland 680b3b94faaSDavid Teigland gfs2_log_lock(sdp); 681b3b94faaSDavid Teigland 682b3b94faaSDavid Teigland sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm; 6832332c443SRobert Peterson sdp->sd_log_commited_databuf += tr->tr_num_databuf_new - 6842332c443SRobert Peterson tr->tr_num_databuf_rm; 6852332c443SRobert Peterson gfs2_assert_withdraw(sdp, (((int)sdp->sd_log_commited_buf) >= 0) || 6862332c443SRobert Peterson (((int)sdp->sd_log_commited_databuf) >= 0)); 687b3b94faaSDavid Teigland sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm; 688b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0); 6892332c443SRobert Peterson reserved = calc_reserved(sdp); 690b3b94faaSDavid Teigland old = sdp->sd_log_blks_free; 691b3b94faaSDavid Teigland sdp->sd_log_blks_free += tr->tr_reserved - 692b3b94faaSDavid Teigland (reserved - sdp->sd_log_blks_reserved); 693b3b94faaSDavid Teigland 694b09e593dSSteven Whitehouse gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old); 6952332c443SRobert Peterson gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= 6962332c443SRobert Peterson sdp->sd_jdesc->jd_blocks); 697b3b94faaSDavid Teigland 698b3b94faaSDavid Teigland sdp->sd_log_blks_reserved = reserved; 699b3b94faaSDavid Teigland 700b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 701b3b94faaSDavid Teigland } 702b3b94faaSDavid Teigland 703b3b94faaSDavid Teigland /** 704b3b94faaSDavid Teigland * gfs2_log_commit - Commit a transaction to the log 705b3b94faaSDavid Teigland * @sdp: the filesystem 706b3b94faaSDavid Teigland * @tr: the transaction 707b3b94faaSDavid Teigland * 708b3b94faaSDavid Teigland * Returns: errno 709b3b94faaSDavid Teigland */ 710b3b94faaSDavid Teigland 711b3b94faaSDavid Teigland void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) 712b3b94faaSDavid Teigland { 713b3b94faaSDavid Teigland log_refund(sdp, tr); 714b3b94faaSDavid Teigland lops_incore_commit(sdp, tr); 715b3b94faaSDavid Teigland 716b3b94faaSDavid Teigland sdp->sd_vfs->s_dirt = 1; 717484adff8SSteven Whitehouse up_read(&sdp->sd_log_flush_lock); 718b3b94faaSDavid Teigland 719b3b94faaSDavid Teigland gfs2_log_lock(sdp); 720b004157aSSteven Whitehouse if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) 721b004157aSSteven Whitehouse wake_up_process(sdp->sd_logd_process); 722b3b94faaSDavid Teigland gfs2_log_unlock(sdp); 723faa31ce8SSteven Whitehouse } 724b3b94faaSDavid Teigland 725b3b94faaSDavid Teigland /** 726b3b94faaSDavid Teigland * gfs2_log_shutdown - write a shutdown header into a journal 727b3b94faaSDavid Teigland * @sdp: the filesystem 728b3b94faaSDavid Teigland * 729b3b94faaSDavid Teigland */ 730b3b94faaSDavid Teigland 731b3b94faaSDavid Teigland void gfs2_log_shutdown(struct gfs2_sbd *sdp) 732b3b94faaSDavid Teigland { 733484adff8SSteven Whitehouse down_write(&sdp->sd_log_flush_lock); 734b3b94faaSDavid Teigland 735b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved); 736b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl); 737b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf); 73818ec7d5cSSteven Whitehouse gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata); 739b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke); 740b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg); 741b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf); 742b3b94faaSDavid Teigland gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list)); 743b3b94faaSDavid Teigland 744b3b94faaSDavid Teigland sdp->sd_log_flush_head = sdp->sd_log_head; 745b3b94faaSDavid Teigland sdp->sd_log_flush_wrapped = 0; 746b3b94faaSDavid Teigland 7472332c443SRobert Peterson log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 7482332c443SRobert Peterson (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL); 749b3b94faaSDavid Teigland 750a74604beSSteven Whitehouse gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks); 751a74604beSSteven Whitehouse gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail); 752a74604beSSteven Whitehouse gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list)); 753b3b94faaSDavid Teigland 754b3b94faaSDavid Teigland sdp->sd_log_head = sdp->sd_log_flush_head; 755b3b94faaSDavid Teigland sdp->sd_log_tail = sdp->sd_log_head; 756b3b94faaSDavid Teigland 757484adff8SSteven Whitehouse up_write(&sdp->sd_log_flush_lock); 758b3b94faaSDavid Teigland } 759b3b94faaSDavid Teigland 760a25311c8SSteven Whitehouse 761a25311c8SSteven Whitehouse /** 762a25311c8SSteven Whitehouse * gfs2_meta_syncfs - sync all the buffers in a filesystem 763a25311c8SSteven Whitehouse * @sdp: the filesystem 764a25311c8SSteven Whitehouse * 765a25311c8SSteven Whitehouse */ 766a25311c8SSteven Whitehouse 767a25311c8SSteven Whitehouse void gfs2_meta_syncfs(struct gfs2_sbd *sdp) 768a25311c8SSteven Whitehouse { 769a25311c8SSteven Whitehouse gfs2_log_flush(sdp, NULL); 770a25311c8SSteven Whitehouse for (;;) { 771a25311c8SSteven Whitehouse gfs2_ail1_start(sdp, DIO_ALL); 772a25311c8SSteven Whitehouse if (gfs2_ail1_empty(sdp, DIO_ALL)) 773a25311c8SSteven Whitehouse break; 774a25311c8SSteven Whitehouse msleep(10); 775a25311c8SSteven Whitehouse } 776a25311c8SSteven Whitehouse } 777a25311c8SSteven Whitehouse 778