Re: [PATCH v4 01/11] iomap: introduce IOMAP_F_ZERO_TAIL flag
From: Namjae Jeon
Date: Mon May 18 2026 - 23:33:19 EST
On Tue, May 19, 2026 at 1:03 AM Darrick J. Wong <djwong@xxxxxxxxxx> wrote:
>
> On Mon, May 18, 2026 at 08:46:55PM +0900, Namjae Jeon wrote:
> > In filesystems that maintain a separate Valid Data Length, such as exFAT
> > and NTFS, a partial write may start at or beyond the current valid_size and
> > extend it. In this case, the region after the previous valid_size but
> > within the same filesystem block is considered unwritten.
> >
> > This patch introduces IOMAP_F_ZERO_TAIL. When this flag is set in iomap,
> > __iomap_write_begin() will zero only the tail portion while preserving any
> > valid data before it in the same block.
> >
> > Without this tail zeroing, stale data in the unwritten portion of the block
> > can remain in the page cache. Subsequent reads can then return incorrect
> > contents from that region.
> >
> > Acked-by: Christoph Hellwig <hch@xxxxxx>
> > Signed-off-by: Namjae Jeon <linkinjeon@xxxxxxxxxx>
>
> AFAICT, the "valid size" means "all space between valid_size and i_size
> is unwritten", and that's why you need the tail of the block to be
> zeroed, right?
Exactly.
>
> So if, say, the fsblock size is 4k and valid_size is 80k; and I initiate
> a pwrite of 300 bytes at 121k, exfat will do its own zeroing to bump
> valid_size up to 121k, right? Then the actual iomap_write call will
> copy the 300 bytes into the pagecache, and now it needs ZERO_TAIL to
> zero the rest of the pagecache from (121k + 300) to 124k, correct?
Yes, that's correct.
>
> (What I'm probing for is, there's no need for a ZERO_HEAD at this time
> because exfat has to take care of that, right?)
Right.
>
> Reviewed-by: "Darrick J. Wong" <djwong@xxxxxxxxxx>
Thanks for the review!
>
> --D
>
> > ---
> > fs/iomap/buffered-io.c | 4 ++++
> > include/linux/iomap.h | 4 ++++
> > 2 files changed, 8 insertions(+)
> >
> > diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
> > index d7b648421a70..44046c648df4 100644
> > --- a/fs/iomap/buffered-io.c
> > +++ b/fs/iomap/buffered-io.c
> > @@ -836,6 +836,7 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
> > return -EIO;
> > folio_zero_segments(folio, poff, from, to, poff + plen);
> > } else {
> > + const struct iomap *iomap = iomap_iter_srcmap(iter);
> > int status;
> >
> > if (iter->flags & IOMAP_NOWAIT)
> > @@ -853,6 +854,9 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
> > len, status, GFP_NOFS);
> > if (status)
> > return status;
> > +
> > + if (iomap->flags & IOMAP_F_ZERO_TAIL)
> > + folio_zero_segment(folio, to, poff + plen);
> > }
> > iomap_set_range_uptodate(folio, poff, plen);
> > } while ((block_start += plen) < block_end);
> > diff --git a/include/linux/iomap.h b/include/linux/iomap.h
> > index 2c5685adf3a9..750602e18750 100644
> > --- a/include/linux/iomap.h
> > +++ b/include/linux/iomap.h
> > @@ -67,6 +67,9 @@ struct vm_fault;
> > * bio, i.e. set REQ_ATOMIC.
> > *
> > * IOMAP_F_INTEGRITY indicates that the filesystems handles integrity metadata.
> > + *
> > + * IOMAP_F_ZERO_TAIL indicates the remainder of the block after the data
> > + * written should be zeroed.
> > */
> > #define IOMAP_F_NEW (1U << 0)
> > #define IOMAP_F_DIRTY (1U << 1)
> > @@ -86,6 +89,7 @@ struct vm_fault;
> > #else
> > #define IOMAP_F_INTEGRITY 0
> > #endif /* CONFIG_BLK_DEV_INTEGRITY */
> > +#define IOMAP_F_ZERO_TAIL (1U << 10)
> >
> > /*
> > * Flag reserved for file system specific usage
> > --
> > 2.25.1
> >