diff mbox series

[RFC,4/4] cifs: Implement FS_IOC_FS[GS]ETXATTR API for Windows attributes

Message ID 20250216164029.20673-5-pali@kernel.org (mailing list archive)
State New
Headers show
Series fs: Add support for Windows file attributes | expand

Commit Message

Pali Rohár Feb. 16, 2025, 4:40 p.m. UTC
Signed-off-by: Pali Rohár <pali@kernel.org>
---
 fs/smb/client/cifsfs.c    |   4 +
 fs/smb/client/cifsfs.h    |   2 +
 fs/smb/client/cifsglob.h  |   4 +-
 fs/smb/client/cifsproto.h |   2 +-
 fs/smb/client/cifssmb.c   |   4 +-
 fs/smb/client/inode.c     | 181 ++++++++++++++++++++++++++++++++++++++
 fs/smb/client/ioctl.c     |   8 +-
 fs/smb/client/smb1ops.c   |   4 +-
 fs/smb/client/smb2ops.c   |   8 +-
 fs/smb/client/smb2pdu.c   |   4 +-
 fs/smb/client/smb2proto.h |   2 +-
 fs/smb/common/smb2pdu.h   |   2 +
 12 files changed, 209 insertions(+), 16 deletions(-)

Comments

Amir Goldstein Feb. 16, 2025, 8:21 p.m. UTC | #1
On Sun, Feb 16, 2025 at 5:42 PM Pali Rohár <pali@kernel.org> wrote:
>

No empty commit message please

> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
>  fs/smb/client/cifsfs.c    |   4 +
>  fs/smb/client/cifsfs.h    |   2 +
>  fs/smb/client/cifsglob.h  |   4 +-
>  fs/smb/client/cifsproto.h |   2 +-
>  fs/smb/client/cifssmb.c   |   4 +-
>  fs/smb/client/inode.c     | 181 ++++++++++++++++++++++++++++++++++++++
>  fs/smb/client/ioctl.c     |   8 +-
>  fs/smb/client/smb1ops.c   |   4 +-
>  fs/smb/client/smb2ops.c   |   8 +-
>  fs/smb/client/smb2pdu.c   |   4 +-
>  fs/smb/client/smb2proto.h |   2 +-
>  fs/smb/common/smb2pdu.h   |   2 +
>  12 files changed, 209 insertions(+), 16 deletions(-)
>
> diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
> index ea31d693ea9f..b441675f9afd 100644
> --- a/fs/smb/client/cifsfs.c
> +++ b/fs/smb/client/cifsfs.c
> @@ -1182,6 +1182,8 @@ const struct inode_operations cifs_dir_inode_ops = {
>         .listxattr = cifs_listxattr,
>         .get_acl = cifs_get_acl,
>         .set_acl = cifs_set_acl,
> +       .fileattr_get = cifs_fileattr_get,
> +       .fileattr_set = cifs_fileattr_set,
>  };
>
>  const struct inode_operations cifs_file_inode_ops = {
> @@ -1192,6 +1194,8 @@ const struct inode_operations cifs_file_inode_ops = {
>         .fiemap = cifs_fiemap,
>         .get_acl = cifs_get_acl,
>         .set_acl = cifs_set_acl,
> +       .fileattr_get = cifs_fileattr_get,
> +       .fileattr_set = cifs_fileattr_set,
>  };
>
>  const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
> diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
> index 831fee962c4d..b1e6025e2cbc 100644
> --- a/fs/smb/client/cifsfs.h
> +++ b/fs/smb/client/cifsfs.h
> @@ -77,6 +77,8 @@ extern int cifs_setattr(struct mnt_idmap *, struct dentry *,
>                         struct iattr *);
>  extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
>                        u64 len);
> +extern int cifs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
> +extern int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa);
>
>  extern const struct inode_operations cifs_file_inode_ops;
>  extern const struct inode_operations cifs_symlink_inode_ops;
> diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
> index b764bfe916b4..233a0a13b0e2 100644
> --- a/fs/smb/client/cifsglob.h
> +++ b/fs/smb/client/cifsglob.h
> @@ -426,7 +426,7 @@ struct smb_version_operations {
>         int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
>                              const unsigned int);
>         int (*set_compression)(const unsigned int, struct cifs_tcon *,
> -                              struct cifsFileInfo *);
> +                              struct cifsFileInfo *, bool);
>         /* check if we can send an echo or nor */
>         bool (*can_echo)(struct TCP_Server_Info *);
>         /* send echo request */
> @@ -538,7 +538,7 @@ struct smb_version_operations {
>         int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
>                                 bool allocate_crypto);
>         int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
> -                            struct cifsFileInfo *src_file);
> +                            struct cifsFileInfo *src_file, bool enable);
>         int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
>                              struct cifsFileInfo *src_file, void __user *);
>         int (*notify)(const unsigned int xid, struct file *pfile,
> diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
> index 47ecc0884a74..f5f6be6f343e 100644
> --- a/fs/smb/client/cifsproto.h
> +++ b/fs/smb/client/cifsproto.h
> @@ -506,7 +506,7 @@ extern struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
>                                                struct kvec *reparse_iov,
>                                                struct kvec *xattr_iov);
>  extern int CIFSSMB_set_compression(const unsigned int xid,
> -                                  struct cifs_tcon *tcon, __u16 fid);
> +                                  struct cifs_tcon *tcon, __u16 fid, bool enable);
>  extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
>                      int *oplock, FILE_ALL_INFO *buf);
>  extern int SMBOldOpen(const unsigned int xid, struct cifs_tcon *tcon,
> diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
> index 3dbff55b639d..643a55db3ca9 100644
> --- a/fs/smb/client/cifssmb.c
> +++ b/fs/smb/client/cifssmb.c
> @@ -3454,7 +3454,7 @@ struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
>
>  int
>  CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
> -                   __u16 fid)
> +                   __u16 fid, bool enable)
>  {
>         int rc = 0;
>         int bytes_returned;
> @@ -3467,7 +3467,7 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
>         if (rc)
>                 return rc;
>
> -       pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
> +       pSMB->compression_state = cpu_to_le16(enable ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE);
>
>         pSMB->TotalParameterCount = 0;
>         pSMB->TotalDataCount = cpu_to_le32(2);
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index dfad9284a87c..d07ebb99c262 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -13,6 +13,7 @@
>  #include <linux/sched/signal.h>
>  #include <linux/wait_bit.h>
>  #include <linux/fiemap.h>
> +#include <linux/fileattr.h>
>  #include <asm/div64.h>
>  #include "cifsfs.h"
>  #include "cifspdu.h"
> @@ -83,6 +84,7 @@ static void cifs_set_ops(struct inode *inode)
>                 inode->i_op = &cifs_symlink_inode_ops;
>                 break;
>         default:
> +               inode->i_op = &cifs_file_inode_ops;
>                 init_special_inode(inode, inode->i_mode, inode->i_rdev);
>                 break;
>         }
> @@ -3282,3 +3284,182 @@ cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
>         /* BB: add cifs_setattr_legacy for really old servers */
>         return rc;
>  }
> +
> +int cifs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
> +{
> +       struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
> +       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
> +       struct inode *inode = d_inode(dentry);
> +       u32 attrs = CIFS_I(inode)->cifsAttrs;
> +       u32 fsattrs = le32_to_cpu(tcon->fsAttrInfo.Attributes);
> +       u32 xflags = 0;
> +       u32 xflags_mask = FS_XFLAG_IMMUTABLEUSER;
> +       u16 xflags2 = 0;
> +       u16 xflags2_mask = FS_XFLAG2_HIDDEN | FS_XFLAG2_SYSTEM | FS_XFLAG2_ARCHIVE |
> +                          FS_XFLAG2_TEMPORARY | FS_XFLAG2_NOTINDEXED |
> +                          FS_XFLAG2_NOSCRUBDATA | FS_XFLAG2_OFFLINE |
> +                          FS_XFLAG2_PINNED | FS_XFLAG2_UNPINNED;
> +
> +       if (fsattrs & FILE_FILE_COMPRESSION)
> +               xflags_mask |= FS_XFLAG_COMPRESSED;
> +       if (fsattrs & FILE_SUPPORTS_ENCRYPTION)
> +               xflags_mask |= FS_XFLAG_COMPRESSED;
> +       if (fsattrs & FILE_SUPPORT_INTEGRITY_STREAMS)
> +               xflags_mask |= FS_XFLAG_CHECKSUMS;
> +
> +       if (attrs & FILE_ATTRIBUTE_READONLY)
> +               xflags |= FS_XFLAG_IMMUTABLEUSER;
> +       if (attrs & FILE_ATTRIBUTE_HIDDEN)
> +               xflags2 |= FS_XFLAG2_HIDDEN;
> +       if (attrs & FILE_ATTRIBUTE_SYSTEM)
> +               xflags2 |= FS_XFLAG2_SYSTEM;
> +       if (attrs & FILE_ATTRIBUTE_ARCHIVE)
> +               xflags2 |= FS_XFLAG2_ARCHIVE;
> +       if (attrs & FILE_ATTRIBUTE_TEMPORARY)
> +               xflags2 |= FS_XFLAG2_TEMPORARY;
> +       if (attrs & FILE_ATTRIBUTE_COMPRESSED)
> +               xflags |= FS_XFLAG_COMPRESSED;
> +       if (attrs & FILE_ATTRIBUTE_OFFLINE)
> +               xflags2 |= FS_XFLAG2_OFFLINE;
> +       if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
> +               xflags2 |= FS_XFLAG2_NOTINDEXED;
> +       if (attrs & FILE_ATTRIBUTE_ENCRYPTED)
> +               xflags |= FS_XFLAG_ENCRYPTED;
> +       if (attrs & FILE_ATTRIBUTE_INTEGRITY_STREAM)
> +               xflags |= FS_XFLAG_CHECKSUMS;
> +       if (attrs & FILE_ATTRIBUTE_NO_SCRUB_DATA)
> +               xflags2 |= FS_XFLAG2_NOSCRUBDATA;
> +       if (attrs & FILE_ATTRIBUTE_PINNED)
> +               xflags2 |= FS_XFLAG2_PINNED;
> +       if (attrs & FILE_ATTRIBUTE_UNPINNED)
> +               xflags2 |= FS_XFLAG2_UNPINNED;
> +
> +       fileattr_fill_xflags(fa, xflags, xflags_mask, xflags2, xflags2_mask);
> +       return 0;
> +}
> +
> +#define MODIFY_ATTRS_COND(attrs, xflags, xflag, attr) (attrs) ^= ((-(!!((xflags) & (xflag))) ^ (attrs)) & (attr))
> +
> +int cifs_fileattr_set(struct mnt_idmap *idmap,
> +                     struct dentry *dentry, struct fileattr *fa)
> +{
> +       struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
> +       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
> +       struct inode *inode = d_inode(dentry);
> +       u32 attrs = CIFS_I(inode)->cifsAttrs;
> +       struct cifsFileInfo open_file_tmp = {};
> +       struct cifsFileInfo *open_file = NULL;
> +       struct cifs_open_parms oparms;
> +       FILE_BASIC_INFO info_buf = {};
> +       bool do_close = false;
> +       const char *full_path;
> +       unsigned int xid;
> +       __u32 oplock;
> +       void *page;
> +       int rc;
> +
> +       if ((fa->fsx_xflags_mask & ~(FS_XFLAG_IMMUTABLEUSER | FS_XFLAG_COMPRESSED |
> +                                FS_XFLAG_ENCRYPTED | FS_XFLAG_CHECKSUMS)) ||
> +           (fa->fsx_xflags2_mask & ~(FS_XFLAG2_HIDDEN | FS_XFLAG2_SYSTEM | FS_XFLAG2_ARCHIVE |
> +                                 FS_XFLAG2_TEMPORARY | FS_XFLAG2_NOTINDEXED |
> +                                 FS_XFLAG2_NOSCRUBDATA | FS_XFLAG2_OFFLINE |
> +                                 FS_XFLAG2_PINNED | FS_XFLAG2_UNPINNED)) ||
> +           (fa->flags & ~FS_COMMON_FL))
> +               return -EOPNOTSUPP;
> +
> +       if (fa->fsx_xflags_mask & FS_XFLAG_IMMUTABLEUSER)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags, FS_XFLAG_IMMUTABLEUSER, FILE_ATTRIBUTE_READONLY);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_HIDDEN)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_HIDDEN, FILE_ATTRIBUTE_HIDDEN);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_SYSTEM)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_SYSTEM, FILE_ATTRIBUTE_SYSTEM);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_ARCHIVE)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_TEMPORARY)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_TEMPORARY, FILE_ATTRIBUTE_TEMPORARY);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_NOTINDEXED)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_NOTINDEXED, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_NOSCRUBDATA)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_NOSCRUBDATA, FILE_ATTRIBUTE_NO_SCRUB_DATA);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_OFFLINE)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_OFFLINE, FILE_ATTRIBUTE_OFFLINE);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_PINNED)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_PINNED, FILE_ATTRIBUTE_PINNED);
> +       if (fa->fsx_xflags2_mask & FS_XFLAG2_UNPINNED)
> +               MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_UNPINNED, FILE_ATTRIBUTE_UNPINNED);
> +
> +       page = alloc_dentry_path();
> +
> +       full_path = build_path_from_dentry(dentry, page);
> +       if (IS_ERR(full_path)) {
> +               rc = PTR_ERR(full_path);
> +               goto out_page;
> +       }
> +
> +       xid = get_xid();
> +
> +       if (attrs != CIFS_I(inode)->cifsAttrs) {
> +               info_buf.Attributes = cpu_to_le32(attrs);
> +               if (tcon->ses->server->ops->set_file_info)
> +                       rc = tcon->ses->server->ops->set_file_info(inode, full_path, &info_buf, xid);
> +               else
> +                       rc = -EOPNOTSUPP;
> +               if (rc)
> +                       goto out_xid;
> +               CIFS_I(inode)->cifsAttrs = attrs;
> +       }
> +
> +       if (fa->fsx_xflags_mask & (FS_XFLAG_COMPRESSED | FS_XFLAG_ENCRYPTED | FS_XFLAG_CHECKSUMS)) {
> +               open_file = find_writable_file(CIFS_I(inode), FIND_WR_FSUID_ONLY);
> +               if (!open_file) {
> +                       oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE);
> +                       oparms.fid = &open_file_tmp.fid;
> +                       oplock = 0;
> +                       oparms.create_options = cifs_create_options(cifs_sb, 0);
> +                       rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
> +                       if (rc)
> +                               goto out_file;
> +                       do_close = true;
> +                       open_file = &open_file_tmp;
> +               }
> +       }
> +
> +       if (fa->fsx_xflags_mask & FS_XFLAG_COMPRESSED) {
> +               if (tcon->ses->server->ops->set_compression)
> +                       rc = tcon->ses->server->ops->set_compression(xid, tcon, open_file, fa->fsx_xflags & FS_XFLAG_COMPRESSED);
> +               else
> +                       rc = -EOPNOTSUPP;
> +               if (rc)
> +                       goto out_file;
> +               CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_COMPRESSED;
> +       }
> +
> +       if (fa->fsx_xflags_mask & FS_XFLAG_ENCRYPTED) {
> +               /* TODO */
> +               rc = -EOPNOTSUPP;
> +               if (rc)
> +                       goto out_file;
> +               CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_ENCRYPTED;
> +       }
> +
> +       if (fa->fsx_xflags_mask & FS_XFLAG_CHECKSUMS) {
> +               if (tcon->ses->server->ops->set_integrity)
> +                       rc = tcon->ses->server->ops->set_integrity(xid, tcon, open_file, fa->fsx_xflags & FS_XFLAG_CHECKSUMS);
> +               else
> +                       rc = -EOPNOTSUPP;
> +               if (rc)
> +                       goto out_file;
> +               CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
> +       }
> +
> +out_file:
> +       if (do_close)
> +               tcon->ses->server->ops->close(xid, tcon, oparms.fid);
> +       else if (open_file)
> +               cifsFileInfo_put(open_file);
> +out_xid:
> +       free_xid(xid);
> +out_page:
> +       free_dentry_path(page);
> +       return rc;
> +}
> diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
> index 56439da4f119..7c245085f891 100644
> --- a/fs/smb/client/ioctl.c
> +++ b/fs/smb/client/ioctl.c
> @@ -356,12 +356,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>         struct cifs_tcon *tcon;
>         struct tcon_link *tlink;
>         struct cifs_sb_info *cifs_sb;
> +#if 0
>         __u64   ExtAttrBits = 0;
>  #ifdef CONFIG_CIFS_POSIX
>  #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
>         __u64   caps;
>  #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
>  #endif /* CONFIG_CIFS_POSIX */
> +#endif
>
>         xid = get_xid();
>
> @@ -372,6 +374,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>                 trace_smb3_ioctl(xid, pSMBFile->fid.persistent_fid, command);
>
>         switch (command) {
> +#if 0
>                 case FS_IOC_GETFLAGS:
>                         if (pSMBFile == NULL)
>                                 break;
> @@ -429,10 +432,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>                         /* Try to set compress flag */
>                         if (tcon->ses->server->ops->set_compression) {
>                                 rc = tcon->ses->server->ops->set_compression(
> -                                                       xid, tcon, pSMBFile);
> +                                                       xid, tcon, pSMBFile, true);
>                                 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
>                         }
>                         break;
> +#endif
>                 case CIFS_IOC_COPYCHUNK_FILE:
>                         rc = cifs_ioctl_copychunk(xid, filep, arg);
>                         break;
> @@ -445,7 +449,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
>                         tcon = tlink_tcon(pSMBFile->tlink);
>                         if (tcon->ses->server->ops->set_integrity)
>                                 rc = tcon->ses->server->ops->set_integrity(xid,
> -                                               tcon, pSMBFile);
> +                                               tcon, pSMBFile, true);
>                         else
>                                 rc = -EOPNOTSUPP;
>                         break;
> diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
> index ba6452d89df3..2e854bde67de 100644
> --- a/fs/smb/client/smb1ops.c
> +++ b/fs/smb/client/smb1ops.c
> @@ -1245,9 +1245,9 @@ smb_set_file_info(struct inode *inode, const char *full_path,
>
>  static int
>  cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
> -                  struct cifsFileInfo *cfile)
> +                  struct cifsFileInfo *cfile, bool enable)
>  {
> -       return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
> +       return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid, enable);
>  }
>
>  static int
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index f8445a9ff9a1..9c66e413c59c 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -2106,20 +2106,20 @@ smb2_duplicate_extents(const unsigned int xid,
>
>  static int
>  smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
> -                  struct cifsFileInfo *cfile)
> +                  struct cifsFileInfo *cfile, bool enable)
>  {
>         return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
> -                           cfile->fid.volatile_fid);
> +                           cfile->fid.volatile_fid, enable);
>  }
>
>  static int
>  smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
> -                  struct cifsFileInfo *cfile)
> +                  struct cifsFileInfo *cfile, bool enable)
>  {
>         struct fsctl_set_integrity_information_req integr_info;
>         unsigned int ret_data_len;
>
> -       integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
> +       integr_info.ChecksumAlgorithm = cpu_to_le16(enable ? CHECKSUM_TYPE_CRC64 : CHECKSUM_TYPE_NONE);
>         integr_info.Flags = 0;
>         integr_info.Reserved = 0;
>
> diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
> index a75947797d58..57d716cfc800 100644
> --- a/fs/smb/client/smb2pdu.c
> +++ b/fs/smb/client/smb2pdu.c
> @@ -3537,14 +3537,14 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
>
>  int
>  SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
> -                    u64 persistent_fid, u64 volatile_fid)
> +                    u64 persistent_fid, u64 volatile_fid, bool enable)
>  {
>         int rc;
>         struct  compress_ioctl fsctl_input;
>         char *ret_data = NULL;
>
>         fsctl_input.CompressionState =
> -                       cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
> +                       cpu_to_le16(enable ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE);
>
>         rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
>                         FSCTL_SET_COMPRESSION,
> diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
> index cec5921bfdd2..6086bbdeeae0 100644
> --- a/fs/smb/client/smb2proto.h
> +++ b/fs/smb/client/smb2proto.h
> @@ -250,7 +250,7 @@ extern int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
>                        u64 persistent_fid, u64 volatile_fid,
>                        struct smb2_file_full_ea_info *buf, int len);
>  extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
> -                               u64 persistent_fid, u64 volatile_fid);
> +                               u64 persistent_fid, u64 volatile_fid, bool enable);
>  extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
>                              const u64 persistent_fid, const u64 volatile_fid,
>                              const __u8 oplock_level);
> diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
> index ab902b155650..a24194bef849 100644
> --- a/fs/smb/common/smb2pdu.h
> +++ b/fs/smb/common/smb2pdu.h
> @@ -1077,6 +1077,8 @@ struct smb2_server_client_notification {
>  #define FILE_ATTRIBUTE_ENCRYPTED               0x00004000
>  #define FILE_ATTRIBUTE_INTEGRITY_STREAM                0x00008000
>  #define FILE_ATTRIBUTE_NO_SCRUB_DATA           0x00020000
> +#define FILE_ATTRIBUTE_PINNED                  0x00080000
> +#define FILE_ATTRIBUTE_UNPINNED                        0x00100000
>  #define FILE_ATTRIBUTE__MASK                   0x00007FB7
>
>  #define FILE_ATTRIBUTE_READONLY_LE              cpu_to_le32(0x00000001)
> --
> 2.20.1
>
Pali Rohár Feb. 16, 2025, 8:25 p.m. UTC | #2
On Sunday 16 February 2025 21:21:27 Amir Goldstein wrote:
> On Sun, Feb 16, 2025 at 5:42 PM Pali Rohár <pali@kernel.org> wrote:
> >
> 
> No empty commit message please

This is mean as RFC, not the final version, I just included the oneline
commit message.
diff mbox series

Patch

diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index ea31d693ea9f..b441675f9afd 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1182,6 +1182,8 @@  const struct inode_operations cifs_dir_inode_ops = {
 	.listxattr = cifs_listxattr,
 	.get_acl = cifs_get_acl,
 	.set_acl = cifs_set_acl,
+	.fileattr_get = cifs_fileattr_get,
+	.fileattr_set = cifs_fileattr_set,
 };
 
 const struct inode_operations cifs_file_inode_ops = {
@@ -1192,6 +1194,8 @@  const struct inode_operations cifs_file_inode_ops = {
 	.fiemap = cifs_fiemap,
 	.get_acl = cifs_get_acl,
 	.set_acl = cifs_set_acl,
+	.fileattr_get = cifs_fileattr_get,
+	.fileattr_set = cifs_fileattr_set,
 };
 
 const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 831fee962c4d..b1e6025e2cbc 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -77,6 +77,8 @@  extern int cifs_setattr(struct mnt_idmap *, struct dentry *,
 			struct iattr *);
 extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
 		       u64 len);
+extern int cifs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
+extern int cifs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa);
 
 extern const struct inode_operations cifs_file_inode_ops;
 extern const struct inode_operations cifs_symlink_inode_ops;
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index b764bfe916b4..233a0a13b0e2 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -426,7 +426,7 @@  struct smb_version_operations {
 	int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
 			     const unsigned int);
 	int (*set_compression)(const unsigned int, struct cifs_tcon *,
-			       struct cifsFileInfo *);
+			       struct cifsFileInfo *, bool);
 	/* check if we can send an echo or nor */
 	bool (*can_echo)(struct TCP_Server_Info *);
 	/* send echo request */
