[PATCH 1/2] ksmbd: avoid restoring only in-memory EOF after allocation change

From: DaeMyung Kang

Date: Fri Oct 16 2026 - 23:41:29 EST


When SetAllocation requests a size below the allocated block count but
above EOF, ksmbd truncates the file to that size and restores only the
in-memory i_size. The larger EOF remains on disk and reappears after a
reboot. A 3-byte file preallocated to 64 KiB can acquire a 4 KiB EOF
after reducing its allocation to 4 KiB. Extending EOF this way is not
a reliable way to reclaim the preallocation beyond the old EOF either.

Only use this truncate path when the requested allocation is at or below
the observed EOF. A truncate to the existing EOF still lets filesystems
release preallocated blocks beyond EOF. Remove the in-memory-only i_size
restoration. The size check still precedes vfs_truncate() taking the
inode lock, so a concurrent shrink can make the truncate extend EOF;
that race also existed in the original path.

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: DaeMyung Kang <charsyam@xxxxxxxxx>
---
fs/smb/server/smb2pdu.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 2da6163ee776..d06bdc8b23db 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8636,24 +8636,17 @@ static int set_file_allocation_info(struct ksmbd_work *work,
pr_err("vfs_fallocate is failed : %d\n", rc);
return rc;
}
- } else if (alloc_blks < stat.blocks) {
- loff_t size;
-
+ } else if (alloc_blks < stat.blocks &&
+ alloc_blks * 512 <= i_size_read(inode)) {
/*
- * Allocation size could be smaller than original one
- * which means allocated blocks in file should be
- * deallocated. use truncate to cut out it, but inode
- * size is also updated with truncate offset.
- * inode size is retained by backup inode size.
+ * Truncate at or below EOF to discard excess allocation.
+ * Truncating above EOF would extend the file on disk.
*/
- size = i_size_read(inode);
rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512);
if (rc) {
pr_err("truncate failed!, err %d\n", rc);
return rc;
}
- if (size < alloc_blks * 512)
- i_size_write(inode, size);
}

fp->allocation_size = le64_to_cpu(file_alloc_info->AllocationSize);
--
2.43.0