mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-19 20:10:43 +09:00
ext4: fix extent tree corruption caused by hole punch
commit c36575e663 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
fc65b0bb8b
commit
8cbe63802d
@@ -2140,13 +2140,14 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
|
||||
* last index in the block only.
|
||||
*/
|
||||
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");
|
||||
@@ -2162,6 +2163,19 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
|
||||
ext_debug("index is empty, remove it, free block %llu\n", leaf);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2509,7 +2523,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;
|
||||
@@ -2639,7 +2653,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);
|
||||
|
||||
Reference in New Issue
Block a user