@@ -538,7 +538,7 @@  struct smb_version_operations {
 	int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
 				bool allocate_crypto);
 	int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
-			     struct cifsFileInfo *src_file);
+			     struct cifsFileInfo *src_file, bool enable);
 	int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
 			     struct cifsFileInfo *src_file, void __user *);
 	int (*notify)(const unsigned int xid, struct file *pfile,
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 47ecc0884a74..f5f6be6f343e 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -506,7 +506,7 @@  extern struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
 					       struct kvec *reparse_iov,
 					       struct kvec *xattr_iov);
 extern int CIFSSMB_set_compression(const unsigned int xid,
-				   struct cifs_tcon *tcon, __u16 fid);
+				   struct cifs_tcon *tcon, __u16 fid, bool enable);
 extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
 		     int *oplock, FILE_ALL_INFO *buf);
 extern int SMBOldOpen(const unsigned int xid, struct cifs_tcon *tcon,
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index 3dbff55b639d..643a55db3ca9 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -3454,7 +3454,7 @@  struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data,
 
 int
 CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
-		    __u16 fid)
+		    __u16 fid, bool enable)
 {
 	int rc = 0;
 	int bytes_returned;
@@ -3467,7 +3467,7 @@  CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
 	if (rc)
 		return rc;
 
-	pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
+	pSMB->compression_state = cpu_to_le16(enable ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE);
 
 	pSMB->TotalParameterCount = 0;
 	pSMB->TotalDataCount = cpu_to_le32(2);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index dfad9284a87c..d07ebb99c262 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -13,6 +13,7 @@ 
 #include <linux/sched/signal.h>
 #include <linux/wait_bit.h>
 #include <linux/fiemap.h>
+#include <linux/fileattr.h>
 #include <asm/div64.h>
 #include "cifsfs.h"
 #include "cifspdu.h"
@@ -83,6 +84,7 @@  static void cifs_set_ops(struct inode *inode)
 		inode->i_op = &cifs_symlink_inode_ops;
 		break;
 	default:
+		inode->i_op = &cifs_file_inode_ops;
 		init_special_inode(inode, inode->i_mode, inode->i_rdev);
 		break;
 	}
