Commit c36575e6 authored by Forrest Liu's avatar Forrest Liu Committed by Theodore Ts'o

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: default avatarForrest Liu <forrestl@synology.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: default avatarAshish Sangwan <ashishsangwan2@gmail.com>
Cc: stable@vger.kernel.org
parent bd9926e8
...@@ -2226,13 +2226,14 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, ...@@ -2226,13 +2226,14 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
* 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, ...@@ -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, ...@@ -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 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, ...@@ -2802,7 +2816,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
/* 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);
......
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