From 4cf1ed8144e740de27c6146c25d5d7ea26679cc5 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 15 Nov 2006 15:21:06 -0500 Subject: [PATCH] [GFS2] Tidy up bmap & fix boundary bug This moves the locking for bmap into the bmap function itself rather than using a wrapper function. It also fixes a bug where the boundary flag was set on the wrong bh. Also the flags on the mapped bh are reset earlier in the function to ensure that they are 100% correct on the error path. Signed-off-by: Steven Whitehouse --- fs/gfs2/bmap.c | 211 +++++++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 110 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 06e3447ea132..8240c1ff94f4 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -423,108 +423,6 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, return 0; } -/** - * gfs2_block_pointers - Map a block from an inode to a disk block - * @inode: The inode - * @lblock: The logical block number - * @map_bh: The bh to be mapped - * @mp: metapath to use - * - * Find the block number on the current device which corresponds to an - * inode's block. If the block had to be created, "new" will be set. - * - * Returns: errno - */ - -static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, - struct buffer_head *bh_map, struct metapath *mp) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct buffer_head *bh; - unsigned int bsize; - unsigned int height; - unsigned int end_of_metadata; - unsigned int x; - int error = 0; - int new = 0; - u64 dblock = 0; - int boundary; - unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; - - BUG_ON(maxlen == 0); - - if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) - return 0; - - bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; - - height = calc_tree_height(ip, (lblock + 1) * bsize); - if (ip->i_di.di_height < height) { - if (!create) - return 0; - - error = build_height(inode, height); - if (error) - return error; - } - - find_metapath(ip, lblock, mp); - end_of_metadata = ip->i_di.di_height - 1; - - error = gfs2_meta_inode_buffer(ip, &bh); - if (error) - return error; - - for (x = 0; x < end_of_metadata; x++) { - lookup_block(ip, bh, x, mp, create, &new, &dblock); - brelse(bh); - if (!dblock) - return 0; - - error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); - if (error) - return error; - } - - boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock); - clear_buffer_mapped(bh_map); - clear_buffer_new(bh_map); - clear_buffer_boundary(bh_map); - - if (dblock) { - map_bh(bh_map, inode->i_sb, dblock); - if (boundary) - set_buffer_boundary(bh); - if (new) { - struct buffer_head *dibh; - error = gfs2_meta_inode_buffer(ip, &dibh); - if (!error) { - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); - } - set_buffer_new(bh_map); - goto out_brelse; - } - while(--maxlen && !buffer_boundary(bh_map)) { - u64 eblock; - - mp->mp_list[end_of_metadata]++; - boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock); - if (eblock != ++dblock) - break; - bh_map->b_size += (1 << inode->i_blkbits); - if (boundary) - set_buffer_boundary(bh_map); - } - } -out_brelse: - brelse(bh); - return 0; -} - - static inline void bmap_lock(struct inode *inode, int create) { struct gfs2_inode *ip = GFS2_I(inode); @@ -543,21 +441,116 @@ static inline void bmap_unlock(struct inode *inode, int create) up_read(&ip->i_rw_mutex); } +/** + * gfs2_block_map - Map a block from an inode to a disk block + * @inode: The inode + * @lblock: The logical block number + * @bh_map: The bh to be mapped + * + * Find the block number on the current device which corresponds to an + * inode's block. If the block had to be created, "new" will be set. + * + * Returns: errno + */ + int gfs2_block_map(struct inode *inode, u64 lblock, int create, - struct buffer_head *bh) + struct buffer_head *bh_map) { + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct buffer_head *bh; + unsigned int bsize; + unsigned int height; + unsigned int end_of_metadata; + unsigned int x; + int error = 0; + int new = 0; + u64 dblock = 0; + int boundary; + unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; struct metapath mp; - int ret; + u64 size; + + BUG_ON(maxlen == 0); + + if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) + return 0; bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, bh, &mp); + clear_buffer_mapped(bh_map); + clear_buffer_new(bh_map); + clear_buffer_boundary(bh_map); + bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize; + size = (lblock + 1) * bsize; + + if (size > ip->i_di.di_size) { + height = calc_tree_height(ip, size); + if (ip->i_di.di_height < height) { + if (!create) + goto out_ok; + + error = build_height(inode, height); + if (error) + goto out_fail; + } + } + + find_metapath(ip, lblock, &mp); + end_of_metadata = ip->i_di.di_height - 1; + error = gfs2_meta_inode_buffer(ip, &bh); + if (error) + goto out_fail; + + for (x = 0; x < end_of_metadata; x++) { + lookup_block(ip, bh, x, &mp, create, &new, &dblock); + brelse(bh); + if (!dblock) + goto out_ok; + + error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); + if (error) + goto out_fail; + } + + boundary = lookup_block(ip, bh, end_of_metadata, &mp, create, &new, &dblock); + if (dblock) { + map_bh(bh_map, inode->i_sb, dblock); + if (boundary) + set_buffer_boundary(bh_map); + if (new) { + struct buffer_head *dibh; + error = gfs2_meta_inode_buffer(ip, &dibh); + if (!error) { + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + } + set_buffer_new(bh_map); + goto out_brelse; + } + while(--maxlen && !buffer_boundary(bh_map)) { + u64 eblock; + + mp.mp_list[end_of_metadata]++; + boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock); + if (eblock != ++dblock) + break; + bh_map->b_size += (1 << inode->i_blkbits); + if (boundary) + set_buffer_boundary(bh_map); + } + } +out_brelse: + brelse(bh); +out_ok: + error = 0; +out_fail: bmap_unlock(inode, create); - return ret; + return error; } int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) { - struct metapath mp; struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 }; int ret; int create = *new; @@ -567,9 +560,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi BUG_ON(!new); bh.b_size = 1 << (inode->i_blkbits + 5); - bmap_lock(inode, create); - ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp); - bmap_unlock(inode, create); + ret = gfs2_block_map(inode, lblock, create, &bh); *extlen = bh.b_size >> inode->i_blkbits; *dblock = bh.b_blocknr; if (buffer_new(&bh))