diff options
author | Steve French <stfrench@microsoft.com> | 2018-06-14 22:56:32 -0400 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2018-06-15 03:38:08 -0400 |
commit | bea851b8babe6c87c36e97c9de0dd0bea0dd5802 (patch) | |
tree | 96f368fbb78d6b4a61e9f8174e35372ea806d240 | |
parent | 662bf5bc0a6f7b2abf7f9125c6319f06bb2efcf9 (diff) |
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>
-rw-r--r-- | fs/cifs/cifsglob.h | 4 | ||||
-rw-r--r-- | fs/cifs/inode.c | 13 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 153 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 4 | ||||
-rw-r--r-- | fs/cifs/trace.h | 3 |
6 files changed, 175 insertions, 3 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9dd5f1a3d64b..bd78da59a4fd 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -315,6 +315,10 @@ struct smb_version_operations { | |||
315 | /* send echo request */ | 315 | /* send echo request */ |
316 | int (*echo)(struct TCP_Server_Info *); | 316 | int (*echo)(struct TCP_Server_Info *); |
317 | /* create directory */ | 317 | /* create directory */ |
318 | int (*posix_mkdir)(const unsigned int xid, struct inode *inode, | ||
319 | umode_t mode, struct cifs_tcon *tcon, | ||
320 | const char *full_path, | ||
321 | struct cifs_sb_info *cifs_sb); | ||
318 | int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, | 322 | int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *, |
319 | struct cifs_sb_info *); | 323 | struct cifs_sb_info *); |
320 | /* set info on created directory */ | 324 | /* set info on created directory */ |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f4697f548a39..a2cfb33e85c1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) | |||
1575 | goto mkdir_out; | 1575 | goto mkdir_out; |
1576 | } | 1576 | } |
1577 | 1577 | ||
1578 | server = tcon->ses->server; | ||
1579 | |||
1580 | #ifdef CONFIG_CIFS_SMB311 | ||
1581 | if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { | ||
1582 | rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, | ||
1583 | cifs_sb); | ||
1584 | d_drop(direntry); /* for time being always refresh inode info */ | ||
1585 | goto mkdir_out; | ||
1586 | } | ||
1587 | #endif /* SMB311 */ | ||
1588 | |||
1578 | if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 1589 | if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
1579 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 1590 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
1580 | rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb, | 1591 | 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) | |||
1583 | goto mkdir_out; | 1594 | goto mkdir_out; |
1584 | } | 1595 | } |
1585 | 1596 | ||
1586 | server = tcon->ses->server; | ||
1587 | |||
1588 | if (!server->ops->mkdir) { | 1597 | if (!server->ops->mkdir) { |
1589 | rc = -ENOSYS; | 1598 | rc = -ENOSYS; |
1590 | goto mkdir_out; | 1599 | goto mkdir_out; |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index b2390e9a6843..badcfb2f3c22 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -3313,6 +3313,7 @@ struct smb_version_operations smb311_operations = { | |||
3313 | .set_compression = smb2_set_compression, | 3313 | .set_compression = smb2_set_compression, |
3314 | .mkdir = smb2_mkdir, | 3314 | .mkdir = smb2_mkdir, |
3315 | .mkdir_setinfo = smb2_mkdir_setinfo, | 3315 | .mkdir_setinfo = smb2_mkdir_setinfo, |
3316 | .posix_mkdir = smb311_posix_mkdir, | ||
3316 | .rmdir = smb2_rmdir, | 3317 | .rmdir = smb2_rmdir, |
3317 | .unlink = smb2_unlink, | 3318 | .unlink = smb2_unlink, |
3318 | .rename = smb2_rename_path, | 3319 | .rename = smb2_rename_path, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 7daf38ab814a..810b85787c91 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1911,6 +1911,159 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, | |||
1911 | return 0; | 1911 | return 0; |
1912 | } | 1912 | } |
1913 | 1913 | ||
1914 | #ifdef CONFIG_CIFS_SMB311 | ||
1915 | int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, | ||
1916 | umode_t mode, struct cifs_tcon *tcon, | ||
1917 | const char *full_path, | ||
1918 | struct cifs_sb_info *cifs_sb) | ||
1919 | { | ||
1920 | struct smb_rqst rqst; | ||
1921 | struct smb2_create_req *req; | ||
1922 | struct smb2_create_rsp *rsp; | ||
1923 | struct TCP_Server_Info *server; | ||
1924 | struct cifs_ses *ses = tcon->ses; | ||
1925 | struct kvec iov[3]; /* make sure at least one for each open context */ | ||
1926 | struct kvec rsp_iov = {NULL, 0}; | ||
1927 | int resp_buftype; | ||
1928 | int uni_path_len; | ||
1929 | __le16 *copy_path = NULL; | ||
1930 | int copy_size; | ||
1931 | int rc = 0; | ||
1932 | unsigned int n_iov = 2; | ||
1933 | __u32 file_attributes = 0; | ||
1934 | char *pc_buf = NULL; | ||
1935 | int flags = 0; | ||
1936 | unsigned int total_len; | ||
1937 | __le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb); | ||
1938 | |||
1939 | if (!path) | ||
1940 | return -ENOMEM; | ||
1941 | |||
1942 | cifs_dbg(FYI, "mkdir\n"); | ||
1943 | |||
1944 | if (ses && (ses->server)) | ||
1945 | server = ses->server; | ||
1946 | else | ||
1947 | return -EIO; | ||
1948 | |||
1949 | rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); | ||
1950 | |||
1951 | if (rc) | ||
1952 | return rc; | ||
1953 | |||
1954 | if (smb3_encryption_required(tcon)) | ||
1955 | flags |= CIFS_TRANSFORM_REQ; | ||
1956 | |||
1957 | |||
1958 | req->ImpersonationLevel = IL_IMPERSONATION; | ||
1959 | req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES); | ||
1960 | /* File attributes ignored on open (used in create though) */ | ||
1961 | req->FileAttributes = cpu_to_le32(file_attributes); | ||
1962 | req->ShareAccess = FILE_SHARE_ALL_LE; | ||
1963 | req->CreateDisposition = cpu_to_le32(FILE_CREATE); | ||
1964 | req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE); | ||
1965 | |||
1966 | iov[0].iov_base = (char *)req; | ||
1967 | /* -1 since last byte is buf[0] which is sent below (path) */ | ||
1968 | iov[0].iov_len = total_len - 1; | ||
1969 | |||
1970 | req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)); | ||
1971 | |||
1972 | /* [MS-SMB2] 2.2.13 NameOffset: | ||
1973 | * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of | ||
1974 | * the SMB2 header, the file name includes a prefix that will | ||
1975 | * be processed during DFS name normalization as specified in | ||
1976 | * section 3.3.5.9. Otherwise, the file name is relative to | ||
1977 | * the share that is identified by the TreeId in the SMB2 | ||
1978 | * header. | ||
1979 | */ | ||
1980 | if (tcon->share_flags & SHI1005_FLAGS_DFS) { | ||
1981 | int name_len; | ||
1982 | |||
1983 | req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS; | ||
1984 | rc = alloc_path_with_tree_prefix(©_path, ©_size, | ||
1985 | &name_len, | ||
1986 | tcon->treeName, path); | ||
1987 | if (rc) { | ||
1988 | cifs_small_buf_release(req); | ||
1989 | return rc; | ||
1990 | } | ||
1991 | req->NameLength = cpu_to_le16(name_len * 2); | ||
1992 | uni_path_len = copy_size; | ||
1993 | path = copy_path; | ||
1994 | } else { | ||
1995 | uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; | ||
1996 | /* MUST set path len (NameLength) to 0 opening root of share */ | ||
1997 | req->NameLength = cpu_to_le16(uni_path_len - 2); | ||
1998 | if (uni_path_len % 8 != 0) { | ||
1999 | copy_size = roundup(uni_path_len, 8); | ||
2000 | copy_path = kzalloc(copy_size, GFP_KERNEL); | ||
2001 | if (!copy_path) { | ||
2002 | cifs_small_buf_release(req); | ||
2003 | return -ENOMEM; | ||
2004 | } | ||
2005 | memcpy((char *)copy_path, (const char *)path, | ||
2006 | uni_path_len); | ||
2007 | uni_path_len = copy_size; | ||
2008 | path = copy_path; | ||
2009 | } | ||
2010 | } | ||
2011 | |||
2012 | iov[1].iov_len = uni_path_len; | ||
2013 | iov[1].iov_base = path; | ||
2014 | req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; | ||
2015 | |||
2016 | if (tcon->posix_extensions) { | ||
2017 | if (n_iov > 2) { | ||
2018 | struct create_context *ccontext = | ||
2019 | (struct create_context *)iov[n_iov-1].iov_base; | ||
2020 | ccontext->Next = | ||
2021 | cpu_to_le32(iov[n_iov-1].iov_len); | ||
2022 | } | ||
2023 | |||
2024 | rc = add_posix_context(iov, &n_iov, mode); | ||
2025 | if (rc) { | ||
2026 | cifs_small_buf_release(req); | ||
2027 | kfree(copy_path); | ||
2028 | return rc; | ||
2029 | } | ||
2030 | pc_buf = iov[n_iov-1].iov_base; | ||
2031 | } | ||
2032 | |||
2033 | |||
2034 | memset(&rqst, 0, sizeof(struct smb_rqst)); | ||
2035 | rqst.rq_iov = iov; | ||
2036 | rqst.rq_nvec = n_iov; | ||
2037 | |||
2038 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, | ||
2039 | &rsp_iov); | ||
2040 | |||
2041 | cifs_small_buf_release(req); | ||
2042 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; | ||
2043 | |||
2044 | if (rc != 0) { | ||
2045 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); | ||
2046 | trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid, | ||
2047 | CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc); | ||
2048 | goto smb311_mkdir_exit; | ||
2049 | } else | ||
2050 | trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid, | ||
2051 | ses->Suid, CREATE_NOT_FILE, | ||
2052 | FILE_WRITE_ATTRIBUTES); | ||
2053 | |||
2054 | SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId); | ||
2055 | |||
2056 | /* Eventually save off posix specific response info and timestaps */ | ||
2057 | |||
2058 | smb311_mkdir_exit: | ||
2059 | kfree(copy_path); | ||
2060 | kfree(pc_buf); | ||
2061 | free_rsp_buf(resp_buftype, rsp); | ||
2062 | return rc; | ||
2063 | |||
2064 | } | ||
2065 | #endif /* SMB311 */ | ||
2066 | |||
1914 | int | 2067 | int |
1915 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | 2068 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, |
1916 | __u8 *oplock, struct smb2_file_all_info *buf, | 2069 | __u8 *oplock, struct smb2_file_all_info *buf, |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index c84020057bd8..78371c1a6503 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon, | |||
79 | struct cifs_sb_info *cifs_sb, bool set_alloc); | 79 | struct cifs_sb_info *cifs_sb, bool set_alloc); |
80 | extern int smb2_set_file_info(struct inode *inode, const char *full_path, | 80 | extern int smb2_set_file_info(struct inode *inode, const char *full_path, |
81 | FILE_BASIC_INFO *buf, const unsigned int xid); | 81 | FILE_BASIC_INFO *buf, const unsigned int xid); |
82 | extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, | ||
83 | umode_t mode, struct cifs_tcon *tcon, | ||
84 | const char *full_path, | ||
85 | struct cifs_sb_info *cifs_sb); | ||
82 | extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, | 86 | extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, |
83 | const char *name, struct cifs_sb_info *cifs_sb); | 87 | const char *name, struct cifs_sb_info *cifs_sb); |
84 | extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, | 88 | extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path, |
diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 61e74d455d90..67e413f6ee4d 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h | |||
@@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \ | |||
378 | TP_ARGS(xid, tid, sesid, create_options, desired_access, rc)) | 378 | TP_ARGS(xid, tid, sesid, create_options, desired_access, rc)) |
379 | 379 | ||
380 | DEFINE_SMB3_OPEN_ERR_EVENT(open_err); | 380 | DEFINE_SMB3_OPEN_ERR_EVENT(open_err); |
381 | 381 | DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err); | |
382 | 382 | ||
383 | DECLARE_EVENT_CLASS(smb3_open_done_class, | 383 | DECLARE_EVENT_CLASS(smb3_open_done_class, |
384 | TP_PROTO(unsigned int xid, | 384 | TP_PROTO(unsigned int xid, |
@@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \ | |||
420 | TP_ARGS(xid, fid, tid, sesid, create_options, desired_access)) | 420 | TP_ARGS(xid, fid, tid, sesid, create_options, desired_access)) |
421 | 421 | ||
422 | DEFINE_SMB3_OPEN_DONE_EVENT(open_done); | 422 | DEFINE_SMB3_OPEN_DONE_EVENT(open_done); |
423 | DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done); | ||
423 | 424 | ||
424 | #endif /* _CIFS_TRACE_H */ | 425 | #endif /* _CIFS_TRACE_H */ |
425 | 426 | ||