@@ -3282,3 +3284,182 @@  cifs_setattr(struct mnt_idmap *idmap, struct dentry *direntry,
 	/* BB: add cifs_setattr_legacy for really old servers */
 	return rc;
 }
+
+int cifs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	struct inode *inode = d_inode(dentry);
+	u32 attrs = CIFS_I(inode)->cifsAttrs;
+	u32 fsattrs = le32_to_cpu(tcon->fsAttrInfo.Attributes);
+	u32 xflags = 0;
+	u32 xflags_mask = FS_XFLAG_IMMUTABLEUSER;
+	u16 xflags2 = 0;
+	u16 xflags2_mask = FS_XFLAG2_HIDDEN | FS_XFLAG2_SYSTEM | FS_XFLAG2_ARCHIVE |
+			   FS_XFLAG2_TEMPORARY | FS_XFLAG2_NOTINDEXED |
+			   FS_XFLAG2_NOSCRUBDATA | FS_XFLAG2_OFFLINE |
+			   FS_XFLAG2_PINNED | FS_XFLAG2_UNPINNED;
+
+	if (fsattrs & FILE_FILE_COMPRESSION)
+		xflags_mask |= FS_XFLAG_COMPRESSED;
+	if (fsattrs & FILE_SUPPORTS_ENCRYPTION)
+		xflags_mask |= FS_XFLAG_COMPRESSED;
+	if (fsattrs & FILE_SUPPORT_INTEGRITY_STREAMS)
+		xflags_mask |= FS_XFLAG_CHECKSUMS;
+
+	if (attrs & FILE_ATTRIBUTE_READONLY)
+		xflags |= FS_XFLAG_IMMUTABLEUSER;
+	if (attrs & FILE_ATTRIBUTE_HIDDEN)
+		xflags2 |= FS_XFLAG2_HIDDEN;
+	if (attrs & FILE_ATTRIBUTE_SYSTEM)
+		xflags2 |= FS_XFLAG2_SYSTEM;
+	if (attrs & FILE_ATTRIBUTE_ARCHIVE)
+		xflags2 |= FS_XFLAG2_ARCHIVE;
+	if (attrs & FILE_ATTRIBUTE_TEMPORARY)
+		xflags2 |= FS_XFLAG2_TEMPORARY;
+	if (attrs & FILE_ATTRIBUTE_COMPRESSED)
+		xflags |= FS_XFLAG_COMPRESSED;
+	if (attrs & FILE_ATTRIBUTE_OFFLINE)
+		xflags2 |= FS_XFLAG2_OFFLINE;
+	if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
+		xflags2 |= FS_XFLAG2_NOTINDEXED;
+	if (attrs & FILE_ATTRIBUTE_ENCRYPTED)
+		xflags |= FS_XFLAG_ENCRYPTED;
+	if (attrs & FILE_ATTRIBUTE_INTEGRITY_STREAM)
+		xflags |= FS_XFLAG_CHECKSUMS;
+	if (attrs & FILE_ATTRIBUTE_NO_SCRUB_DATA)
+		xflags2 |= FS_XFLAG2_NOSCRUBDATA;
+	if (attrs & FILE_ATTRIBUTE_PINNED)
+		xflags2 |= FS_XFLAG2_PINNED;
+	if (attrs & FILE_ATTRIBUTE_UNPINNED)
+		xflags2 |= FS_XFLAG2_UNPINNED;
+
+	fileattr_fill_xflags(fa, xflags, xflags_mask, xflags2, xflags2_mask);
+	return 0;
+}
+
+#define MODIFY_ATTRS_COND(attrs, xflags, xflag, attr) (attrs) ^= ((-(!!((xflags) & (xflag))) ^ (attrs)) & (attr))
+
+int cifs_fileattr_set(struct mnt_idmap *idmap,
+		      struct dentry *dentry, struct fileattr *fa)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	struct inode *inode = d_inode(dentry);
+	u32 attrs = CIFS_I(inode)->cifsAttrs;
+	struct cifsFileInfo open_file_tmp = {};
+	struct cifsFileInfo *open_file = NULL;
+	struct cifs_open_parms oparms;
+	FILE_BASIC_INFO info_buf = {};
+	bool do_close = false;
+	const char *full_path;
+	unsigned int xid;
+	__u32 oplock;
+	void *page;
+	int rc;
+
+	if ((fa->fsx_xflags_mask & ~(FS_XFLAG_IMMUTABLEUSER | FS_XFLAG_COMPRESSED |
+				 FS_XFLAG_ENCRYPTED | FS_XFLAG_CHECKSUMS)) ||
+	    (fa->fsx_xflags2_mask & ~(FS_XFLAG2_HIDDEN | FS_XFLAG2_SYSTEM | FS_XFLAG2_ARCHIVE |
+				  FS_XFLAG2_TEMPORARY | FS_XFLAG2_NOTINDEXED |
+				  FS_XFLAG2_NOSCRUBDATA | FS_XFLAG2_OFFLINE |
+				  FS_XFLAG2_PINNED | FS_XFLAG2_UNPINNED)) ||
+	    (fa->flags & ~FS_COMMON_FL))
+		return -EOPNOTSUPP;
+
+	if (fa->fsx_xflags_mask & FS_XFLAG_IMMUTABLEUSER)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags, FS_XFLAG_IMMUTABLEUSER, FILE_ATTRIBUTE_READONLY);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_HIDDEN)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_HIDDEN, FILE_ATTRIBUTE_HIDDEN);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_SYSTEM)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_SYSTEM, FILE_ATTRIBUTE_SYSTEM);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_ARCHIVE)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_ARCHIVE, FILE_ATTRIBUTE_ARCHIVE);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_TEMPORARY)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_TEMPORARY, FILE_ATTRIBUTE_TEMPORARY);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_NOTINDEXED)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_NOTINDEXED, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_NOSCRUBDATA)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_NOSCRUBDATA, FILE_ATTRIBUTE_NO_SCRUB_DATA);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_OFFLINE)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_OFFLINE, FILE_ATTRIBUTE_OFFLINE);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_PINNED)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_PINNED, FILE_ATTRIBUTE_PINNED);
+	if (fa->fsx_xflags2_mask & FS_XFLAG2_UNPINNED)
+		MODIFY_ATTRS_COND(attrs, fa->fsx_xflags2, FS_XFLAG2_UNPINNED, FILE_ATTRIBUTE_UNPINNED);
+
+	page = alloc_dentry_path();
+
+	full_path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
+		goto out_page;
+	}
+
+	xid = get_xid();
+
+	if (attrs != CIFS_I(inode)->cifsAttrs) {
+		info_buf.Attributes = cpu_to_le32(attrs);
+		if (tcon->ses->server->ops->set_file_info)
+			rc = tcon->ses->server->ops->set_file_info(inode, full_path, &info_buf, xid);
+		else
+			rc = -EOPNOTSUPP;
+		if (rc)
+			goto out_xid;
+		CIFS_I(inode)->cifsAttrs = attrs;
+	}
+
+	if (fa->fsx_xflags_mask & (FS_XFLAG_COMPRESSED | FS_XFLAG_ENCRYPTED | FS_XFLAG_CHECKSUMS)) {
+		open_file = find_writable_file(CIFS_I(inode), FIND_WR_FSUID_ONLY);
+		if (!open_file) {
+			oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE);
+			oparms.fid = &open_file_tmp.fid;
+			oplock = 0;
+			oparms.create_options = cifs_create_options(cifs_sb, 0);
+			rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
+			if (rc)
+				goto out_file;
+			do_close = true;
+			open_file = &open_file_tmp;
+		}
+	}
+
+	if (fa->fsx_xflags_mask & FS_XFLAG_COMPRESSED) {
+		if (tcon->ses->server->ops->set_compression)
+			rc = tcon->ses->server->ops->set_compression(xid, tcon, open_file, fa->fsx_xflags & FS_XFLAG_COMPRESSED);
+		else
+			rc = -EOPNOTSUPP;
+		if (rc)
+			goto out_file;
+		CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_COMPRESSED;
+	}
+
+	if (fa->fsx_xflags_mask & FS_XFLAG_ENCRYPTED) {
+		/* TODO */
+		rc = -EOPNOTSUPP;
+		if (rc)
+			goto out_file;
+		CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_ENCRYPTED;
+	}
+
+	if (fa->fsx_xflags_mask & FS_XFLAG_CHECKSUMS) {
+		if (tcon->ses->server->ops->set_integrity)
+			rc = tcon->ses->server->ops->set_integrity(xid, tcon, open_file, fa->fsx_xflags & FS_XFLAG_CHECKSUMS);
+		else
+			rc = -EOPNOTSUPP;
+		if (rc)
+			goto out_file;
+		CIFS_I(inode)->cifsAttrs |= FILE_ATTRIBUTE_INTEGRITY_STREAM;
+	}
+
+out_file:
+	if (do_close)
+		tcon->ses->server->ops->close(xid, tcon, oparms.fid);
+	else if (open_file)
+		cifsFileInfo_put(open_file);
+out_xid:
+	free_xid(xid);
+out_page:
+	free_dentry_path(page);
+	return rc;
+}
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 56439da4f119..7c245085f891 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -356,12 +356,14 @@  long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
 	struct cifs_sb_info *cifs_sb;
