smb/client: refresh allocation after EOF-extending fallocate

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>
This commit is contained in:
Huiwen He
2026-07-03 13:32:59 +08:00
committed by Steve French
parent 7a06d3b816
commit 5bd1d3dcc2
5 changed files with 67 additions and 7 deletions

View 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;
}

View 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,

View 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,

View 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;

View 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;