Skip to content

Commit e9fe2b8

Browse files
LiBaokun96tytso
authored andcommitted
ext4: using nofail preallocation in ext4_es_remove_extent()
If __es_remove_extent() returns an error it means that when splitting extent, allocating an extent that must be kept failed, where returning an error directly would cause the extent tree to be inconsistent. So we use GFP_NOFAIL to pre-allocate an extent_status and pass it to __es_remove_extent() to avoid this problem. In addition, since the allocated memory is outside the i_es_lock, the extent_status tree may change and the pre-allocated extent_status is no longer needed, so we release the pre-allocated extent_status when es->es_len is not initialized. Suggested-by: Jan Kara <jack@suse.cz> Signed-off-by: Baokun Li <libaokun1@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://lore.kernel.org/r/20230424033846.4732-7-libaokun1@huawei.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent bda3efa commit e9fe2b8

1 file changed

Lines changed: 11 additions & 2 deletions

File tree

fs/ext4/extents_status.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,7 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
14541454
ext4_lblk_t end;
14551455
int err = 0;
14561456
int reserved = 0;
1457+
struct extent_status *es = NULL;
14571458

14581459
if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)
14591460
return 0;
@@ -1468,17 +1469,25 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
14681469
end = lblk + len - 1;
14691470
BUG_ON(end < lblk);
14701471

1472+
retry:
1473+
if (err && !es)
1474+
es = __es_alloc_extent(true);
14711475
/*
14721476
* ext4_clear_inode() depends on us taking i_es_lock unconditionally
14731477
* so that we are sure __es_shrink() is done with the inode before it
14741478
* is reclaimed.
14751479
*/
14761480
write_lock(&EXT4_I(inode)->i_es_lock);
1477-
err = __es_remove_extent(inode, lblk, end, &reserved, NULL);
1481+
err = __es_remove_extent(inode, lblk, end, &reserved, es);
1482+
if (es && !es->es_len)
1483+
__es_free_extent(es);
14781484
write_unlock(&EXT4_I(inode)->i_es_lock);
1485+
if (err)
1486+
goto retry;
1487+
14791488
ext4_es_print_tree(inode);
14801489
ext4_da_release_space(inode, reserved);
1481-
return err;
1490+
return 0;
14821491
}
14831492

14841493
static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,

0 commit comments

Comments
 (0)