mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-05-22 15:13:47 +00:00
smb3: Fix mode on mkdir on smb311 mounts
mkdir was not passing the mode on smb3.11 mounts with posix extensions Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
662bf5bc0a
commit
bea851b8ba
6 changed files with 175 additions and 3 deletions
|
@ -315,6 +315,10 @@ struct smb_version_operations {
|
||||||
/* send echo request */
|
/* send echo request */
|
||||||
int (*echo)(struct TCP_Server_Info *);
|
int (*echo)(struct TCP_Server_Info *);
|
||||||
/* create directory */
|
/* 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 *,
|
int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
|
||||||
struct cifs_sb_info *);
|
struct cifs_sb_info *);
|
||||||
/* set info on created directory */
|
/* set info on created directory */
|
||||||
|
|
|
@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
|
||||||
goto mkdir_out;
|
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 &
|
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||||
rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
|
rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
|
||||||
|
@ -1583,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
|
||||||
goto mkdir_out;
|
goto mkdir_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
server = tcon->ses->server;
|
|
||||||
|
|
||||||
if (!server->ops->mkdir) {
|
if (!server->ops->mkdir) {
|
||||||
rc = -ENOSYS;
|
rc = -ENOSYS;
|
||||||
goto mkdir_out;
|
goto mkdir_out;
|
||||||
|
|
|
@ -3313,6 +3313,7 @@ struct smb_version_operations smb311_operations = {
|
||||||
.set_compression = smb2_set_compression,
|
.set_compression = smb2_set_compression,
|
||||||
.mkdir = smb2_mkdir,
|
.mkdir = smb2_mkdir,
|
||||||
.mkdir_setinfo = smb2_mkdir_setinfo,
|
.mkdir_setinfo = smb2_mkdir_setinfo,
|
||||||
|
.posix_mkdir = smb311_posix_mkdir,
|
||||||
.rmdir = smb2_rmdir,
|
.rmdir = smb2_rmdir,
|
||||||
.unlink = smb2_unlink,
|
.unlink = smb2_unlink,
|
||||||
.rename = smb2_rename_path,
|
.rename = smb2_rename_path,
|
||||||
|
|
|
@ -1911,6 +1911,159 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
||||||
return 0;
|
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(©_path, ©_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
|
int
|
||||||
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||||
__u8 *oplock, struct smb2_file_all_info *buf,
|
__u8 *oplock, struct smb2_file_all_info *buf,
|
||||||
|
|
|
@ -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);
|
struct cifs_sb_info *cifs_sb, bool set_alloc);
|
||||||
extern int smb2_set_file_info(struct inode *inode, const char *full_path,
|
extern int smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||||
FILE_BASIC_INFO *buf, const unsigned int xid);
|
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,
|
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const char *name, struct cifs_sb_info *cifs_sb);
|
const char *name, struct cifs_sb_info *cifs_sb);
|
||||||
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
|
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
|
||||||
|
|
|
@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
|
||||||
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
|
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
|
||||||
|
|
||||||
DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
|
DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
|
||||||
|
DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(smb3_open_done_class,
|
DECLARE_EVENT_CLASS(smb3_open_done_class,
|
||||||
TP_PROTO(unsigned int xid,
|
TP_PROTO(unsigned int xid,
|
||||||
|
@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
|
||||||
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
|
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
|
||||||
|
|
||||||
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
|
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
|
||||||
|
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
|
||||||
|
|
||||||
#endif /* _CIFS_TRACE_H */
|
#endif /* _CIFS_TRACE_H */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue