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:
parent
bd9926e803
commit
c36575e663
@ -2226,13 +2226,14 @@ errout:
|
||||
* 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");
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -2802,7 +2816,7 @@ again:
|
||||
/* 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);
|
||||
|
Loading…
Reference in New Issue
Block a user