Re: [PATCH] exfat: preserve allocated extents for swap activation

From: Namjae Jeon

Date: Fri Jul 24 2026 - 21:18:43 EST


On Sat, Jul 25, 2026 at 12:53 AM Darrick J. Wong <djwong@xxxxxxxxxx> wrote:
>
> On Fri, Jul 24, 2026 at 09:57:49AM +0900, Namjae Jeon wrote:
> > On Fri, Jul 24, 2026 at 4:19 AM Harshit Mogalapalli
> > <harshit.m.mogalapalli@xxxxxxxxxx> wrote:
> > >
> > > exFAT reports allocated ranges beyond valid_size as IOMAP_HOLE whenever
> > > IOMAP_REPORT is set. iomap_swapfile_activate() also uses IOMAP_REPORT
> > > while collecting a swapfile's physical extents, so it treats the
> > > preallocated tail as unallocated and rejects the file with -EINVAL.
> > >
> > > Allocated space beyond valid_size is not a hole. Keep it as
> > > IOMAP_UNWRITTEN so iomap consumers that need physical extent identity,
> > > such as swap activation, can still use it. The iomap seek helpers
> > > already handle unwritten extents appropriately for SEEK_HOLE and
> > > SEEK_DATA.
> > >
> > > Fixes: b4b7fe2c7cbf ("exfat: add support for SEEK_HOLE and SEEK_DATA in llseek")
> > > Assisted-by: Codex:GPT-5.6
> > > Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@xxxxxxxxxx>
> > > ---
> > > LTP swapon/swapoff tests failed on exFAT, with this patch the tests
> > > pass.
> > > ---
> > > fs/exfat/iomap.c | 16 ++++++----------
> > > 1 file changed, 6 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
> > > index 190fc6471f84..24d93288a432 100644
> > > --- a/fs/exfat/iomap.c
> > > +++ b/fs/exfat/iomap.c
> > > @@ -105,18 +105,14 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
> > > * marks the exact boundary between valid data and
> > > * holes (or unwritten space).
> > > *
> > > - * When IOMAP_REPORT is set (used by lseek(SEEK_HOLE)
> > > - * and SEEK_DATA), we return IOMAP_HOLE. This allows
> > > - * iomap_seek_hole_iter() to directly return the
> > > - * precise byte position.
> > > - *
> > > - * For normal I/O paths (without IOMAP_REPORT) we
> > > - * return IOMAP_UNWRITTEN so the write path can
> > > - * distinguish it from a real hole.
> > > + * Allocated space beyond valid_size is not a hole. Report it
> > > + * as IOMAP_UNWRITTEN so iomap consumers that need physical
> > > + * extent identity, such as swap activation, can still use it.
> > > + * The iomap seek helpers already handle unwritten extents
> > > + * appropriately for SEEK_HOLE and SEEK_DATA.
> > > */
> > > if (offset >= ei->valid_size) {
> > > - iomap->type = flags & IOMAP_REPORT ?
> > > - IOMAP_HOLE : IOMAP_UNWRITTEN;
> > > + iomap->type = IOMAP_UNWRITTEN;
> > Returning IOMAP_UNWRITTEN with IOMAP_REPORT can make SEEK_HOLE rely on
> > page-cache/block-granularity handling, which can lose the
> > byte-accurate valid_size boundary. Before activating the swapfile,
> > extending ->valid_size to i_size through exfat_extend_valid_size()
> > safely zeroes the preallocated range and makes it valid for swap use.
>
> iomap swapfile activation can handle unwritten extents (unlike the bmap
> activation codepath) so you probably only need to bump valid_size up to
> the next max(PAGE_SIZE, i_blocksize) boundary. The swap code writes
> to the underlying disk blocks directly, bypassing the filesystem.
That makes sense. We can call exfat_extend_valid_size() to extend
->valid_size only to the next page/block boundary in
exfat_iomap_swap_activate().
Thanks.