Skip to content

Commit

Permalink
ext4: fix extent tree corruption caused by hole punch
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Forrest Liu authored and Theodore Ts'o committed Dec 17, 2012
1 parent bd9926e commit c36575e
Showing 1 changed file with 18 additions and 4 deletions.
22 changes: 18 additions & 4 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -2226,13 +2226,14 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
* removes index from the index block.
*/
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;
ext4_fsblk_t leaf;

/* free index block */
path--;
depth--;
path = path + depth;
leaf = ext4_idx_pblock(path->p_idx);
if (unlikely(path->p_hdr->eh_entries == 0)) {
EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
Expand All @@ -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_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;
}

Expand Down Expand Up @@ -2599,7 +2613,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
/* if this leaf is free, then we should
* remove it from index block above */
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:
return err;
Expand Down Expand Up @@ -2802,7 +2816,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
/* index is empty, remove it;
* handle must be already prepared by the
* 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 */
brelse(path[i].p_bh);
Expand Down

0 comments on commit c36575e

Please sign in to comment.