[PATCH 29/49] ext4: Make ext4_get_blocks_wrap take the truncate_mutex early.
From: Aneesh Kumar K.V <[EMAIL PROTECTED]> When doing a migrate from ext3 to ext4 inode we need to make sure the test for inode type and walking inode data happens inside lock. To make this happen move truncate_mutex early before checking the i_flags. This actually should enable us to remove the verify_chain(). Signed-off-by: Aneesh Kumar K.V <[EMAIL PROTECTED]> --- fs/ext4/extents.c |9 -- fs/ext4/inode.c | 69 +- include/linux/ext4_fs.h |2 + 3 files changed, 16 insertions(+), 64 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 8593e59..ec5019f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2129,6 +2129,10 @@ out: return err ? err : allocated; } +/* + * Need to be called with + * mutex_lock(_I(inode)->truncate_mutex); + */ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, ext4_lblk_t iblock, unsigned long max_blocks, struct buffer_head *bh_result, @@ -2144,7 +2148,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, __clear_bit(BH_New, _result->b_state); ext_debug("blocks %u/%lu requested for inode %u\n", iblock, max_blocks, inode->i_ino); - mutex_lock(_I(inode)->truncate_mutex); /* check in cache */ goal = ext4_ext_in_cache(inode, iblock, ); @@ -2318,8 +2321,6 @@ out2: ext4_ext_drop_refs(path); kfree(path); } - mutex_unlock(_I(inode)->truncate_mutex); - return err ? err : allocated; } @@ -2449,6 +2450,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) * modify 1 super block, 1 block bitmap and 1 group descriptor. */ credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3; + mutex_lock(_I(inode)->truncate_mutex) retry: while (ret >= 0 && ret < max_blocks) { block = block + ret; @@ -2505,6 +2507,7 @@ retry: if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, )) goto retry; + mutex_unlock(_I(inode)->truncate_mutex) /* * Time to update the file size. * Update only when preallocation was requested beyond the file size. diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index eaace13..71c7ad0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -243,13 +243,6 @@ static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) p->bh = bh; } -static int verify_chain(Indirect *from, Indirect *to) -{ - while (from <= to && from->key == *from->p) - from++; - return (from > to); -} - /** * ext4_block_to_path - parse the block number into array of offsets * @inode: inode in question (we are only interested in its superblock) @@ -348,10 +341,11 @@ static int ext4_block_to_path(struct inode *inode, * (pointer to last triple returned, [EMAIL PROTECTED] == 0) * or when it gets an IO error reading an indirect block * (ditto, [EMAIL PROTECTED] == -EIO) - * or when it notices that chain had been changed while it was reading - * (ditto, [EMAIL PROTECTED] == -EAGAIN) * or when it reads all @depth-1 indirect blocks successfully and finds * the whole chain, all way to the data (returns %NULL, *err == 0). + * + * Need to be called with + * mutex_lock(_I(inode)->truncate_mutex) */ static Indirect *ext4_get_branch(struct inode *inode, int depth, ext4_lblk_t *offsets, @@ -370,9 +364,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, bh = sb_bread(sb, le32_to_cpu(p->key)); if (!bh) goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); /* Reader: end */ if (!p->key) @@ -380,10 +371,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, } return NULL; -changed: - brelse(bh); - *err = -EAGAIN; - goto no_block; failure: *err = -EIO; no_block: @@ -787,6 +774,10 @@ err_out: * return > 0, # of blocks mapped or allocated. * return = 0, if plain lookup failed. * return < 0, error case. + * + * + * Need to be called with + * mutex_lock(_I(inode)->truncate_mutex) */ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, ext4_lblk_t iblock, unsigned long maxblocks, @@ -825,18 +816,6 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, while (count < maxblocks && count <= blocks_to_boundary) { ext4_fsblk_t blk; - if (!verify_chain(chain, partial)) { - /* -
[PATCH 29/49] ext4: Make ext4_get_blocks_wrap take the truncate_mutex early.
From: Aneesh Kumar K.V [EMAIL PROTECTED] When doing a migrate from ext3 to ext4 inode we need to make sure the test for inode type and walking inode data happens inside lock. To make this happen move truncate_mutex early before checking the i_flags. This actually should enable us to remove the verify_chain(). Signed-off-by: Aneesh Kumar K.V [EMAIL PROTECTED] --- fs/ext4/extents.c |9 -- fs/ext4/inode.c | 69 +- include/linux/ext4_fs.h |2 + 3 files changed, 16 insertions(+), 64 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 8593e59..ec5019f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2129,6 +2129,10 @@ out: return err ? err : allocated; } +/* + * Need to be called with + * mutex_lock(EXT4_I(inode)-truncate_mutex); + */ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, ext4_lblk_t iblock, unsigned long max_blocks, struct buffer_head *bh_result, @@ -2144,7 +2148,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, __clear_bit(BH_New, bh_result-b_state); ext_debug(blocks %u/%lu requested for inode %u\n, iblock, max_blocks, inode-i_ino); - mutex_lock(EXT4_I(inode)-truncate_mutex); /* check in cache */ goal = ext4_ext_in_cache(inode, iblock, newex); @@ -2318,8 +2321,6 @@ out2: ext4_ext_drop_refs(path); kfree(path); } - mutex_unlock(EXT4_I(inode)-truncate_mutex); - return err ? err : allocated; } @@ -2449,6 +2450,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) * modify 1 super block, 1 block bitmap and 1 group descriptor. */ credits = EXT4_DATA_TRANS_BLOCKS(inode-i_sb) + 3; + mutex_lock(EXT4_I(inode)-truncate_mutex) retry: while (ret = 0 ret max_blocks) { block = block + ret; @@ -2505,6 +2507,7 @@ retry: if (ret == -ENOSPC ext4_should_retry_alloc(inode-i_sb, retries)) goto retry; + mutex_unlock(EXT4_I(inode)-truncate_mutex) /* * Time to update the file size. * Update only when preallocation was requested beyond the file size. diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index eaace13..71c7ad0 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -243,13 +243,6 @@ static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) p-bh = bh; } -static int verify_chain(Indirect *from, Indirect *to) -{ - while (from = to from-key == *from-p) - from++; - return (from to); -} - /** * ext4_block_to_path - parse the block number into array of offsets * @inode: inode in question (we are only interested in its superblock) @@ -348,10 +341,11 @@ static int ext4_block_to_path(struct inode *inode, * (pointer to last triple returned, [EMAIL PROTECTED] == 0) * or when it gets an IO error reading an indirect block * (ditto, [EMAIL PROTECTED] == -EIO) - * or when it notices that chain had been changed while it was reading - * (ditto, [EMAIL PROTECTED] == -EAGAIN) * or when it reads all @depth-1 indirect blocks successfully and finds * the whole chain, all way to the data (returns %NULL, *err == 0). + * + * Need to be called with + * mutex_lock(EXT4_I(inode)-truncate_mutex) */ static Indirect *ext4_get_branch(struct inode *inode, int depth, ext4_lblk_t *offsets, @@ -370,9 +364,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, bh = sb_bread(sb, le32_to_cpu(p-key)); if (!bh) goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; add_chain(++p, bh, (__le32*)bh-b_data + *++offsets); /* Reader: end */ if (!p-key) @@ -380,10 +371,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, } return NULL; -changed: - brelse(bh); - *err = -EAGAIN; - goto no_block; failure: *err = -EIO; no_block: @@ -787,6 +774,10 @@ err_out: * return 0, # of blocks mapped or allocated. * return = 0, if plain lookup failed. * return 0, error case. + * + * + * Need to be called with + * mutex_lock(EXT4_I(inode)-truncate_mutex) */ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, ext4_lblk_t iblock, unsigned long maxblocks, @@ -825,18 +816,6 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, while (count maxblocks count = blocks_to_boundary) { ext4_fsblk_t blk; - if (!verify_chain(chain, partial)) { -