Commit 4cf1ed81 authored by Steven Whitehouse's avatar Steven Whitehouse

[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: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent ab923031
...@@ -423,12 +423,29 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -423,12 +423,29 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
return 0; return 0;
} }
static inline void bmap_lock(struct inode *inode, int create)
{
struct gfs2_inode *ip = GFS2_I(inode);
if (create)
down_write(&ip->i_rw_mutex);
else
down_read(&ip->i_rw_mutex);
}
static inline void bmap_unlock(struct inode *inode, int create)
{
struct gfs2_inode *ip = GFS2_I(inode);
if (create)
up_write(&ip->i_rw_mutex);
else
up_read(&ip->i_rw_mutex);
}
/** /**
* gfs2_block_pointers - Map a block from an inode to a disk block * gfs2_block_map - Map a block from an inode to a disk block
* @inode: The inode * @inode: The inode
* @lblock: The logical block number * @lblock: The logical block number
* @map_bh: The bh to be mapped * @bh_map: The bh to be mapped
* @mp: metapath to use
* *
* Find the block number on the current device which corresponds to an * 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. * inode's block. If the block had to be created, "new" will be set.
...@@ -436,8 +453,8 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -436,8 +453,8 @@ static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
* Returns: errno * Returns: errno
*/ */
static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, int gfs2_block_map(struct inode *inode, u64 lblock, int create,
struct buffer_head *bh_map, struct metapath *mp) struct buffer_head *bh_map)
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_sbd *sdp = GFS2_SB(inode);
...@@ -451,51 +468,55 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, ...@@ -451,51 +468,55 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
u64 dblock = 0; u64 dblock = 0;
int boundary; int boundary;
unsigned int maxlen = bh_map->b_size >> inode->i_blkbits; unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
struct metapath mp;
u64 size;
BUG_ON(maxlen == 0); BUG_ON(maxlen == 0);
if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
return 0; return 0;
bmap_lock(inode, create);
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; bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
size = (lblock + 1) * bsize;
height = calc_tree_height(ip, (lblock + 1) * bsize); if (size > ip->i_di.di_size) {
height = calc_tree_height(ip, size);
if (ip->i_di.di_height < height) { if (ip->i_di.di_height < height) {
if (!create) if (!create)
return 0; goto out_ok;
error = build_height(inode, height); error = build_height(inode, height);
if (error) if (error)
return error; goto out_fail;
}
} }
find_metapath(ip, lblock, mp); find_metapath(ip, lblock, &mp);
end_of_metadata = ip->i_di.di_height - 1; end_of_metadata = ip->i_di.di_height - 1;
error = gfs2_meta_inode_buffer(ip, &bh); error = gfs2_meta_inode_buffer(ip, &bh);
if (error) if (error)
return error; goto out_fail;
for (x = 0; x < end_of_metadata; x++) { for (x = 0; x < end_of_metadata; x++) {
lookup_block(ip, bh, x, mp, create, &new, &dblock); lookup_block(ip, bh, x, &mp, create, &new, &dblock);
brelse(bh); brelse(bh);
if (!dblock) if (!dblock)
return 0; goto out_ok;
error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh); error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
if (error) if (error)
return error; goto out_fail;
} }
boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock); 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) { if (dblock) {
map_bh(bh_map, inode->i_sb, dblock); map_bh(bh_map, inode->i_sb, dblock);
if (boundary) if (boundary)
set_buffer_boundary(bh); set_buffer_boundary(bh_map);
if (new) { if (new) {
struct buffer_head *dibh; struct buffer_head *dibh;
error = gfs2_meta_inode_buffer(ip, &dibh); error = gfs2_meta_inode_buffer(ip, &dibh);
...@@ -510,8 +531,8 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, ...@@ -510,8 +531,8 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
while(--maxlen && !buffer_boundary(bh_map)) { while(--maxlen && !buffer_boundary(bh_map)) {
u64 eblock; u64 eblock;
mp->mp_list[end_of_metadata]++; mp.mp_list[end_of_metadata]++;
boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock); boundary = lookup_block(ip, bh, end_of_metadata, &mp, 0, &new, &eblock);
if (eblock != ++dblock) if (eblock != ++dblock)
break; break;
bh_map->b_size += (1 << inode->i_blkbits); bh_map->b_size += (1 << inode->i_blkbits);
...@@ -521,43 +542,15 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create, ...@@ -521,43 +542,15 @@ static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
} }
out_brelse: out_brelse:
brelse(bh); brelse(bh);
return 0; out_ok:
} error = 0;
out_fail:
static inline void bmap_lock(struct inode *inode, int create)
{
struct gfs2_inode *ip = GFS2_I(inode);
if (create)
down_write(&ip->i_rw_mutex);
else
down_read(&ip->i_rw_mutex);
}
static inline void bmap_unlock(struct inode *inode, int create)
{
struct gfs2_inode *ip = GFS2_I(inode);
if (create)
up_write(&ip->i_rw_mutex);
else
up_read(&ip->i_rw_mutex);
}
int gfs2_block_map(struct inode *inode, u64 lblock, int create,
struct buffer_head *bh)
{
struct metapath mp;
int ret;
bmap_lock(inode, create);
ret = gfs2_block_pointers(inode, lblock, create, bh, &mp);
bmap_unlock(inode, create); bmap_unlock(inode, create);
return ret; return error;
} }
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen) 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 }; struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 };
int ret; int ret;
int create = *new; int create = *new;
...@@ -567,9 +560,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi ...@@ -567,9 +560,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi
BUG_ON(!new); BUG_ON(!new);
bh.b_size = 1 << (inode->i_blkbits + 5); bh.b_size = 1 << (inode->i_blkbits + 5);
bmap_lock(inode, create); ret = gfs2_block_map(inode, lblock, create, &bh);
ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp);
bmap_unlock(inode, create);
*extlen = bh.b_size >> inode->i_blkbits; *extlen = bh.b_size >> inode->i_blkbits;
*dblock = bh.b_blocknr; *dblock = bh.b_blocknr;
if (buffer_new(&bh)) if (buffer_new(&bh))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment