Signed-off-by: Andrew Morton --- 25-akpm/fs/ext3/inode.c | 34 ++++++++++++++++++++++------------ 1 files changed, 22 insertions(+), 12 deletions(-) diff -puN fs/ext3/inode.c~ext3-remove-unnecessary-race-then-retry-in-ext3_get_block-leak-fix fs/ext3/inode.c --- 25/fs/ext3/inode.c~ext3-remove-unnecessary-race-then-retry-in-ext3_get_block-leak-fix 2005-04-07 04:27:06.000000000 -0700 +++ 25-akpm/fs/ext3/inode.c 2005-04-07 04:27:47.000000000 -0700 @@ -699,8 +699,9 @@ ext3_get_block_handle(handle_t *handle, goto cleanup; down(&ei->truncate_sem); + /* - * if the indirect block is missing while we are reading + * If the indirect block is missing while we are reading * the chain(ext3_get_branch() returns -EAGAIN err), or * if the chain has been changed after we grab the semaphore, * (either because another process truncated this branch, or @@ -711,7 +712,11 @@ ext3_get_block_handle(handle_t *handle, * at this point, we will have the current copy of the chain when we * splice the branch into the tree. */ - if ((err = -EAGAIN) || !verify_chain(chain, partial)) { + if (err == -EAGAIN || !verify_chain(chain, partial)) { + while (partial > chain) { + brelse(partial->bh); + partial--; + } partial = ext3_get_branch(inode, depth, offsets, chain, &err); if (!partial) { up(&ei->truncate_sem); @@ -722,11 +727,12 @@ ext3_get_block_handle(handle_t *handle, } } - /* Okey, we need to do block allocation */ - /* lazy initialize the block allocation info here if necessary */ - if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) { + /* + * Okay, we need to do block allocation. Lazily initialize the block + * allocation info here if necessary + */ + if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext3_init_block_alloc_info(inode); - } goal = ext3_find_goal(inode, iblock, chain, partial); @@ -736,19 +742,23 @@ ext3_get_block_handle(handle_t *handle, * Block out ext3_truncate while we alter the tree */ err = ext3_alloc_branch(handle, inode, left, goal, - offsets+(partial-chain), partial); + offsets + (partial - chain), partial); - /* The ext3_splice_branch call will free and forget any buffers + /* + * The ext3_splice_branch call will free and forget any buffers * on the new chain if there is a failure, but that risks using * up transaction credits, especially for bitmaps where the * credits cannot be returned. Can we handle this somehow? We - * may need to return -EAGAIN upwards in the worst case. --sct */ + * may need to return -EAGAIN upwards in the worst case. --sct + */ if (!err) err = ext3_splice_branch(handle, inode, iblock, chain, partial, left); - /* i_disksize growing is protected by truncate_sem - * don't forget to protect it if you're about to implement - * concurrent ext3_get_block() -bzzz */ + /* + * i_disksize growing is protected by truncate_sem. Don't forget to + * protect it if you're about to implement concurrent + * ext3_get_block() -bzzz + */ if (!err && extend_disksize && inode->i_size > ei->i_disksize) ei->i_disksize = inode->i_size; up(&ei->truncate_sem); _