]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb/client: reduce fallocate zero buffer allocation
authorHuiwen He <hehuiwen@kylinos.cn>
Fri, 3 Jul 2026 05:32:57 +0000 (13:32 +0800)
committerSteve French <stfrench@microsoft.com>
Mon, 13 Jul 2026 15:37:55 +0000 (10:37 -0500)
The fallocate emulation allocates a 1 MiB zero-filled buffer even
though each SMB2_write request is limited to SMB2_MAX_BUFFER_SIZE,
which is 64 KiB. A high-order 1 MiB allocation is more likely to
fail on a fragmented system.

Allocate only the smaller of the requested range and SMB2_MAX_BUFFER_SIZE,
and reuse that zero-filled buffer for every write request. Also reject
a successful write that makes no progress to avoid looping indefinitely.

This reduces the contiguous allocation required by fallocate emulation
without changing the written data or range semantics.

Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2ops.c

index ddb28464ff81874b413d5bb51439a02f9f1fbf9e..ce607915a48376fe39b3d12fecffc84f65a0b04e 100644 (file)
@@ -3573,7 +3573,7 @@ static int smb3_simple_fallocate_write_range(unsigned int xid,
                                             char *buf)
 {
        struct cifs_io_parms io_parms = {0};
-       int nbytes;
+       unsigned int nbytes;
        int rc = 0;
        struct kvec iov[2];
 
@@ -3594,9 +3594,10 @@ static int smb3_simple_fallocate_write_range(unsigned int xid,
                rc = SMB2_write(xid, &io_parms, &nbytes, iov, 1);
                if (rc)
                        break;
+               if (!nbytes)
+                       return -EIO;
                if (nbytes > len)
                        return -EINVAL;
-               buf += nbytes;
                off += nbytes;
                len -= nbytes;
        }
@@ -3626,7 +3627,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
        if (rc)
                goto out;
 
-       buf = kvzalloc(1024 * 1024, GFP_KERNEL);
+       buf = kvzalloc(min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE), GFP_KERNEL);
        if (buf == NULL) {
                rc = -ENOMEM;
                goto out;