Re: [PATCH v2 1/6] ext4: move partial block zeroing earlier in ext4_zero_range()

From: Zhang Yi

Date: Tue Jul 07 2026 - 01:02:05 EST


On 7/7/2026 10:13 AM, Zhang Yi wrote:
> In ext4_zero_range(), move the ext4_zero_partial_blocks() call, which
> handles unaligned edges, into the same branch where the unaligned range
> is preallocated, immediately after ext4_alloc_file_blocks(). This is
> safe because there is no dependency between partial block handling and
> the subsequent full block handling.
>
> This change will be used by later patches that handle unaligned
> FALLOC_FL_WRITE_ZEROES operations, which will need to check the partial
> zeroed result.
>
> Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
> Reviewed-by: Jan Kara <jack@xxxxxxx>
> ---
> fs/ext4/extents.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 125f628e738a..27ca641e701b 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -4734,10 +4734,16 @@ static long ext4_zero_range(struct file *file, loff_t offset,
> }
>
> flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
> - /* Preallocate the range including the unaligned edges */
> + /*
> + * Preallocate the range including the unaligned edges, and zero
> + * out partial blocks if they already contain data.
> + */
> if (!IS_ALIGNED(offset | end, blocksize)) {
> ret = ext4_alloc_file_blocks(file, offset, len, new_size,
> flags);
> + if (!ret)
> + ret = ext4_zero_partial_blocks(inode, offset, len,
> + &partial_zeroed);
> if (ret)
> return ret;

Sashiko pointed out below:

>Is it safe to modify these folios before calling
>ext4_truncate_page_cache_block_range()?

>Previously, ext4_zero_range() called ext4_truncate_page_cache_block_range()
>first, which waits for writeback on the boundary folios via
>truncate_pagecache_range() -> truncate_inode_pages_range() ->
>truncate_inode_partial_folio().

>By zeroing the partial blocks earlier, ext4_block_do_zero_range() might
>acquire the folio lock and mutate the folio data while PG_writeback is still
>set, potentially causing data corruption or checksum mismatches if the block
>layer is actively DMA-ing it to disk.

I think this issue is confined to stable devices. The proposed fix is
to modify the fgf_flags passed to the folio lookup function in
ext4_load_tail_bh() by setting them to FGP_WRITEBEGIN | FGP_ACCESSED.

Thanks,
Yi.

> }
> @@ -4770,10 +4776,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
> if (IS_ALIGNED(offset | end, blocksize))
> return ret;
>
> - /* Zero out partial block at the edges of the range */
> - ret = ext4_zero_partial_blocks(inode, offset, len, &partial_zeroed);
> - if (ret)
> - return ret;
> if (((file->f_flags & O_SYNC) || IS_SYNC(inode)) && partial_zeroed) {
> ret = filemap_write_and_wait_range(inode->i_mapping, offset,
> end - 1);