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

From: Namjae Jeon

Date: Sat Jul 25 2026 - 00:59:31 EST


On Sat, Jul 25, 2026 at 1:26 PM Darrick J. Wong <djwong@xxxxxxxxxx> wrote:
>
> On Sat, Jul 25, 2026 at 10:51:21AM +0900, Namjae Jeon wrote:
> > On Sat, Jul 25, 2026 at 10:18 AM Namjae Jeon <linkinjeon@xxxxxxxxxx> wrote:
> > >
> > > 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().
> > Thinking about this more, returning IOMAP_UNWRITTEN for the
> > preallocated tail under IOMAP_REPORT would affect normal
> > SEEK_HOLE/SEEK_DATA as well, where we need to preserve the
> > byte-accurate valid_size boundary. Would extending valid_size through
> > the full swap-usable range, i.e. ALIGN_DOWN(i_size, PAGE_SIZE),
> > before activation be the better approach? That would let us retain the
> > existing IOMAP_REPORT hole handling for normal seeks.
>
> Manually zeroing by pushing valid_size out would also work, but that's a
> lot of zeroes to write to the storage, flash wearout, blah blah blah.
> In the ideal world the whole swapfile would be all unwritten blocks
> (except the swapfile header) so that nobody could reread the swapfile
> contents after swapoff.
I do not have a good idea for resolving these two conflicting
requirements, other than simply not supporting swapfiles on exFAT...