+#if 0
 	__u64	ExtAttrBits = 0;
 #ifdef CONFIG_CIFS_POSIX
 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
 	__u64   caps;
 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
 #endif /* CONFIG_CIFS_POSIX */
+#endif
 
 	xid = get_xid();
 
@@ -372,6 +374,7 @@  long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 		trace_smb3_ioctl(xid, pSMBFile->fid.persistent_fid, command);
 
 	switch (command) {
+#if 0
 		case FS_IOC_GETFLAGS:
 			if (pSMBFile == NULL)
 				break;
@@ -429,10 +432,11 @@  long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 			/* Try to set compress flag */
 			if (tcon->ses->server->ops->set_compression) {
 				rc = tcon->ses->server->ops->set_compression(
-							xid, tcon, pSMBFile);
+							xid, tcon, pSMBFile, true);
 				cifs_dbg(FYI, "set compress flag rc %d\n", rc);
 			}
 			break;
+#endif
 		case CIFS_IOC_COPYCHUNK_FILE:
 			rc = cifs_ioctl_copychunk(xid, filep, arg);
 			break;
@@ -445,7 +449,7 @@  long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 			tcon = tlink_tcon(pSMBFile->tlink);
 			if (tcon->ses->server->ops->set_integrity)
 				rc = tcon->ses->server->ops->set_integrity(xid,
-						tcon, pSMBFile);
+						tcon, pSMBFile, true);
 			else
 				rc = -EOPNOTSUPP;
 			break;
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index ba6452d89df3..2e854bde67de 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -1245,9 +1245,9 @@  smb_set_file_info(struct inode *inode, const char *full_path,
 
 static int
 cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifsFileInfo *cfile)
