Skip to content

Commit 7f0d8e1

Browse files
Eric Whitneytytso
authored andcommitted
ext4: fix extent status tree race in writeback error recovery path
A race can occur in the unlikely event ext4 is unable to allocate a physical cluster for a delayed allocation in a bigalloc file system during writeback. Failure to allocate a cluster forces error recovery that includes a call to mpage_release_unused_pages(). That function removes any corresponding delayed allocated blocks from the extent status tree. If a new delayed write is in progress on the same cluster simultaneously, resulting in the addition of an new extent containing one or more blocks in that cluster to the extent status tree, delayed block accounting can be thrown off if that delayed write then encounters a similar cluster allocation failure during future writeback. Write lock the i_data_sem in mpage_release_unused_pages() to fix this problem. Ext4's block/cluster accounting code for bigalloc relies on i_data_sem for mutual exclusion, as is found in the delayed write path, and the locking in mpage_release_unused_pages() is missing. Cc: stable@kernel.org Reported-by: Ye Bin <yebin10@huawei.com> Signed-off-by: Eric Whitney <enwlinux@gmail.com> Link: https://lore.kernel.org/r/20220615160530.1928801-1-enwlinux@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent a89573c commit 7f0d8e1

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

fs/ext4/inode.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,7 +1571,14 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd,
15711571
ext4_lblk_t start, last;
15721572
start = index << (PAGE_SHIFT - inode->i_blkbits);
15731573
last = end << (PAGE_SHIFT - inode->i_blkbits);
1574+
1575+
/*
1576+
* avoid racing with extent status tree scans made by
1577+
* ext4_insert_delayed_block()
1578+
*/
1579+
down_write(&EXT4_I(inode)->i_data_sem);
15741580
ext4_es_remove_extent(inode, start, last - start + 1);
1581+
up_write(&EXT4_I(inode)->i_data_sem);
15751582
}
15761583

15771584
pagevec_init(&pvec);

0 commit comments

Comments
 (0)