[PATCH v3 0/9] ext4: fix unaligned edge handling in FALLOC_FL_WRITE_ZEROES
From: Zhang Yi
Date: Wed Jul 08 2026 - 02:31:42 EST
From: Zhang Yi <yi.zhang@xxxxxxxxxx>
Hi,
This is v3 of the series to fix unaligned edge handling in
FALLOC_FL_WRITE_ZEROES. This version folds in the two pre-existing
fixes around ext4_block_zero_eof() and ext4_load_tail_bh() that Sashiko
reported[1] (they were planned to be sent separately in v2, but due to
dependencies between them, I've combined them into v3), and adds a third
fix to ext4_load_tail_bh() itself for the stable-writes case that
patch 4's reordering exposes[2].
Changes since v2:
- Add patch 1 to use FGP_WRITEBEGIN in ext4_load_tail_bh(), fixing a
pre-existing stable-writes bug exposed by patch 4's reordering.
- Fold in two pre-existing fixes (now patches 2 and 3) that were
originally going to be sent separately.
- Rework patch 9 per Sashiko's review on the orphan list handling
around the unwritten-to-written conversion.
Changes since v1:
- Pick up Jan's Reviewed-by on patches 1, 3, and 5.
- Expand patch 2 to also explain why a clean unwritten buffer returns
NULL (a lookup-only get_block never sets BH_Mapped for unwritten
extents), per Jan's review.
- Drop the last cleanup patch "skip ext4_update_disksize_before_punch()
in WRITE_ZEROES" because it's wrong.
- Add a new patch to protect the WRITE_ZEROES crash window by adding
the inode to the orphan list in the same handle that does the
unwritten-to-written conversion, and removing it once i_disksize
has caught up.
v2: https://lore.kernel.org/linux-ext4/20260707021338.1182268-1-yi.zhang@xxxxxxxxxx/
v1: https://lore.kernel.org/linux-ext4/20260701142009.1510104-1-yizhang089@xxxxxxxxx/
Origin cover-letter
===================
The current FALLOC_FL_WRITE_ZEROES implementation in ext4 does not
correctly handle unaligned edge blocks. FALLOC_FL_WRITE_ZEROES is needed
to convert the requested range to written extents with zeroed content,
but the existing code only partially zero the edges and never guarantees
that:
1) edges that are clean unwritten extents or holes get promoted to
written extents, and
2) edges that are dirty unwritten or delalloc get their underlying
extents converted to written before the syscall returns.
Both cases leave the on-disk extent type unwritten, violating the
WRITE_ZEROES contract, and in these cases a subsequent sync buffered
overwrite would still observe pending metadata changes from the
conversion work that should have been completed by WRITE_ZEROES itself.
This series fixes the unaligned edge handling and cleans up a related
redundant i_disksize update. The first three patches are preparatory:
moving ext4_zero_partial_blocks() earlier in ext4_zero_range(),
documenting the return semantics of ext4_load_tail_bh(), and replacing
the single bool output of ext4_zero_partial_blocks() with a per-edge
bitmask (EXT4_PARTIAL_ZERO_START/END). The next two patches fix the two
scenarios above by expanding the aligned allocation range outward for
skipped (clean unwritten or hole) edges, and by writing back
partial-zeroed edges so the underlying extents are converted to written.
The final patch drops the now-redundant
ext4_update_disksize_before_punch() call on the WRITE_ZEROES path, since
WRITE_ZEROES is mutually exclusive with KEEP_SIZE and the i_disksize
update is already handled by ext4_alloc_file_blocks().
Thanks,
Yi.
[1] https://sashiko.dev/#/patchset/20260701142009.1510104-1-yizhang089%40gmail.com?part=2
[2] https://sashiko.dev/#/patchset/20260707021338.1182268-1-yi.zhang%40huawei.com?part=1
Discussion Link:
https://lore.kernel.org/linux-xfs/0b7f1a4f-da1c-4297-8099-98d738070ab7@xxxxxxxxxxxxxxx/
Zhang Yi (9):
ext4: use FGP_WRITEBEGIN for tail block zeroing
ext4: skip tail block zeroing for inline data files
ext4: check return value of ext4_get_block() in ext4_load_tail_bh()
ext4: move partial block zeroing earlier in ext4_zero_range()
ext4: clarify return semantics of ext4_load_tail_bh()
ext4: track partial-zero outcome per edge in
ext4_zero_partial_blocks()
ext4: zero out whole block for clean edges in WRITE_ZEROES
ext4: write back partial-zeroed edges in WRITE_ZEROES
ext4: protect WRITE_ZEROES written extents with orphan list
fs/ext4/ext4.h | 5 ++-
fs/ext4/extents.c | 84 +++++++++++++++++++++++++++++++++++++++--------
fs/ext4/inode.c | 56 ++++++++++++++++++++++++++-----
3 files changed, 122 insertions(+), 23 deletions(-)
--
2.52.0