From 73cababf93cb371e2e9d06da5261ca6ddd2404b6 Mon Sep 17 00:00:00 2001 From: Hengyu Liang Date: Sat, 10 Oct 2026 00:44:20 -0400 Subject: [PATCH] exfat: fix a large buffered write failing when the volume is nearly full Commit 82a81a7352bc ("exfat: add iomap buffered I/O support") made a buffered write map the whole range of the write in one step, so the clusters for all of it are allocated at once. However, exfat_alloc_cluster() returns -ENOSPC when fewer clusters are free than it is asked for. As of now, a write() that is larger than the free space writes nothing and fails with ENOSPC, while it used to write as much as fits and return a short count. The issue can be reproduced with a 16M image made by mkfs.exfat that is filled except for 256K: mount -o loop /img /mnt dd if=/dev/zero of=/mnt/hole bs=256k count=1 dd if=/dev/zero of=/mnt/fill bs=4k rm /mnt/hole dd if=/dev/zero of=/mnt/f bs=1M count=1 wc -c < /mnt/f Before commit 82a81a7352bc ("exfat: add iomap buffered I/O support"), the result is: 262144 After that commit, the result is: 0 This patch will map a single cluster when the clusters for the whole range cannot be allocated, so that the write goes on until the volume is full. Direct I/O is not changed, it still fails without writing as it did before that commit. Fixes: 82a81a7352bc ("exfat: add iomap buffered I/O support") Cc: stable@vger.kernel.org Signed-off-by: Hengyu Liang Signed-off-by: Namjae Jeon --- fs/exfat/iomap.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c index bec0b35b9420..e50ecbfbfbe0 100644 --- a/fs/exfat/iomap.c +++ b/fs/exfat/iomap.c @@ -75,6 +75,17 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length err = exfat_map_cluster(inode, exfat_bytes_to_cluster(sbi, offset), &cluster, &num_clusters, may_alloc, &balloc); + if (err == -ENOSPC && !(flags & IOMAP_DIRECT)) { + /* + * There are not enough free clusters for the whole range. A + * buffered write can be short, so map what still fits. + */ + num_clusters = 1; + err = exfat_map_cluster(inode, + exfat_bytes_to_cluster(sbi, offset), + &cluster, &num_clusters, may_alloc, + &balloc); + } if (err) goto out;