From: ChenXiaoSong Date: Mon, 8 Jun 2026 14:01:26 +0000 (+0000) Subject: smb/server: implement FSCTL_SET_COMPRESSION ioctl handler X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7eeb7b6772f02772b92c39146603005d0a1cb324;p=thirdparty%2Flinux.git smb/server: implement FSCTL_SET_COMPRESSION ioctl handler Example: 1. client: smbinfo setcompression no /mnt/file 2. client: smbinfo getcompression /mnt/file Compression: 0 (NONE) 3. client: smbinfo setcompression lznt1 /mnt/file 4. client: smbinfo getcompression /mnt/file Compression: 2 (LZNT1) 5. client: smbinfo setcompression default /mnt/file 6. client: smbinfo getcompression /mnt/file Compression: 2 (LZNT1) Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- diff --git a/fs/smb/common/smbfsctl.h b/fs/smb/common/smbfsctl.h index 9debdd709d1c1..d1fcb46a7cde3 100644 --- a/fs/smb/common/smbfsctl.h +++ b/fs/smb/common/smbfsctl.h @@ -62,7 +62,7 @@ #define FSCTL_UNLOCK_VOLUME 0x0009001C #define FSCTL_IS_PATHNAME_VALID 0x0009002C /* BB add struct */ #define FSCTL_GET_COMPRESSION 0x0009003C -#define FSCTL_SET_COMPRESSION 0x0009C040 /* BB add struct */ +#define FSCTL_SET_COMPRESSION 0x0009C040 #define FSCTL_QUERY_FAT_BPB 0x00090058 /* BB add struct */ /* Verify the next FSCTL number, we had it as 0x00090090 before */ #define FSCTL_FILESYSTEM_GET_STATS 0x00090060 /* BB add struct */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 975ca2ed84df6..4aed23a0fc0a3 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8382,6 +8382,34 @@ int smb2_ioctl(struct ksmbd_work *work) rsp->VolatileFileId = req->VolatileFileId; break; } + case FSCTL_SET_COMPRESSION: { + struct compress_ioctl *cmpr_req; + struct ksmbd_file *fp; + + if (in_buf_len < sizeof(struct compress_ioctl)) { + ret = -EINVAL; + goto out; + } + + if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { + ksmbd_debug(SMB, "User does not have write permission\n"); + ret = -EACCES; + goto out; + } + + cmpr_req = (struct compress_ioctl *)buffer; + fp = ksmbd_lookup_fd_fast(work, id); + if (!fp) { + ret = -ENOENT; + goto out; + } + + ret = ksmbd_vfs_set_compression(work, fp, le16_to_cpu(cmpr_req->CompressionState)); + ksmbd_fd_put(work, fp); + if (ret) + goto out; + break; + } case FSCTL_CREATE_OR_GET_OBJECT_ID: { struct file_object_buf_type1_ioctl_rsp *obj_buf; diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 82cfd0b2a4cb7..e865ae91650a1 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -1922,3 +1922,73 @@ int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt) out: return rc; } + +int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt) +{ + struct file_kattr fa; + struct dentry *dentry = fp->filp->f_path.dentry; + struct mnt_idmap *idmap = file_mnt_idmap(fp->filp); + u32 flags; + __le32 old_fattr; + int rc; + + if (!(fp->daccess & FILE_WRITE_DATA_LE)) { + rc = -EACCES; + goto out; + } + + rc = vfs_fileattr_get(dentry, &fa); + if (rc) + goto out; + + flags = fa.flags; + if (fmt == COMPRESSION_FORMAT_NONE) { + flags &= ~FS_COMPR_FL; + } else if (fmt == COMPRESSION_FORMAT_DEFAULT || + fmt == COMPRESSION_FORMAT_LZNT1) { + flags |= FS_COMPR_FL; + } else { + rc = -EINVAL; + goto out; + } + + if (flags != fa.flags) { + fileattr_fill_flags(&fa, flags); + rc = mnt_want_write_file(fp->filp); + if (rc) + goto out; + + rc = vfs_fileattr_set(idmap, dentry, &fa); + mnt_drop_write_file(fp->filp); + if (rc) + goto out; + } + + old_fattr = fp->f_ci->m_fattr; + if (fmt == COMPRESSION_FORMAT_NONE) + fp->f_ci->m_fattr &= ~FILE_ATTRIBUTE_COMPRESSED_LE; + else + fp->f_ci->m_fattr |= FILE_ATTRIBUTE_COMPRESSED_LE; + + if (fp->f_ci->m_fattr != old_fattr && + test_share_config_flag(work->tcon->share_conf, + KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) { + struct xattr_dos_attrib da; + + rc = ksmbd_vfs_get_dos_attrib_xattr(idmap, dentry, &da); + if (rc <= 0) { + rc = 0; + goto out; + } + + da.attr = le32_to_cpu(fp->f_ci->m_fattr); + rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, + &fp->filp->f_path, + &da, true); + if (rc) + rc = 0; + } + +out: + return rc; +} diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h index f6121207dbda4..7b3d2f4fd985c 100644 --- a/fs/smb/server/vfs.h +++ b/fs/smb/server/vfs.h @@ -170,4 +170,5 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, struct inode *parent_inode); void ksmbd_vfs_update_compressed_fattr(struct dentry *dentry, __le32 *fattr); int ksmbd_vfs_get_compression(struct ksmbd_file *fp, u16 *fmt); +int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt); #endif /* __KSMBD_VFS_H__ */