dect
/
linux-2.6
Archived
13
0
Fork 0

ext4: fix extent tree corruption caused by hole punch

When depth of extent tree is greater than 1, logical start value of
interior node is not correctly updated in ext4_ext_rm_idx.

Signed-off-by: Forrest Liu <forrestl@synology.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Ashish Sangwan <ashishsangwan2@gmail.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Forrest Liu 2012-12-17 09:55:39 -05:00 committed by Theodore Ts'o
parent bd9926e803
commit c36575e663
1 changed files with 18 additions and 4 deletions

View File

@ -2226,13 +2226,14 @@ errout:
* removes index from the index block. * removes index from the index block.
*/ */
static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
struct ext4_ext_path *path) struct ext4_ext_path *path, int depth)
{ {
int err; int err;
ext4_fsblk_t leaf; ext4_fsblk_t leaf;
/* free index block */ /* free index block */
path--; depth--;
path = path + depth;
leaf = ext4_idx_pblock(path->p_idx); leaf = ext4_idx_pblock(path->p_idx);
if (unlikely(path->p_hdr->eh_entries == 0)) { if (unlikely(path->p_hdr->eh_entries == 0)) {
EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0"); EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
@ -2257,6 +2258,19 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
ext4_free_blocks(handle, inode, NULL, leaf, 1, ext4_free_blocks(handle, inode, NULL, leaf, 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
while (--depth >= 0) {
if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr))
break;
path--;
err = ext4_ext_get_access(handle, inode, path);
if (err)
break;
path->p_idx->ei_block = (path+1)->p_idx->ei_block;
err = ext4_ext_dirty(handle, inode, path);
if (err)
break;
}
return err; return err;
} }
@ -2599,7 +2613,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
/* if this leaf is free, then we should /* if this leaf is free, then we should
* remove it from index block above */ * remove it from index block above */
if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
err = ext4_ext_rm_idx(handle, inode, path + depth); err = ext4_ext_rm_idx(handle, inode, path, depth);
out: out:
return err; return err;
@ -2802,7 +2816,7 @@ again:
/* index is empty, remove it; /* index is empty, remove it;
* handle must be already prepared by the * handle must be already prepared by the
* truncatei_leaf() */ * truncatei_leaf() */
err = ext4_ext_rm_idx(handle, inode, path + i); err = ext4_ext_rm_idx(handle, inode, path, i);
} }
/* root level has p_bh == NULL, brelse() eats this */ /* root level has p_bh == NULL, brelse() eats this */
brelse(path[i].p_bh); brelse(path[i].p_bh);