]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/cifs/smb2pdu.c
smb3: fill in statfs fsid and correct namelen
[linux.git] / fs / cifs / smb2pdu.c
index 3c92678cb45bc8fab4ce27cfcbadaef43586a3e9..6852ff5f06be53c19c762ace8a4ed74de2d67ecd 100644 (file)
@@ -1928,7 +1928,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 {
        struct smb_rqst rqst;
        struct smb2_create_req *req;
-       struct smb2_create_rsp *rsp;
+       struct smb2_create_rsp *rsp = NULL;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
        struct kvec iov[3]; /* make sure at least one for each open context */
@@ -1943,27 +1943,31 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
        char *pc_buf = NULL;
        int flags = 0;
        unsigned int total_len;
-       __le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-
-       if (!path)
-               return -ENOMEM;
+       __le16 *utf16_path = NULL;
 
        cifs_dbg(FYI, "mkdir\n");
 
+       /* resource #1: path allocation */
+       utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+       if (!utf16_path)
+               return -ENOMEM;
+
        if (ses && (ses->server))
                server = ses->server;
-       else
-               return -EIO;
+       else {
+               rc = -EIO;
+               goto err_free_path;
+       }
 
+       /* resource #2: request */
        rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
-
        if (rc)
-               return rc;
+               goto err_free_path;
+
 
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-
        req->ImpersonationLevel = IL_IMPERSONATION;
        req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
        /* File attributes ignored on open (used in create though) */
@@ -1992,50 +1996,44 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
                req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
                rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
                                                 &name_len,
-                                                tcon->treeName, path);
-               if (rc) {
-                       cifs_small_buf_release(req);
-                       return rc;
-               }
+                                                tcon->treeName, utf16_path);
+               if (rc)
+                       goto err_free_req;
+
                req->NameLength = cpu_to_le16(name_len * 2);
                uni_path_len = copy_size;
-               path = copy_path;
+               /* free before overwriting resource */
+               kfree(utf16_path);
+               utf16_path = copy_path;
        } else {
-               uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
+               uni_path_len = (2 * UniStrnlen((wchar_t *)utf16_path, PATH_MAX)) + 2;
                /* MUST set path len (NameLength) to 0 opening root of share */
                req->NameLength = cpu_to_le16(uni_path_len - 2);
                if (uni_path_len % 8 != 0) {
                        copy_size = roundup(uni_path_len, 8);
                        copy_path = kzalloc(copy_size, GFP_KERNEL);
                        if (!copy_path) {
-                               cifs_small_buf_release(req);
-                               return -ENOMEM;
+                               rc = -ENOMEM;
+                               goto err_free_req;
                        }
-                       memcpy((char *)copy_path, (const char *)path,
+                       memcpy((char *)copy_path, (const char *)utf16_path,
                               uni_path_len);
                        uni_path_len = copy_size;
-                       path = copy_path;
+                       /* free before overwriting resource */
+                       kfree(utf16_path);
+                       utf16_path = copy_path;
                }
        }
 
        iov[1].iov_len = uni_path_len;
-       iov[1].iov_base = path;
+       iov[1].iov_base = utf16_path;
        req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 
        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);
-               }
-
+               /* resource #3: posix buf */
                rc = add_posix_context(iov, &n_iov, mode);
-               if (rc) {
-                       cifs_small_buf_release(req);
-                       kfree(copy_path);
-                       return rc;
-               }
+               if (rc)
+                       goto err_free_req;
                pc_buf = iov[n_iov-1].iov_base;
        }
 
@@ -2044,32 +2042,33 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
        rqst.rq_iov = iov;
        rqst.rq_nvec = n_iov;
 
-       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
-                           &rsp_iov);
-
-       cifs_small_buf_release(req);
-       rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
-
-       if (rc != 0) {
+       /* resource #4: response buffer */
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+       if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
                trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
-                                   CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc);
-               goto smb311_mkdir_exit;
-       } else
-               trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid,
-                                    ses->Suid, CREATE_NOT_FILE,
-                                    FILE_WRITE_ATTRIBUTES);
+                                          CREATE_NOT_FILE,
+                                          FILE_WRITE_ATTRIBUTES, rc);
+               goto err_free_rsp_buf;
+       }
+
+       rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
+       trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid,
+                                   ses->Suid, CREATE_NOT_FILE,
+                                   FILE_WRITE_ATTRIBUTES);
 
        SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId);
 
        /* Eventually save off posix specific response info and timestaps */
 
-smb311_mkdir_exit:
-       kfree(copy_path);
-       kfree(pc_buf);
+err_free_rsp_buf:
        free_rsp_buf(resp_buftype, rsp);
+       kfree(pc_buf);
+err_free_req:
+       cifs_small_buf_release(req);
+err_free_path:
+       kfree(utf16_path);
        return rc;
-
 }
 #endif /* SMB311 */
 
@@ -4046,6 +4045,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        } else if (level == FS_SECTOR_SIZE_INFORMATION) {
                max_len = sizeof(struct smb3_fs_ss_info);
                min_len = sizeof(struct smb3_fs_ss_info);
+       } else if (level == FS_VOLUME_INFORMATION) {
+               max_len = sizeof(struct smb3_fs_vol_info) + MAX_VOL_LABEL_LEN;
+               min_len = sizeof(struct smb3_fs_vol_info);
        } else {
                cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level);
                return -EINVAL;
@@ -4090,6 +4092,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
                tcon->ss_flags = le32_to_cpu(ss_info->Flags);
                tcon->perf_sector_size =
                        le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
+       } else if (level == FS_VOLUME_INFORMATION) {
+               struct smb3_fs_vol_info *vol_info = (struct smb3_fs_vol_info *)
+                       (offset + (char *)rsp);
+               tcon->vol_serial_number = vol_info->VolumeSerialNumber;
+               tcon->vol_create_time = vol_info->VolumeCreationTime;
        }
 
 qfsattr_exit: