Re: [PATCH 1/2] ext4: don't cache unzeroed blocks as written after a failed zeroout

From: Ojaswin Mujoo

Date: Thu Oct 08 2026 - 02:22:46 EST


On Wed, Oct 07, 2026 at 09:41:20AM +0900, Daejun Park via B4 Relay wrote:
> From: Daejun Park <daejun7.park@xxxxxxxxxxx>
>
> 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@xxxxxxxxxxxxxxx
> Signed-off-by: Daejun Park <daejun7.park@xxxxxxxxxxx>

Hi Daejun,

Feel free to add:

Reviewed-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx>

btw, did you catch this with some fstests? If not I think it would be
good to add a test for this.

Regards
ojaswin

> ---
> 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
>
>