]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
smb/server: implement FSCTL_SET_COMPRESSION ioctl handler
authorChenXiaoSong <chenxiaosong@kylinos.cn>
Mon, 8 Jun 2026 14:01:26 +0000 (14:01 +0000)
committerSteve French <stfrench@microsoft.com>
Tue, 16 Jun 2026 23:57:21 +0000 (18:57 -0500)
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 <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/common/smbfsctl.h
fs/smb/server/smb2pdu.c
fs/smb/server/vfs.c
fs/smb/server/vfs.h

index 9debdd709d1c139feabbb1c41430c350a50e74b9..d1fcb46a7cde3d1479566c3b33417ceaa4430d65 100644 (file)
@@ -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 */
index 975ca2ed84df6a7e0d69a2ea38c92a39f60b3a6f..4aed23a0fc0a3d48d23edf7f2f001ce5e72d3bb1 100644 (file)
@@ -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;
index 82cfd0b2a4cb70f29bf09ca32e13e017dcfbd1da..e865ae91650a1c3ab1730aaafa57e6d4eacbd735 100644 (file)
@@ -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;
+}
index f6121207dbda431f9b1945c46292d9a7b23304a8..7b3d2f4fd985c7c9e1f9739b82d2660a8e58845c 100644 (file)
@@ -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__ */