smb3: Add posix create context for smb3.11 posix mounts
authorSteve French <stfrench@microsoft.com>
Fri, 1 Jun 2018 00:16:54 +0000 (19:16 -0500)
committerSteve French <stfrench@microsoft.com>
Fri, 1 Jun 2018 02:23:07 +0000 (21:23 -0500)
Signed-off-by: Steve French <smfrench@gmail.com>
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/smb2misc.c
fs/cifs/smb2pdu.c

index 3e2ee7e1d85e2f93f31ff4c395ac519b2653e14e..76a579a0dd439447f6b5e3b9194a963945321e06 100644 (file)
@@ -1082,6 +1082,7 @@ struct cifs_open_parms {
        int create_options;
        const char *path;
        struct cifs_fid *fid;
+       umode_t mode;
        bool reconnect:1;
 };
 
index 4c0e3f6ae356c841890b8688cf7ae011f4c43dac..560b335fa752707e297cfd5d3156009cb0f256c7 100644 (file)
@@ -3963,6 +3963,12 @@ try_mount_again:
                goto remote_path_check;
        }
 
+#ifdef CONFIG_CIFS_SMB311
+       /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
+       if (tcon->posix_extensions)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+#endif /* SMB3.11 */
+
        /* tell server which Unix caps we support */
        if (cap_unix(tcon->ses)) {
                /* reset of caps checks mount to see if unix extensions
@@ -4424,6 +4430,11 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
                goto out;
        }
 
+#ifdef CONFIG_CIFS_SMB311
+       /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
+       if (tcon->posix_extensions)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+#endif /* SMB3.11 */
        if (cap_unix(ses))
                reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 
index 925844343038aaa04b479fcdd2063c9ddfb811a0..ad345ac0590157e892814d05e5efd54304ff0e9a 100644 (file)
@@ -369,7 +369,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        oparms.path = full_path;
        oparms.fid = fid;
        oparms.reconnect = false;
-
+       oparms.mode = mode;
        rc = server->ops->open(xid, &oparms, oplock, buf);
        if (rc) {
                cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
index 8cee72eebc39bff4764e5c2e13f82e212455c784..8e45e28ce3ac0d2b69e4f5b4c3d36dca2e7274c1 100644 (file)
@@ -455,8 +455,14 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
        /* Windows doesn't allow paths beginning with \ */
        if (from[0] == '\\')
                start_of_path = from + 1;
+#ifdef CONFIG_CIFS_SMB311
+       /* SMB311 POSIX extensions paths do not include leading slash */
+       else if (cifs_sb_master_tcon(cifs_sb)->posix_extensions)
+               start_of_path = from + 1;
+#endif /* 311 */
        else
                start_of_path = from;
+
        to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
                                   cifs_sb->local_nls, map_type);
        return to;
index 6436e9187045385d7571503e7430206235d6967d..c92b4e6689bd0cee8f51e9c3f606bb7a2f1abce9 100644 (file)
@@ -519,6 +519,64 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
        return rc;
 }
 
+static struct create_posix *
+create_posix_buf(umode_t mode)
+{
+       struct create_posix *buf;
+
+       buf = kzalloc(sizeof(struct create_posix),
+                       GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset =
+               cpu_to_le16(offsetof(struct create_posix, Mode));
+       buf->ccontext.DataLength = cpu_to_le32(4);
+       buf->ccontext.NameOffset =
+               cpu_to_le16(offsetof(struct create_posix, Name));
+       buf->ccontext.NameLength = cpu_to_le16(16);
+
+       /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */
+       buf->Name[0] = 0x93;
+       buf->Name[1] = 0xAD;
+       buf->Name[2] = 0x25;
+       buf->Name[3] = 0x50;
+       buf->Name[4] = 0x9C;
+       buf->Name[5] = 0xB4;
+       buf->Name[6] = 0x11;
+       buf->Name[7] = 0xE7;
+       buf->Name[8] = 0xB4;
+       buf->Name[9] = 0x23;
+       buf->Name[10] = 0x83;
+       buf->Name[11] = 0xDE;
+       buf->Name[12] = 0x96;
+       buf->Name[13] = 0x8B;
+       buf->Name[14] = 0xCD;
+       buf->Name[15] = 0x7C;
+       buf->Mode = cpu_to_le32(mode);
+       cifs_dbg(FYI, "mode on posix create 0%o", mode);
+       return buf;
+}
+
+static int
+add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_posix_buf(mode);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_posix);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset = cpu_to_le32(
+                               sizeof(struct smb2_create_req) +
+                               iov[num - 1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_posix));
+       *num_iovec = num + 1;
+       return 0;
+}
+
 #else
 static void assemble_neg_contexts(struct smb2_negotiate_req *req,
                                  unsigned int *total_len)
@@ -1837,7 +1895,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        struct TCP_Server_Info *server;
        struct cifs_tcon *tcon = oparms->tcon;
        struct cifs_ses *ses = tcon->ses;
-       struct kvec iov[4];
+       struct kvec iov[5]; /* make sure at least one for each open context */
        struct kvec rsp_iov = {NULL, 0};
        int resp_buftype;
        int uni_path_len;
@@ -1846,7 +1904,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        int rc = 0;
        unsigned int n_iov = 2;
        __u32 file_attributes = 0;
-       char *dhc_buf = NULL, *lc_buf = NULL;
+       char *dhc_buf = NULL, *lc_buf = NULL, *pc_buf = NULL;
        int flags = 0;
        unsigned int total_len;
 
@@ -1963,6 +2021,27 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                dhc_buf = iov[n_iov-1].iov_base;
        }
 
+#ifdef CONFIG_CIFS_SMB311
+       if (tcon->posix_extensions) {
+               if (n_iov > 2) {
+                       struct create_context *ccontext =
+                           (struct create_context *)iov[n_iov-1].iov_base;
+                       ccontext->Next =
+                               cpu_to_le32(iov[n_iov-1].iov_len);
+               }
+
+               rc = add_posix_context(iov, &n_iov, oparms->mode);
+               if (rc) {
+                       cifs_small_buf_release(req);
+                       kfree(copy_path);
+                       kfree(lc_buf);
+                       kfree(dhc_buf);
+                       return rc;
+               }
+               pc_buf = iov[n_iov-1].iov_base;
+       }
+#endif /* SMB311 */
+
        rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags,
                            &rsp_iov);
        cifs_small_buf_release(req);
@@ -2004,6 +2083,7 @@ creat_exit:
        kfree(copy_path);
        kfree(lc_buf);
        kfree(dhc_buf);
+       kfree(pc_buf);
        free_rsp_buf(resp_buftype, rsp);
        return rc;
 }