summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorZhang Yi <yi.zhang@huawei.com>2026-10-09 18:30:19 +0800
committerTheodore Ts'o <tytso@mit.edu>2026-10-15 10:53:13 -0400
commit3c612a572094291a752fe983af2868cde634ba02 (patch)
tree00463c9f214e713793f65b9ddadebf535570622b /include
parent68738d77ce86cd4028e23ac2fbc45c56683bea7a (diff)
ext4: drain writeback before removing extents on the iomap path
Because the iomap infrastructure does not always create an ifs to manage sub-folio state when folio size is larger than blocksize, invalidating a partial dirty folio during punch hole may fail to clear the dirty state of the affected range. As a result, writeback of that folio may observe a hole. At writeback submit time, ext4_map_blocks() already handles this case and will not allocate blocks. However, when punch hole races with writeback, the following scenario can cause I/O completion to encounter a hole. punch hole writeback ---------- --------- ext4_punch_hole() ext4_truncate_page_cache_block_range() iomap_invalidate_folio() [partial folio] iomap_clear_range_dirty() -- no ifs, sub-block dirty bits NOT cleared ext4_iomap_writepages() iomap_writepages() ext4_iomap_writeback_submit() ext4_iomap_map_writeback_range() ext4_map_blocks(IO_SUBMIT) -> extent exists, not a hole submit_io() -> bio in flight down_write(&i_data_sem) ext4_es_remove_extent() ext4_ext_remove_space() -> extent removed, hole inserted up_write(&i_data_sem) [ transaction commits, freed blocks released to buddy ] [ allocator reuses freed blocks for another inode ] [bio completes] ext4_iomap_finish_ioend() ext4_convert_unwritten_extents() ext4_map_blocks(IO_CONVERT_EXT) -> returns 0 (hole found) [bio writes to reallocated blocks ] -> silent data corruption If the bio completes after the freed blocks have been reallocated to another inode, it silently overwrites them and causes data corruption. Therefore, on the iomap path, drain writeback in ext4_punch_hole() after partial zeroing and before starting the freeing transaction, so any bio in flight on a partial folio completes against blocks still owned by this inode before extent removal. Once extent removal begins, the ES hole insert and the existing IO_SUBMIT short-circuit prevent further bio submission. This is a workaround. The proper fix is for the iomap infrastructure to always maintain an ifs when folio size is larger than blocksize, so that partial invalidate reliably clears sub-block dirty bits and no draining is needed. Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Tested-by: syzbot@syzkaller.appspotmail.com Link: https://patch.msgid.link/20261009103033.2920530-19-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'include')
0 files changed, 0 insertions, 0 deletions