+		   struct cifsFileInfo *cfile, bool enable)
 {
-	return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
+	return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid, enable);
 }
 
 static int
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index f8445a9ff9a1..9c66e413c59c 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2106,20 +2106,20 @@  smb2_duplicate_extents(const unsigned int xid,
 
 static int
 smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifsFileInfo *cfile)
+		   struct cifsFileInfo *cfile, bool enable)
 {
 	return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
-			    cfile->fid.volatile_fid);
+			    cfile->fid.volatile_fid, enable);
 }
 
 static int
 smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifsFileInfo *cfile)
+		   struct cifsFileInfo *cfile, bool enable)
 {
 	struct fsctl_set_integrity_information_req integr_info;
 	unsigned int ret_data_len;
 
-	integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
+	integr_info.ChecksumAlgorithm = cpu_to_le16(enable ? CHECKSUM_TYPE_CRC64 : CHECKSUM_TYPE_NONE);
 	integr_info.Flags = 0;
 	integr_info.Reserved = 0;
 
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index a75947797d58..57d716cfc800 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -3537,14 +3537,14 @@  SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
 int
 SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
-		     u64 persistent_fid, u64 volatile_fid)
+		     u64 persistent_fid, u64 volatile_fid, bool enable)
 {
 	int rc;
 	struct  compress_ioctl fsctl_input;
 	char *ret_data = NULL;
 
 	fsctl_input.CompressionState =
-			cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
+			cpu_to_le16(enable ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE);
 
 	rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
 			FSCTL_SET_COMPRESSION,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index cec5921bfdd2..6086bbdeeae0 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -250,7 +250,7 @@  extern int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 		       u64 persistent_fid, u64 volatile_fid,
 		       struct smb2_file_full_ea_info *buf, int len);
 extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
-				u64 persistent_fid, u64 volatile_fid);
+				u64 persistent_fid, u64 volatile_fid, bool enable);
 extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 			     const u64 persistent_fid, const u64 volatile_fid,
 			     const __u8 oplock_level);
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index ab902b155650..a24194bef849 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -1077,6 +1077,8 @@  struct smb2_server_client_notification {
 #define FILE_ATTRIBUTE_ENCRYPTED		0x00004000
 #define FILE_ATTRIBUTE_INTEGRITY_STREAM		0x00008000
 #define FILE_ATTRIBUTE_NO_SCRUB_DATA		0x00020000
+#define FILE_ATTRIBUTE_PINNED			0x00080000
+#define FILE_ATTRIBUTE_UNPINNED			0x00100000
 #define FILE_ATTRIBUTE__MASK			0x00007FB7
 
 #define FILE_ATTRIBUTE_READONLY_LE              cpu_to_le32(0x00000001)