Re: [PATCH] ksmbd: truncate files before allocating space below EOF

From: Namjae Jeon

Date: Tue Oct 13 2026 - 18:17:47 EST


> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index 12a43efdb53f..b155a27eaeac 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -8533,23 +8533,15 @@ static int set_file_allocation_info(struct ksmbd_work *work,
> alloc_blks = (alloc_size + 511) >> 9;
> inode = file_inode(fp->filp);
>
> - if (alloc_blks > stat.blocks) {
> - smb_break_all_levII_oplock(work, fp, 1);
> - rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
> - alloc_blks * 512);
> - if (rc && rc != -EOPNOTSUPP) {
> - pr_err("vfs_fallocate is failed : %d\n", rc);
> - return rc;
> - }
> - } else if (alloc_blks < stat.blocks) {
> + if (alloc_blks * 512 < i_size_read(inode) ||
> + alloc_blks < stat.blocks) {
> loff_t size;
>
> /*
> - * 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 before considering allocation when the new size is below
> + * EOF. This avoids allocating holes in a sparse file just before
> + * shrinking it. Also release excess blocks if EOF is already
> + * smaller than the requested allocation size.
> */
> size = i_size_read(inode);
> rc = ksmbd_vfs_truncate(work, fp, alloc_blks * 512);
Using alloc_blks * 512 for fallocate() and truncate() doesn't look right.
MS-FSCC section 2.4.4 describe:

"The file system rounds the requested allocation size up to an integer
multiple of the cluster size for nonresident files, or an
implementation-defined multiple for resident files."

And the truncate branch skips fallocate(), so it can return success
without reserving the requested space. For example, if a file has data
only at offset 1MB, setting AllocationSize to 512 KiB removes that
data. The file size will be 512KB, but the file will have no allocated
blocks.


> @@ -8559,6 +8551,14 @@ static int set_file_allocation_info(struct ksmbd_work *work,
> }
> if (size < alloc_blks * 512)
> i_size_write(inode, size);
> + } else if (alloc_blks > stat.blocks) {
> + smb_break_all_levII_oplock(work, fp, 1);
> + rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
> + alloc_blks * 512);
> + if (rc && rc != -EOPNOTSUPP) {
> + pr_err("vfs_fallocate is failed : %d\n", rc);
> + return rc;
> + }
> }
>
> fp->allocation_size = le64_to_cpu(file_alloc_info->AllocationSize);
> --
> 2.43.0
>