cifs: Add support for writing attributes on SMB2+
authorRonnie Sahlberg <lsahlber@redhat.com>
Thu, 24 Aug 2017 01:24:56 +0000 (11:24 +1000)
committerSteve French <smfrench@gmail.com>
Mon, 4 Sep 2017 19:03:45 +0000 (14:03 -0500)
This adds support for writing extended attributes on SMB2+ shares.
Attributes can be written using the setfattr command.

RH-bz: 1110709

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/xattr.c

index 221693f..808486c 100644 (file)
@@ -421,7 +421,7 @@ struct smb_version_operations {
                        size_t, struct cifs_sb_info *);
        int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
                        const char *, const void *, const __u16,
-                       const struct nls_table *, int);
+                       const struct nls_table *, struct cifs_sb_info *);
        struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
                        const char *, u32 *);
        struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
index 6eb3147..4143c9d 100644 (file)
@@ -484,7 +484,8 @@ extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
 extern int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
                const char *fileName, const char *ea_name,
                const void *ea_value, const __u16 ea_value_len,
-               const struct nls_table *nls_codepage, int remap_special_chars);
+               const struct nls_table *nls_codepage,
+               struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
                        __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
 extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
index 72a53bd..48455af 100644 (file)
@@ -6264,7 +6264,7 @@ int
 CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
             const char *fileName, const char *ea_name, const void *ea_value,
             const __u16 ea_value_len, const struct nls_table *nls_codepage,
-            int remap)
+            struct cifs_sb_info *cifs_sb)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -6273,6 +6273,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        int bytes_returned = 0;
        __u16 params, param_offset, byte_count, offset, count;
+       int remap = cifs_remap(cifs_sb);
 
        cifs_dbg(FYI, "In SetEA\n");
 SetEARetry:
index 78516d3..fb2934b 100644 (file)
@@ -558,6 +558,62 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
+
+static int
+smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
+           const char *path, const char *ea_name, const void *ea_value,
+           const __u16 ea_value_len, const struct nls_table *nls_codepage,
+           struct cifs_sb_info *cifs_sb)
+{
+       int rc;
+       __le16 *utf16_path;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
+       struct smb2_file_full_ea_info *ea;
+       int ea_name_len = strlen(ea_name);
+       int len;
+
+       if (ea_name_len > 255)
+               return -EINVAL;
+
+       utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+       if (!utf16_path)
+               return -ENOMEM;
+
+       oparms.tcon = tcon;
+       oparms.desired_access = FILE_WRITE_EA;
+       oparms.disposition = FILE_OPEN;
+       oparms.create_options = 0;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
+       kfree(utf16_path);
+       if (rc) {
+               cifs_dbg(FYI, "open failed rc=%d\n", rc);
+               return rc;
+       }
+
+       len = sizeof(ea) + ea_name_len + ea_value_len + 1;
+       ea = kzalloc(len, GFP_KERNEL);
+       if (ea == NULL) {
+               SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+               return -ENOMEM;
+       }
+
+       ea->ea_name_length = ea_name_len;
+       ea->ea_value_length = cpu_to_le16(ea_value_len);
+       memcpy(ea->ea_data, ea_name, ea_name_len + 1);
+       memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
+
+       rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
+                        len);
+       SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+
+       return rc;
+}
+
 static bool
 smb2_can_echo(struct TCP_Server_Info *server)
 {
@@ -2706,6 +2762,7 @@ struct smb_version_operations smb20_operations = {
        .select_sectype = smb2_select_sectype,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = smb2_query_eas,
+       .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
 #ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
@@ -2799,6 +2856,7 @@ struct smb_version_operations smb21_operations = {
        .select_sectype = smb2_select_sectype,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = smb2_query_eas,
+       .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
 #ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
@@ -2902,6 +2960,7 @@ struct smb_version_operations smb30_operations = {
        .select_sectype = smb2_select_sectype,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = smb2_query_eas,
+       .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
 #ifdef CONFIG_CIFS_ACL
        .get_acl = get_smb2_acl,
@@ -3006,6 +3065,7 @@ struct smb_version_operations smb311_operations = {
        .select_sectype = smb2_select_sectype,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = smb2_query_eas,
+       .set_EA = smb2_set_ea,
 #endif /* CIFS_XATTR */
 };
 #endif /* CIFS_SMB311 */
index bf0ba3c..d7595e7 100644 (file)
@@ -3197,6 +3197,16 @@ SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
 }
 
 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)
+{
+       return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+               current->tgid, FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE,
+               0, 1, (void **)&buf, &len);
+}
+
+int
 SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
                  const u64 persistent_fid, const u64 volatile_fid,
                  __u8 oplock_level)
index 183389b..0032170 100644 (file)
@@ -172,6 +172,9 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
 extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
                        u64 persistent_fid, u64 volatile_fid,
                        struct cifs_ntsd *pnntsd, int pacllen, int aclflag);
+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);
 extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
index de50e74..52f975d 100644 (file)
@@ -84,7 +84,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
                if (pTcon->ses->server->ops->set_EA)
                        rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
                                full_path, name, value, (__u16)size,
-                               cifs_sb->local_nls, cifs_remap(cifs_sb));
+                               cifs_sb->local_nls, cifs_sb);
                break;
 
        case XATTR_CIFS_ACL: {