From: Daejun Park ext4_ext_convert_to_initialized() may zero out the blocks before and after the range being written and convert them to written together with it, instead of splitting them off the unwritten extent. If ext4_ext_zeroout() fails for one side, it falls back to splitting the extent, so the blocks on that side stay unwritten in the extent tree. But zero_ex1 or zero_ex2 keeps its length, and ext4_zeroout_es() still inserts those blocks into the extent status tree as written. Until that entry goes away, a read of those blocks returns whatever was on the disk before the extent was allocated. A write to them is mapped from the cache and goes in place without converting the extent, so its data would read back as zeroes once the entry is dropped. To reproduce on 4 KiB blocks with -o nodelalloc: fallocate 32 KiB, map the last seven blocks of that extent to dm-error, write the first block, restore the mapping and read the second block. It returns the old disk contents instead of zeroes. Clear the length of an extent that could not be zeroed out, so that ext4_zeroout_es() skips it, as the comment at the out label intends. Fixes: 308c57ccf431 ("ext4: if zeroout fails fall back to splitting the extent node") Cc: stable@vger.kernel.org Reviewed-by: Jan Kara Signed-off-by: Daejun Park --- fs/ext4/extents.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 836396ea79..d65e30f3c1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3755,8 +3755,10 @@ ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode, ext4_ext_pblock(ex) + split_map.m_lblk + split_map.m_len - ee_block); err = ext4_ext_zeroout(inode, &zero_ex1); - if (err) + if (err) { + zero_ex1.ee_len = 0; goto fallback; + } split_map.m_len = *allocated; } if (split_map.m_lblk - ee_block + split_map.m_len < @@ -3769,8 +3771,10 @@ ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode, ext4_ext_store_pblock(&zero_ex2, ext4_ext_pblock(ex)); err = ext4_ext_zeroout(inode, &zero_ex2); - if (err) + if (err) { + zero_ex2.ee_len = 0; goto fallback; + } } split_map.m_len += split_map.m_lblk - ee_block; -- 2.43.0