exfat: fix a large buffered write failing when the volume is nearly full

Commit 82a81a7352 ("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 82a81a7352 ("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: 82a81a7352 ("exfat: add iomap buffered I/O support")
Cc: stable@vger.kernel.org
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Hengyu Liang 2026-10-10 00:44:20 -04:00 committed by Namjae Jeon
parent 748ad4ba13
commit 73cababf93

View File

@ -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;