]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb/client: refresh allocation after EOF-extending fallocate
authorHuiwen He <hehuiwen@kylinos.cn>
Fri, 3 Jul 2026 05:32:59 +0000 (13:32 +0800)
committerSteve French <stfrench@microsoft.com>
Mon, 13 Jul 2026 15:37:55 +0000 (10:37 -0500)
Before this change, xfstests generic/496 was not supported on ksmbd:

        generic/496 ... [not run] fallocated swap not supported here

ksmbd handles SetEOF as truncate, so EOF extension alone does not
allocate backing blocks. A fallocated swapfile can therefore still
look sparse to swapon.

Request allocation for EOF-extending fallocate ranges that can be
represented by FILE_ALLOCATION_INFORMATION, and refresh the allocation
state afterwards.

With this change, xfstests generic/496 and generic/701 pass on ksmbd.

However, Samba "strict allocate = no" now exposes the real generic/701
failure: the old pass came from inflated local i_blocks, not from
server allocation. generic/213 also fails in that case because an
oversized allocation request may not return ENOSPC.

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
fs/smb/client/smb2pdu.c
fs/smb/client/smb2proto.h
fs/smb/common/fscc.h
fs/smb/server/smb2pdu.h

index 3e32ad18e6c21b9aeeca864e5fbfd85c9365bedb..05f2ab6d345a26cbced2d703bd1b8711cd23c872 100644 (file)
@@ -3788,12 +3788,49 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
                        smb2_set_sparse(xid, tcon, cfile, inode, false);
 
                new_eof = off + len;
+
+               qrc = SMB2_query_info(xid, tcon,
+                                     cfile->fid.persistent_fid,
+                                     cfile->fid.volatile_fid, &file_inf);
+               if (qrc == 0)
+                       asize = le64_to_cpu(file_inf.AllocationSize);
+
+               /*
+                * FILE_ALLOCATION_INFORMATION can only describe allocation up to
+                * new_eof. Some servers may accept it without allocating blocks,
+                * so refresh AllocationSize before updating i_blocks.
+                */
+               if (off == 0 || off == old_eof) {
+                       if (qrc || asize < new_eof) {
+                               rc = SMB2_set_allocation(xid, tcon,
+                                                        cfile->fid.persistent_fid,
+                                                        cfile->fid.volatile_fid,
+                                                        cfile->pid, new_eof);
+                               if (rc)
+                                       goto out;
+                       }
+               }
+
                rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                                  cfile->fid.volatile_fid, cfile->pid, new_eof);
-               if (rc == 0) {
-                       netfs_resize_file(&cifsi->netfs, new_eof, true);
-                       cifs_setsize(inode, new_eof);
+               if (rc)
+                       goto out;
+
+               netfs_resize_file(&cifsi->netfs, new_eof, true);
+               cifs_setsize(inode, new_eof);
+
+               qrc = SMB2_query_info(xid, tcon,
+                                     cfile->fid.persistent_fid,
+                                     cfile->fid.volatile_fid, &file_inf);
+               spin_lock(&inode->i_lock);
+               if (qrc == 0) {
+                       asize = le64_to_cpu(file_inf.AllocationSize);
+                       if (asize >= new_eof)
+                               inode->i_blocks = CIFS_INO_BLOCKS(asize);
+               } else {
+                       cifsi->time = 0;
                }
+               spin_unlock(&inode->i_lock);
                goto out;
        }
 
index 8f83ab377db143354c7d052739b7a15cd9dfbf32..4ce165e40657f3cd27024ef0c8aff773f122d8a7 100644 (file)
@@ -5949,6 +5949,25 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
                        0, 1, &data, &size);
 }
 
+int
+SMB2_set_allocation(const unsigned int xid, struct cifs_tcon *tcon,
+                   u64 persistent_fid, u64 volatile_fid, u32 pid,
+                   loff_t allocation_size)
+{
+       struct smb2_file_alloc_info info;
+       void *data;
+       unsigned int size;
+
+       info.AllocationSize = cpu_to_le64(allocation_size);
+
+       data = &info;
+       size = sizeof(struct smb2_file_alloc_info);
+
+       return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+                       pid, FILE_ALLOCATION_INFORMATION, SMB2_O_INFO_FILE,
+                       0, 1, &data, &size);
+}
+
 int
 SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
                u64 persistent_fid, u64 volatile_fid,
index e01effe45ae2e66009b88644654c5ef0c3eb9e1a..2e9f7009682512c758f3f88c850e4e670fcf48e4 100644 (file)
@@ -204,6 +204,9 @@ void SMB2_query_directory_free(struct smb_rqst *rqst);
 int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
                 u64 persistent_fid, u64 volatile_fid, u32 pid,
                 loff_t new_eof);
+int SMB2_set_allocation(const unsigned int xid, struct cifs_tcon *tcon,
+                       u64 persistent_fid, u64 volatile_fid, u32 pid,
+                       loff_t allocation_size);
 int SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
                       struct smb_rqst *rqst, u64 persistent_fid,
                       u64 volatile_fid, u32 pid, u8 info_class, u8 info_type,
index 859849a42fec5e07ca68a4d1cd895ae7eaf68109..941db5a95564b6ae1b954cbd522e1fa44183c48f 100644 (file)
@@ -283,6 +283,11 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
        __le64 EndOfFile; /* new end of file value */
 } __packed; /* level 20 Set */
 
+/* See MS-FSCC 2.4.4 */
+struct smb2_file_alloc_info { /* encoding of request for level 19 */
+       __le64 AllocationSize;
+} __packed;
+
 /* See MS-FSCC 2.4.15 */
 typedef struct {
        __le32 NextEntryOffset;
index c2512dbcdec8569a890840dff23e434f7e3f4b68..aa06c8c905f1fc35cd6043e4e9074c65e3d91189 100644 (file)
@@ -212,10 +212,6 @@ struct smb2_file_ea_info {
        __le32 EASize;
 } __packed;
 
-struct smb2_file_alloc_info {
-       __le64 AllocationSize;
-} __packed;
-
 struct smb2_file_disposition_info {
        __u8 DeletePending;
 } __packed;