[PATCH 1/2] exfat: fix iomap mapping when writeback races with truncate

From: Youling Tang

Date: Fri Nov 13 2026 - 10:02:47 EST


From: Youling Tang <tangyouling@xxxxxxxxxx>

__exfat_iomap_begin() reads i_size twice: once to detect a range that
starts beyond EOF, and once to clamp the mapping to EOF. A concurrent
truncate can shrink i_size between the two reads, so the clamp can
produce a negative length. The unsigned cluster index subtraction then
underflows, making exfat_map_cluster() believe it has to allocate a huge
number of clusters and report a hole.

Fix this by reading i_size once for both the EOF check and the
block-aligned clamp.

Fixes: 82a81a7352bc ("exfat: add iomap buffered I/O support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Youling Tang <tangyouling@xxxxxxxxxx>
---
fs/exfat/iomap.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
index 4e6f3ed9dcc8..11823591b3a8 100644
--- a/fs/exfat/iomap.c
+++ b/fs/exfat/iomap.c
@@ -51,8 +51,10 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
bool balloc = false;

if (!may_alloc) {
+ loff_t isize = i_size_read(inode);
+
/* Completely beyond EOF. Treat as hole */
- if (i_size_read(inode) <= offset) {
+ if (offset >= isize) {
iomap->type = IOMAP_HOLE;
iomap->addr = IOMAP_NULL_ADDR;
iomap->offset = offset;
@@ -61,9 +63,8 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
}

/* Clamp length if the requested range goes beyond i_size */
- if (offset + length > i_size_read(inode))
- length = round_up(i_size_read(inode),
- i_blocksize(inode)) - offset;
+ if (offset + length > isize)
+ length = round_up(isize, i_blocksize(inode)) - offset;
}

num_clusters = exfat_bytes_to_cluster_round_up(sbi,
--
2.43.0