Skip to content

Commit

Permalink
smb3: Fix mode on mkdir on smb311 mounts
Browse files Browse the repository at this point in the history
mkdir was not passing the mode on smb3.11 mounts with posix extensions

Signed-off-by: Steve French <stfrench@microsoft.com>
  • Loading branch information
Steve French committed Jun 15, 2018
1 parent 662bf5b commit bea851b
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 3 deletions.
4 changes: 4 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ struct smb_version_operations {
/* send echo request */
int (*echo)(struct TCP_Server_Info *);
/* create directory */
int (*posix_mkdir)(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
struct cifs_sb_info *);
/* set info on created directory */
Expand Down
13 changes: 11 additions & 2 deletions fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}

server = tcon->ses->server;

#ifdef CONFIG_CIFS_SMB311
if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
cifs_sb);
d_drop(direntry); /* for time being always refresh inode info */
goto mkdir_out;
}
#endif /* SMB311 */

if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
Expand All @@ -1583,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}

server = tcon->ses->server;

if (!server->ops->mkdir) {
rc = -ENOSYS;
goto mkdir_out;
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -3313,6 +3313,7 @@ struct smb_version_operations smb311_operations = {
.set_compression = smb2_set_compression,
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
.posix_mkdir = smb311_posix_mkdir,
.rmdir = smb2_rmdir,
.unlink = smb2_unlink,
.rename = smb2_rename_path,
Expand Down
153 changes: 153 additions & 0 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,159 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
return 0;
}

#ifdef CONFIG_CIFS_SMB311
int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb)
{
struct smb_rqst rqst;
struct smb2_create_req *req;
struct smb2_create_rsp *rsp;
struct TCP_Server_Info *server;
struct cifs_ses *ses = tcon->ses;
struct kvec iov[3]; /* make sure at least one for each open context */
struct kvec rsp_iov = {NULL, 0};
int resp_buftype;
int uni_path_len;
__le16 *copy_path = NULL;
int copy_size;
int rc = 0;
unsigned int n_iov = 2;
__u32 file_attributes = 0;
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;

cifs_dbg(FYI, "mkdir\n");

if (ses && (ses->server))
server = ses->server;
else
return -EIO;

rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);

if (rc)
return rc;

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) */
req->FileAttributes = cpu_to_le32(file_attributes);
req->ShareAccess = FILE_SHARE_ALL_LE;
req->CreateDisposition = cpu_to_le32(FILE_CREATE);
req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE);

iov[0].iov_base = (char *)req;
/* -1 since last byte is buf[0] which is sent below (path) */
iov[0].iov_len = total_len - 1;

req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));

/* [MS-SMB2] 2.2.13 NameOffset:
* If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
* the SMB2 header, the file name includes a prefix that will
* be processed during DFS name normalization as specified in
* section 3.3.5.9. Otherwise, the file name is relative to
* the share that is identified by the TreeId in the SMB2
* header.
*/
if (tcon->share_flags & SHI1005_FLAGS_DFS) {
int name_len;

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;
}
req->NameLength = cpu_to_le16(name_len * 2);
uni_path_len = copy_size;
path = copy_path;
} else {
uni_path_len = (2 * UniStrnlen((wchar_t *)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;
}
memcpy((char *)copy_path, (const char *)path,
uni_path_len);
uni_path_len = copy_size;
path = copy_path;
}
}

iov[1].iov_len = uni_path_len;
iov[1].iov_base = 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);
}

rc = add_posix_context(iov, &n_iov, mode);
if (rc) {
cifs_small_buf_release(req);
kfree(copy_path);
return rc;
}
pc_buf = iov[n_iov-1].iov_base;
}


memset(&rqst, 0, sizeof(struct smb_rqst));
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) {
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);

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);
free_rsp_buf(resp_buftype, rsp);
return rc;

}
#endif /* SMB311 */

int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
__u8 *oplock, struct smb2_file_all_info *buf,
Expand Down
4 changes: 4 additions & 0 deletions fs/cifs/smb2proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, bool set_alloc);
extern int smb2_set_file_info(struct inode *inode, const char *full_path,
FILE_BASIC_INFO *buf, const unsigned int xid);
extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
Expand Down
3 changes: 2 additions & 1 deletion fs/cifs/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))

DEFINE_SMB3_OPEN_ERR_EVENT(open_err);

DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);

DECLARE_EVENT_CLASS(smb3_open_done_class,
TP_PROTO(unsigned int xid,
Expand Down Expand Up @@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))

DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);

#endif /* _CIFS_TRACE_H */

Expand Down

0 comments on commit bea851b

Please sign in to comment.