[PATCH] exfat: implement swap activate

From: Andrea Cervesato

Date: Thu Jun 18 2026 - 05:36:07 EST


From: Andrea Cervesato <andrea.cervesato@xxxxxxxx>

exfat's fallocate allocates clusters without updating valid_size,
leaving them invisible to bmap(). Extend valid_size to i_size so
that generic_swapfile_activate() can map all blocks.

This bug has been found during a Linux Test Project regression test
using swapon/swapoff testing suite.

Signed-off-by: Andrea Cervesato <andrea.cervesato@xxxxxxxx>
Fixes: bf1797960c20 ("exfat: add fallocate FALLOC_FL_ALLOCATE_RANGE support")
Link: https://patchwork.ozlabs.org/project/ltp/patch/20260608155241.270875-1-japo@xxxxxxxxxxxxx/
---
bf1797960c20 - ("exfat: add fallocate FALLOC_FL_ALLOCATE_RANGE support")
introduces fallocate() support in exfat, but omits the swap activate
implementation, causing EINVAL inside Linux Test Project swapon/swapoff
testing suites which are testing these syscalls with many filesystems,
including exfat.

This turned out to be a bug inside the kernel. The patch implements
swap activate in order to ensure that exfat valid_size is correctly
updated and the generic_swapfile_activate() doesn't fail with EINVAL
due to valid_size=0, which is passed to bmap().
---
fs/exfat/exfat_fs.h | 1 +
fs/exfat/file.c | 2 +-
fs/exfat/inode.c | 23 +++++++++++++++++++++++
3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index aff4dcd4e75a55296d536c19306813a566d6f0bb..18382c661d4358f8b80e6f7b5032a356a5905614 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -489,6 +489,7 @@ int exfat_trim_fs(struct inode *inode, struct fstrim_range *range);

/* file.c */
extern const struct file_operations exfat_file_operations;
+int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size);
int __exfat_truncate(struct inode *inode);
void exfat_truncate(struct inode *inode);
int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 91e5511945d11b12658908dc6287fabd572d1d6a..12ed28c3ff896fb545bad58b47cccf808b48618d 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -642,7 +642,7 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
return blkdev_issue_flush(inode->i_sb->s_bdev);
}

-static int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size)
+int exfat_extend_valid_size(struct inode *inode, loff_t new_valid_size)
{
int err;
loff_t pos;
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index 1ea4c740fef9ef6932a75e122e1b0130c85533b2..5a395851062e4a14b456fa79546541227d8427e6 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -11,6 +11,7 @@
#include <linux/time.h>
#include <linux/writeback.h>
#include <linux/uio.h>
+#include <linux/swap.h>
#include <linux/random.h>
#include <linux/iversion.h>

@@ -534,6 +535,27 @@ int exfat_block_truncate_page(struct inode *inode, loff_t from)
return block_truncate_page(inode->i_mapping, from, exfat_get_block);
}

+static int exfat_swap_activate(struct swap_info_struct *sis,
+ struct file *file, sector_t *span)
+{
+ struct inode *inode = file_inode(file);
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ int ret;
+
+ /*
+ * exfat's fallocate allocates clusters without updating valid_size,
+ * leaving them invisible to bmap(). Extend valid_size to i_size so
+ * that generic_swapfile_activate() can map all blocks.
+ */
+ if (ei->valid_size < i_size_read(inode)) {
+ ret = exfat_extend_valid_size(inode, i_size_read(inode));
+ if (ret)
+ return ret;
+ }
+
+ return generic_swapfile_activate(sis, file, span);
+}
+
static const struct address_space_operations exfat_aops = {
.dirty_folio = block_dirty_folio,
.invalidate_folio = block_invalidate_folio,
@@ -545,6 +567,7 @@ static const struct address_space_operations exfat_aops = {
.direct_IO = exfat_direct_IO,
.bmap = exfat_aop_bmap,
.migrate_folio = buffer_migrate_folio,
+ .swap_activate = exfat_swap_activate,
};

static inline unsigned long exfat_hash(loff_t i_pos)

---
base-commit: e771677c937da5808f7b6c1f0e4a97ec1a84f8a8
change-id: 20260618-exfat_swap_activate-86e4f1a475ef

Best regards,
--
Andrea Cervesato <andrea.cervesato@xxxxxxxx>