Re: [PATCH] exfat: free clusters beyond EOF when a write fails or is short

From: Namjae Jeon

Date: Tue Oct 13 2026 - 09:53:23 EST


On Mon, Oct 12, 2026 at 6:41 PM Hengyu Liang <hengyul@xxxxxxxxxx> wrote:
>
> Commit 82a81a7352bc ("exfat: add iomap buffered I/O support") and commit
> 867b9c96dc83 ("exfat: add iomap direct I/O support") made a write
> allocate the clusters for its whole range in one step. They also dropped
> exfat_write_failed(), which freed the clusters beyond the end of the
> file after a failed or short write.
>
> However, a write can stop early, for example when the process is killed
> or when a part of the buffer cannot be read. As of now, the clusters for
> the part that was not written stay allocated beyond the end of the file.
> exfat_cont_expand() does not expect them, so a later write or truncate
> that extends the file fails with ENOSPC. The directory entry records
> only the size of the file, so the space can be lost for good once the
> volume is unmounted.
>
> The issue can be reproduced on a 64M volume made by mkfs.exfat and
> mounted on /mnt, with a write of 1M from a buffer that has only its
> first 4K mapped:
>
> #include <fcntl.h>
> #include <stdio.h>
> #include <sys/mman.h>
> #include <sys/stat.h>
> #include <unistd.h>
>
> int main(void)
> {
> char *p = mmap(NULL, 8192, PROT_READ | PROT_WRITE,
> MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> int fd = open("/mnt/f", O_CREAT | O_WRONLY, 0644);
> struct stat st;
>
> munmap(p + 4096, 4096);
> printf("write: %zd\n", write(fd, p, 1 << 20));
> fstat(fd, &st);
> printf("blocks: %ld\n", (long)st.st_blocks);
> printf("ftruncate: %d\n", ftruncate(fd, 1 << 16));
> return 0;
> }
>
> Before commit 82a81a7352bc ("exfat: add iomap buffered I/O support"),
> the result is:
>
> write: 4096
> blocks: 8
> ftruncate: 0
>
> After that commit, the result is:
>
> write: 4096
> blocks: 2048
> ftruncate: -1
>
> This patch will bring back exfat_write_failed() and call it when a write
> ends before the end of its range, so that the clusters beyond the end of
> the file are freed again. It waits for direct I/O in flight first, as
> exfat_setattr() does before it frees clusters.
>
> Fixes: 82a81a7352bc ("exfat: add iomap buffered I/O support")
> Fixes: 867b9c96dc83 ("exfat: add iomap direct I/O support")
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: LLM
> Signed-off-by: Hengyu Liang <hengyul@xxxxxxxxxx>
Applied it to #exfat-next.
Thanks!