From 21ac58f495849844dfb4479cda1427bf42493262 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:24:14 -0600 Subject: cifs: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix multiple warnings by explicitly adding multiple break/goto statements instead of just letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Steve French --- fs/cifs/inode.c | 1 + fs/cifs/sess.c | 1 + fs/cifs/smbdirect.c | 1 + 3 files changed, 3 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 9ee5f304592f..ac01f9684b39 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -771,6 +771,7 @@ cifs_get_file_info(struct file *filp) */ rc = 0; CIFS_I(inode)->time = 0; + goto cgfi_exit; default: goto cgfi_exit; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index de564368a887..6c2c42f8d893 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -812,6 +812,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) return NTLMv2; if (global_secflags & CIFSSEC_MAY_NTLM) return NTLM; + break; default: break; } diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index b029ed31ef91..10dfe5006792 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c @@ -246,6 +246,7 @@ smbd_qp_async_error_upcall(struct ib_event *event, void *context) case IB_EVENT_CQ_ERR: case IB_EVENT_QP_FATAL: smbd_disconnect_rdma_connection(info); + break; default: break; -- cgit v1.2.3 From ebcd6de98754d9b6a5f89d7835864b1c365d432f Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 8 Dec 2020 21:13:31 -0600 Subject: SMB3: avoid confusing warning message on mount to Azure Mounts to Azure cause an unneeded warning message in dmesg "CIFS: VFS: parse_server_interfaces: incomplete interface info" Azure rounds up the size (by 8 additional bytes, to a 16 byte boundary) of the structure returned on the query of the server interfaces at mount time. This is permissible even though different than other servers so do not log a warning if query network interfaces response is only rounded up by 8 bytes or fewer. CC: Stable Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 3d914d7d0d11..22f1d8dc12b0 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -477,7 +477,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, goto out; } - if (bytes_left || p->Next) + /* Azure rounds the buffer size up 8, to a 16 byte boundary */ + if ((bytes_left > 8) || p->Next) cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); -- cgit v1.2.3 From bc7c4129d4cdc56d1b5477c1714246f27df914dd Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 9 Dec 2020 01:12:35 -0600 Subject: SMB3.1.1: remove confusing mount warning when no SPNEGO info on negprot rsp Azure does not send an SPNEGO blob in the negotiate protocol response, so we shouldn't assume that it is there when validating the location of the first negotiate context. This avoids the potential confusing mount warning: CIFS: Invalid negotiate context offset CC: Stable Reviewed-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/smb2misc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index d88e2683626e..2da6b41cb552 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -94,6 +94,8 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24) }; +#define SMB311_NEGPROT_BASE_SIZE (sizeof(struct smb2_sync_hdr) + sizeof(struct smb2_negotiate_rsp)) + static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, __u32 non_ctxlen) { @@ -109,11 +111,17 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, /* Make sure that negotiate contexts start after gss security blob */ nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset); - if (nc_offset < non_ctxlen) { - pr_warn_once("Invalid negotiate context offset\n"); + if (nc_offset + 1 < non_ctxlen) { + pr_warn_once("Invalid negotiate context offset %d\n", nc_offset); return 0; - } - size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen; + } else if (nc_offset + 1 == non_ctxlen) { + cifs_dbg(FYI, "no SPNEGO security blob in negprot rsp\n"); + size_of_pad_before_neg_ctxts = 0; + } else if (non_ctxlen == SMB311_NEGPROT_BASE_SIZE) + /* has padding, but no SPNEGO blob */ + size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen + 1; + else + size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen; /* Verify that at least minimal negotiate contexts fit within frame */ if (len < nc_offset + (neg_count * sizeof(struct smb2_neg_context))) { -- cgit v1.2.3 From 0f22053e811ca5dd5d51b919741e02396ea600f3 Mon Sep 17 00:00:00 2001 From: Shyam Prasad N Date: Mon, 17 Aug 2020 03:23:12 -0700 Subject: cifs: Fix unix perm bits to cifsacl conversion for "other" bits. With the "cifsacl" mount option, the mode bits set on the file/dir is converted to corresponding ACEs in DACL. However, only the ALLOWED ACEs were being set for "owner" and "group" SIDs. Since owner is a subset of group, and group is a subset of everyone/world SID, in order to properly emulate unix perm groups, we need to add DENIED ACEs. If we don't do that, "owner" and "group" SIDs could get more access rights than they should. Which is what was happening. This fixes it. We try to keep the "preferred" order of ACEs, i.e. DENYs followed by ALLOWs. However, for a small subset of cases we cannot maintain the preferred order. In that case, we'll end up with the DENY ACE for group after the ALLOW for the owner. If owner SID == group SID, use the more restrictive among the two perm bits and convert them to ACEs. Also, for reverse mapping, i.e. to convert ACL to unix perm bits, for the "others" bits, we needed to add the masked bits of the owner and group masks to others mask. Updated version of patch fixes a problem noted by the kernel test robot. Reported-by: kernel test robot Signed-off-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 212 +++++++++++++++++++++++++++++++++++----------------- fs/cifs/cifsproto.h | 4 +- fs/cifs/inode.c | 12 ++- 3 files changed, 155 insertions(+), 73 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index ef4784e72b1d..9b7f727b0e88 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -557,30 +557,37 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd, bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007 */ static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, - umode_t *pbits_to_set) + umode_t *pdenied, umode_t mask) { __u32 flags = le32_to_cpu(ace_flags); - /* the order of ACEs is important. The canonical order is to begin with - DENY entries followed by ALLOW, otherwise an allow entry could be - encountered first, making the subsequent deny entry like "dead code" - which would be superflous since Windows stops when a match is made - for the operation you are trying to perform for your user */ - - /* For deny ACEs we change the mask so that subsequent allow access - control entries do not turn on the bits we are denying */ + /* + * Do not assume "preferred" or "canonical" order. + * The first DENY or ALLOW ACE which matches perfectly is + * the permission to be used. Once allowed or denied, same + * permission in later ACEs do not matter. + */ + + /* If not already allowed, deny these bits */ if (type == ACCESS_DENIED) { - if (flags & GENERIC_ALL) - *pbits_to_set &= ~S_IRWXUGO; - - if ((flags & GENERIC_WRITE) || - ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) - *pbits_to_set &= ~S_IWUGO; - if ((flags & GENERIC_READ) || - ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) - *pbits_to_set &= ~S_IRUGO; - if ((flags & GENERIC_EXECUTE) || - ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) - *pbits_to_set &= ~S_IXUGO; + if (flags & GENERIC_ALL && + !(*pmode & mask & 0777)) + *pdenied |= mask & 0777; + + if (((flags & GENERIC_WRITE) || + ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) && + !(*pmode & mask & 0222)) + *pdenied |= mask & 0222; + + if (((flags & GENERIC_READ) || + ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) && + !(*pmode & mask & 0444)) + *pdenied |= mask & 0444; + + if (((flags & GENERIC_EXECUTE) || + ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) && + !(*pmode & mask & 0111)) + *pdenied |= mask & 0111; + return; } else if (type != ACCESS_ALLOWED) { cifs_dbg(VFS, "unknown access control type %d\n", type); @@ -588,20 +595,27 @@ static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, } /* else ACCESS_ALLOWED type */ - if (flags & GENERIC_ALL) { - *pmode |= (S_IRWXUGO & (*pbits_to_set)); + if ((flags & GENERIC_ALL) && + !(*pdenied & mask & 0777)) { + *pmode |= mask & 0777; cifs_dbg(NOISY, "all perms\n"); return; } - if ((flags & GENERIC_WRITE) || - ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) - *pmode |= (S_IWUGO & (*pbits_to_set)); - if ((flags & GENERIC_READ) || - ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) - *pmode |= (S_IRUGO & (*pbits_to_set)); - if ((flags & GENERIC_EXECUTE) || - ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) - *pmode |= (S_IXUGO & (*pbits_to_set)); + + if (((flags & GENERIC_WRITE) || + ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) && + !(*pdenied & mask & 0222)) + *pmode |= mask & 0222; + + if (((flags & GENERIC_READ) || + ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) && + !(*pdenied & mask & 0444)) + *pmode |= mask & 0444; + + if (((flags & GENERIC_EXECUTE) || + ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) && + !(*pdenied & mask & 0111)) + *pmode |= mask & 0111; cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode); return; @@ -638,17 +652,19 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, } static __u16 fill_ace_for_sid(struct cifs_ace *pntace, - const struct cifs_sid *psid, __u64 nmode, umode_t bits) + const struct cifs_sid *psid, __u64 nmode, umode_t bits, __u8 access_type) { int i; __u16 size = 0; __u32 access_req = 0; - pntace->type = ACCESS_ALLOWED; + pntace->type = access_type; pntace->flags = 0x0; mode_to_access_flags(nmode, bits, &access_req); - if (!access_req) + if (access_type == ACCESS_ALLOWED && !access_req) access_req = SET_MINIMUM_RIGHTS; + else if (access_type == ACCESS_DENIED) + access_req &= ~SET_MINIMUM_RIGHTS; pntace->access_req = cpu_to_le32(access_req); pntace->sid.revision = psid->revision; @@ -701,6 +717,10 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl) } #endif +#define ACL_OWNER_MASK 0700 +#define ACL_GROUP_MASK 0770 +#define ACL_EVERYONE_MASK 0777 + static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, struct cifs_fattr *fattr, bool mode_from_special_sid) @@ -716,7 +736,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, if (!pdacl) { /* no DACL in the security descriptor, set all the permissions for user/group/other */ - fattr->cf_mode |= S_IRWXUGO; + fattr->cf_mode |= 0777; return; } @@ -733,16 +753,14 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, /* reset rwx permissions for user/group/other. Also, if num_aces is 0 i.e. DACL has no ACEs, user/group/other have no permissions */ - fattr->cf_mode &= ~(S_IRWXUGO); + fattr->cf_mode &= ~(0777); acl_base = (char *)pdacl; acl_size = sizeof(struct cifs_acl); num_aces = le32_to_cpu(pdacl->num_aces); if (num_aces > 0) { - umode_t user_mask = S_IRWXU; - umode_t group_mask = S_IRWXG; - umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; + umode_t denied_mode = 0; if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *)) return; @@ -768,26 +786,28 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, fattr->cf_mode |= le32_to_cpu(ppace[i]->sid.sub_auth[2]); break; - } else if (compare_sids(&(ppace[i]->sid), pownersid) == 0) - access_flags_to_mode(ppace[i]->access_req, - ppace[i]->type, - &fattr->cf_mode, - &user_mask); - else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) - access_flags_to_mode(ppace[i]->access_req, - ppace[i]->type, - &fattr->cf_mode, - &group_mask); - else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) - access_flags_to_mode(ppace[i]->access_req, - ppace[i]->type, - &fattr->cf_mode, - &other_mask); - else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) - access_flags_to_mode(ppace[i]->access_req, - ppace[i]->type, - &fattr->cf_mode, - &other_mask); + } else { + if (compare_sids(&(ppace[i]->sid), pownersid) == 0) { + access_flags_to_mode(ppace[i]->access_req, + ppace[i]->type, + &fattr->cf_mode, + &denied_mode, + ACL_OWNER_MASK); + } else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) { + access_flags_to_mode(ppace[i]->access_req, + ppace[i]->type, + &fattr->cf_mode, + &denied_mode, + ACL_GROUP_MASK); + } else if ((compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) || + (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)) { + access_flags_to_mode(ppace[i]->access_req, + ppace[i]->type, + &fattr->cf_mode, + &denied_mode, + ACL_EVERYONE_MASK); + } + } /* memcpy((void *)(&(cifscred->aces[i])), @@ -873,32 +893,86 @@ unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace) } static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, - struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid) + struct cifs_sid *pgrpsid, __u64 *pnmode, bool modefromsid) { u16 size = 0; u32 num_aces = 0; struct cifs_acl *pnndacl; + __u64 nmode; + __u64 user_mode; + __u64 group_mode; + __u64 other_mode; + __u64 deny_user_mode = 0; + __u64 deny_group_mode = 0; pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); + nmode = *pnmode; + if (modefromsid) { struct cifs_ace *pntace = (struct cifs_ace *)((char *)pnndacl + size); size += setup_special_mode_ACE(pntace, nmode); num_aces++; + goto set_size; } + /* + * We'll try to keep the mode as requested by the user. + * But in cases where we cannot meaningfully convert that + * into ACL, return back the updated mode, so that it is + * updated in the inode. + */ + + if (!memcmp(pownersid, pgrpsid, sizeof(struct cifs_sid))) { + /* + * Case when owner and group SIDs are the same. + * Set the more restrictive of the two modes. + */ + user_mode = nmode & (nmode << 3) & 0700; + group_mode = nmode & (nmode >> 3) & 0070; + } else { + user_mode = nmode & 0700; + group_mode = nmode & 0070; + } + + other_mode = nmode & 0007; + + /* We need DENY ACE when the perm is more restrictive than the next sets. */ + deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700; + deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070; + + *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777); + + if (deny_user_mode) { + size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), + pownersid, deny_user_mode, 0700, ACCESS_DENIED); + num_aces++; + } + /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/ + if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) { + size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), + pgrpsid, deny_group_mode, 0070, ACCESS_DENIED); + num_aces++; + } size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size), - pownersid, nmode, S_IRWXU); + pownersid, user_mode, 0700, ACCESS_ALLOWED); num_aces++; + /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */ + if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) { + size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), + pgrpsid, deny_group_mode, 0070, ACCESS_DENIED); + num_aces++; + } size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pgrpsid, nmode, S_IRWXG); + pgrpsid, group_mode, 0070, ACCESS_ALLOWED); num_aces++; size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - &sid_everyone, nmode, S_IRWXO); + &sid_everyone, other_mode, 0007, ACCESS_ALLOWED); num_aces++; +set_size: pndacl->num_aces = cpu_to_le32(num_aces); pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); @@ -1000,7 +1074,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, /* Convert permission bits from mode to equivalent CIFS ACL */ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, - __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, + __u32 secdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, bool mode_from_sid, bool id_from_sid, int *aclflag) { int rc = 0; @@ -1012,7 +1086,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ - if (nmode != NO_CHANGE_64) { /* chmod */ + if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + le32_to_cpu(pntsd->osidoffset)); group_sid_ptr = (struct cifs_sid *)((char *)pntsd + @@ -1026,7 +1100,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, ndacl_ptr->num_aces = 0; rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, - nmode, mode_from_sid); + pnmode, mode_from_sid); sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); /* copy sec desc control portion & owner and group sids */ copy_sec_desc(pntsd, pnntsd, sidsoffset); @@ -1282,7 +1356,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, /* Convert mode bits to an ACL so we can update the ACL on the server */ int -id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, +id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, kuid_t uid, kgid_t gid) { int rc = 0; @@ -1341,7 +1415,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, else id_from_sid = false; - rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, + rc = build_sec_desc(pntsd, pnntsd, secdesclen, pnmode, uid, gid, mode_from_sid, id_from_sid, &aclflag); cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 24c6f36177ba..2ed98d4a30c1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -215,8 +215,8 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, bool get_mode_from_special_sid, const char *path, const struct cifs_fid *pfid); -extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, - kuid_t, kgid_t); +extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, + kuid_t uid, kgid_t gid); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ac01f9684b39..8debd4c18faf 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2813,7 +2813,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { if (uid_valid(uid) || gid_valid(gid)) { - rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64, + mode = NO_CHANGE_64; + rc = id_mode_to_cifs_acl(inode, full_path, &mode, uid, gid); if (rc) { cifs_dbg(FYI, "%s: Setting id failed with error: %d\n", @@ -2834,13 +2835,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) rc = 0; if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { - rc = id_mode_to_cifs_acl(inode, full_path, mode, + rc = id_mode_to_cifs_acl(inode, full_path, &mode, INVALID_UID, INVALID_GID); if (rc) { cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n", __func__, rc); goto cifs_setattr_exit; } + + /* + * In case of CIFS_MOUNT_CIFS_ACL, we cannot support all modes. + * Pick up the actual mode bits that were set. + */ + if (mode != attrs->ia_mode) + attrs->ia_mode = mode; } else if (((mode & S_IWUGO) == 0) && (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { -- cgit v1.2.3 From f2156d35c9584a4afdb71de4bc24b3fef674a63d Mon Sep 17 00:00:00 2001 From: Shyam Prasad N Date: Mon, 9 Nov 2020 06:12:49 -0800 Subject: cifs: Enable sticky bit with cifsacl mount option. For the cifsacl mount option, we did not support sticky bits. With this patch, we do support it, by setting the DELETE_CHILD perm on the directory only for the owner user. When sticky bit is not enabled, allow DELETE_CHILD perm for everyone. Signed-off-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 41 ++++++++++++++++++++++++++++++----------- fs/cifs/cifsacl.h | 4 ++++ fs/cifs/cifspdu.h | 2 +- 3 files changed, 35 insertions(+), 12 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 9b7f727b0e88..c3954bfcb666 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -617,6 +617,17 @@ static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, !(*pdenied & mask & 0111)) *pmode |= mask & 0111; + /* If DELETE_CHILD is set only on an owner ACE, set sticky bit */ + if (flags & FILE_DELETE_CHILD) { + if (mask == ACL_OWNER_MASK) { + if (!(*pdenied & 01000)) + *pmode |= 01000; + } else if (!(*pdenied & 01000)) { + *pmode &= ~01000; + *pdenied |= 01000; + } + } + cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode); return; } @@ -652,7 +663,9 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, } static __u16 fill_ace_for_sid(struct cifs_ace *pntace, - const struct cifs_sid *psid, __u64 nmode, umode_t bits, __u8 access_type) + const struct cifs_sid *psid, __u64 nmode, + umode_t bits, __u8 access_type, + bool allow_delete_child) { int i; __u16 size = 0; @@ -661,10 +674,15 @@ static __u16 fill_ace_for_sid(struct cifs_ace *pntace, pntace->type = access_type; pntace->flags = 0x0; mode_to_access_flags(nmode, bits, &access_req); + + if (access_type == ACCESS_ALLOWED && allow_delete_child) + access_req |= FILE_DELETE_CHILD; + if (access_type == ACCESS_ALLOWED && !access_req) access_req = SET_MINIMUM_RIGHTS; else if (access_type == ACCESS_DENIED) access_req &= ~SET_MINIMUM_RIGHTS; + pntace->access_req = cpu_to_le32(access_req); pntace->sid.revision = psid->revision; @@ -717,10 +735,6 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl) } #endif -#define ACL_OWNER_MASK 0700 -#define ACL_GROUP_MASK 0770 -#define ACL_EVERYONE_MASK 0777 - static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, struct cifs_fattr *fattr, bool mode_from_special_sid) @@ -904,6 +918,7 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, __u64 other_mode; __u64 deny_user_mode = 0; __u64 deny_group_mode = 0; + bool sticky_set = false; pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); @@ -945,31 +960,35 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777); + /* This tells if we should allow delete child for group and everyone. */ + if (nmode & 01000) + sticky_set = true; + if (deny_user_mode) { size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pownersid, deny_user_mode, 0700, ACCESS_DENIED); + pownersid, deny_user_mode, 0700, ACCESS_DENIED, false); num_aces++; } /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/ if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) { size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pgrpsid, deny_group_mode, 0070, ACCESS_DENIED); + pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false); num_aces++; } size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size), - pownersid, user_mode, 0700, ACCESS_ALLOWED); + pownersid, user_mode, 0700, ACCESS_ALLOWED, true); num_aces++; /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */ if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) { size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pgrpsid, deny_group_mode, 0070, ACCESS_DENIED); + pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false); num_aces++; } size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - pgrpsid, group_mode, 0070, ACCESS_ALLOWED); + pgrpsid, group_mode, 0070, ACCESS_ALLOWED, !sticky_set); num_aces++; size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), - &sid_everyone, other_mode, 0007, ACCESS_ALLOWED); + &sid_everyone, other_mode, 0007, ACCESS_ALLOWED, !sticky_set); num_aces++; set_size: diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 45665ff87b64..ff7fd0862e28 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -30,6 +30,10 @@ #define WRITE_BIT 0x2 #define EXEC_BIT 0x1 +#define ACL_OWNER_MASK 0700 +#define ACL_GROUP_MASK 0770 +#define ACL_EVERYONE_MASK 0777 + #define UBITSHIFT 6 #define GBITSHIFT 3 diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 593d826820c3..ce51183ecaf4 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -262,7 +262,7 @@ | WRITE_OWNER | SYNCHRONIZE) #define SET_FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ | FILE_READ_EA | FILE_WRITE_EA \ - | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES \ + | FILE_READ_ATTRIBUTES \ | FILE_WRITE_ATTRIBUTES \ | DELETE | READ_CONTROL | WRITE_DAC \ | WRITE_OWNER | SYNCHRONIZE) -- cgit v1.2.3 From 145024e3e4a32353420660ec689fb98c960ac3c8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 9 Dec 2020 21:25:13 -0600 Subject: SMB3.1.1: update comments clarifying SPNEGO info in negprot response Trivial changes to clarify confusing comment about SPNEGO blog (and also one length comparisons in negotiate context parsing). Suggested-by: Tom Talpey Suggested-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/smb2misc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 2da6b41cb552..c2c5e4122a04 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -109,8 +109,17 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, (pneg_rsp->DialectRevision != cpu_to_le16(SMB311_PROT_ID))) return 0; - /* Make sure that negotiate contexts start after gss security blob */ + /* + * if SPNEGO blob present (ie the RFC2478 GSS info which indicates + * which security mechanisms the server supports) make sure that + * the negotiate contexts start after it + */ nc_offset = le32_to_cpu(pneg_rsp->NegotiateContextOffset); + /* + * non_ctxlen is at least shdr->StructureSize + pdu->StructureSize2 + * and the latter is 1 byte bigger than the fix-sized area of the + * NEGOTIATE response + */ if (nc_offset + 1 < non_ctxlen) { pr_warn_once("Invalid negotiate context offset %d\n", nc_offset); return 0; -- cgit v1.2.3 From 7955f105afb6034af344038d663bc98809483cdd Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 9 Dec 2020 22:19:00 -0600 Subject: SMB3.1.1: do not log warning message if server doesn't populate salt In the negotiate protocol preauth context, the server is not required to populate the salt (although it is done by most servers) so do not warn on mount. We retain the checks (warn) that the preauth context is the minimum size and that the salt does not exceed DataLength of the SMB response. Although we use the defaults in the case that the preauth context response is invalid, these checks may be useful in the future as servers add support for additional mechanisms. CC: Stable Reviewed-by: Shyam Prasad N Reviewed-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/smb2pdu.c | 7 +++++-- fs/cifs/smb2pdu.h | 14 +++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index acb72705062d..fc06c762fbbf 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -427,8 +427,8 @@ build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt) pneg_ctxt->ContextType = SMB2_PREAUTH_INTEGRITY_CAPABILITIES; pneg_ctxt->DataLength = cpu_to_le16(38); pneg_ctxt->HashAlgorithmCount = cpu_to_le16(1); - pneg_ctxt->SaltLength = cpu_to_le16(SMB311_SALT_SIZE); - get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE); + pneg_ctxt->SaltLength = cpu_to_le16(SMB311_LINUX_CLIENT_SALT_SIZE); + get_random_bytes(pneg_ctxt->Salt, SMB311_LINUX_CLIENT_SALT_SIZE); pneg_ctxt->HashAlgorithms = SMB2_PREAUTH_INTEGRITY_SHA512; } @@ -566,6 +566,9 @@ static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) if (len < MIN_PREAUTH_CTXT_DATA_LEN) { pr_warn_once("server sent bad preauth context\n"); return; + } else if (len < MIN_PREAUTH_CTXT_DATA_LEN + le16_to_cpu(ctxt->SaltLength)) { + pr_warn_once("server sent invalid SaltLength\n"); + return; } if (le16_to_cpu(ctxt->HashAlgorithmCount) != 1) pr_warn_once("Invalid SMB3 hash algorithm count\n"); diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index fa57b03ca98c..204a622b89ed 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -333,12 +333,20 @@ struct smb2_neg_context { /* Followed by array of data */ } __packed; -#define SMB311_SALT_SIZE 32 +#define SMB311_LINUX_CLIENT_SALT_SIZE 32 /* Hash Algorithm Types */ #define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001) #define SMB2_PREAUTH_HASH_SIZE 64 -#define MIN_PREAUTH_CTXT_DATA_LEN (SMB311_SALT_SIZE + 6) +/* + * SaltLength that the server send can be zero, so the only three required + * fields (all __le16) end up six bytes total, so the minimum context data len + * in the response is six bytes which accounts for + * + * HashAlgorithmCount, SaltLength, and 1 HashAlgorithm. + */ +#define MIN_PREAUTH_CTXT_DATA_LEN 6 + struct smb2_preauth_neg_context { __le16 ContextType; /* 1 */ __le16 DataLength; @@ -346,7 +354,7 @@ struct smb2_preauth_neg_context { __le16 HashAlgorithmCount; /* 1 */ __le16 SaltLength; __le16 HashAlgorithms; /* HashAlgorithms[0] since only one defined */ - __u8 Salt[SMB311_SALT_SIZE]; + __u8 Salt[SMB311_LINUX_CLIENT_SALT_SIZE]; } __packed; /* Encryption Algorithms Ciphers */ -- cgit v1.2.3 From 3fa1c6d1b8f5c3d9be9e8047ad894ab3de67dc6e Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 9 Dec 2020 23:07:12 -0600 Subject: cifs: rename smb_vol as smb3_fs_context and move it to fs_context.h Harmonize and change all such variables to 'ctx', where possible. No changes to actual logic. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 25 +- fs/cifs/cifsglob.h | 99 +----- fs/cifs/cifsproto.h | 24 +- fs/cifs/connect.c | 960 +++++++++++++++++++++++++-------------------------- fs/cifs/dfs_cache.c | 83 ++--- fs/cifs/dfs_cache.h | 2 +- fs/cifs/dir.c | 7 +- fs/cifs/fs_context.c | 102 +++--- fs/cifs/fs_context.h | 105 +++++- fs/cifs/sess.c | 51 +-- fs/cifs/smb1ops.c | 11 +- fs/cifs/smb2ops.c | 17 +- 12 files changed, 750 insertions(+), 736 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 472cb7777e3e..9fb85fcff6ae 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -55,6 +55,7 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#include "fs_context.h" /* * DOS dates from 1980/1/1 through 2107/12/31 @@ -720,7 +721,7 @@ static const struct super_operations cifs_super_ops = { * Return dentry with refcount + 1 on success and NULL otherwise. */ static struct dentry * -cifs_get_root(struct smb_vol *vol, struct super_block *sb) +cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb) { struct dentry *dentry; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); @@ -731,7 +732,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) return dget(sb->s_root); - full_path = cifs_build_path_to_root(vol, cifs_sb, + full_path = cifs_build_path_to_root(ctx, cifs_sb, cifs_sb_master_tcon(cifs_sb), 0); if (full_path == NULL) return ERR_PTR(-ENOMEM); @@ -784,7 +785,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, int rc; struct super_block *sb; struct cifs_sb_info *cifs_sb; - struct smb_vol *volume_info; + struct smb3_fs_context *ctx; struct cifs_mnt_data mnt_data; struct dentry *root; @@ -797,9 +798,9 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, else cifs_info("Attempting to mount %s\n", dev_name); - volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3); - if (IS_ERR(volume_info)) - return ERR_CAST(volume_info); + ctx = cifs_get_volume_info((char *)data, dev_name, is_smb3); + if (IS_ERR(ctx)) + return ERR_CAST(ctx); cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { @@ -813,13 +814,13 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out_free; } - rc = cifs_setup_cifs_sb(volume_info, cifs_sb); + rc = cifs_setup_cifs_sb(ctx, cifs_sb); if (rc) { root = ERR_PTR(rc); goto out_free; } - rc = cifs_mount(cifs_sb, volume_info); + rc = cifs_mount(cifs_sb, ctx); if (rc) { if (!(flags & SB_SILENT)) cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", @@ -828,7 +829,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out_free; } - mnt_data.vol = volume_info; + mnt_data.ctx = ctx; mnt_data.cifs_sb = cifs_sb; mnt_data.flags = flags; @@ -855,7 +856,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, sb->s_flags |= SB_ACTIVE; } - root = cifs_get_root(volume_info, sb); + root = cifs_get_root(ctx, sb); if (IS_ERR(root)) goto out_super; @@ -865,7 +866,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, out_super: deactivate_locked_super(sb); out: - cifs_cleanup_volume_info(volume_info); + cifs_cleanup_volume_info(ctx); return root; out_free: @@ -873,7 +874,7 @@ out_free: kfree(cifs_sb->mountdata); kfree(cifs_sb); out_nls: - unload_nls(volume_info->local_nls); + unload_nls(ctx->local_nls); goto out; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 484ec2d8c5c9..b46809260e79 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -202,7 +202,7 @@ struct cifs_ses; struct cifs_tcon; struct dfs_info3_param; struct cifs_fattr; -struct smb_vol; +struct smb3_fs_context; struct cifs_fid; struct cifs_readdata; struct cifs_writedata; @@ -268,9 +268,9 @@ struct smb_version_operations { /* negotiate to the server */ int (*negotiate)(const unsigned int, struct cifs_ses *); /* set negotiated write size */ - unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *); + unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); /* set negotiated read size */ - unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *); + unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); /* setup smb sessionn */ int (*sess_setup)(const unsigned int, struct cifs_ses *, const struct nls_table *); @@ -530,97 +530,6 @@ struct smb_version_values { #define HEADER_SIZE(server) (server->vals->header_size) #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) -struct smb_vol { - char *username; - char *password; - char *domainname; - char *UNC; - char *iocharset; /* local code page for mapping to and from Unicode */ - char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ - char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ - kuid_t cred_uid; - kuid_t linux_uid; - kgid_t linux_gid; - kuid_t backupuid; - kgid_t backupgid; - umode_t file_mode; - umode_t dir_mode; - enum securityEnum sectype; /* sectype requested via mnt opts */ - bool sign; /* was signing requested via mnt opts? */ - bool ignore_signature:1; - bool retry:1; - bool intr:1; - bool setuids:1; - bool setuidfromacl:1; - bool override_uid:1; - bool override_gid:1; - bool dynperm:1; - bool noperm:1; - bool nodelete:1; - bool mode_ace:1; - bool no_psx_acl:1; /* set if posix acl support should be disabled */ - bool cifs_acl:1; - bool backupuid_specified; /* mount option backupuid is specified */ - bool backupgid_specified; /* mount option backupgid is specified */ - bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ - bool server_ino:1; /* use inode numbers from server ie UniqueId */ - bool direct_io:1; - bool strict_io:1; /* strict cache behavior */ - bool cache_ro:1; - bool cache_rw:1; - bool remap:1; /* set to remap seven reserved chars in filenames */ - bool sfu_remap:1; /* remap seven reserved chars ala SFU */ - bool posix_paths:1; /* unset to not ask for posix pathnames. */ - bool no_linux_ext:1; - bool linux_ext:1; - bool sfu_emul:1; - bool nullauth:1; /* attempt to authenticate with null user */ - bool nocase:1; /* request case insensitive filenames */ - bool nobrl:1; /* disable sending byte range locks to srv */ - bool nohandlecache:1; /* disable caching dir handles if srvr probs */ - bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ - bool seal:1; /* request transport encryption on share */ - bool nodfs:1; /* Do not request DFS, even if available */ - bool local_lease:1; /* check leases only on local system, not remote */ - bool noblocksnd:1; - bool noautotune:1; - bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ - bool no_lease:1; /* disable requesting leases */ - bool fsc:1; /* enable fscache */ - bool mfsymlinks:1; /* use Minshall+French Symlinks */ - bool multiuser:1; - bool rwpidforward:1; /* pid forward for read/write operations */ - bool nosharesock:1; - bool persistent:1; - bool nopersistent:1; - bool resilient:1; /* noresilient not required since not fored for CA */ - bool domainauto:1; - bool rdma:1; - bool multichannel:1; - bool use_client_guid:1; - /* reuse existing guid for multichannel */ - u8 client_guid[SMB2_CLIENT_GUID_SIZE]; - unsigned int bsize; - unsigned int rsize; - unsigned int wsize; - unsigned int min_offload; - bool sockopt_tcp_nodelay:1; - unsigned long actimeo; /* attribute cache timeout (jiffies) */ - struct smb_version_operations *ops; - struct smb_version_values *vals; - char *prepath; - struct sockaddr_storage dstaddr; /* destination address */ - struct sockaddr_storage srcaddr; /* allow binding to a local IP */ - struct nls_table *local_nls; - unsigned int echo_interval; /* echo interval in secs */ - __u64 snapshot_time; /* needed for timewarp tokens */ - __u32 handle_timeout; /* persistent and durable handle timeout in ms */ - unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ - unsigned int max_channels; - __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */ - bool rootfs:1; /* if it's a SMB root file system */ -}; - /** * CIFS superblock mount flags (mnt_cifs_flags) to consider when * trying to reuse existing superblock for a new mount @@ -649,7 +558,7 @@ struct smb_vol { struct cifs_mnt_data { struct cifs_sb_info *cifs_sb; - struct smb_vol *vol; + struct smb3_fs_context *ctx; int flags; }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2ed98d4a30c1..e891a4f421a6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -27,8 +27,8 @@ #endif struct statfs; -struct smb_vol; struct smb_rqst; +struct smb3_fs_context; /* ***************************************************************** @@ -72,7 +72,7 @@ extern void exit_cifs_spnego(void); extern char *build_path_from_dentry(struct dentry *); extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix); -extern char *cifs_build_path_to_root(struct smb_vol *vol, +extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, int add_treename); @@ -234,13 +234,13 @@ extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, unsigned int page_offset, unsigned int to_read); -extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, +extern int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb); extern int cifs_match_super(struct super_block *, void *); -extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); -extern struct smb_vol *cifs_get_volume_info(char *mount_data, +extern void cifs_cleanup_volume_info(struct smb3_fs_context *ctx); +extern struct smb3_fs_context *cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3); -extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol); +extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon); @@ -256,7 +256,7 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink, struct cifs_pending_open *open); extern void cifs_del_pending_open(struct cifs_pending_open *open); -extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb_vol *vol); +extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx); extern void cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect); extern void cifs_put_tcon(struct cifs_tcon *tcon); @@ -332,7 +332,7 @@ extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, const char *searchName, bool is_unicode); extern void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, - struct smb_vol *vol); + struct smb3_fs_context *ctx); extern int CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *FSData); extern int SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, @@ -553,18 +553,18 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); extern int -cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, +cifs_setup_volume_info(struct smb3_fs_context *ctx, char *mount_data, const char *devname, bool is_smb3); extern void -cifs_cleanup_volume_info_contents(struct smb_vol *volume_info); +cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx); extern struct TCP_Server_Info * -cifs_find_tcp_session(struct smb_vol *vol); +cifs_find_tcp_session(struct smb3_fs_context *ctx); extern void cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * -cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info); +cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx); void cifs_readdata_release(struct kref *refcount); int cifs_async_readv(struct cifs_readdata *rdata); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 44f9cce57099..fedb904b516f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1320,7 +1320,7 @@ static int get_option_gid(substring_t args[], kgid_t *result) * fields with the result. Returns 0 on success and an error otherwise. */ static int -cifs_parse_devname(const char *devname, struct smb_vol *vol) +cifs_parse_devname(const char *devname, struct smb3_fs_context *ctx) { char *pos; const char *delims = "/\\"; @@ -1349,11 +1349,11 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) /* move "pos" up to delimiter or NULL */ pos += len; - vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); - if (!vol->UNC) + ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); + if (!ctx->UNC) return -ENOMEM; - convert_delimiter(vol->UNC, '\\'); + convert_delimiter(ctx->UNC, '\\'); /* skip any delimiter */ if (*pos == '/' || *pos == '\\') @@ -1363,8 +1363,8 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) if (!*pos) return 0; - vol->prepath = kstrdup(pos, GFP_KERNEL); - if (!vol->prepath) + ctx->prepath = kstrdup(pos, GFP_KERNEL); + if (!ctx->prepath) return -ENOMEM; return 0; @@ -1372,7 +1372,7 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) static int cifs_parse_mount_options(const char *mountdata, const char *devname, - struct smb_vol *vol, bool is_smb3) + struct smb3_fs_context *ctx, bool is_smb3) { char *data, *end; char *mountdata_copy = NULL, *options; @@ -1391,66 +1391,66 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, bool got_ip = false; bool got_version = false; unsigned short port = 0; - struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr; + struct sockaddr *dstaddr = (struct sockaddr *)&ctx->dstaddr; separator[0] = ','; separator[1] = 0; delim = separator[0]; - /* ensure we always start with zeroed-out smb_vol */ - memset(vol, 0, sizeof(*vol)); + /* ensure we always start with zeroed-out ctx */ + memset(ctx, 0, sizeof(*ctx)); /* * does not have to be perfect mapping since field is * informational, only used for servers that do not support * port 445 and it can be overridden at mount time */ - memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); + memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) - vol->source_rfc1001_name[i] = toupper(nodename[i]); + ctx->source_rfc1001_name[i] = toupper(nodename[i]); - vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0; + ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0; /* null target name indicates to use *SMBSERVR default called name if we end up sending RFC1001 session initialize */ - vol->target_rfc1001_name[0] = 0; - vol->cred_uid = current_uid(); - vol->linux_uid = current_uid(); - vol->linux_gid = current_gid(); - vol->bsize = 1024 * 1024; /* can improve cp performance significantly */ + ctx->target_rfc1001_name[0] = 0; + ctx->cred_uid = current_uid(); + ctx->linux_uid = current_uid(); + ctx->linux_gid = current_gid(); + ctx->bsize = 1024 * 1024; /* can improve cp performance significantly */ /* * default to SFM style remapping of seven reserved characters * unless user overrides it or we negotiate CIFS POSIX where * it is unnecessary. Can not simultaneously use more than one mapping * since then readdir could list files that open could not open */ - vol->remap = true; + ctx->remap = true; /* default to only allowing write access to owner of the mount */ - vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; + ctx->dir_mode = ctx->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; - /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ + /* ctx->retry default is 0 (i.e. "soft" limited retry not hard retry) */ /* default is always to request posix paths. */ - vol->posix_paths = 1; + ctx->posix_paths = 1; /* default to using server inode numbers where available */ - vol->server_ino = 1; + ctx->server_ino = 1; /* default is to use strict cifs caching semantics */ - vol->strict_io = true; + ctx->strict_io = true; - vol->actimeo = CIFS_DEF_ACTIMEO; + ctx->actimeo = CIFS_DEF_ACTIMEO; /* Most clients set timeout to 0, allows server to use its default */ - vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ + ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ - vol->ops = &smb30_operations; - vol->vals = &smbdefault_values; + ctx->ops = &smb30_operations; + ctx->vals = &smbdefault_values; - vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; + ctx->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; /* default to no multichannel (single server connection) */ - vol->multichannel = false; - vol->max_channels = 1; + ctx->multichannel = false; + ctx->max_channels = 1; if (!mountdata) goto cifs_parse_mount_err; @@ -1470,10 +1470,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, cifs_dbg(FYI, "Null separator not allowed\n"); } } - vol->backupuid_specified = false; /* no backup intent for a user */ - vol->backupgid_specified = false; /* no backup intent for a group */ + ctx->backupuid_specified = false; /* no backup intent for a user */ + ctx->backupgid_specified = false; /* no backup intent for a group */ - switch (cifs_parse_devname(devname, vol)) { + switch (cifs_parse_devname(devname, ctx)) { case 0: break; case -ENOMEM: @@ -1505,10 +1505,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, /* Boolean values */ case Opt_user_xattr: - vol->no_xattr = 0; + ctx->no_xattr = 0; break; case Opt_nouser_xattr: - vol->no_xattr = 1; + ctx->no_xattr = 1; break; case Opt_forceuid: override_uid = 1; @@ -1523,175 +1523,175 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, override_gid = 0; break; case Opt_noblocksend: - vol->noblocksnd = 1; + ctx->noblocksnd = 1; break; case Opt_noautotune: - vol->noautotune = 1; + ctx->noautotune = 1; break; case Opt_nolease: - vol->no_lease = 1; + ctx->no_lease = 1; break; case Opt_hard: - vol->retry = 1; + ctx->retry = 1; break; case Opt_soft: - vol->retry = 0; + ctx->retry = 0; break; case Opt_perm: - vol->noperm = 0; + ctx->noperm = 0; break; case Opt_noperm: - vol->noperm = 1; + ctx->noperm = 1; break; case Opt_nodelete: - vol->nodelete = 1; + ctx->nodelete = 1; break; case Opt_mapchars: - vol->sfu_remap = true; - vol->remap = false; /* disable SFM mapping */ + ctx->sfu_remap = true; + ctx->remap = false; /* disable SFM mapping */ break; case Opt_nomapchars: - vol->sfu_remap = false; + ctx->sfu_remap = false; break; case Opt_mapposix: - vol->remap = true; - vol->sfu_remap = false; /* disable SFU mapping */ + ctx->remap = true; + ctx->sfu_remap = false; /* disable SFU mapping */ break; case Opt_nomapposix: - vol->remap = false; + ctx->remap = false; break; case Opt_sfu: - vol->sfu_emul = 1; + ctx->sfu_emul = 1; break; case Opt_nosfu: - vol->sfu_emul = 0; + ctx->sfu_emul = 0; break; case Opt_nodfs: - vol->nodfs = 1; + ctx->nodfs = 1; break; case Opt_rootfs: #ifdef CONFIG_CIFS_ROOT - vol->rootfs = true; + ctx->rootfs = true; #endif break; case Opt_posixpaths: - vol->posix_paths = 1; + ctx->posix_paths = 1; break; case Opt_noposixpaths: - vol->posix_paths = 0; + ctx->posix_paths = 0; break; case Opt_nounix: - if (vol->linux_ext) + if (ctx->linux_ext) cifs_dbg(VFS, "conflicting unix mount options\n"); - vol->no_linux_ext = 1; + ctx->no_linux_ext = 1; break; case Opt_unix: - if (vol->no_linux_ext) + if (ctx->no_linux_ext) cifs_dbg(VFS, "conflicting unix mount options\n"); - vol->linux_ext = 1; + ctx->linux_ext = 1; break; case Opt_nocase: - vol->nocase = 1; + ctx->nocase = 1; break; case Opt_brl: - vol->nobrl = 0; + ctx->nobrl = 0; break; case Opt_nobrl: - vol->nobrl = 1; + ctx->nobrl = 1; /* * turn off mandatory locking in mode * if remote locking is turned off since the * local vfs will do advisory */ - if (vol->file_mode == + if (ctx->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) - vol->file_mode = S_IALLUGO; + ctx->file_mode = S_IALLUGO; break; case Opt_nohandlecache: - vol->nohandlecache = 1; + ctx->nohandlecache = 1; break; case Opt_handlecache: - vol->nohandlecache = 0; + ctx->nohandlecache = 0; break; case Opt_forcemandatorylock: - vol->mand_lock = 1; + ctx->mand_lock = 1; break; case Opt_setuids: - vol->setuids = 1; + ctx->setuids = 1; break; case Opt_nosetuids: - vol->setuids = 0; + ctx->setuids = 0; break; case Opt_setuidfromacl: - vol->setuidfromacl = 1; + ctx->setuidfromacl = 1; break; case Opt_dynperm: - vol->dynperm = true; + ctx->dynperm = true; break; case Opt_nodynperm: - vol->dynperm = false; + ctx->dynperm = false; break; case Opt_nohard: - vol->retry = 0; + ctx->retry = 0; break; case Opt_nosoft: - vol->retry = 1; + ctx->retry = 1; break; case Opt_nointr: - vol->intr = 0; + ctx->intr = 0; break; case Opt_intr: - vol->intr = 1; + ctx->intr = 1; break; case Opt_nostrictsync: - vol->nostrictsync = 1; + ctx->nostrictsync = 1; break; case Opt_strictsync: - vol->nostrictsync = 0; + ctx->nostrictsync = 0; break; case Opt_serverino: - vol->server_ino = 1; + ctx->server_ino = 1; break; case Opt_noserverino: - vol->server_ino = 0; + ctx->server_ino = 0; break; case Opt_rwpidforward: - vol->rwpidforward = 1; + ctx->rwpidforward = 1; break; case Opt_modesid: - vol->mode_ace = 1; + ctx->mode_ace = 1; break; case Opt_cifsacl: - vol->cifs_acl = 1; + ctx->cifs_acl = 1; break; case Opt_nocifsacl: - vol->cifs_acl = 0; + ctx->cifs_acl = 0; break; case Opt_acl: - vol->no_psx_acl = 0; + ctx->no_psx_acl = 0; break; case Opt_noacl: - vol->no_psx_acl = 1; + ctx->no_psx_acl = 1; break; case Opt_locallease: - vol->local_lease = 1; + ctx->local_lease = 1; break; case Opt_sign: - vol->sign = true; + ctx->sign = true; break; case Opt_ignore_signature: - vol->sign = true; - vol->ignore_signature = true; + ctx->sign = true; + ctx->ignore_signature = true; break; case Opt_seal: /* we do not do the following in secFlags because seal * is a per tree connection (mount) not a per socket * or per-smb connection option in the protocol - * vol->secFlg |= CIFSSEC_MUST_SEAL; + * ctx->secFlg |= CIFSSEC_MUST_SEAL; */ - vol->seal = 1; + ctx->seal = 1; break; case Opt_noac: pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); @@ -1701,88 +1701,88 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); goto cifs_parse_mount_err; #endif - vol->fsc = true; + ctx->fsc = true; break; case Opt_mfsymlinks: - vol->mfsymlinks = true; + ctx->mfsymlinks = true; break; case Opt_multiuser: - vol->multiuser = true; + ctx->multiuser = true; break; case Opt_sloppy: sloppy = true; break; case Opt_nosharesock: - vol->nosharesock = true; + ctx->nosharesock = true; break; case Opt_nopersistent: - vol->nopersistent = true; - if (vol->persistent) { + ctx->nopersistent = true; + if (ctx->persistent) { cifs_dbg(VFS, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } break; case Opt_persistent: - vol->persistent = true; - if ((vol->nopersistent) || (vol->resilient)) { + ctx->persistent = true; + if ((ctx->nopersistent) || (ctx->resilient)) { cifs_dbg(VFS, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } break; case Opt_resilient: - vol->resilient = true; - if (vol->persistent) { + ctx->resilient = true; + if (ctx->persistent) { cifs_dbg(VFS, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } break; case Opt_noresilient: - vol->resilient = false; /* already the default */ + ctx->resilient = false; /* already the default */ break; case Opt_domainauto: - vol->domainauto = true; + ctx->domainauto = true; break; case Opt_rdma: - vol->rdma = true; + ctx->rdma = true; break; case Opt_multichannel: - vol->multichannel = true; + ctx->multichannel = true; /* if number of channels not specified, default to 2 */ - if (vol->max_channels < 2) - vol->max_channels = 2; + if (ctx->max_channels < 2) + ctx->max_channels = 2; break; case Opt_nomultichannel: - vol->multichannel = false; - vol->max_channels = 1; + ctx->multichannel = false; + ctx->max_channels = 1; break; case Opt_compress: - vol->compression = UNKNOWN_TYPE; + ctx->compression = UNKNOWN_TYPE; cifs_dbg(VFS, "SMB3 compression support is experimental\n"); break; /* Numeric Values */ case Opt_backupuid: - if (get_option_uid(args, &vol->backupuid)) { + if (get_option_uid(args, &ctx->backupuid)) { cifs_dbg(VFS, "%s: Invalid backupuid value\n", __func__); goto cifs_parse_mount_err; } - vol->backupuid_specified = true; + ctx->backupuid_specified = true; break; case Opt_backupgid: - if (get_option_gid(args, &vol->backupgid)) { + if (get_option_gid(args, &ctx->backupgid)) { cifs_dbg(VFS, "%s: Invalid backupgid value\n", __func__); goto cifs_parse_mount_err; } - vol->backupgid_specified = true; + ctx->backupgid_specified = true; break; case Opt_uid: - if (get_option_uid(args, &vol->linux_uid)) { + if (get_option_uid(args, &ctx->linux_uid)) { cifs_dbg(VFS, "%s: Invalid uid value\n", __func__); goto cifs_parse_mount_err; @@ -1790,14 +1790,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, uid_specified = true; break; case Opt_cruid: - if (get_option_uid(args, &vol->cred_uid)) { + if (get_option_uid(args, &ctx->cred_uid)) { cifs_dbg(VFS, "%s: Invalid cruid value\n", __func__); goto cifs_parse_mount_err; } break; case Opt_gid: - if (get_option_gid(args, &vol->linux_gid)) { + if (get_option_gid(args, &ctx->linux_gid)) { cifs_dbg(VFS, "%s: Invalid gid value\n", __func__); goto cifs_parse_mount_err; @@ -1810,7 +1810,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->file_mode = option; + ctx->file_mode = option; break; case Opt_dirmode: if (get_option_ul(args, &option)) { @@ -1818,7 +1818,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->dir_mode = option; + ctx->dir_mode = option; break; case Opt_port: if (get_option_ul(args, &option) || @@ -1834,7 +1834,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n"); goto cifs_parse_mount_err; } - vol->min_offload = option; + ctx->min_offload = option; break; case Opt_blocksize: if (get_option_ul(args, &option)) { @@ -1854,7 +1854,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->bsize = option; + ctx->bsize = option; break; case Opt_rsize: if (get_option_ul(args, &option)) { @@ -1862,7 +1862,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->rsize = option; + ctx->rsize = option; break; case Opt_wsize: if (get_option_ul(args, &option)) { @@ -1870,7 +1870,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->wsize = option; + ctx->wsize = option; break; case Opt_actimeo: if (get_option_ul(args, &option)) { @@ -1878,8 +1878,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->actimeo = HZ * option; - if (vol->actimeo > CIFS_MAX_ACTIMEO) { + ctx->actimeo = HZ * option; + if (ctx->actimeo > CIFS_MAX_ACTIMEO) { cifs_dbg(VFS, "attribute cache timeout too large\n"); goto cifs_parse_mount_err; } @@ -1890,8 +1890,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->handle_timeout = option; - if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { + ctx->handle_timeout = option; + if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); goto cifs_parse_mount_err; } @@ -1902,7 +1902,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->echo_interval = option; + ctx->echo_interval = option; break; case Opt_snapshot: if (get_option_ul(args, &option)) { @@ -1910,7 +1910,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->snapshot_time = option; + ctx->snapshot_time = option; break; case Opt_max_credits: if (get_option_ul(args, &option) || (option < 20) || @@ -1919,7 +1919,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__); goto cifs_parse_mount_err; } - vol->max_credits = option; + ctx->max_credits = option; break; case Opt_max_channels: if (get_option_ul(args, &option) || option < 1 || @@ -1928,15 +1928,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, __func__, CIFS_MAX_CHANNELS); goto cifs_parse_mount_err; } - vol->max_channels = option; + ctx->max_channels = option; break; /* String Arguments */ case Opt_blank_user: /* null user, ie. anonymous authentication */ - vol->nullauth = 1; - vol->username = NULL; + ctx->nullauth = 1; + ctx->username = NULL; break; case Opt_user: string = match_strdup(args); @@ -1949,9 +1949,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } - kfree(vol->username); - vol->username = kstrdup(string, GFP_KERNEL); - if (!vol->username) + kfree(ctx->username); + ctx->username = kstrdup(string, GFP_KERNEL); + if (!ctx->username) goto cifs_parse_mount_err; break; case Opt_blank_pass: @@ -1968,8 +1968,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, tmp_end++; if (!(tmp_end < end && tmp_end[1] == delim)) { /* No it is not. Set the password to NULL */ - kfree_sensitive(vol->password); - vol->password = NULL; + kfree_sensitive(ctx->password); + ctx->password = NULL; break; } fallthrough; /* to Opt_pass below */ @@ -2006,23 +2006,23 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, options = end; } - kfree_sensitive(vol->password); + kfree_sensitive(ctx->password); /* Now build new password string */ temp_len = strlen(value); - vol->password = kzalloc(temp_len+1, GFP_KERNEL); - if (vol->password == NULL) { + ctx->password = kzalloc(temp_len+1, GFP_KERNEL); + if (ctx->password == NULL) { pr_warn("no memory for password\n"); goto cifs_parse_mount_err; } for (i = 0, j = 0; i < temp_len; i++, j++) { - vol->password[j] = value[i]; + ctx->password[j] = value[i]; if ((value[i] == delim) && value[i+1] == delim) /* skip the second deliminator */ i++; } - vol->password[j] = '\0'; + ctx->password[j] = '\0'; break; case Opt_blank_ip: /* FIXME: should this be an error instead? */ @@ -2051,9 +2051,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } - kfree(vol->domainname); - vol->domainname = kstrdup(string, GFP_KERNEL); - if (!vol->domainname) { + kfree(ctx->domainname); + ctx->domainname = kstrdup(string, GFP_KERNEL); + if (!ctx->domainname) { pr_warn("no memory for domainname\n"); goto cifs_parse_mount_err; } @@ -2065,7 +2065,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto out_nomem; if (!cifs_convert_address( - (struct sockaddr *)&vol->srcaddr, + (struct sockaddr *)&ctx->srcaddr, string, strlen(string))) { pr_warn("Could not parse srcaddr: %s\n", string); @@ -2083,10 +2083,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } if (strncasecmp(string, "default", 7) != 0) { - kfree(vol->iocharset); - vol->iocharset = kstrdup(string, + kfree(ctx->iocharset); + ctx->iocharset = kstrdup(string, GFP_KERNEL); - if (!vol->iocharset) { + if (!ctx->iocharset) { pr_warn("no memory for charset\n"); goto cifs_parse_mount_err; } @@ -2101,7 +2101,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, if (string == NULL) goto out_nomem; - memset(vol->source_rfc1001_name, 0x20, + memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); /* * FIXME: are there cases in which a comma can @@ -2112,7 +2112,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, /* don't ucase netbiosname for user */ if (string[i] == 0) break; - vol->source_rfc1001_name[i] = string[i]; + ctx->source_rfc1001_name[i] = string[i]; } /* The string has 16th byte zero still from * set at top of the function @@ -2127,7 +2127,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto out_nomem; /* last byte, type, is 0x20 for servr type */ - memset(vol->target_rfc1001_name, 0x20, + memset(ctx->target_rfc1001_name, 0x20, RFC1001_NAME_LEN_WITH_NULL); /* BB are there cases in which a comma can be @@ -2139,7 +2139,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, for (i = 0; i < 15; i++) { if (string[i] == 0) break; - vol->target_rfc1001_name[i] = string[i]; + ctx->target_rfc1001_name[i] = string[i]; } /* The string has 16th byte zero still from set at top of the function */ @@ -2171,7 +2171,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, if (string == NULL) goto out_nomem; - if (cifs_parse_smb_version(string, vol, is_smb3) != 0) + if (cifs_parse_smb_version(string, ctx, is_smb3) != 0) goto cifs_parse_mount_err; got_version = true; break; @@ -2180,7 +2180,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, if (string == NULL) goto out_nomem; - if (cifs_parse_security_flavors(string, vol) != 0) + if (cifs_parse_security_flavors(string, ctx) != 0) goto cifs_parse_mount_err; break; case Opt_cache: @@ -2188,7 +2188,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, if (string == NULL) goto out_nomem; - if (cifs_parse_cache_flavor(string, vol) != 0) + if (cifs_parse_cache_flavor(string, ctx) != 0) goto cifs_parse_mount_err; break; default: @@ -2210,25 +2210,25 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } - if (vol->rdma && vol->vals->protocol_id < SMB30_PROT_ID) { + if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) { cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n"); goto cifs_parse_mount_err; } #ifndef CONFIG_KEYS /* Muliuser mounts require CONFIG_KEYS support */ - if (vol->multiuser) { + if (ctx->multiuser) { cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); goto cifs_parse_mount_err; } #endif - if (!vol->UNC) { + if (!ctx->UNC) { cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n"); goto cifs_parse_mount_err; } /* make sure UNC has a share name */ - if (!strchr(vol->UNC + 3, '\\')) { + if (!strchr(ctx->UNC + 3, '\\')) { cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n"); goto cifs_parse_mount_err; } @@ -2239,9 +2239,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, /* No ip= option specified? Try to get it from UNC */ /* Use the address part of the UNC. */ - slash = strchr(&vol->UNC[2], '\\'); - len = slash - &vol->UNC[2]; - if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) { + slash = strchr(&ctx->UNC[2], '\\'); + len = slash - &ctx->UNC[2]; + if (!cifs_convert_address(dstaddr, &ctx->UNC[2], len)) { pr_err("Unable to determine destination address\n"); goto cifs_parse_mount_err; } @@ -2251,12 +2251,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, cifs_set_port(dstaddr, port); if (uid_specified) - vol->override_uid = override_uid; + ctx->override_uid = override_uid; else if (override_uid == 1) pr_notice("ignoring forceuid mount option specified with no uid= option\n"); if (gid_specified) - vol->override_gid = override_gid; + ctx->override_gid = override_gid; else if (override_gid == 1) pr_notice("ignoring forcegid mount option specified with no gid= option\n"); @@ -2377,14 +2377,14 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr, } static bool -match_security(struct TCP_Server_Info *server, struct smb_vol *vol) +match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { /* - * The select_sectype function should either return the vol->sectype + * The select_sectype function should either return the ctx->sectype * that was specified, or "Unspecified" if that sectype was not * compatible with the given NEGOTIATE request. */ - if (server->ops->select_sectype(server, vol->sectype) + if (server->ops->select_sectype(server, ctx->sectype) == Unspecified) return false; @@ -2393,60 +2393,60 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) * global_secflags at this point since if MUST_SIGN is set then * the server->sign had better be too. */ - if (vol->sign && !server->sign) + if (ctx->sign && !server->sign) return false; return true; } -static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol) +static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { - struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr; + struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr; - if (vol->nosharesock) + if (ctx->nosharesock) return 0; /* If multidialect negotiation see if existing sessions match one */ - if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { + if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { if (server->vals->protocol_id < SMB30_PROT_ID) return 0; - } else if (strcmp(vol->vals->version_string, + } else if (strcmp(ctx->vals->version_string, SMBDEFAULT_VERSION_STRING) == 0) { if (server->vals->protocol_id < SMB21_PROT_ID) return 0; - } else if ((server->vals != vol->vals) || (server->ops != vol->ops)) + } else if ((server->vals != ctx->vals) || (server->ops != ctx->ops)) return 0; if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) return 0; if (!match_address(server, addr, - (struct sockaddr *)&vol->srcaddr)) + (struct sockaddr *)&ctx->srcaddr)) return 0; if (!match_port(server, addr)) return 0; - if (!match_security(server, vol)) + if (!match_security(server, ctx)) return 0; - if (server->echo_interval != vol->echo_interval * HZ) + if (server->echo_interval != ctx->echo_interval * HZ) return 0; - if (server->rdma != vol->rdma) + if (server->rdma != ctx->rdma) return 0; - if (server->ignore_signature != vol->ignore_signature) + if (server->ignore_signature != ctx->ignore_signature) return 0; - if (server->min_offload != vol->min_offload) + if (server->min_offload != ctx->min_offload) return 0; return 1; } struct TCP_Server_Info * -cifs_find_tcp_session(struct smb_vol *vol) +cifs_find_tcp_session(struct smb3_fs_context *ctx) { struct TCP_Server_Info *server; @@ -2456,7 +2456,7 @@ cifs_find_tcp_session(struct smb_vol *vol) * Skip ses channels since they're only handled in lower layers * (e.g. cifs_send_recv). */ - if (server->is_channel || !match_server(server, vol)) + if (server->is_channel || !match_server(server, ctx)) continue; ++server->srv_count; @@ -2514,15 +2514,15 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) } struct TCP_Server_Info * -cifs_get_tcp_session(struct smb_vol *volume_info) +cifs_get_tcp_session(struct smb3_fs_context *ctx) { struct TCP_Server_Info *tcp_ses = NULL; int rc; - cifs_dbg(FYI, "UNC: %s\n", volume_info->UNC); + cifs_dbg(FYI, "UNC: %s\n", ctx->UNC); /* see if we already have a matching tcp_ses */ - tcp_ses = cifs_find_tcp_session(volume_info); + tcp_ses = cifs_find_tcp_session(ctx); if (tcp_ses) return tcp_ses; @@ -2532,20 +2532,20 @@ cifs_get_tcp_session(struct smb_vol *volume_info) goto out_err; } - tcp_ses->ops = volume_info->ops; - tcp_ses->vals = volume_info->vals; + tcp_ses->ops = ctx->ops; + tcp_ses->vals = ctx->vals; cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); - tcp_ses->hostname = extract_hostname(volume_info->UNC); + tcp_ses->hostname = extract_hostname(ctx->UNC); if (IS_ERR(tcp_ses->hostname)) { rc = PTR_ERR(tcp_ses->hostname); goto out_err_crypto_release; } - tcp_ses->noblockcnt = volume_info->rootfs; - tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs; - tcp_ses->noautotune = volume_info->noautotune; - tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; - tcp_ses->rdma = volume_info->rdma; + tcp_ses->noblockcnt = ctx->rootfs; + tcp_ses->noblocksnd = ctx->noblocksnd || ctx->rootfs; + tcp_ses->noautotune = ctx->noautotune; + tcp_ses->tcp_nodelay = ctx->sockopt_tcp_nodelay; + tcp_ses->rdma = ctx->rdma; tcp_ses->in_flight = 0; tcp_ses->max_in_flight = 0; tcp_ses->credits = 1; @@ -2554,26 +2554,26 @@ cifs_get_tcp_session(struct smb_vol *volume_info) INIT_LIST_HEAD(&tcp_ses->pending_mid_q); mutex_init(&tcp_ses->srv_mutex); memcpy(tcp_ses->workstation_RFC1001_name, - volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); + ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); memcpy(tcp_ses->server_RFC1001_name, - volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); + ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); tcp_ses->session_estab = false; tcp_ses->sequence_number = 0; tcp_ses->reconnect_instance = 1; tcp_ses->lstrp = jiffies; - tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression); + tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression); spin_lock_init(&tcp_ses->req_lock); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list); INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); mutex_init(&tcp_ses->reconnect_mutex); - memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, + memcpy(&tcp_ses->srcaddr, &ctx->srcaddr, sizeof(tcp_ses->srcaddr)); - memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, + memcpy(&tcp_ses->dstaddr, &ctx->dstaddr, sizeof(tcp_ses->dstaddr)); - if (volume_info->use_client_guid) - memcpy(tcp_ses->client_guid, volume_info->client_guid, + if (ctx->use_client_guid) + memcpy(tcp_ses->client_guid, ctx->client_guid, SMB2_CLIENT_GUID_SIZE); else generate_random_uuid(tcp_ses->client_guid); @@ -2585,9 +2585,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->tcpStatus = CifsNew; ++tcp_ses->srv_count; - if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN && - volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX) - tcp_ses->echo_interval = volume_info->echo_interval * HZ; + if (ctx->echo_interval >= SMB_ECHO_INTERVAL_MIN && + ctx->echo_interval <= SMB_ECHO_INTERVAL_MAX) + tcp_ses->echo_interval = ctx->echo_interval * HZ; else tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ; if (tcp_ses->rdma) { @@ -2597,7 +2597,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) goto out_err_crypto_release; #endif tcp_ses->smbd_conn = smbd_get_connection( - tcp_ses, (struct sockaddr *)&volume_info->dstaddr); + tcp_ses, (struct sockaddr *)&ctx->dstaddr); if (tcp_ses->smbd_conn) { cifs_dbg(VFS, "RDMA transport established\n"); rc = 0; @@ -2626,11 +2626,11 @@ smbd_connected: module_put(THIS_MODULE); goto out_err_crypto_release; } - tcp_ses->min_offload = volume_info->min_offload; + tcp_ses->min_offload = ctx->min_offload; tcp_ses->tcpStatus = CifsNeedNegotiate; tcp_ses->nr_targets = 1; - tcp_ses->ignore_signature = volume_info->ignore_signature; + tcp_ses->ignore_signature = ctx->ignore_signature; /* thread spawned, put it on the list */ spin_lock(&cifs_tcp_ses_lock); list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); @@ -2659,41 +2659,41 @@ out_err: return ERR_PTR(rc); } -static int match_session(struct cifs_ses *ses, struct smb_vol *vol) +static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) { - if (vol->sectype != Unspecified && - vol->sectype != ses->sectype) + if (ctx->sectype != Unspecified && + ctx->sectype != ses->sectype) return 0; /* * If an existing session is limited to less channels than * requested, it should not be reused */ - if (ses->chan_max < vol->max_channels) + if (ses->chan_max < ctx->max_channels) return 0; switch (ses->sectype) { case Kerberos: - if (!uid_eq(vol->cred_uid, ses->cred_uid)) + if (!uid_eq(ctx->cred_uid, ses->cred_uid)) return 0; break; default: /* NULL username means anonymous session */ if (ses->user_name == NULL) { - if (!vol->nullauth) + if (!ctx->nullauth) return 0; break; } /* anything else takes username/password */ if (strncmp(ses->user_name, - vol->username ? vol->username : "", + ctx->username ? ctx->username : "", CIFS_MAX_USERNAME_LEN)) return 0; - if ((vol->username && strlen(vol->username) != 0) && + if ((ctx->username && strlen(ctx->username) != 0) && ses->password != NULL && strncmp(ses->password, - vol->password ? vol->password : "", + ctx->password ? ctx->password : "", CIFS_MAX_PASSWORD_LEN)) return 0; } @@ -2707,7 +2707,7 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol) * tcon_ipc. The IPC tcon has the same lifetime as the session. */ static int -cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info) +cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) { int rc = 0, xid; struct cifs_tcon *tcon; @@ -2720,7 +2720,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info) * If the mount request that resulted in the creation of the * session requires encryption, force IPC to be encrypted too. */ - if (volume_info->seal) { + if (ctx->seal) { if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) seal = true; else { @@ -2789,7 +2789,7 @@ cifs_free_ipc(struct cifs_ses *ses) } static struct cifs_ses * -cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) +cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { struct cifs_ses *ses; @@ -2797,7 +2797,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { if (ses->status == CifsExiting) continue; - if (!match_session(ses, vol)) + if (!match_session(ses, ctx)) continue; ++ses->ses_count; spin_unlock(&cifs_tcp_ses_lock); @@ -2861,7 +2861,7 @@ void cifs_put_smb_ses(struct cifs_ses *ses) /* Populate username and pw fields from keyring if possible */ static int -cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) +cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) { int rc = 0; int is_domain = 0; @@ -2941,32 +2941,32 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) goto out_key_put; } - vol->username = kstrndup(payload, len, GFP_KERNEL); - if (!vol->username) { + ctx->username = kstrndup(payload, len, GFP_KERNEL); + if (!ctx->username) { cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n", len); rc = -ENOMEM; goto out_key_put; } - cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username); + cifs_dbg(FYI, "%s: username=%s\n", __func__, ctx->username); len = key->datalen - (len + 1); if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) { cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len); rc = -EINVAL; - kfree(vol->username); - vol->username = NULL; + kfree(ctx->username); + ctx->username = NULL; goto out_key_put; } ++delim; - vol->password = kstrndup(delim, len, GFP_KERNEL); - if (!vol->password) { + ctx->password = kstrndup(delim, len, GFP_KERNEL); + if (!ctx->password) { cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n", len); rc = -ENOMEM; - kfree(vol->username); - vol->username = NULL; + kfree(ctx->username); + ctx->username = NULL; goto out_key_put; } @@ -2975,17 +2975,17 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) * for the request. */ if (is_domain && ses->domainName) { - vol->domainname = kstrndup(ses->domainName, + ctx->domainname = kstrndup(ses->domainName, strlen(ses->domainName), GFP_KERNEL); - if (!vol->domainname) { + if (!ctx->domainname) { cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n", len); rc = -ENOMEM; - kfree(vol->username); - vol->username = NULL; - kfree_sensitive(vol->password); - vol->password = NULL; + kfree(ctx->username); + ctx->username = NULL; + kfree_sensitive(ctx->password); + ctx->password = NULL; goto out_key_put; } } @@ -3000,7 +3000,7 @@ out_err: } #else /* ! CONFIG_KEYS */ static inline int -cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), +cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)), struct cifs_ses *ses __attribute__((unused))) { return -ENOSYS; @@ -3008,14 +3008,14 @@ cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), #endif /* CONFIG_KEYS */ /** - * cifs_get_smb_ses - get a session matching @volume_info data from @server + * cifs_get_smb_ses - get a session matching @ctx data from @server * * This function assumes it is being called from cifs_mount() where we * already got a server reference (server refcount +1). See * cifs_get_tcon() for refcount explanations. */ struct cifs_ses * -cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) +cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { int rc = -ENOMEM; unsigned int xid; @@ -3025,7 +3025,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) xid = get_xid(); - ses = cifs_find_smb_ses(server, volume_info); + ses = cifs_find_smb_ses(server, ctx); if (ses) { cifs_dbg(FYI, "Existing smb sess found (status=%d)\n", ses->status); @@ -3042,7 +3042,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) if (ses->need_reconnect) { cifs_dbg(FYI, "Session needs reconnect\n"); rc = cifs_setup_session(xid, ses, - volume_info->local_nls); + ctx->local_nls); if (rc) { mutex_unlock(&ses->session_mutex); /* problem -- put our reference */ @@ -3071,40 +3071,40 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) else sprintf(ses->serverName, "%pI4", &addr->sin_addr); - if (volume_info->username) { - ses->user_name = kstrdup(volume_info->username, GFP_KERNEL); + if (ctx->username) { + ses->user_name = kstrdup(ctx->username, GFP_KERNEL); if (!ses->user_name) goto get_ses_fail; } - /* volume_info->password freed at unmount */ - if (volume_info->password) { - ses->password = kstrdup(volume_info->password, GFP_KERNEL); + /* ctx->password freed at unmount */ + if (ctx->password) { + ses->password = kstrdup(ctx->password, GFP_KERNEL); if (!ses->password) goto get_ses_fail; } - if (volume_info->domainname) { - ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); + if (ctx->domainname) { + ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL); if (!ses->domainName) goto get_ses_fail; } - if (volume_info->domainauto) - ses->domainAuto = volume_info->domainauto; - ses->cred_uid = volume_info->cred_uid; - ses->linux_uid = volume_info->linux_uid; + if (ctx->domainauto) + ses->domainAuto = ctx->domainauto; + ses->cred_uid = ctx->cred_uid; + ses->linux_uid = ctx->linux_uid; - ses->sectype = volume_info->sectype; - ses->sign = volume_info->sign; + ses->sectype = ctx->sectype; + ses->sign = ctx->sign; mutex_lock(&ses->session_mutex); /* add server as first channel */ ses->chans[0].server = server; ses->chan_count = 1; - ses->chan_max = volume_info->multichannel ? volume_info->max_channels:1; + ses->chan_max = ctx->multichannel ? ctx->max_channels:1; rc = cifs_negotiate_protocol(xid, ses); if (!rc) - rc = cifs_setup_session(xid, ses, volume_info->local_nls); + rc = cifs_setup_session(xid, ses, ctx->local_nls); /* each channel uses a different signing key */ memcpy(ses->chans[0].signkey, ses->smb3signingkey, @@ -3121,7 +3121,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) free_xid(xid); - cifs_setup_ipc(ses, volume_info); + cifs_setup_ipc(ses, ctx); return ses; @@ -3131,27 +3131,27 @@ get_ses_fail: return ERR_PTR(rc); } -static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info) +static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { if (tcon->tidStatus == CifsExiting) return 0; - if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE)) + if (strncmp(tcon->treeName, ctx->UNC, MAX_TREE_SIZE)) return 0; - if (tcon->seal != volume_info->seal) + if (tcon->seal != ctx->seal) return 0; - if (tcon->snapshot_time != volume_info->snapshot_time) + if (tcon->snapshot_time != ctx->snapshot_time) return 0; - if (tcon->handle_timeout != volume_info->handle_timeout) + if (tcon->handle_timeout != ctx->handle_timeout) return 0; - if (tcon->no_lease != volume_info->no_lease) + if (tcon->no_lease != ctx->no_lease) return 0; - if (tcon->nodelete != volume_info->nodelete) + if (tcon->nodelete != ctx->nodelete) return 0; return 1; } static struct cifs_tcon * -cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) +cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) { struct list_head *tmp; struct cifs_tcon *tcon; @@ -3163,7 +3163,7 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) if (tcon->dfs_path) continue; #endif - if (!match_tcon(tcon, volume_info)) + if (!match_tcon(tcon, ctx)) continue; ++tcon->tc_count; spin_unlock(&cifs_tcp_ses_lock); @@ -3208,7 +3208,7 @@ cifs_put_tcon(struct cifs_tcon *tcon) } /** - * cifs_get_tcon - get a tcon matching @volume_info data from @ses + * cifs_get_tcon - get a tcon matching @ctx data from @ses * * - tcon refcount is the number of mount points using the tcon. * - ses refcount is the number of tcon using the session. @@ -3228,12 +3228,12 @@ cifs_put_tcon(struct cifs_tcon *tcon) * decrement the ses refcount. */ static struct cifs_tcon * -cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) +cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) { int rc, xid; struct cifs_tcon *tcon; - tcon = cifs_find_tcon(ses, volume_info); + tcon = cifs_find_tcon(ses, ctx); if (tcon) { /* * tcon has refcount already incremented but we need to @@ -3255,36 +3255,36 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) goto out_fail; } - if (volume_info->snapshot_time) { + if (ctx->snapshot_time) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "Use SMB2 or later for snapshot mount option\n"); rc = -EOPNOTSUPP; goto out_fail; } else - tcon->snapshot_time = volume_info->snapshot_time; + tcon->snapshot_time = ctx->snapshot_time; } - if (volume_info->handle_timeout) { + if (ctx->handle_timeout) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "Use SMB2.1 or later for handle timeout option\n"); rc = -EOPNOTSUPP; goto out_fail; } else - tcon->handle_timeout = volume_info->handle_timeout; + tcon->handle_timeout = ctx->handle_timeout; } tcon->ses = ses; - if (volume_info->password) { - tcon->password = kstrdup(volume_info->password, GFP_KERNEL); + if (ctx->password) { + tcon->password = kstrdup(ctx->password, GFP_KERNEL); if (!tcon->password) { rc = -ENOMEM; goto out_fail; } } - if (volume_info->seal) { + if (ctx->seal) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "SMB3 or later required for encryption\n"); @@ -3300,7 +3300,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) } } - if (volume_info->linux_ext) { + if (ctx->linux_ext) { if (ses->server->posix_ext_supported) { tcon->posix_extensions = true; pr_warn_once("SMB3.11 POSIX Extensions are experimental\n"); @@ -3316,8 +3316,8 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) * SetFS as we do on SessSetup and reconnect? */ xid = get_xid(); - rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon, - volume_info->local_nls); + rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon, + ctx->local_nls); free_xid(xid); cifs_dbg(FYI, "Tcon rc = %d\n", rc); if (rc) @@ -3325,7 +3325,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) tcon->use_persistent = false; /* check if SMB2 or later, CIFS does not support persistent handles */ - if (volume_info->persistent) { + if (ctx->persistent) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "SMB3 or later required for persistent handles\n"); @@ -3342,10 +3342,10 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) } } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY) && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) - && (volume_info->nopersistent == false)) { + && (ctx->nopersistent == false)) { cifs_dbg(FYI, "enabling persistent handles\n"); tcon->use_persistent = true; - } else if (volume_info->resilient) { + } else if (ctx->resilient) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "SMB2.1 or later required for resilient handles\n"); @@ -3357,20 +3357,20 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) /* If the user really knows what they are doing they can override */ if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { - if (volume_info->cache_ro) + if (ctx->cache_ro) cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n"); - else if (volume_info->cache_rw) + else if (ctx->cache_rw) cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n"); } - if (volume_info->no_lease) { + if (ctx->no_lease) { if (ses->server->vals->protocol_id == 0) { cifs_dbg(VFS, "SMB2 or later required for nolease option\n"); rc = -EOPNOTSUPP; goto out_fail; } else - tcon->no_lease = volume_info->no_lease; + tcon->no_lease = ctx->no_lease; } /* @@ -3378,14 +3378,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) * resources mounted more than once to the same server share the last * value passed in for the retry flag is used. */ - tcon->retry = volume_info->retry; - tcon->nocase = volume_info->nocase; + tcon->retry = ctx->retry; + tcon->nocase = ctx->nocase; if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING) - tcon->nohandlecache = volume_info->nohandlecache; + tcon->nohandlecache = ctx->nohandlecache; else tcon->nohandlecache = 1; - tcon->nodelete = volume_info->nodelete; - tcon->local_lease = volume_info->local_lease; + tcon->nodelete = ctx->nodelete; + tcon->local_lease = ctx->local_lease; INIT_LIST_HEAD(&tcon->pending_opens); spin_lock(&cifs_tcp_ses_lock); @@ -3484,7 +3484,7 @@ int cifs_match_super(struct super_block *sb, void *data) { struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data; - struct smb_vol *volume_info; + struct smb3_fs_context *ctx; struct cifs_sb_info *cifs_sb; struct TCP_Server_Info *tcp_srv; struct cifs_ses *ses; @@ -3503,11 +3503,11 @@ cifs_match_super(struct super_block *sb, void *data) ses = tcon->ses; tcp_srv = ses->server; - volume_info = mnt_data->vol; + ctx = mnt_data->ctx; - if (!match_server(tcp_srv, volume_info) || - !match_session(ses, volume_info) || - !match_tcon(tcon, volume_info) || + if (!match_server(tcp_srv, ctx) || + !match_session(ses, ctx) || + !match_tcon(tcon, ctx) || !match_prepath(sb, mnt_data)) { rc = 0; goto out; @@ -3792,7 +3792,7 @@ ip_connect(struct TCP_Server_Info *server) } void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, - struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info) + struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) { /* if we are reconnecting then should we check to see if * any requested capabilities changed locally e.g. via @@ -3805,12 +3805,12 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, * and once without posixacls or posix paths? */ __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); - if (vol_info && vol_info->no_linux_ext) { + if (ctx && ctx->no_linux_ext) { tcon->fsUnixInfo.Capability = 0; tcon->unix_ext = 0; /* Unix Extensions disabled */ cifs_dbg(FYI, "Linux protocol extensions disabled\n"); return; - } else if (vol_info) + } else if (ctx) tcon->unix_ext = 1; /* Unix Extensions supported */ if (tcon->unix_ext == 0) { @@ -3823,7 +3823,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); /* check for reconnect case in which we do not want to change the mount behavior if we can avoid it */ - if (vol_info == NULL) { + if (ctx == NULL) { /* turn off POSIX ACL and PATHNAMES if not set originally at mount time */ if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) @@ -3842,7 +3842,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(VFS, "per-share encryption not supported yet\n"); cap &= CIFS_UNIX_CAP_MASK; - if (vol_info && vol_info->no_psx_acl) + if (ctx && ctx->no_psx_acl) cap &= ~CIFS_UNIX_POSIX_ACL_CAP; else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { cifs_dbg(FYI, "negotiated posix acl support\n"); @@ -3851,7 +3851,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, CIFS_MOUNT_POSIXACL; } - if (vol_info && vol_info->posix_paths == 0) + if (ctx && ctx->posix_paths == 0) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { cifs_dbg(FYI, "negotiate posix pathnames\n"); @@ -3882,16 +3882,16 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, cifs_dbg(FYI, "mandatory transport encryption cap\n"); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - if (vol_info == NULL) { + if (ctx == NULL) cifs_dbg(FYI, "resetting capabilities failed\n"); - } else + else cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n"); } } } -int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, +int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb) { INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); @@ -3899,91 +3899,91 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; - cifs_sb->bsize = pvolume_info->bsize; + cifs_sb->bsize = ctx->bsize; /* * Temporarily set r/wsize for matching superblock. If we end up using * new sb then client will later negotiate it downward if needed. */ - cifs_sb->rsize = pvolume_info->rsize; - cifs_sb->wsize = pvolume_info->wsize; + cifs_sb->rsize = ctx->rsize; + cifs_sb->wsize = ctx->wsize; - cifs_sb->mnt_uid = pvolume_info->linux_uid; - cifs_sb->mnt_gid = pvolume_info->linux_gid; - cifs_sb->mnt_file_mode = pvolume_info->file_mode; - cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; + cifs_sb->mnt_uid = ctx->linux_uid; + cifs_sb->mnt_gid = ctx->linux_gid; + cifs_sb->mnt_file_mode = ctx->file_mode; + cifs_sb->mnt_dir_mode = ctx->dir_mode; cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); - cifs_sb->actimeo = pvolume_info->actimeo; - cifs_sb->local_nls = pvolume_info->local_nls; + cifs_sb->actimeo = ctx->actimeo; + cifs_sb->local_nls = ctx->local_nls; - if (pvolume_info->nodfs) + if (ctx->nodfs) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; - if (pvolume_info->noperm) + if (ctx->noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; - if (pvolume_info->setuids) + if (ctx->setuids) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; - if (pvolume_info->setuidfromacl) + if (ctx->setuidfromacl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL; - if (pvolume_info->server_ino) + if (ctx->server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; - if (pvolume_info->remap) + if (ctx->remap) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR; - if (pvolume_info->sfu_remap) + if (ctx->sfu_remap) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; - if (pvolume_info->no_xattr) + if (ctx->no_xattr) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; - if (pvolume_info->sfu_emul) + if (ctx->sfu_emul) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; - if (pvolume_info->nobrl) + if (ctx->nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; - if (pvolume_info->nohandlecache) + if (ctx->nohandlecache) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE; - if (pvolume_info->nostrictsync) + if (ctx->nostrictsync) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; - if (pvolume_info->mand_lock) + if (ctx->mand_lock) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; - if (pvolume_info->rwpidforward) + if (ctx->rwpidforward) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; - if (pvolume_info->mode_ace) + if (ctx->mode_ace) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID; - if (pvolume_info->cifs_acl) + if (ctx->cifs_acl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; - if (pvolume_info->backupuid_specified) { + if (ctx->backupuid_specified) { cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; - cifs_sb->mnt_backupuid = pvolume_info->backupuid; + cifs_sb->mnt_backupuid = ctx->backupuid; } - if (pvolume_info->backupgid_specified) { + if (ctx->backupgid_specified) { cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; - cifs_sb->mnt_backupgid = pvolume_info->backupgid; + cifs_sb->mnt_backupgid = ctx->backupgid; } - if (pvolume_info->override_uid) + if (ctx->override_uid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; - if (pvolume_info->override_gid) + if (ctx->override_gid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; - if (pvolume_info->dynperm) + if (ctx->dynperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; - if (pvolume_info->fsc) + if (ctx->fsc) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; - if (pvolume_info->multiuser) + if (ctx->multiuser) cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_NO_PERM); - if (pvolume_info->strict_io) + if (ctx->strict_io) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO; - if (pvolume_info->direct_io) { + if (ctx->direct_io) { cifs_dbg(FYI, "mounting share using direct i/o\n"); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; } - if (pvolume_info->cache_ro) { + if (ctx->cache_ro) { cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n"); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE; - } else if (pvolume_info->cache_rw) { + } else if (ctx->cache_rw) { cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n"); cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE | CIFS_MOUNT_RW_CACHE); } - if (pvolume_info->mfsymlinks) { - if (pvolume_info->sfu_emul) { + if (ctx->mfsymlinks) { + if (ctx->sfu_emul) { /* * Our SFU ("Services for Unix" emulation does not allow * creating symlinks but does allow reading existing SFU @@ -4000,11 +4000,11 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; } - if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) + if ((ctx->cifs_acl) && (ctx->dynperm)) cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n"); - if (pvolume_info->prepath) { - cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL); + if (ctx->prepath) { + cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL); if (cifs_sb->prepath == NULL) return -ENOMEM; } @@ -4013,23 +4013,23 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, } void -cifs_cleanup_volume_info_contents(struct smb_vol *volume_info) +cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx) { - kfree(volume_info->username); - kfree_sensitive(volume_info->password); - kfree(volume_info->UNC); - kfree(volume_info->domainname); - kfree(volume_info->iocharset); - kfree(volume_info->prepath); + kfree(ctx->username); + kfree_sensitive(ctx->password); + kfree(ctx->UNC); + kfree(ctx->domainname); + kfree(ctx->iocharset); + kfree(ctx->prepath); } void -cifs_cleanup_volume_info(struct smb_vol *volume_info) +cifs_cleanup_volume_info(struct smb3_fs_context *ctx) { - if (!volume_info) + if (!ctx) return; - cifs_cleanup_volume_info_contents(volume_info); - kfree(volume_info); + cifs_cleanup_volume_info_contents(ctx); + kfree(ctx); } /* Release all succeed connections */ @@ -4051,7 +4051,7 @@ static inline void mount_put_conns(struct cifs_sb_info *cifs_sb, } /* Get connections for tcp, ses and tcon */ -static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, +static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, unsigned int *xid, struct TCP_Server_Info **nserver, struct cifs_ses **nses, struct cifs_tcon **ntcon) @@ -4068,7 +4068,7 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, *xid = get_xid(); /* get a reference to a tcp session */ - server = cifs_get_tcp_session(vol); + server = cifs_get_tcp_session(ctx); if (IS_ERR(server)) { rc = PTR_ERR(server); return rc; @@ -4076,13 +4076,13 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, *nserver = server; - if ((vol->max_credits < 20) || (vol->max_credits > 60000)) + if ((ctx->max_credits < 20) || (ctx->max_credits > 60000)) server->max_credits = SMB2_MAX_CREDITS_AVAILABLE; else - server->max_credits = vol->max_credits; + server->max_credits = ctx->max_credits; /* get a reference to a SMB session */ - ses = cifs_get_smb_ses(server, vol); + ses = cifs_get_smb_ses(server, ctx); if (IS_ERR(ses)) { rc = PTR_ERR(ses); return rc; @@ -4090,14 +4090,14 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, *nses = ses; - if ((vol->persistent == true) && (!(ses->server->capabilities & + if ((ctx->persistent == true) && (!(ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) { cifs_server_dbg(VFS, "persistent handles not supported by server\n"); return -EOPNOTSUPP; } /* search for existing tcon to this server share */ - tcon = cifs_get_tcon(ses, vol); + tcon = cifs_get_tcon(ses, ctx); if (IS_ERR(tcon)) { rc = PTR_ERR(tcon); return rc; @@ -4115,7 +4115,7 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, * reset of caps checks mount to see if unix extensions disabled * for just this mount. */ - reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol); + reset_cifs_unix_caps(*xid, tcon, cifs_sb, ctx); if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && (le64_to_cpu(tcon->fsUnixInfo.Capability) & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) @@ -4137,8 +4137,8 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, } } - cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol); - cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol); + cifs_sb->wsize = server->ops->negotiate_wsize(tcon, ctx); + cifs_sb->rsize = server->ops->negotiate_rsize(tcon, ctx); return 0; } @@ -4175,13 +4175,13 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, * exiting connection (tcon) */ static char * -build_unc_path_to_root(const struct smb_vol *vol, +build_unc_path_to_root(const struct smb3_fs_context *ctx, const struct cifs_sb_info *cifs_sb, bool useppath) { char *full_path, *pos; - unsigned int pplen = useppath && vol->prepath ? - strlen(vol->prepath) + 1 : 0; - unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); + unsigned int pplen = useppath && ctx->prepath ? + strlen(ctx->prepath) + 1 : 0; + unsigned int unc_len = strnlen(ctx->UNC, MAX_TREE_SIZE + 1); if (unc_len > MAX_TREE_SIZE) return ERR_PTR(-EINVAL); @@ -4190,12 +4190,12 @@ build_unc_path_to_root(const struct smb_vol *vol, if (full_path == NULL) return ERR_PTR(-ENOMEM); - memcpy(full_path, vol->UNC, unc_len); + memcpy(full_path, ctx->UNC, unc_len); pos = full_path + unc_len; if (pplen) { *pos = CIFS_DIR_SEP(cifs_sb); - memcpy(pos + 1, vol->prepath, pplen); + memcpy(pos + 1, ctx->prepath, pplen); pos += pplen; } @@ -4218,7 +4218,7 @@ build_unc_path_to_root(const struct smb_vol *vol, */ static int expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, - struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, + struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, char *ref_path) { int rc; @@ -4228,7 +4228,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) return -EREMOTE; - full_path = build_unc_path_to_root(volume_info, cifs_sb, true); + full_path = build_unc_path_to_root(ctx, cifs_sb, true); if (IS_ERR(full_path)) return PTR_ERR(full_path); @@ -4246,8 +4246,8 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, rc = PTR_ERR(mdata); mdata = NULL; } else { - cifs_cleanup_volume_info_contents(volume_info); - rc = cifs_setup_volume_info(volume_info, mdata, + cifs_cleanup_volume_info_contents(ctx); + rc = cifs_setup_volume_info(ctx, mdata, fake_devname, false); } kfree(fake_devname); @@ -4270,7 +4270,7 @@ static inline int get_next_dfs_tgt(const char *path, } static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, - struct smb_vol *fake_vol, struct smb_vol *vol) + struct smb3_fs_context *fake_ctx, struct smb3_fs_context *ctx) { const char *tgt = dfs_cache_get_tgt_name(tgt_it); int len = strlen(tgt) + 2; @@ -4281,29 +4281,29 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, return -ENOMEM; scnprintf(new_unc, len, "\\%s", tgt); - kfree(vol->UNC); - vol->UNC = new_unc; + kfree(ctx->UNC); + ctx->UNC = new_unc; - if (fake_vol->prepath) { - kfree(vol->prepath); - vol->prepath = fake_vol->prepath; - fake_vol->prepath = NULL; + if (fake_ctx->prepath) { + kfree(ctx->prepath); + ctx->prepath = fake_ctx->prepath; + fake_ctx->prepath = NULL; } - memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr)); + memcpy(&ctx->dstaddr, &fake_ctx->dstaddr, sizeof(ctx->dstaddr)); return 0; } static int setup_dfs_tgt_conn(const char *path, const char *full_path, const struct dfs_cache_tgt_iterator *tgt_it, - struct cifs_sb_info *cifs_sb, struct smb_vol *vol, unsigned int *xid, - struct TCP_Server_Info **server, struct cifs_ses **ses, - struct cifs_tcon **tcon) + struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, + unsigned int *xid, struct TCP_Server_Info **server, + struct cifs_ses **ses, struct cifs_tcon **tcon) { int rc; struct dfs_info3_param ref = {0}; char *mdata = NULL, *fake_devname = NULL; - struct smb_vol fake_vol = {NULL}; + struct smb3_fs_context fake_ctx = {NULL}; cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); @@ -4319,37 +4319,37 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, mdata = NULL; } else { cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname); - rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname, - false); + rc = cifs_setup_volume_info((struct smb3_fs_context *)&fake_ctx, + mdata, fake_devname, false); } kfree(mdata); kfree(fake_devname); if (!rc) { /* - * We use a 'fake_vol' here because we need pass it down to the + * We use a 'fake_ctx' here because we need pass it down to the * mount_{get,put} functions to test connection against new DFS * targets. */ mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); - rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses, + rc = mount_get_conns(&fake_ctx, cifs_sb, xid, server, ses, tcon); if (!rc || (*server && *ses)) { /* * We were able to connect to new target server. - * Update current volume info with new target server. + * Update current context with new target server. */ - rc = update_vol_info(tgt_it, &fake_vol, vol); + rc = update_vol_info(tgt_it, &fake_ctx, ctx); } } - cifs_cleanup_volume_info_contents(&fake_vol); + cifs_cleanup_volume_info_contents((struct smb3_fs_context *)&fake_ctx); return rc; } static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb, - struct smb_vol *vol, struct cifs_ses *root_ses, unsigned int *xid, - struct TCP_Server_Info **server, struct cifs_ses **ses, - struct cifs_tcon **tcon) + struct smb3_fs_context *ctx, struct cifs_ses *root_ses, + unsigned int *xid, struct TCP_Server_Info **server, + struct cifs_ses **ses, struct cifs_tcon **tcon) { int rc; struct dfs_cache_tgt_list tgt_list; @@ -4368,7 +4368,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ if (rc) break; /* Connect to next DFS target */ - rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, vol, xid, server, ses, + rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, ctx, xid, server, ses, tcon); if (!rc || (*server && *ses)) break; @@ -4389,21 +4389,21 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ #endif int -cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, +cifs_setup_volume_info(struct smb3_fs_context *ctx, char *mount_data, const char *devname, bool is_smb3) { int rc = 0; - if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3)) + if (cifs_parse_mount_options(mount_data, devname, ctx, is_smb3)) return -EINVAL; - if (volume_info->nullauth) { + if (ctx->nullauth) { cifs_dbg(FYI, "Anonymous login\n"); - kfree(volume_info->username); - volume_info->username = NULL; - } else if (volume_info->username) { + kfree(ctx->username); + ctx->username = NULL; + } else if (ctx->username) { /* BB fixme parse for domain name here */ - cifs_dbg(FYI, "Username: %s\n", volume_info->username); + cifs_dbg(FYI, "Username: %s\n", ctx->username); } else { cifs_dbg(VFS, "No username specified\n"); /* In userspace mount helper we can get user name from alternate @@ -4412,14 +4412,14 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, } /* this is needed for ASCII cp to Unicode converts */ - if (volume_info->iocharset == NULL) { + if (ctx->iocharset == NULL) { /* load_nls_default cannot return null */ - volume_info->local_nls = load_nls_default(); + ctx->local_nls = load_nls_default(); } else { - volume_info->local_nls = load_nls(volume_info->iocharset); - if (volume_info->local_nls == NULL) { + ctx->local_nls = load_nls(ctx->iocharset); + if (ctx->local_nls == NULL) { cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n", - volume_info->iocharset); + ctx->iocharset); return -ELIBACC; } } @@ -4427,23 +4427,23 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, return rc; } -struct smb_vol * +struct smb3_fs_context * cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3) { int rc; - struct smb_vol *volume_info; + struct smb3_fs_context *ctx; - volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL); - if (!volume_info) + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) return ERR_PTR(-ENOMEM); - rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3); + rc = cifs_setup_volume_info(ctx, mount_data, devname, is_smb3); if (rc) { - cifs_cleanup_volume_info(volume_info); - volume_info = ERR_PTR(rc); + cifs_cleanup_volume_info(ctx); + ctx = ERR_PTR(rc); } - return volume_info; + return ctx; } static int @@ -4497,7 +4497,7 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server, * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is, * otherwise 0. */ -static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, +static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, const unsigned int xid, struct TCP_Server_Info *server, struct cifs_tcon *tcon) @@ -4511,7 +4511,7 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, /* * cifs_build_path_to_root works only when we have a valid tcon */ - full_path = cifs_build_path_to_root(vol, cifs_sb, tcon, + full_path = cifs_build_path_to_root(ctx, cifs_sb, tcon, tcon->Flags & SMB_SHARE_IS_IN_DFS); if (full_path == NULL) return -ENOMEM; @@ -4560,7 +4560,7 @@ static void put_root_ses(struct cifs_ses *ses) } /* Check if a path component is remote and then update @dfs_path accordingly */ -static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, +static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx, const unsigned int xid, struct TCP_Server_Info *server, struct cifs_tcon *tcon, char **dfs_path) { @@ -4571,7 +4571,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS; int skip = added_treename; - path = cifs_build_path_to_root(vol, cifs_sb, tcon, added_treename); + path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename); if (!path) return -ENOMEM; @@ -4602,7 +4602,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, *s = 0; rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path); if (rc && rc == -EREMOTE) { - struct smb_vol v = {NULL}; + struct smb3_fs_context v = {NULL}; /* if @path contains a tree name, skip it in the prefix path */ if (added_treename) { rc = cifs_parse_devname(path, &v); @@ -4612,7 +4612,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, npath = build_unc_path_to_root(&v, cifs_sb, true); cifs_cleanup_volume_info_contents(&v); } else { - v.UNC = vol->UNC; + v.UNC = ctx->UNC; v.prepath = path + 1; npath = build_unc_path_to_root(&v, cifs_sb, true); } @@ -4630,7 +4630,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, return rc; } -int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) +int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) { int rc = 0; unsigned int xid; @@ -4642,7 +4642,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) char *oldmnt = NULL; char *mntdata = NULL; - rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); + rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); /* * Unconditionally try to get an DFS referral (even cached) to determine whether it is an * DFS mount. @@ -4650,13 +4650,13 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem * to respond with PATH_NOT_COVERED to requests that include the prefix. */ - if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), vol->UNC + 1, NULL, + if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL, NULL)) { /* No DFS referral was returned. Looks like a regular share. */ if (rc) goto error; /* Check if it is fully accessible and then mount it */ - rc = is_path_remote(cifs_sb, vol, xid, server, tcon); + rc = is_path_remote(cifs_sb, ctx, xid, server, tcon); if (!rc) goto out; if (rc != -EREMOTE) @@ -4669,7 +4669,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) goto error; } /* Get path of DFS root */ - ref_path = build_unc_path_to_root(vol, cifs_sb, false); + ref_path = build_unc_path_to_root(ctx, cifs_sb, false); if (IS_ERR(ref_path)) { rc = PTR_ERR(ref_path); ref_path = NULL; @@ -4680,7 +4680,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) do { /* Save full path of last DFS path we used to resolve final target server */ kfree(full_path); - full_path = build_unc_path_to_root(vol, cifs_sb, !!count); + full_path = build_unc_path_to_root(ctx, cifs_sb, !!count); if (IS_ERR(full_path)) { rc = PTR_ERR(full_path); full_path = NULL; @@ -4688,17 +4688,17 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) } /* Chase referral */ oldmnt = cifs_sb->mountdata; - rc = expand_dfs_referral(xid, root_ses, vol, cifs_sb, ref_path + 1); + rc = expand_dfs_referral(xid, root_ses, ctx, cifs_sb, ref_path + 1); if (rc) break; /* Connect to new DFS target only if we were redirected */ if (oldmnt != cifs_sb->mountdata) { mount_put_conns(cifs_sb, xid, server, ses, tcon); - rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); + rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); } if (rc && !server && !ses) { /* Failed to connect. Try to connect to other targets in the referral. */ - rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, vol, root_ses, &xid, + rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, ctx, root_ses, &xid, &server, &ses, &tcon); } if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses) @@ -4711,7 +4711,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) set_root_ses(cifs_sb, ses, &root_ses); } /* Check for remaining path components and then continue chasing them (-EREMOTE) */ - rc = check_dfs_prepath(cifs_sb, vol, xid, server, tcon, &ref_path); + rc = check_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path); /* Prevent recursion on broken link referrals */ if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS) rc = -ELOOP; @@ -4742,8 +4742,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) tcon->remap = cifs_remap(cifs_sb); spin_unlock(&cifs_tcp_ses_lock); - /* Add original volume information for DFS cache to be used when refreshing referrals */ - rc = dfs_cache_add_vol(mntdata, vol, cifs_sb->origin_fullpath); + /* Add original context for DFS cache to be used when refreshing referrals */ + rc = dfs_cache_add_vol(mntdata, ctx, cifs_sb->origin_fullpath); if (rc) goto error; /* @@ -4758,8 +4758,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) */ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; kfree(cifs_sb->prepath); - cifs_sb->prepath = vol->prepath; - vol->prepath = NULL; + cifs_sb->prepath = ctx->prepath; + ctx->prepath = NULL; out: free_xid(xid); @@ -4776,7 +4776,7 @@ error: return rc; } #else -int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) +int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) { int rc = 0; unsigned int xid; @@ -4784,12 +4784,12 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) struct cifs_tcon *tcon; struct TCP_Server_Info *server; - rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); + rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); if (rc) goto error; if (tcon) { - rc = is_path_remote(cifs_sb, vol, xid, server, tcon); + rc = is_path_remote(cifs_sb, ctx, xid, server, tcon); if (rc == -EREMOTE) rc = -EOPNOTSUPP; if (rc) @@ -5066,15 +5066,15 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, } static int -cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses) +cifs_set_vol_auth(struct smb3_fs_context *ctx, struct cifs_ses *ses) { - vol->sectype = ses->sectype; + ctx->sectype = ses->sectype; /* krb5 is special, since we don't need username or pw */ - if (vol->sectype == Kerberos) + if (ctx->sectype == Kerberos) return 0; - return cifs_set_cifscreds(vol, ses); + return cifs_set_cifscreds(ctx, ses); } static struct cifs_tcon * @@ -5084,31 +5084,31 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); struct cifs_ses *ses; struct cifs_tcon *tcon = NULL; - struct smb_vol *vol_info; + struct smb3_fs_context *ctx; - vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); - if (vol_info == NULL) + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx == NULL) return ERR_PTR(-ENOMEM); - vol_info->local_nls = cifs_sb->local_nls; - vol_info->linux_uid = fsuid; - vol_info->cred_uid = fsuid; - vol_info->UNC = master_tcon->treeName; - vol_info->retry = master_tcon->retry; - vol_info->nocase = master_tcon->nocase; - vol_info->nohandlecache = master_tcon->nohandlecache; - vol_info->local_lease = master_tcon->local_lease; - vol_info->no_lease = master_tcon->no_lease; - vol_info->resilient = master_tcon->use_resilient; - vol_info->persistent = master_tcon->use_persistent; - vol_info->handle_timeout = master_tcon->handle_timeout; - vol_info->no_linux_ext = !master_tcon->unix_ext; - vol_info->linux_ext = master_tcon->posix_extensions; - vol_info->sectype = master_tcon->ses->sectype; - vol_info->sign = master_tcon->ses->sign; - vol_info->seal = master_tcon->seal; - - rc = cifs_set_vol_auth(vol_info, master_tcon->ses); + ctx->local_nls = cifs_sb->local_nls; + ctx->linux_uid = fsuid; + ctx->cred_uid = fsuid; + ctx->UNC = master_tcon->treeName; + ctx->retry = master_tcon->retry; + ctx->nocase = master_tcon->nocase; + ctx->nohandlecache = master_tcon->nohandlecache; + ctx->local_lease = master_tcon->local_lease; + ctx->no_lease = master_tcon->no_lease; + ctx->resilient = master_tcon->use_resilient; + ctx->persistent = master_tcon->use_persistent; + ctx->handle_timeout = master_tcon->handle_timeout; + ctx->no_linux_ext = !master_tcon->unix_ext; + ctx->linux_ext = master_tcon->posix_extensions; + ctx->sectype = master_tcon->ses->sectype; + ctx->sign = master_tcon->ses->sign; + ctx->seal = master_tcon->seal; + + rc = cifs_set_vol_auth(ctx, master_tcon->ses); if (rc) { tcon = ERR_PTR(rc); goto out; @@ -5119,26 +5119,26 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ++master_tcon->ses->server->srv_count; spin_unlock(&cifs_tcp_ses_lock); - ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); + ses = cifs_get_smb_ses(master_tcon->ses->server, ctx); if (IS_ERR(ses)) { tcon = (struct cifs_tcon *)ses; cifs_put_tcp_session(master_tcon->ses->server, 0); goto out; } - tcon = cifs_get_tcon(ses, vol_info); + tcon = cifs_get_tcon(ses, ctx); if (IS_ERR(tcon)) { cifs_put_smb_ses(ses); goto out; } if (cap_unix(ses)) - reset_cifs_unix_caps(0, tcon, NULL, vol_info); + reset_cifs_unix_caps(0, tcon, NULL, ctx); out: - kfree(vol_info->username); - kfree_sensitive(vol_info->password); - kfree(vol_info); + kfree(ctx->username); + kfree_sensitive(ctx->password); + kfree(ctx); return tcon; } diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 6ee849698962..3860241dcc03 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -20,6 +20,7 @@ #include "smb2glob.h" #include "dfs_cache.h" +#include "fs_context.h" #define CACHE_HTABLE_SIZE 32 #define CACHE_MAX_ENTRIES 64 @@ -48,8 +49,8 @@ struct cache_entry { struct vol_info { char *fullpath; - spinlock_t smb_vol_lock; - struct smb_vol smb_vol; + spinlock_t ctx_lock; + struct smb3_fs_context ctx; char *mntdata; struct list_head list; struct list_head rlist; @@ -586,7 +587,7 @@ static void __vol_release(struct vol_info *vi) { kfree(vi->fullpath); kfree(vi->mntdata); - cifs_cleanup_volume_info_contents(&vi->smb_vol); + cifs_cleanup_volume_info_contents(&vi->ctx); kfree(vi); } @@ -1140,43 +1141,43 @@ out_unlock: return rc; } -static int dup_vol(struct smb_vol *vol, struct smb_vol *new) +static int dup_vol(struct smb3_fs_context *ctx, struct smb3_fs_context *new) { - memcpy(new, vol, sizeof(*new)); + memcpy(new, ctx, sizeof(*new)); - if (vol->username) { - new->username = kstrndup(vol->username, strlen(vol->username), + if (ctx->username) { + new->username = kstrndup(ctx->username, strlen(ctx->username), GFP_KERNEL); if (!new->username) return -ENOMEM; } - if (vol->password) { - new->password = kstrndup(vol->password, strlen(vol->password), + if (ctx->password) { + new->password = kstrndup(ctx->password, strlen(ctx->password), GFP_KERNEL); if (!new->password) goto err_free_username; } - if (vol->UNC) { - cifs_dbg(FYI, "%s: vol->UNC: %s\n", __func__, vol->UNC); - new->UNC = kstrndup(vol->UNC, strlen(vol->UNC), GFP_KERNEL); + if (ctx->UNC) { + cifs_dbg(FYI, "%s: ctx->UNC: %s\n", __func__, ctx->UNC); + new->UNC = kstrndup(ctx->UNC, strlen(ctx->UNC), GFP_KERNEL); if (!new->UNC) goto err_free_password; } - if (vol->domainname) { - new->domainname = kstrndup(vol->domainname, - strlen(vol->domainname), GFP_KERNEL); + if (ctx->domainname) { + new->domainname = kstrndup(ctx->domainname, + strlen(ctx->domainname), GFP_KERNEL); if (!new->domainname) goto err_free_unc; } - if (vol->iocharset) { - new->iocharset = kstrndup(vol->iocharset, - strlen(vol->iocharset), GFP_KERNEL); + if (ctx->iocharset) { + new->iocharset = kstrndup(ctx->iocharset, + strlen(ctx->iocharset), GFP_KERNEL); if (!new->iocharset) goto err_free_domainname; } - if (vol->prepath) { - cifs_dbg(FYI, "%s: vol->prepath: %s\n", __func__, vol->prepath); - new->prepath = kstrndup(vol->prepath, strlen(vol->prepath), + if (ctx->prepath) { + cifs_dbg(FYI, "%s: ctx->prepath: %s\n", __func__, ctx->prepath); + new->prepath = kstrndup(ctx->prepath, strlen(ctx->prepath), GFP_KERNEL); if (!new->prepath) goto err_free_iocharset; @@ -1203,17 +1204,17 @@ err_free_username: * DFS cache refresh worker. * * @mntdata: mount data. - * @vol: cifs volume. + * @ctx: cifs context. * @fullpath: origin full path. * * Return zero if volume was set up correctly, otherwise non-zero. */ -int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath) +int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fullpath) { int rc; struct vol_info *vi; - if (!vol || !fullpath || !mntdata) + if (!ctx || !fullpath || !mntdata) return -EINVAL; cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath); @@ -1228,12 +1229,12 @@ int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath) goto err_free_vi; } - rc = dup_vol(vol, &vi->smb_vol); + rc = dup_vol(ctx, &vi->ctx); if (rc) goto err_free_fullpath; vi->mntdata = mntdata; - spin_lock_init(&vi->smb_vol_lock); + spin_lock_init(&vi->ctx_lock); kref_init(&vi->refcnt); spin_lock(&vol_list_lock); @@ -1289,10 +1290,10 @@ int dfs_cache_update_vol(const char *fullpath, struct TCP_Server_Info *server) spin_unlock(&vol_list_lock); cifs_dbg(FYI, "%s: updating volume info\n", __func__); - spin_lock(&vi->smb_vol_lock); - memcpy(&vi->smb_vol.dstaddr, &server->dstaddr, - sizeof(vi->smb_vol.dstaddr)); - spin_unlock(&vi->smb_vol_lock); + spin_lock(&vi->ctx_lock); + memcpy(&vi->ctx.dstaddr, &server->dstaddr, + sizeof(vi->ctx.dstaddr)); + spin_unlock(&vi->ctx_lock); kref_put(&vi->refcnt, vol_release); @@ -1445,11 +1446,11 @@ static inline void put_tcp_server(struct TCP_Server_Info *server) cifs_put_tcp_session(server, 0); } -static struct TCP_Server_Info *get_tcp_server(struct smb_vol *vol) +static struct TCP_Server_Info *get_tcp_server(struct smb3_fs_context *ctx) { struct TCP_Server_Info *server; - server = cifs_find_tcp_session(vol); + server = cifs_find_tcp_session(ctx); if (IS_ERR_OR_NULL(server)) return NULL; @@ -1476,7 +1477,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, char *mdata = NULL, *devname = NULL; struct TCP_Server_Info *server; struct cifs_ses *ses; - struct smb_vol vol = {NULL}; + struct smb3_fs_context ctx = {NULL}; rpath = get_dfs_root(path); if (IS_ERR(rpath)) @@ -1510,7 +1511,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, goto out; } - rc = cifs_setup_volume_info(&vol, mdata, devname, false); + rc = cifs_setup_volume_info(&ctx, mdata, devname, false); kfree(devname); if (rc) { @@ -1518,16 +1519,16 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, goto out; } - server = get_tcp_server(&vol); + server = get_tcp_server(&ctx); if (!server) { ses = ERR_PTR(-EHOSTDOWN); goto out; } - ses = cifs_get_smb_ses(server, &vol); + ses = cifs_get_smb_ses(server, &ctx); out: - cifs_cleanup_volume_info_contents(&vol); + cifs_cleanup_volume_info_contents(&ctx); kfree(mdata); kfree(rpath); @@ -1619,7 +1620,7 @@ static void refresh_cache_worker(struct work_struct *work) */ spin_lock(&vol_list_lock); list_for_each_entry(vi, &vol_list, list) { - server = get_tcp_server(&vi->smb_vol); + server = get_tcp_server(&vi->ctx); if (!server) continue; @@ -1631,9 +1632,9 @@ static void refresh_cache_worker(struct work_struct *work) /* Walk through all TCONs and refresh any expired cache entry */ list_for_each_entry_safe(vi, nvi, &vols, rlist) { - spin_lock(&vi->smb_vol_lock); - server = get_tcp_server(&vi->smb_vol); - spin_unlock(&vi->smb_vol_lock); + spin_lock(&vi->ctx_lock); + server = get_tcp_server(&vi->ctx); + spin_unlock(&vi->ctx_lock); if (!server) goto next_vol; diff --git a/fs/cifs/dfs_cache.h b/fs/cifs/dfs_cache.h index 3d7c05194536..1afc4f590c47 100644 --- a/fs/cifs/dfs_cache.h +++ b/fs/cifs/dfs_cache.h @@ -44,7 +44,7 @@ dfs_cache_noreq_update_tgthint(const char *path, extern int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it, struct dfs_info3_param *ref); -extern int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, +extern int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fullpath); extern int dfs_cache_update_vol(const char *fullpath, struct TCP_Server_Info *server); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 398c1eef7190..68900f1629bf 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -33,6 +33,7 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" #include "cifs_unicode.h" +#include "fs_context.h" static void renew_parental_timestamps(struct dentry *direntry) @@ -46,10 +47,10 @@ renew_parental_timestamps(struct dentry *direntry) } char * -cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, +cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, int add_treename) { - int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; + int pplen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0; int dfsplen; char *full_path = NULL; @@ -71,7 +72,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, if (dfsplen) memcpy(full_path, tcon->treeName, dfsplen); full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb); - memcpy(full_path + dfsplen + 1, vol->prepath, pplen); + memcpy(full_path + dfsplen + 1, ctx->prepath, pplen); convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); return full_path; } diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index ad6c2fed4055..3d071c87353e 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -25,7 +25,7 @@ static const match_table_t cifs_smb_version_tokens = { }; int -cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) +cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) { substring_t args[MAX_OPT_ARGS]; @@ -41,8 +41,8 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) return 1; } cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); - vol->ops = &smb1_operations; - vol->vals = &smb1_values; + ctx->ops = &smb1_operations; + ctx->vals = &smb1_values; break; case Smb_20: if (disable_legacy_dialects) { @@ -53,8 +53,8 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); return 1; } - vol->ops = &smb20_operations; - vol->vals = &smb20_values; + ctx->ops = &smb20_operations; + ctx->vals = &smb20_values; break; #else case Smb_1: @@ -65,28 +65,28 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) return 1; #endif /* CIFS_ALLOW_INSECURE_LEGACY */ case Smb_21: - vol->ops = &smb21_operations; - vol->vals = &smb21_values; + ctx->ops = &smb21_operations; + ctx->vals = &smb21_values; break; case Smb_30: - vol->ops = &smb30_operations; - vol->vals = &smb30_values; + ctx->ops = &smb30_operations; + ctx->vals = &smb30_values; break; case Smb_302: - vol->ops = &smb30_operations; /* currently identical with 3.0 */ - vol->vals = &smb302_values; + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smb302_values; break; case Smb_311: - vol->ops = &smb311_operations; - vol->vals = &smb311_values; + ctx->ops = &smb311_operations; + ctx->vals = &smb311_values; break; case Smb_3any: - vol->ops = &smb30_operations; /* currently identical with 3.0 */ - vol->vals = &smb3any_values; + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smb3any_values; break; case Smb_default: - vol->ops = &smb30_operations; /* currently identical with 3.0 */ - vol->vals = &smbdefault_values; + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smbdefault_values; break; default: cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); @@ -112,7 +112,7 @@ static const match_table_t cifs_secflavor_tokens = { { Opt_sec_err, NULL } }; -int cifs_parse_security_flavors(char *value, struct smb_vol *vol) +int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) { substring_t args[MAX_OPT_ARGS]; @@ -121,44 +121,44 @@ int cifs_parse_security_flavors(char *value, struct smb_vol *vol) * With mount options, the last one should win. Reset any existing * settings back to default. */ - vol->sectype = Unspecified; - vol->sign = false; + ctx->sectype = Unspecified; + ctx->sign = false; switch (match_token(value, cifs_secflavor_tokens, args)) { case Opt_sec_krb5p: cifs_dbg(VFS, "sec=krb5p is not supported!\n"); return 1; case Opt_sec_krb5i: - vol->sign = true; + ctx->sign = true; fallthrough; case Opt_sec_krb5: - vol->sectype = Kerberos; + ctx->sectype = Kerberos; break; case Opt_sec_ntlmsspi: - vol->sign = true; + ctx->sign = true; fallthrough; case Opt_sec_ntlmssp: - vol->sectype = RawNTLMSSP; + ctx->sectype = RawNTLMSSP; break; case Opt_sec_ntlmi: - vol->sign = true; + ctx->sign = true; fallthrough; case Opt_ntlm: - vol->sectype = NTLM; + ctx->sectype = NTLM; break; case Opt_sec_ntlmv2i: - vol->sign = true; + ctx->sign = true; fallthrough; case Opt_sec_ntlmv2: - vol->sectype = NTLMv2; + ctx->sectype = NTLMv2; break; #ifdef CONFIG_CIFS_WEAK_PW_HASH case Opt_sec_lanman: - vol->sectype = LANMAN; + ctx->sectype = LANMAN; break; #endif case Opt_sec_none: - vol->nullauth = 1; + ctx->nullauth = 1; break; default: cifs_dbg(VFS, "bad security option: %s\n", value); @@ -178,40 +178,40 @@ static const match_table_t cifs_cacheflavor_tokens = { }; int -cifs_parse_cache_flavor(char *value, struct smb_vol *vol) +cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx) { substring_t args[MAX_OPT_ARGS]; switch (match_token(value, cifs_cacheflavor_tokens, args)) { case Opt_cache_loose: - vol->direct_io = false; - vol->strict_io = false; - vol->cache_ro = false; - vol->cache_rw = false; + ctx->direct_io = false; + ctx->strict_io = false; + ctx->cache_ro = false; + ctx->cache_rw = false; break; case Opt_cache_strict: - vol->direct_io = false; - vol->strict_io = true; - vol->cache_ro = false; - vol->cache_rw = false; + ctx->direct_io = false; + ctx->strict_io = true; + ctx->cache_ro = false; + ctx->cache_rw = false; break; case Opt_cache_none: - vol->direct_io = true; - vol->strict_io = false; - vol->cache_ro = false; - vol->cache_rw = false; + ctx->direct_io = true; + ctx->strict_io = false; + ctx->cache_ro = false; + ctx->cache_rw = false; break; case Opt_cache_ro: - vol->direct_io = false; - vol->strict_io = false; - vol->cache_ro = true; - vol->cache_rw = false; + ctx->direct_io = false; + ctx->strict_io = false; + ctx->cache_ro = true; + ctx->cache_rw = false; break; case Opt_cache_rw: - vol->direct_io = false; - vol->strict_io = false; - vol->cache_ro = false; - vol->cache_rw = true; + ctx->direct_io = false; + ctx->strict_io = false; + ctx->cache_ro = false; + ctx->cache_rw = true; break; default: cifs_dbg(VFS, "bad cache= option: %s\n", value); diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 886208a1b0ef..f217bd600c1e 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -24,7 +24,7 @@ enum smb_version { Smb_version_err }; -int cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3); +int cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3); enum { Opt_cache_loose, @@ -35,7 +35,7 @@ enum { Opt_cache_err }; -int cifs_parse_cache_flavor(char *value, struct smb_vol *vol); +int cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx); enum cifs_sec_param { Opt_sec_krb5, @@ -53,6 +53,105 @@ enum cifs_sec_param { Opt_sec_err }; -int cifs_parse_security_flavors(char *value, struct smb_vol *vol); +struct smb3_fs_context { + bool uid_specified; + bool gid_specified; + bool sloppy; + char *nodename; + bool got_ip; + bool got_version; + unsigned short port; + + char *username; + char *password; + char *domainname; + char *UNC; + char *iocharset; /* local code page for mapping to and from Unicode */ + char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ + char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ + kuid_t cred_uid; + kuid_t linux_uid; + kgid_t linux_gid; + kuid_t backupuid; + kgid_t backupgid; + umode_t file_mode; + umode_t dir_mode; + enum securityEnum sectype; /* sectype requested via mnt opts */ + bool sign; /* was signing requested via mnt opts? */ + bool ignore_signature:1; + bool retry:1; + bool intr:1; + bool setuids:1; + bool setuidfromacl:1; + bool override_uid:1; + bool override_gid:1; + bool dynperm:1; + bool noperm:1; + bool nodelete:1; + bool mode_ace:1; + bool no_psx_acl:1; /* set if posix acl support should be disabled */ + bool cifs_acl:1; + bool backupuid_specified; /* mount option backupuid is specified */ + bool backupgid_specified; /* mount option backupgid is specified */ + bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ + bool server_ino:1; /* use inode numbers from server ie UniqueId */ + bool direct_io:1; + bool strict_io:1; /* strict cache behavior */ + bool cache_ro:1; + bool cache_rw:1; + bool remap:1; /* set to remap seven reserved chars in filenames */ + bool sfu_remap:1; /* remap seven reserved chars ala SFU */ + bool posix_paths:1; /* unset to not ask for posix pathnames. */ + bool no_linux_ext:1; + bool linux_ext:1; + bool sfu_emul:1; + bool nullauth:1; /* attempt to authenticate with null user */ + bool nocase:1; /* request case insensitive filenames */ + bool nobrl:1; /* disable sending byte range locks to srv */ + bool nohandlecache:1; /* disable caching dir handles if srvr probs */ + bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ + bool seal:1; /* request transport encryption on share */ + bool nodfs:1; /* Do not request DFS, even if available */ + bool local_lease:1; /* check leases only on local system, not remote */ + bool noblocksnd:1; + bool noautotune:1; + bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ + bool no_lease:1; /* disable requesting leases */ + bool fsc:1; /* enable fscache */ + bool mfsymlinks:1; /* use Minshall+French Symlinks */ + bool multiuser:1; + bool rwpidforward:1; /* pid forward for read/write operations */ + bool nosharesock:1; + bool persistent:1; + bool nopersistent:1; + bool resilient:1; /* noresilient not required since not fored for CA */ + bool domainauto:1; + bool rdma:1; + bool multichannel:1; + bool use_client_guid:1; + /* reuse existing guid for multichannel */ + u8 client_guid[SMB2_CLIENT_GUID_SIZE]; + unsigned int bsize; + unsigned int rsize; + unsigned int wsize; + unsigned int min_offload; + bool sockopt_tcp_nodelay:1; + unsigned long actimeo; /* attribute cache timeout (jiffies) */ + struct smb_version_operations *ops; + struct smb_version_values *vals; + char *prepath; + struct sockaddr_storage dstaddr; /* destination address */ + struct sockaddr_storage srcaddr; /* allow binding to a local IP */ + struct nls_table *local_nls; + unsigned int echo_interval; /* echo interval in secs */ + __u64 snapshot_time; /* needed for timewarp tokens */ + __u32 handle_timeout; /* persistent and durable handle timeout in ms */ + unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ + unsigned int max_channels; + __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */ + bool rootfs:1; /* if it's a SMB root file system */ +}; + +int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx); #endif diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 6c2c42f8d893..5c71f2730166 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -32,6 +32,7 @@ #include #include "cifs_spnego.h" #include "smb2proto.h" +#include "fs_context.h" bool is_server_using_iface(struct TCP_Server_Info *server, @@ -170,7 +171,7 @@ int cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) { struct cifs_chan *chan; - struct smb_vol vol = {NULL}; + struct smb3_fs_context ctx = {NULL}; static const char unc_fmt[] = "\\%s\\foo"; char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0}; struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr; @@ -188,7 +189,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) &ipv6->sin6_addr); /* - * Setup a smb_vol with mostly the same info as the existing + * Setup a ctx with mostly the same info as the existing * session and overwrite it with the requested iface data. * * We need to setup at least the fields used for negprot and @@ -200,30 +201,30 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) */ /* Always make new connection for now (TODO?) */ - vol.nosharesock = true; + ctx.nosharesock = true; /* Auth */ - vol.domainauto = ses->domainAuto; - vol.domainname = ses->domainName; - vol.username = ses->user_name; - vol.password = ses->password; - vol.sectype = ses->sectype; - vol.sign = ses->sign; + ctx.domainauto = ses->domainAuto; + ctx.domainname = ses->domainName; + ctx.username = ses->user_name; + ctx.password = ses->password; + ctx.sectype = ses->sectype; + ctx.sign = ses->sign; /* UNC and paths */ /* XXX: Use ses->server->hostname? */ sprintf(unc, unc_fmt, ses->serverName); - vol.UNC = unc; - vol.prepath = ""; + ctx.UNC = unc; + ctx.prepath = ""; /* Reuse same version as master connection */ - vol.vals = ses->server->vals; - vol.ops = ses->server->ops; + ctx.vals = ses->server->vals; + ctx.ops = ses->server->ops; - vol.noblocksnd = ses->server->noblocksnd; - vol.noautotune = ses->server->noautotune; - vol.sockopt_tcp_nodelay = ses->server->tcp_nodelay; - vol.echo_interval = ses->server->echo_interval / HZ; + ctx.noblocksnd = ses->server->noblocksnd; + ctx.noautotune = ses->server->noautotune; + ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay; + ctx.echo_interval = ses->server->echo_interval / HZ; /* * This will be used for encoding/decoding user/domain/pw @@ -234,21 +235,21 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) * stored. This might break when dealing with non-ascii * strings. */ - vol.local_nls = load_nls_default(); + ctx.local_nls = load_nls_default(); /* Use RDMA if possible */ - vol.rdma = iface->rdma_capable; - memcpy(&vol.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage)); + ctx.rdma = iface->rdma_capable; + memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage)); /* reuse master con client guid */ - memcpy(&vol.client_guid, ses->server->client_guid, + memcpy(&ctx.client_guid, ses->server->client_guid, SMB2_CLIENT_GUID_SIZE); - vol.use_client_guid = true; + ctx.use_client_guid = true; mutex_lock(&ses->session_mutex); chan = ses->binding_chan = &ses->chans[ses->chan_count]; - chan->server = cifs_get_tcp_session(&vol); + chan->server = cifs_get_tcp_session(&ctx); if (IS_ERR(chan->server)) { rc = PTR_ERR(chan->server); chan->server = NULL; @@ -274,7 +275,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) if (rc) goto out; - rc = cifs_setup_session(xid, ses, vol.local_nls); + rc = cifs_setup_session(xid, ses, ctx.local_nls); if (rc) goto out; @@ -297,7 +298,7 @@ out: if (rc && chan->server) cifs_put_tcp_session(chan->server, 0); - unload_nls(vol.local_nls); + unload_nls(ctx.local_nls); return rc; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 80287c26cfac..359a0ef796de 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -12,6 +12,7 @@ #include "cifs_debug.h" #include "cifspdu.h" #include "cifs_unicode.h" +#include "fs_context.h" /* * An NT cancel request header looks just like the original request except: @@ -428,15 +429,15 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses) } static unsigned int -cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); struct TCP_Server_Info *server = tcon->ses->server; unsigned int wsize; /* start with specified wsize, or default */ - if (volume_info->wsize) - wsize = volume_info->wsize; + if (ctx->wsize) + wsize = ctx->wsize; else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) wsize = CIFS_DEFAULT_IOSIZE; else @@ -463,7 +464,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) } static unsigned int -cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); struct TCP_Server_Info *server = tcon->ses->server; @@ -488,7 +489,7 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) else defsize = server->maxBuf - sizeof(READ_RSP); - rsize = volume_info->rsize ? volume_info->rsize : defsize; + rsize = ctx->rsize ? ctx->rsize : defsize; /* * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 22f1d8dc12b0..940e61e92a8c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -24,6 +24,7 @@ #include "smb2glob.h" #include "cifs_ioctl.h" #include "smbdirect.h" +#include "fs_context.h" /* Change credits for different ops and return the total number of credits */ static int @@ -339,13 +340,13 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses) } static unsigned int -smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { struct TCP_Server_Info *server = tcon->ses->server; unsigned int wsize; /* start with specified wsize, or default */ - wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; + wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE; wsize = min_t(unsigned int, wsize, server->max_write); if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); @@ -354,13 +355,13 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) } static unsigned int -smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { struct TCP_Server_Info *server = tcon->ses->server; unsigned int wsize; /* start with specified wsize, or default */ - wsize = volume_info->wsize ? volume_info->wsize : SMB3_DEFAULT_IOSIZE; + wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE; wsize = min_t(unsigned int, wsize, server->max_write); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { @@ -386,13 +387,13 @@ smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) } static unsigned int -smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { struct TCP_Server_Info *server = tcon->ses->server; unsigned int rsize; /* start with specified rsize, or default */ - rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; + rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE; rsize = min_t(unsigned int, rsize, server->max_read); if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) @@ -402,13 +403,13 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) } static unsigned int -smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) +smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) { struct TCP_Server_Info *server = tcon->ses->server; unsigned int rsize; /* start with specified rsize, or default */ - rsize = volume_info->rsize ? volume_info->rsize : SMB3_DEFAULT_IOSIZE; + rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE; rsize = min_t(unsigned int, rsize, server->max_read); #ifdef CONFIG_CIFS_SMB_DIRECT if (server->rdma) { -- cgit v1.2.3 From 837e3a1bbfdc105216972c83f693e96969c62351 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 2 Nov 2020 09:36:24 +1000 Subject: cifs: rename dup_vol to smb3_fs_context_dup and move it into fs_context.c Continue restructuring needed for support of new mount API Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/dfs_cache.c | 60 +--------------------------------------------------- fs/cifs/fs_context.c | 41 +++++++++++++++++++++++++++++++++++ fs/cifs/fs_context.h | 3 ++- 3 files changed, 44 insertions(+), 60 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 3860241dcc03..2b77d39d7d22 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -1141,64 +1141,6 @@ out_unlock: return rc; } -static int dup_vol(struct smb3_fs_context *ctx, struct smb3_fs_context *new) -{ - memcpy(new, ctx, sizeof(*new)); - - if (ctx->username) { - new->username = kstrndup(ctx->username, strlen(ctx->username), - GFP_KERNEL); - if (!new->username) - return -ENOMEM; - } - if (ctx->password) { - new->password = kstrndup(ctx->password, strlen(ctx->password), - GFP_KERNEL); - if (!new->password) - goto err_free_username; - } - if (ctx->UNC) { - cifs_dbg(FYI, "%s: ctx->UNC: %s\n", __func__, ctx->UNC); - new->UNC = kstrndup(ctx->UNC, strlen(ctx->UNC), GFP_KERNEL); - if (!new->UNC) - goto err_free_password; - } - if (ctx->domainname) { - new->domainname = kstrndup(ctx->domainname, - strlen(ctx->domainname), GFP_KERNEL); - if (!new->domainname) - goto err_free_unc; - } - if (ctx->iocharset) { - new->iocharset = kstrndup(ctx->iocharset, - strlen(ctx->iocharset), GFP_KERNEL); - if (!new->iocharset) - goto err_free_domainname; - } - if (ctx->prepath) { - cifs_dbg(FYI, "%s: ctx->prepath: %s\n", __func__, ctx->prepath); - new->prepath = kstrndup(ctx->prepath, strlen(ctx->prepath), - GFP_KERNEL); - if (!new->prepath) - goto err_free_iocharset; - } - - return 0; - -err_free_iocharset: - kfree(new->iocharset); -err_free_domainname: - kfree(new->domainname); -err_free_unc: - kfree(new->UNC); -err_free_password: - kfree_sensitive(new->password); -err_free_username: - kfree(new->username); - kfree(new); - return -ENOMEM; -} - /** * dfs_cache_add_vol - add a cifs volume during mount() that will be handled by * DFS cache refresh worker. @@ -1229,7 +1171,7 @@ int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fu goto err_free_vi; } - rc = dup_vol(ctx, &vi->ctx); + rc = smb3_fs_context_dup(&vi->ctx, ctx); if (rc) goto err_free_fullpath; diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 3d071c87353e..af6ff0192d5e 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -7,6 +7,7 @@ */ #include "cifsglob.h" +#include "cifsproto.h" #include "cifs_debug.h" #include "fs_context.h" @@ -219,3 +220,43 @@ cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx) } return 0; } + +#define DUP_CTX_STR(field) \ +do { \ + if (ctx->field) { \ + new_ctx->field = kstrdup(ctx->field, GFP_ATOMIC); \ + if (new_ctx->field == NULL) { \ + cifs_cleanup_volume_info_contents(new_ctx); \ + return -ENOMEM; \ + } \ + } \ +} while (0) + +int +smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx) +{ + int rc = 0; + + memcpy(new_ctx, ctx, sizeof(*ctx)); + new_ctx->prepath = NULL; + new_ctx->local_nls = NULL; + new_ctx->nodename = NULL; + new_ctx->username = NULL; + new_ctx->password = NULL; + new_ctx->domainname = NULL; + new_ctx->UNC = NULL; + new_ctx->iocharset = NULL; + + /* + * Make sure to stay in sync with cifs_cleanup_volume_info_contents() + */ + DUP_CTX_STR(prepath); + DUP_CTX_STR(username); + DUP_CTX_STR(password); + DUP_CTX_STR(UNC); + DUP_CTX_STR(domainname); + DUP_CTX_STR(nodename); + DUP_CTX_STR(iocharset); + + return rc; +} diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index f217bd600c1e..1ac5e1d202b6 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -152,6 +152,7 @@ struct smb3_fs_context { bool rootfs:1; /* if it's a SMB root file system */ }; -int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx); +extern int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx); +extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx); #endif -- cgit v1.2.3 From 15c7d09af2156ee84018cc8ba08c4a0218acb55e Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 2 Nov 2020 10:59:55 +1000 Subject: cifs: move the enum for cifs parameters into fs_context.h No change to logic, just moving the enum of cifs mount parms into a header Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/connect.c | 57 ------------------------------ fs/cifs/fs_context.h | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 57 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index fedb904b516f..ee40bce9c99f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -73,63 +73,6 @@ extern bool disable_legacy_dialects; /* Drop the connection to not overload the server */ #define NUM_STATUS_IO_TIMEOUT 5 -enum { - /* Mount options that take no arguments */ - Opt_user_xattr, Opt_nouser_xattr, - Opt_forceuid, Opt_noforceuid, - Opt_forcegid, Opt_noforcegid, - Opt_noblocksend, Opt_noautotune, Opt_nolease, - Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete, - Opt_mapposix, Opt_nomapposix, - Opt_mapchars, Opt_nomapchars, Opt_sfu, - Opt_nosfu, Opt_nodfs, Opt_posixpaths, - Opt_noposixpaths, Opt_nounix, Opt_unix, - Opt_nocase, - Opt_brl, Opt_nobrl, - Opt_handlecache, Opt_nohandlecache, - Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids, - Opt_nosetuids, Opt_dynperm, Opt_nodynperm, - Opt_nohard, Opt_nosoft, - Opt_nointr, Opt_intr, - Opt_nostrictsync, Opt_strictsync, - Opt_serverino, Opt_noserverino, - Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl, - Opt_acl, Opt_noacl, Opt_locallease, - Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac, - Opt_fsc, Opt_mfsymlinks, - Opt_multiuser, Opt_sloppy, Opt_nosharesock, - Opt_persistent, Opt_nopersistent, - Opt_resilient, Opt_noresilient, - Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, - Opt_multichannel, Opt_nomultichannel, - Opt_compress, - - /* Mount options which take numeric value */ - Opt_backupuid, Opt_backupgid, Opt_uid, - Opt_cruid, Opt_gid, Opt_file_mode, - Opt_dirmode, Opt_port, - Opt_min_enc_offload, - Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo, - Opt_echo_interval, Opt_max_credits, Opt_handletimeout, - Opt_snapshot, Opt_max_channels, - - /* Mount options which take string value */ - Opt_user, Opt_pass, Opt_ip, - Opt_domain, Opt_srcaddr, Opt_iocharset, - Opt_netbiosname, Opt_servern, - Opt_ver, Opt_vers, Opt_sec, Opt_cache, - - /* Mount options to be ignored */ - Opt_ignore, - - /* Options which could be blank */ - Opt_blank_pass, - Opt_blank_user, - Opt_blank_ip, - - Opt_err -}; - static const match_table_t cifs_mount_option_tokens = { { Opt_user_xattr, "user_xattr" }, diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 1ac5e1d202b6..3a66199f3cb7 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -53,6 +53,103 @@ enum cifs_sec_param { Opt_sec_err }; +enum cifs_param { + /* Mount options that take no arguments */ + Opt_user_xattr, Opt_nouser_xattr, + Opt_forceuid, Opt_noforceuid, + Opt_forcegid, Opt_noforcegid, + Opt_noblocksend, + Opt_noautotune, + Opt_nolease, + Opt_hard, Opt_nohard, + Opt_soft, Opt_nosoft, + Opt_perm, Opt_noperm, + Opt_nodelete, + Opt_mapposix, Opt_nomapposix, + Opt_mapchars, + Opt_nomapchars, + Opt_sfu, Opt_nosfu, + Opt_nodfs, + Opt_posixpaths, Opt_noposixpaths, + Opt_unix, Opt_nounix, + Opt_nocase, + Opt_brl, Opt_nobrl, + Opt_handlecache, Opt_nohandlecache, + Opt_forcemandatorylock, + Opt_setuidfromacl, + Opt_setuids, Opt_nosetuids, + Opt_dynperm, Opt_nodynperm, + Opt_intr, Opt_nointr, + Opt_strictsync, Opt_nostrictsync, + Opt_serverino, Opt_noserverino, + Opt_rwpidforward, + Opt_cifsacl, Opt_nocifsacl, + Opt_acl, Opt_noacl, + Opt_locallease, + Opt_sign, + Opt_ignore_signature, + Opt_seal, + Opt_noac, + Opt_fsc, + Opt_mfsymlinks, + Opt_multiuser, + Opt_sloppy, + Opt_nosharesock, + Opt_persistent, Opt_nopersistent, + Opt_resilient, Opt_noresilient, + Opt_domainauto, + Opt_rdma, + Opt_modesid, + Opt_rootfs, + Opt_multichannel, Opt_nomultichannel, + Opt_compress, + + /* Mount options which take numeric value */ + Opt_backupuid, + Opt_backupgid, + Opt_uid, + Opt_cruid, + Opt_gid, + Opt_port, + Opt_file_mode, + Opt_dirmode, + Opt_min_enc_offload, + Opt_blocksize, + Opt_rsize, + Opt_wsize, + Opt_actimeo, + Opt_echo_interval, + Opt_max_credits, + Opt_snapshot, + Opt_max_channels, + Opt_handletimeout, + + /* Mount options which take string value */ + Opt_source, + Opt_user, + Opt_pass, + Opt_ip, + Opt_domain, + Opt_srcaddr, + Opt_iocharset, + Opt_netbiosname, + Opt_servern, + Opt_ver, + Opt_vers, + Opt_sec, + Opt_cache, + + /* Mount options to be ignored */ + Opt_ignore, + + /* Options which could be blank */ + Opt_blank_pass, + Opt_blank_user, + Opt_blank_ip, + + Opt_err +}; + struct smb3_fs_context { bool uid_specified; bool gid_specified; -- cgit v1.2.3 From 66e7b09c731175064de5a3682c692ec166e02499 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 5 Nov 2020 13:58:14 +1000 Subject: cifs: move cifs_parse_devname to fs_context.c Also rename the function from cifs_ to smb3_ Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 1 + fs/cifs/connect.c | 59 ++-------------------------------------------------- fs/cifs/fs_context.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 57 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e891a4f421a6..0ef3deeb085f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -89,6 +89,7 @@ extern void cifs_mid_q_entry_release(struct mid_q_entry *midEntry); extern void cifs_wake_up_task(struct mid_q_entry *mid); extern int cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid); +extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); extern int cifs_discard_remaining_data(struct TCP_Server_Info *server); extern int cifs_call_async(struct TCP_Server_Info *server, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ee40bce9c99f..8ae45367109c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1258,61 +1258,6 @@ static int get_option_gid(substring_t args[], kgid_t *result) return 0; } -/* - * Parse a devname into substrings and populate the vol->UNC and vol->prepath - * fields with the result. Returns 0 on success and an error otherwise. - */ -static int -cifs_parse_devname(const char *devname, struct smb3_fs_context *ctx) -{ - char *pos; - const char *delims = "/\\"; - size_t len; - - if (unlikely(!devname || !*devname)) { - cifs_dbg(VFS, "Device name not specified\n"); - return -EINVAL; - } - - /* make sure we have a valid UNC double delimiter prefix */ - len = strspn(devname, delims); - if (len != 2) - return -EINVAL; - - /* find delimiter between host and sharename */ - pos = strpbrk(devname + 2, delims); - if (!pos) - return -EINVAL; - - /* skip past delimiter */ - ++pos; - - /* now go until next delimiter or end of string */ - len = strcspn(pos, delims); - - /* move "pos" up to delimiter or NULL */ - pos += len; - ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); - if (!ctx->UNC) - return -ENOMEM; - - convert_delimiter(ctx->UNC, '\\'); - - /* skip any delimiter */ - if (*pos == '/' || *pos == '\\') - pos++; - - /* If pos is NULL then no prepath */ - if (!*pos) - return 0; - - ctx->prepath = kstrdup(pos, GFP_KERNEL); - if (!ctx->prepath) - return -ENOMEM; - - return 0; -} - static int cifs_parse_mount_options(const char *mountdata, const char *devname, struct smb3_fs_context *ctx, bool is_smb3) @@ -1416,7 +1361,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ctx->backupuid_specified = false; /* no backup intent for a user */ ctx->backupgid_specified = false; /* no backup intent for a group */ - switch (cifs_parse_devname(devname, ctx)) { + switch (smb3_parse_devname(devname, ctx)) { case 0: break; case -ENOMEM: @@ -4548,7 +4493,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_contex struct smb3_fs_context v = {NULL}; /* if @path contains a tree name, skip it in the prefix path */ if (added_treename) { - rc = cifs_parse_devname(path, &v); + rc = smb3_parse_devname(path, &v); if (rc) break; rc = -EREMOTE; diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index af6ff0192d5e..84354cd4c960 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -260,3 +260,59 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx return rc; } + +/* + * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath + * fields with the result. Returns 0 on success and an error otherwise + * (e.g. ENOMEM or EINVAL) + */ +int +smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx) +{ + char *pos; + const char *delims = "/\\"; + size_t len; + + if (unlikely(!devname || !*devname)) { + cifs_dbg(VFS, "Device name not specified\n"); + return -EINVAL; + } + + /* make sure we have a valid UNC double delimiter prefix */ + len = strspn(devname, delims); + if (len != 2) + return -EINVAL; + + /* find delimiter between host and sharename */ + pos = strpbrk(devname + 2, delims); + if (!pos) + return -EINVAL; + + /* skip past delimiter */ + ++pos; + + /* now go until next delimiter or end of string */ + len = strcspn(pos, delims); + + /* move "pos" up to delimiter or NULL */ + pos += len; + ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); + if (!ctx->UNC) + return -ENOMEM; + + convert_delimiter(ctx->UNC, '\\'); + + /* skip any delimiter */ + if (*pos == '/' || *pos == '\\') + pos++; + + /* If pos is NULL then no prepath */ + if (!*pos) + return 0; + + ctx->prepath = kstrdup(pos, GFP_KERNEL); + if (!ctx->prepath) + return -ENOMEM; + + return 0; +} -- cgit v1.2.3 From 24e0a1eff9e2b9835a6e7c17039dfb6ecfd81f1f Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 10 Dec 2020 00:06:02 -0600 Subject: cifs: switch to new mount api See Documentation/filesystems/mount_api.rst for details on new mount API Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 4 + fs/cifs/cifsencrypt.c | 5 + fs/cifs/cifsfs.c | 54 +-- fs/cifs/cifsfs.h | 4 + fs/cifs/cifsproto.h | 5 +- fs/cifs/connect.c | 1158 +----------------------------------------------- fs/cifs/dfs_cache.c | 8 +- fs/cifs/fs_context.c | 1063 +++++++++++++++++++++++++++++++++++++++++--- fs/cifs/fs_context.h | 74 ++-- fs/cifs/sess.c | 2 +- 10 files changed, 1096 insertions(+), 1281 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index cc3ada12848d..4b0b9cfe2ab1 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -275,6 +275,10 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt, convert_delimiter(devname, '/'); + /* TODO: change to call fs_context_for_mount(), fill in context directly, call fc_mount */ + + /* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */ + /* strip first '\' from fullpath */ mountdata = cifs_compose_mount_options(cifs_sb->mountdata, fullpath + 1, NULL, NULL); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 9daa256f69d4..51d53e4bdf6b 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -661,6 +661,11 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) unsigned char *tiblob = NULL; /* target info blob */ __le64 rsp_timestamp; + if (nls_cp == NULL) { + cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); + return -EINVAL; + } + if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (!ses->domainName) { if (ses->domainAuto) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9fb85fcff6ae..907c82428c42 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -682,13 +682,6 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) } #endif -static int cifs_remount(struct super_block *sb, int *flags, char *data) -{ - sync_filesystem(sb); - *flags |= SB_NODIRATIME; - return 0; -} - static int cifs_drop_inode(struct inode *inode) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -710,7 +703,6 @@ static const struct super_operations cifs_super_ops = { as opens */ .show_options = cifs_show_options, .umount_begin = cifs_umount_begin, - .remount_fs = cifs_remount, #ifdef CONFIG_CIFS_STATS2 .show_stats = cifs_show_stats, #endif @@ -778,9 +770,9 @@ static int cifs_set_super(struct super_block *sb, void *data) return set_anon_super(sb, NULL); } -static struct dentry * +struct dentry * cifs_smb3_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, bool is_smb3) + int flags, struct smb3_fs_context *old_ctx) { int rc; struct super_block *sb; @@ -794,13 +786,24 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, * If CIFS_DEBUG && cifs_FYI */ if (cifsFYI) - cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags); + cifs_dbg(FYI, "Devname: %s flags: %d\n", old_ctx->UNC, flags); else - cifs_info("Attempting to mount %s\n", dev_name); + cifs_info("Attempting to mount %s\n", old_ctx->UNC); + + ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + rc = smb3_fs_context_dup(ctx, old_ctx); + if (rc) { + root = ERR_PTR(rc); + goto out; + } - ctx = cifs_get_volume_info((char *)data, dev_name, is_smb3); - if (IS_ERR(ctx)) - return ERR_CAST(ctx); + rc = cifs_setup_volume_info(ctx); + if (rc) { + root = ERR_PTR(rc); + goto out; + } cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); if (cifs_sb == NULL) { @@ -808,7 +811,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out_nls; } - cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); + cifs_sb->mountdata = kstrndup(ctx->mount_options, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { root = ERR_PTR(-ENOMEM); goto out_free; @@ -878,19 +881,6 @@ out_nls: goto out; } -static struct dentry * -smb3_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return cifs_smb3_do_mount(fs_type, flags, dev_name, data, true); -} - -static struct dentry * -cifs_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return cifs_smb3_do_mount(fs_type, flags, dev_name, data, false); -} static ssize_t cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) @@ -1027,7 +1017,8 @@ cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, .name = "cifs", - .mount = cifs_do_mount, + .init_fs_context = smb3_init_fs_context, + .parameters = smb3_fs_parameters, .kill_sb = cifs_kill_sb, .fs_flags = FS_RENAME_DOES_D_MOVE, }; @@ -1036,7 +1027,8 @@ MODULE_ALIAS_FS("cifs"); static struct file_system_type smb3_fs_type = { .owner = THIS_MODULE, .name = "smb3", - .mount = smb3_do_mount, + .init_fs_context = smb3_init_fs_context, + .parameters = smb3_fs_parameters, .kill_sb = cifs_kill_sb, .fs_flags = FS_RENAME_DOES_D_MOVE, }; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 905d03863721..d6976c28970d 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -152,6 +152,10 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern void cifs_setsize(struct inode *inode, loff_t offset); extern int cifs_truncate_page(struct address_space *mapping, loff_t from); +struct smb3_fs_context; +extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, + int flags, struct smb3_fs_context *ctx); + #ifdef CONFIG_CIFS_NFSD_EXPORT extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0ef3deeb085f..8dde386d4893 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -239,8 +239,6 @@ extern int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb); extern int cifs_match_super(struct super_block *, void *); extern void cifs_cleanup_volume_info(struct smb3_fs_context *ctx); -extern struct smb3_fs_context *cifs_get_volume_info(char *mount_data, - const char *devname, bool is_smb3); extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); @@ -554,8 +552,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); extern int -cifs_setup_volume_info(struct smb3_fs_context *ctx, char *mount_data, - const char *devname, bool is_smb3); +cifs_setup_volume_info(struct smb3_fs_context *ctx); extern void cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8ae45367109c..1c463ca16226 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -73,156 +73,6 @@ extern bool disable_legacy_dialects; /* Drop the connection to not overload the server */ #define NUM_STATUS_IO_TIMEOUT 5 -static const match_table_t cifs_mount_option_tokens = { - - { Opt_user_xattr, "user_xattr" }, - { Opt_nouser_xattr, "nouser_xattr" }, - { Opt_forceuid, "forceuid" }, - { Opt_noforceuid, "noforceuid" }, - { Opt_forcegid, "forcegid" }, - { Opt_noforcegid, "noforcegid" }, - { Opt_noblocksend, "noblocksend" }, - { Opt_noautotune, "noautotune" }, - { Opt_nolease, "nolease" }, - { Opt_hard, "hard" }, - { Opt_soft, "soft" }, - { Opt_perm, "perm" }, - { Opt_noperm, "noperm" }, - { Opt_nodelete, "nodelete" }, - { Opt_mapchars, "mapchars" }, /* SFU style */ - { Opt_nomapchars, "nomapchars" }, - { Opt_mapposix, "mapposix" }, /* SFM style */ - { Opt_nomapposix, "nomapposix" }, - { Opt_sfu, "sfu" }, - { Opt_nosfu, "nosfu" }, - { Opt_nodfs, "nodfs" }, - { Opt_posixpaths, "posixpaths" }, - { Opt_noposixpaths, "noposixpaths" }, - { Opt_nounix, "nounix" }, - { Opt_nounix, "nolinux" }, - { Opt_nounix, "noposix" }, - { Opt_unix, "unix" }, - { Opt_unix, "linux" }, - { Opt_unix, "posix" }, - { Opt_nocase, "nocase" }, - { Opt_nocase, "ignorecase" }, - { Opt_brl, "brl" }, - { Opt_nobrl, "nobrl" }, - { Opt_handlecache, "handlecache" }, - { Opt_nohandlecache, "nohandlecache" }, - { Opt_nobrl, "nolock" }, - { Opt_forcemandatorylock, "forcemandatorylock" }, - { Opt_forcemandatorylock, "forcemand" }, - { Opt_setuids, "setuids" }, - { Opt_nosetuids, "nosetuids" }, - { Opt_setuidfromacl, "idsfromsid" }, - { Opt_dynperm, "dynperm" }, - { Opt_nodynperm, "nodynperm" }, - { Opt_nohard, "nohard" }, - { Opt_nosoft, "nosoft" }, - { Opt_nointr, "nointr" }, - { Opt_intr, "intr" }, - { Opt_nostrictsync, "nostrictsync" }, - { Opt_strictsync, "strictsync" }, - { Opt_serverino, "serverino" }, - { Opt_noserverino, "noserverino" }, - { Opt_rwpidforward, "rwpidforward" }, - { Opt_modesid, "modefromsid" }, - { Opt_cifsacl, "cifsacl" }, - { Opt_nocifsacl, "nocifsacl" }, - { Opt_acl, "acl" }, - { Opt_noacl, "noacl" }, - { Opt_locallease, "locallease" }, - { Opt_sign, "sign" }, - { Opt_ignore_signature, "signloosely" }, - { Opt_seal, "seal" }, - { Opt_noac, "noac" }, - { Opt_fsc, "fsc" }, - { Opt_mfsymlinks, "mfsymlinks" }, - { Opt_multiuser, "multiuser" }, - { Opt_sloppy, "sloppy" }, - { Opt_nosharesock, "nosharesock" }, - { Opt_persistent, "persistenthandles"}, - { Opt_nopersistent, "nopersistenthandles"}, - { Opt_resilient, "resilienthandles"}, - { Opt_noresilient, "noresilienthandles"}, - { Opt_domainauto, "domainauto"}, - { Opt_rdma, "rdma"}, - { Opt_multichannel, "multichannel" }, - { Opt_nomultichannel, "nomultichannel" }, - - { Opt_backupuid, "backupuid=%s" }, - { Opt_backupgid, "backupgid=%s" }, - { Opt_uid, "uid=%s" }, - { Opt_cruid, "cruid=%s" }, - { Opt_gid, "gid=%s" }, - { Opt_file_mode, "file_mode=%s" }, - { Opt_dirmode, "dirmode=%s" }, - { Opt_dirmode, "dir_mode=%s" }, - { Opt_port, "port=%s" }, - { Opt_min_enc_offload, "esize=%s" }, - { Opt_blocksize, "bsize=%s" }, - { Opt_rsize, "rsize=%s" }, - { Opt_wsize, "wsize=%s" }, - { Opt_actimeo, "actimeo=%s" }, - { Opt_handletimeout, "handletimeout=%s" }, - { Opt_echo_interval, "echo_interval=%s" }, - { Opt_max_credits, "max_credits=%s" }, - { Opt_snapshot, "snapshot=%s" }, - { Opt_max_channels, "max_channels=%s" }, - { Opt_compress, "compress=%s" }, - - { Opt_blank_user, "user=" }, - { Opt_blank_user, "username=" }, - { Opt_user, "user=%s" }, - { Opt_user, "username=%s" }, - { Opt_blank_pass, "pass=" }, - { Opt_blank_pass, "password=" }, - { Opt_pass, "pass=%s" }, - { Opt_pass, "password=%s" }, - { Opt_blank_ip, "ip=" }, - { Opt_blank_ip, "addr=" }, - { Opt_ip, "ip=%s" }, - { Opt_ip, "addr=%s" }, - { Opt_ignore, "unc=%s" }, - { Opt_ignore, "target=%s" }, - { Opt_ignore, "path=%s" }, - { Opt_domain, "dom=%s" }, - { Opt_domain, "domain=%s" }, - { Opt_domain, "workgroup=%s" }, - { Opt_srcaddr, "srcaddr=%s" }, - { Opt_ignore, "prefixpath=%s" }, - { Opt_iocharset, "iocharset=%s" }, - { Opt_netbiosname, "netbiosname=%s" }, - { Opt_servern, "servern=%s" }, - { Opt_ver, "ver=%s" }, - { Opt_vers, "vers=%s" }, - { Opt_sec, "sec=%s" }, - { Opt_cache, "cache=%s" }, - - { Opt_ignore, "cred" }, - { Opt_ignore, "credentials" }, - { Opt_ignore, "cred=%s" }, - { Opt_ignore, "credentials=%s" }, - { Opt_ignore, "guest" }, - { Opt_ignore, "rw" }, - { Opt_ignore, "ro" }, - { Opt_ignore, "suid" }, - { Opt_ignore, "nosuid" }, - { Opt_ignore, "exec" }, - { Opt_ignore, "noexec" }, - { Opt_ignore, "nodev" }, - { Opt_ignore, "noauto" }, - { Opt_ignore, "dev" }, - { Opt_ignore, "mand" }, - { Opt_ignore, "nomand" }, - { Opt_ignore, "relatime" }, - { Opt_ignore, "_netdev" }, - { Opt_rootfs, "rootfs" }, - - { Opt_err, NULL } -}; - static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); @@ -1208,960 +1058,6 @@ extract_hostname(const char *unc) return dst; } -static int get_option_ul(substring_t args[], unsigned long *option) -{ - int rc; - char *string; - - string = match_strdup(args); - if (string == NULL) - return -ENOMEM; - rc = kstrtoul(string, 0, option); - kfree(string); - - return rc; -} - -static int get_option_uid(substring_t args[], kuid_t *result) -{ - unsigned long value; - kuid_t uid; - int rc; - - rc = get_option_ul(args, &value); - if (rc) - return rc; - - uid = make_kuid(current_user_ns(), value); - if (!uid_valid(uid)) - return -EINVAL; - - *result = uid; - return 0; -} - -static int get_option_gid(substring_t args[], kgid_t *result) -{ - unsigned long value; - kgid_t gid; - int rc; - - rc = get_option_ul(args, &value); - if (rc) - return rc; - - gid = make_kgid(current_user_ns(), value); - if (!gid_valid(gid)) - return -EINVAL; - - *result = gid; - return 0; -} - -static int -cifs_parse_mount_options(const char *mountdata, const char *devname, - struct smb3_fs_context *ctx, bool is_smb3) -{ - char *data, *end; - char *mountdata_copy = NULL, *options; - unsigned int temp_len, i, j; - char separator[2]; - short int override_uid = -1; - short int override_gid = -1; - bool uid_specified = false; - bool gid_specified = false; - bool sloppy = false; - char *invalid = NULL; - char *nodename = utsname()->nodename; - char *string = NULL; - char *tmp_end, *value; - char delim; - bool got_ip = false; - bool got_version = false; - unsigned short port = 0; - struct sockaddr *dstaddr = (struct sockaddr *)&ctx->dstaddr; - - separator[0] = ','; - separator[1] = 0; - delim = separator[0]; - - /* ensure we always start with zeroed-out ctx */ - memset(ctx, 0, sizeof(*ctx)); - - /* - * does not have to be perfect mapping since field is - * informational, only used for servers that do not support - * port 445 and it can be overridden at mount time - */ - memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); - for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) - ctx->source_rfc1001_name[i] = toupper(nodename[i]); - - ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0; - /* null target name indicates to use *SMBSERVR default called name - if we end up sending RFC1001 session initialize */ - ctx->target_rfc1001_name[0] = 0; - ctx->cred_uid = current_uid(); - ctx->linux_uid = current_uid(); - ctx->linux_gid = current_gid(); - ctx->bsize = 1024 * 1024; /* can improve cp performance significantly */ - /* - * default to SFM style remapping of seven reserved characters - * unless user overrides it or we negotiate CIFS POSIX where - * it is unnecessary. Can not simultaneously use more than one mapping - * since then readdir could list files that open could not open - */ - ctx->remap = true; - - /* default to only allowing write access to owner of the mount */ - ctx->dir_mode = ctx->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; - - /* ctx->retry default is 0 (i.e. "soft" limited retry not hard retry) */ - /* default is always to request posix paths. */ - ctx->posix_paths = 1; - /* default to using server inode numbers where available */ - ctx->server_ino = 1; - - /* default is to use strict cifs caching semantics */ - ctx->strict_io = true; - - ctx->actimeo = CIFS_DEF_ACTIMEO; - - /* Most clients set timeout to 0, allows server to use its default */ - ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ - - /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ - ctx->ops = &smb30_operations; - ctx->vals = &smbdefault_values; - - ctx->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; - - /* default to no multichannel (single server connection) */ - ctx->multichannel = false; - ctx->max_channels = 1; - - if (!mountdata) - goto cifs_parse_mount_err; - - mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL); - if (!mountdata_copy) - goto cifs_parse_mount_err; - - options = mountdata_copy; - end = options + strlen(options); - - if (strncmp(options, "sep=", 4) == 0) { - if (options[4] != 0) { - separator[0] = options[4]; - options += 5; - } else { - cifs_dbg(FYI, "Null separator not allowed\n"); - } - } - ctx->backupuid_specified = false; /* no backup intent for a user */ - ctx->backupgid_specified = false; /* no backup intent for a group */ - - switch (smb3_parse_devname(devname, ctx)) { - case 0: - break; - case -ENOMEM: - cifs_dbg(VFS, "Unable to allocate memory for devname\n"); - goto cifs_parse_mount_err; - case -EINVAL: - cifs_dbg(VFS, "Malformed UNC in devname\n"); - goto cifs_parse_mount_err; - default: - cifs_dbg(VFS, "Unknown error parsing devname\n"); - goto cifs_parse_mount_err; - } - - while ((data = strsep(&options, separator)) != NULL) { - substring_t args[MAX_OPT_ARGS]; - unsigned long option; - int token; - - if (!*data) - continue; - - token = match_token(data, cifs_mount_option_tokens, args); - - switch (token) { - - /* Ingnore the following */ - case Opt_ignore: - break; - - /* Boolean values */ - case Opt_user_xattr: - ctx->no_xattr = 0; - break; - case Opt_nouser_xattr: - ctx->no_xattr = 1; - break; - case Opt_forceuid: - override_uid = 1; - break; - case Opt_noforceuid: - override_uid = 0; - break; - case Opt_forcegid: - override_gid = 1; - break; - case Opt_noforcegid: - override_gid = 0; - break; - case Opt_noblocksend: - ctx->noblocksnd = 1; - break; - case Opt_noautotune: - ctx->noautotune = 1; - break; - case Opt_nolease: - ctx->no_lease = 1; - break; - case Opt_hard: - ctx->retry = 1; - break; - case Opt_soft: - ctx->retry = 0; - break; - case Opt_perm: - ctx->noperm = 0; - break; - case Opt_noperm: - ctx->noperm = 1; - break; - case Opt_nodelete: - ctx->nodelete = 1; - break; - case Opt_mapchars: - ctx->sfu_remap = true; - ctx->remap = false; /* disable SFM mapping */ - break; - case Opt_nomapchars: - ctx->sfu_remap = false; - break; - case Opt_mapposix: - ctx->remap = true; - ctx->sfu_remap = false; /* disable SFU mapping */ - break; - case Opt_nomapposix: - ctx->remap = false; - break; - case Opt_sfu: - ctx->sfu_emul = 1; - break; - case Opt_nosfu: - ctx->sfu_emul = 0; - break; - case Opt_nodfs: - ctx->nodfs = 1; - break; - case Opt_rootfs: -#ifdef CONFIG_CIFS_ROOT - ctx->rootfs = true; -#endif - break; - case Opt_posixpaths: - ctx->posix_paths = 1; - break; - case Opt_noposixpaths: - ctx->posix_paths = 0; - break; - case Opt_nounix: - if (ctx->linux_ext) - cifs_dbg(VFS, - "conflicting unix mount options\n"); - ctx->no_linux_ext = 1; - break; - case Opt_unix: - if (ctx->no_linux_ext) - cifs_dbg(VFS, - "conflicting unix mount options\n"); - ctx->linux_ext = 1; - break; - case Opt_nocase: - ctx->nocase = 1; - break; - case Opt_brl: - ctx->nobrl = 0; - break; - case Opt_nobrl: - ctx->nobrl = 1; - /* - * turn off mandatory locking in mode - * if remote locking is turned off since the - * local vfs will do advisory - */ - if (ctx->file_mode == - (S_IALLUGO & ~(S_ISUID | S_IXGRP))) - ctx->file_mode = S_IALLUGO; - break; - case Opt_nohandlecache: - ctx->nohandlecache = 1; - break; - case Opt_handlecache: - ctx->nohandlecache = 0; - break; - case Opt_forcemandatorylock: - ctx->mand_lock = 1; - break; - case Opt_setuids: - ctx->setuids = 1; - break; - case Opt_nosetuids: - ctx->setuids = 0; - break; - case Opt_setuidfromacl: - ctx->setuidfromacl = 1; - break; - case Opt_dynperm: - ctx->dynperm = true; - break; - case Opt_nodynperm: - ctx->dynperm = false; - break; - case Opt_nohard: - ctx->retry = 0; - break; - case Opt_nosoft: - ctx->retry = 1; - break; - case Opt_nointr: - ctx->intr = 0; - break; - case Opt_intr: - ctx->intr = 1; - break; - case Opt_nostrictsync: - ctx->nostrictsync = 1; - break; - case Opt_strictsync: - ctx->nostrictsync = 0; - break; - case Opt_serverino: - ctx->server_ino = 1; - break; - case Opt_noserverino: - ctx->server_ino = 0; - break; - case Opt_rwpidforward: - ctx->rwpidforward = 1; - break; - case Opt_modesid: - ctx->mode_ace = 1; - break; - case Opt_cifsacl: - ctx->cifs_acl = 1; - break; - case Opt_nocifsacl: - ctx->cifs_acl = 0; - break; - case Opt_acl: - ctx->no_psx_acl = 0; - break; - case Opt_noacl: - ctx->no_psx_acl = 1; - break; - case Opt_locallease: - ctx->local_lease = 1; - break; - case Opt_sign: - ctx->sign = true; - break; - case Opt_ignore_signature: - ctx->sign = true; - ctx->ignore_signature = true; - break; - case Opt_seal: - /* we do not do the following in secFlags because seal - * is a per tree connection (mount) not a per socket - * or per-smb connection option in the protocol - * ctx->secFlg |= CIFSSEC_MUST_SEAL; - */ - ctx->seal = 1; - break; - case Opt_noac: - pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); - break; - case Opt_fsc: -#ifndef CONFIG_CIFS_FSCACHE - cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); - goto cifs_parse_mount_err; -#endif - ctx->fsc = true; - break; - case Opt_mfsymlinks: - ctx->mfsymlinks = true; - break; - case Opt_multiuser: - ctx->multiuser = true; - break; - case Opt_sloppy: - sloppy = true; - break; - case Opt_nosharesock: - ctx->nosharesock = true; - break; - case Opt_nopersistent: - ctx->nopersistent = true; - if (ctx->persistent) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); - goto cifs_parse_mount_err; - } - break; - case Opt_persistent: - ctx->persistent = true; - if ((ctx->nopersistent) || (ctx->resilient)) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); - goto cifs_parse_mount_err; - } - break; - case Opt_resilient: - ctx->resilient = true; - if (ctx->persistent) { - cifs_dbg(VFS, - "persistenthandles mount options conflict\n"); - goto cifs_parse_mount_err; - } - break; - case Opt_noresilient: - ctx->resilient = false; /* already the default */ - break; - case Opt_domainauto: - ctx->domainauto = true; - break; - case Opt_rdma: - ctx->rdma = true; - break; - case Opt_multichannel: - ctx->multichannel = true; - /* if number of channels not specified, default to 2 */ - if (ctx->max_channels < 2) - ctx->max_channels = 2; - break; - case Opt_nomultichannel: - ctx->multichannel = false; - ctx->max_channels = 1; - break; - case Opt_compress: - ctx->compression = UNKNOWN_TYPE; - cifs_dbg(VFS, - "SMB3 compression support is experimental\n"); - break; - - /* Numeric Values */ - case Opt_backupuid: - if (get_option_uid(args, &ctx->backupuid)) { - cifs_dbg(VFS, "%s: Invalid backupuid value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->backupuid_specified = true; - break; - case Opt_backupgid: - if (get_option_gid(args, &ctx->backupgid)) { - cifs_dbg(VFS, "%s: Invalid backupgid value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->backupgid_specified = true; - break; - case Opt_uid: - if (get_option_uid(args, &ctx->linux_uid)) { - cifs_dbg(VFS, "%s: Invalid uid value\n", - __func__); - goto cifs_parse_mount_err; - } - uid_specified = true; - break; - case Opt_cruid: - if (get_option_uid(args, &ctx->cred_uid)) { - cifs_dbg(VFS, "%s: Invalid cruid value\n", - __func__); - goto cifs_parse_mount_err; - } - break; - case Opt_gid: - if (get_option_gid(args, &ctx->linux_gid)) { - cifs_dbg(VFS, "%s: Invalid gid value\n", - __func__); - goto cifs_parse_mount_err; - } - gid_specified = true; - break; - case Opt_file_mode: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid file_mode value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->file_mode = option; - break; - case Opt_dirmode: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid dir_mode value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->dir_mode = option; - break; - case Opt_port: - if (get_option_ul(args, &option) || - option > USHRT_MAX) { - cifs_dbg(VFS, "%s: Invalid port value\n", - __func__); - goto cifs_parse_mount_err; - } - port = (unsigned short)option; - break; - case Opt_min_enc_offload: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n"); - goto cifs_parse_mount_err; - } - ctx->min_offload = option; - break; - case Opt_blocksize: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid blocksize value\n", - __func__); - goto cifs_parse_mount_err; - } - /* - * inode blocksize realistically should never need to be - * less than 16K or greater than 16M and default is 1MB. - * Note that small inode block sizes (e.g. 64K) can lead - * to very poor performance of common tools like cp and scp - */ - if ((option < CIFS_MAX_MSGSIZE) || - (option > (4 * SMB3_DEFAULT_IOSIZE))) { - cifs_dbg(VFS, "%s: Invalid blocksize\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->bsize = option; - break; - case Opt_rsize: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid rsize value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->rsize = option; - break; - case Opt_wsize: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid wsize value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->wsize = option; - break; - case Opt_actimeo: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid actimeo value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->actimeo = HZ * option; - if (ctx->actimeo > CIFS_MAX_ACTIMEO) { - cifs_dbg(VFS, "attribute cache timeout too large\n"); - goto cifs_parse_mount_err; - } - break; - case Opt_handletimeout: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid handletimeout value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->handle_timeout = option; - if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { - cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); - goto cifs_parse_mount_err; - } - break; - case Opt_echo_interval: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid echo interval value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->echo_interval = option; - break; - case Opt_snapshot: - if (get_option_ul(args, &option)) { - cifs_dbg(VFS, "%s: Invalid snapshot time\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->snapshot_time = option; - break; - case Opt_max_credits: - if (get_option_ul(args, &option) || (option < 20) || - (option > 60000)) { - cifs_dbg(VFS, "%s: Invalid max_credits value\n", - __func__); - goto cifs_parse_mount_err; - } - ctx->max_credits = option; - break; - case Opt_max_channels: - if (get_option_ul(args, &option) || option < 1 || - option > CIFS_MAX_CHANNELS) { - cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n", - __func__, CIFS_MAX_CHANNELS); - goto cifs_parse_mount_err; - } - ctx->max_channels = option; - break; - - /* String Arguments */ - - case Opt_blank_user: - /* null user, ie. anonymous authentication */ - ctx->nullauth = 1; - ctx->username = NULL; - break; - case Opt_user: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (strnlen(string, CIFS_MAX_USERNAME_LEN) > - CIFS_MAX_USERNAME_LEN) { - pr_warn("username too long\n"); - goto cifs_parse_mount_err; - } - - kfree(ctx->username); - ctx->username = kstrdup(string, GFP_KERNEL); - if (!ctx->username) - goto cifs_parse_mount_err; - break; - case Opt_blank_pass: - /* passwords have to be handled differently - * to allow the character used for deliminator - * to be passed within them - */ - - /* - * Check if this is a case where the password - * starts with a delimiter - */ - tmp_end = strchr(data, '='); - tmp_end++; - if (!(tmp_end < end && tmp_end[1] == delim)) { - /* No it is not. Set the password to NULL */ - kfree_sensitive(ctx->password); - ctx->password = NULL; - break; - } - fallthrough; /* to Opt_pass below */ - case Opt_pass: - /* Obtain the value string */ - value = strchr(data, '='); - value++; - - /* Set tmp_end to end of the string */ - tmp_end = (char *) value + strlen(value); - - /* Check if following character is the deliminator - * If yes, we have encountered a double deliminator - * reset the NULL character to the deliminator - */ - if (tmp_end < end && tmp_end[1] == delim) { - tmp_end[0] = delim; - - /* Keep iterating until we get to a single - * deliminator OR the end - */ - while ((tmp_end = strchr(tmp_end, delim)) - != NULL && (tmp_end[1] == delim)) { - tmp_end = (char *) &tmp_end[2]; - } - - /* Reset var options to point to next element */ - if (tmp_end) { - tmp_end[0] = '\0'; - options = (char *) &tmp_end[1]; - } else - /* Reached the end of the mount option - * string */ - options = end; - } - - kfree_sensitive(ctx->password); - /* Now build new password string */ - temp_len = strlen(value); - ctx->password = kzalloc(temp_len+1, GFP_KERNEL); - if (ctx->password == NULL) { - pr_warn("no memory for password\n"); - goto cifs_parse_mount_err; - } - - for (i = 0, j = 0; i < temp_len; i++, j++) { - ctx->password[j] = value[i]; - if ((value[i] == delim) && - value[i+1] == delim) - /* skip the second deliminator */ - i++; - } - ctx->password[j] = '\0'; - break; - case Opt_blank_ip: - /* FIXME: should this be an error instead? */ - got_ip = false; - break; - case Opt_ip: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (!cifs_convert_address(dstaddr, string, - strlen(string))) { - pr_err("bad ip= option (%s)\n", string); - goto cifs_parse_mount_err; - } - got_ip = true; - break; - case Opt_domain: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN) - == CIFS_MAX_DOMAINNAME_LEN) { - pr_warn("domain name too long\n"); - goto cifs_parse_mount_err; - } - - kfree(ctx->domainname); - ctx->domainname = kstrdup(string, GFP_KERNEL); - if (!ctx->domainname) { - pr_warn("no memory for domainname\n"); - goto cifs_parse_mount_err; - } - cifs_dbg(FYI, "Domain name set\n"); - break; - case Opt_srcaddr: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (!cifs_convert_address( - (struct sockaddr *)&ctx->srcaddr, - string, strlen(string))) { - pr_warn("Could not parse srcaddr: %s\n", - string); - goto cifs_parse_mount_err; - } - break; - case Opt_iocharset: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (strnlen(string, 1024) >= 65) { - pr_warn("iocharset name too long\n"); - goto cifs_parse_mount_err; - } - - if (strncasecmp(string, "default", 7) != 0) { - kfree(ctx->iocharset); - ctx->iocharset = kstrdup(string, - GFP_KERNEL); - if (!ctx->iocharset) { - pr_warn("no memory for charset\n"); - goto cifs_parse_mount_err; - } - } - /* if iocharset not set then load_nls_default - * is used by caller - */ - cifs_dbg(FYI, "iocharset set to %s\n", string); - break; - case Opt_netbiosname: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - memset(ctx->source_rfc1001_name, 0x20, - RFC1001_NAME_LEN); - /* - * FIXME: are there cases in which a comma can - * be valid in workstation netbios name (and - * need special handling)? - */ - for (i = 0; i < RFC1001_NAME_LEN; i++) { - /* don't ucase netbiosname for user */ - if (string[i] == 0) - break; - ctx->source_rfc1001_name[i] = string[i]; - } - /* The string has 16th byte zero still from - * set at top of the function - */ - if (i == RFC1001_NAME_LEN && string[i] != 0) - pr_warn("netbiosname longer than 15 truncated\n"); - break; - case Opt_servern: - /* servernetbiosname specified override *SMBSERVER */ - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - /* last byte, type, is 0x20 for servr type */ - memset(ctx->target_rfc1001_name, 0x20, - RFC1001_NAME_LEN_WITH_NULL); - - /* BB are there cases in which a comma can be - valid in this workstation netbios name - (and need special handling)? */ - - /* user or mount helper must uppercase the - netbios name */ - for (i = 0; i < 15; i++) { - if (string[i] == 0) - break; - ctx->target_rfc1001_name[i] = string[i]; - } - /* The string has 16th byte zero still from - set at top of the function */ - if (i == RFC1001_NAME_LEN && string[i] != 0) - pr_warn("server netbiosname longer than 15 truncated\n"); - break; - case Opt_ver: - /* version of mount userspace tools, not dialect */ - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - /* If interface changes in mount.cifs bump to new ver */ - if (strncasecmp(string, "1", 1) == 0) { - if (strlen(string) > 1) { - pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n", - string); - goto cifs_parse_mount_err; - } - /* This is the default */ - break; - } - /* For all other value, error */ - pr_warn("Invalid mount helper version specified\n"); - goto cifs_parse_mount_err; - case Opt_vers: - /* protocol version (dialect) */ - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (cifs_parse_smb_version(string, ctx, is_smb3) != 0) - goto cifs_parse_mount_err; - got_version = true; - break; - case Opt_sec: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (cifs_parse_security_flavors(string, ctx) != 0) - goto cifs_parse_mount_err; - break; - case Opt_cache: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (cifs_parse_cache_flavor(string, ctx) != 0) - goto cifs_parse_mount_err; - break; - default: - /* - * An option we don't recognize. Save it off for later - * if we haven't already found one - */ - if (!invalid) - invalid = data; - break; - } - /* Free up any allocated string */ - kfree(string); - string = NULL; - } - - if (!sloppy && invalid) { - pr_err("Unknown mount option \"%s\"\n", invalid); - goto cifs_parse_mount_err; - } - - if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) { - cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n"); - goto cifs_parse_mount_err; - } - -#ifndef CONFIG_KEYS - /* Muliuser mounts require CONFIG_KEYS support */ - if (ctx->multiuser) { - cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); - goto cifs_parse_mount_err; - } -#endif - if (!ctx->UNC) { - cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n"); - goto cifs_parse_mount_err; - } - - /* make sure UNC has a share name */ - if (!strchr(ctx->UNC + 3, '\\')) { - cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n"); - goto cifs_parse_mount_err; - } - - if (!got_ip) { - int len; - const char *slash; - - /* No ip= option specified? Try to get it from UNC */ - /* Use the address part of the UNC. */ - slash = strchr(&ctx->UNC[2], '\\'); - len = slash - &ctx->UNC[2]; - if (!cifs_convert_address(dstaddr, &ctx->UNC[2], len)) { - pr_err("Unable to determine destination address\n"); - goto cifs_parse_mount_err; - } - } - - /* set the port that we got earlier */ - cifs_set_port(dstaddr, port); - - if (uid_specified) - ctx->override_uid = override_uid; - else if (override_uid == 1) - pr_notice("ignoring forceuid mount option specified with no uid= option\n"); - - if (gid_specified) - ctx->override_gid = override_gid; - else if (override_gid == 1) - pr_notice("ignoring forcegid mount option specified with no gid= option\n"); - - if (got_version == false) - pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n"); - - kfree(mountdata_copy); - return 0; - -out_nomem: - pr_warn("Could not allocate temporary buffer\n"); -cifs_parse_mount_err: - kfree(string); - kfree(mountdata_copy); - return 1; -} - /** Returns true if srcaddr isn't specified and rhs isn't * specified, or if srcaddr is specified and * matches the IP address of the rhs argument. @@ -3903,12 +2799,25 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, void cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx) { + /* + * Make sure this stays in sync with smb3_fs_context_dup() + */ + kfree(ctx->mount_options); + ctx->mount_options = NULL; kfree(ctx->username); + ctx->username = NULL; kfree_sensitive(ctx->password); + ctx->password = NULL; kfree(ctx->UNC); + ctx->UNC = NULL; kfree(ctx->domainname); + ctx->domainname = NULL; + kfree(ctx->nodename); + ctx->nodename = NULL; kfree(ctx->iocharset); + ctx->iocharset = NULL; kfree(ctx->prepath); + ctx->prepath = NULL; } void @@ -4135,8 +3044,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, mdata = NULL; } else { cifs_cleanup_volume_info_contents(ctx); - rc = cifs_setup_volume_info(ctx, mdata, - fake_devname, false); + rc = cifs_setup_volume_info(ctx); } kfree(fake_devname); kfree(cifs_sb->mountdata); @@ -4205,11 +3113,9 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); mdata = NULL; - } else { - cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname); - rc = cifs_setup_volume_info((struct smb3_fs_context *)&fake_ctx, - mdata, fake_devname, false); - } + } else + rc = cifs_setup_volume_info(&fake_ctx); + kfree(mdata); kfree(fake_devname); @@ -4230,7 +3136,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, rc = update_vol_info(tgt_it, &fake_ctx, ctx); } } - cifs_cleanup_volume_info_contents((struct smb3_fs_context *)&fake_ctx); + cifs_cleanup_volume_info_contents(&fake_ctx); return rc; } @@ -4276,15 +3182,14 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_ } #endif +/* TODO: all callers to this are broken. We are not parsing mount_options here + * we should pass a clone of the original context? + */ int -cifs_setup_volume_info(struct smb3_fs_context *ctx, char *mount_data, - const char *devname, bool is_smb3) +cifs_setup_volume_info(struct smb3_fs_context *ctx) { int rc = 0; - if (cifs_parse_mount_options(mount_data, devname, ctx, is_smb3)) - return -EINVAL; - if (ctx->nullauth) { cifs_dbg(FYI, "Anonymous login\n"); kfree(ctx->username); @@ -4315,25 +3220,6 @@ cifs_setup_volume_info(struct smb3_fs_context *ctx, char *mount_data, return rc; } -struct smb3_fs_context * -cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3) -{ - int rc; - struct smb3_fs_context *ctx; - - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); - - rc = cifs_setup_volume_info(ctx, mount_data, devname, is_smb3); - if (rc) { - cifs_cleanup_volume_info(ctx); - ctx = ERR_PTR(rc); - } - - return ctx; -} - static int cifs_are_all_path_components_accessible(struct TCP_Server_Info *server, unsigned int xid, diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 2b77d39d7d22..dde859c21f1a 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -18,9 +18,9 @@ #include "cifs_debug.h" #include "cifs_unicode.h" #include "smb2glob.h" +#include "fs_context.h" #include "dfs_cache.h" -#include "fs_context.h" #define CACHE_HTABLE_SIZE 32 #define CACHE_MAX_ENTRIES 64 @@ -1142,14 +1142,14 @@ out_unlock: } /** - * dfs_cache_add_vol - add a cifs volume during mount() that will be handled by + * dfs_cache_add_vol - add a cifs context during mount() that will be handled by * DFS cache refresh worker. * * @mntdata: mount data. * @ctx: cifs context. * @fullpath: origin full path. * - * Return zero if volume was set up correctly, otherwise non-zero. + * Return zero if context was set up correctly, otherwise non-zero. */ int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fullpath) { @@ -1453,7 +1453,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, goto out; } - rc = cifs_setup_volume_info(&ctx, mdata, devname, false); + rc = cifs_setup_volume_info(&ctx); kfree(devname); if (rc) { diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 84354cd4c960..9120d148c5f1 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -6,9 +6,32 @@ * David Howells */ +/* +#include +#include +#include +#include +#include +#include +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "cifsfs.h" +#include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" +#include "cifs_unicode.h" #include "cifs_debug.h" +#include "cifs_fs_sb.h" +#include "ntlmssp.h" +#include "nterr.h" +#include "rfc1002pdu.h" #include "fs_context.h" static const match_table_t cifs_smb_version_tokens = { @@ -25,77 +48,6 @@ static const match_table_t cifs_smb_version_tokens = { { Smb_version_err, NULL } }; -int -cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) -{ - substring_t args[MAX_OPT_ARGS]; - - switch (match_token(value, cifs_smb_version_tokens, args)) { -#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY - case Smb_1: - if (disable_legacy_dialects) { - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); - return 1; - } - if (is_smb3) { - cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); - return 1; - } - cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); - ctx->ops = &smb1_operations; - ctx->vals = &smb1_values; - break; - case Smb_20: - if (disable_legacy_dialects) { - cifs_dbg(VFS, "mount with legacy dialect disabled\n"); - return 1; - } - if (is_smb3) { - cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); - return 1; - } - ctx->ops = &smb20_operations; - ctx->vals = &smb20_values; - break; -#else - case Smb_1: - cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); - return 1; - case Smb_20: - cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); - return 1; -#endif /* CIFS_ALLOW_INSECURE_LEGACY */ - case Smb_21: - ctx->ops = &smb21_operations; - ctx->vals = &smb21_values; - break; - case Smb_30: - ctx->ops = &smb30_operations; - ctx->vals = &smb30_values; - break; - case Smb_302: - ctx->ops = &smb30_operations; /* currently identical with 3.0 */ - ctx->vals = &smb302_values; - break; - case Smb_311: - ctx->ops = &smb311_operations; - ctx->vals = &smb311_values; - break; - case Smb_3any: - ctx->ops = &smb30_operations; /* currently identical with 3.0 */ - ctx->vals = &smb3any_values; - break; - case Smb_default: - ctx->ops = &smb30_operations; /* currently identical with 3.0 */ - ctx->vals = &smbdefault_values; - break; - default: - cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); - return 1; - } - return 0; -} - static const match_table_t cifs_secflavor_tokens = { { Opt_sec_krb5, "krb5" }, { Opt_sec_krb5i, "krb5i" }, @@ -113,7 +65,117 @@ static const match_table_t cifs_secflavor_tokens = { { Opt_sec_err, NULL } }; -int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) +const struct fs_parameter_spec smb3_fs_parameters[] = { + /* Mount options that take no arguments */ + fsparam_flag_no("user_xattr", Opt_user_xattr), + fsparam_flag_no("forceuid", Opt_forceuid), + fsparam_flag_no("multichannel", Opt_multichannel), + fsparam_flag_no("forcegid", Opt_forcegid), + fsparam_flag("noblocksend", Opt_noblocksend), + fsparam_flag("noautotune", Opt_noautotune), + fsparam_flag("nolease", Opt_nolease), + fsparam_flag_no("hard", Opt_hard), + fsparam_flag_no("soft", Opt_soft), + fsparam_flag_no("perm", Opt_perm), + fsparam_flag("nodelete", Opt_nodelete), + fsparam_flag_no("mapposix", Opt_mapposix), + fsparam_flag("mapchars", Opt_mapchars), + fsparam_flag("nomapchars", Opt_nomapchars), + fsparam_flag_no("sfu", Opt_sfu), + fsparam_flag("nodfs", Opt_nodfs), + fsparam_flag_no("posixpaths", Opt_posixpaths), + fsparam_flag_no("unix", Opt_unix), + fsparam_flag_no("linux", Opt_unix), + fsparam_flag_no("posix", Opt_unix), + fsparam_flag("nocase", Opt_nocase), + fsparam_flag("ignorecase", Opt_nocase), + fsparam_flag_no("brl", Opt_brl), + fsparam_flag_no("handlecache", Opt_handlecache), + fsparam_flag("forcemandatorylock", Opt_forcemandatorylock), + fsparam_flag("forcemand", Opt_forcemandatorylock), + fsparam_flag("setuidfromacl", Opt_setuidfromacl), + fsparam_flag_no("setuids", Opt_setuids), + fsparam_flag_no("dynperm", Opt_dynperm), + fsparam_flag_no("intr", Opt_intr), + fsparam_flag_no("strictsync", Opt_strictsync), + fsparam_flag_no("serverino", Opt_serverino), + fsparam_flag("rwpidforward", Opt_rwpidforward), + fsparam_flag("cifsacl", Opt_cifsacl), + fsparam_flag_no("acl", Opt_acl), + fsparam_flag("locallease", Opt_locallease), + fsparam_flag("sign", Opt_sign), + fsparam_flag("ignore_signature", Opt_ignore_signature), + fsparam_flag("seal", Opt_seal), + fsparam_flag("noac", Opt_noac), + fsparam_flag("fsc", Opt_fsc), + fsparam_flag("mfsymlinks", Opt_mfsymlinks), + fsparam_flag("multiuser", Opt_multiuser), + fsparam_flag("sloppy", Opt_sloppy), + fsparam_flag("nosharesock", Opt_nosharesock), + fsparam_flag_no("persistent", Opt_persistent), + fsparam_flag_no("resilient", Opt_resilient), + fsparam_flag("domainauto", Opt_domainauto), + fsparam_flag("rdma", Opt_rdma), + fsparam_flag("modesid", Opt_modesid), + fsparam_flag("rootfs", Opt_rootfs), + fsparam_flag("compress", Opt_compress), + + /* Mount options which take numeric value */ + fsparam_u32("backupuid", Opt_backupuid), + fsparam_u32("backupgid", Opt_backupgid), + fsparam_u32("uid", Opt_uid), + fsparam_u32("cruid", Opt_cruid), + fsparam_u32("gid", Opt_gid), + fsparam_u32("file_mode", Opt_file_mode), + fsparam_u32("dirmode", Opt_dirmode), + fsparam_u32("dir_mode", Opt_dirmode), + fsparam_u32("port", Opt_port), + fsparam_u32("min_enc_offload", Opt_min_enc_offload), + fsparam_u32("bsize", Opt_blocksize), + fsparam_u32("rsize", Opt_rsize), + fsparam_u32("wsize", Opt_wsize), + fsparam_u32("actimeo", Opt_actimeo), + fsparam_u32("echo_interval", Opt_echo_interval), + fsparam_u32("max_credits", Opt_max_credits), + fsparam_u32("handletimeout", Opt_handletimeout), + fsparam_u32("snapshot", Opt_snapshot), + fsparam_u32("max_channels", Opt_max_channels), + + /* Mount options which take string value */ + fsparam_string("source", Opt_source), + fsparam_string("unc", Opt_source), + fsparam_string("user", Opt_user), + fsparam_string("username", Opt_user), + fsparam_string("pass", Opt_pass), + fsparam_string("password", Opt_pass), + fsparam_string("ip", Opt_ip), + fsparam_string("addr", Opt_ip), + fsparam_string("domain", Opt_domain), + fsparam_string("dom", Opt_domain), + fsparam_string("srcaddr", Opt_srcaddr), + fsparam_string("iocharset", Opt_iocharset), + fsparam_string("netbiosname", Opt_netbiosname), + fsparam_string("servern", Opt_servern), + fsparam_string("ver", Opt_ver), + fsparam_string("vers", Opt_vers), + fsparam_string("sec", Opt_sec), + fsparam_string("cache", Opt_cache), + + /* Arguments that should be ignored */ + fsparam_flag("guest", Opt_ignore), + fsparam_flag("noatime", Opt_ignore), + fsparam_flag("relatime", Opt_ignore), + fsparam_flag("_netdev", Opt_ignore), + fsparam_flag_no("suid", Opt_ignore), + fsparam_flag_no("exec", Opt_ignore), + fsparam_flag_no("dev", Opt_ignore), + fsparam_flag_no("mand", Opt_ignore), + fsparam_string("cred", Opt_ignore), + fsparam_string("credentials", Opt_ignore), +}; + +int +cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx) { substring_t args[MAX_OPT_ARGS]; @@ -239,6 +301,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx memcpy(new_ctx, ctx, sizeof(*ctx)); new_ctx->prepath = NULL; + new_ctx->mount_options = NULL; new_ctx->local_nls = NULL; new_ctx->nodename = NULL; new_ctx->username = NULL; @@ -251,6 +314,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx * Make sure to stay in sync with cifs_cleanup_volume_info_contents() */ DUP_CTX_STR(prepath); + DUP_CTX_STR(mount_options); DUP_CTX_STR(username); DUP_CTX_STR(password); DUP_CTX_STR(UNC); @@ -261,6 +325,77 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx return rc; } +static int +cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3) +{ + substring_t args[MAX_OPT_ARGS]; + + switch (match_token(value, cifs_smb_version_tokens, args)) { +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY + case Smb_1: + if (disable_legacy_dialects) { + cifs_dbg(VFS, "mount with legacy dialect disabled\n"); + return 1; + } + if (is_smb3) { + cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); + return 1; + } + cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); + ctx->ops = &smb1_operations; + ctx->vals = &smb1_values; + break; + case Smb_20: + if (disable_legacy_dialects) { + cifs_dbg(VFS, "mount with legacy dialect disabled\n"); + return 1; + } + if (is_smb3) { + cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); + return 1; + } + ctx->ops = &smb20_operations; + ctx->vals = &smb20_values; + break; +#else + case Smb_1: + cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); + return 1; + case Smb_20: + cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); + return 1; +#endif /* CIFS_ALLOW_INSECURE_LEGACY */ + case Smb_21: + ctx->ops = &smb21_operations; + ctx->vals = &smb21_values; + break; + case Smb_30: + ctx->ops = &smb30_operations; + ctx->vals = &smb30_values; + break; + case Smb_302: + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smb302_values; + break; + case Smb_311: + ctx->ops = &smb311_operations; + ctx->vals = &smb311_values; + break; + case Smb_3any: + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smb3any_values; + break; + case Smb_default: + ctx->ops = &smb30_operations; /* currently identical with 3.0 */ + ctx->vals = &smbdefault_values; + break; + default: + cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); + return 1; + } + return 0; +} + /* * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath * fields with the result. Returns 0 on success and an error otherwise @@ -316,3 +451,787 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx) return 0; } + +static void smb3_fs_context_free(struct fs_context *fc); +static int smb3_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param); +static int smb3_fs_context_parse_monolithic(struct fs_context *fc, + void *data); +static int smb3_get_tree(struct fs_context *fc); +static int smb3_reconfigure(struct fs_context *fc); + +static const struct fs_context_operations smb3_fs_context_ops = { + .free = smb3_fs_context_free, + .parse_param = smb3_fs_context_parse_param, + .parse_monolithic = smb3_fs_context_parse_monolithic, + .get_tree = smb3_get_tree, + .reconfigure = smb3_reconfigure, +}; + +/* + * Parse a monolithic block of data from sys_mount(). + * smb3_fs_context_parse_monolithic - Parse key[=val][,key[=val]]* mount data + * @ctx: The superblock configuration to fill in. + * @data: The data to parse + * + * Parse a blob of data that's in key[=val][,key[=val]]* form. This can be + * called from the ->monolithic_mount_data() fs_context operation. + * + * Returns 0 on success or the error returned by the ->parse_option() fs_context + * operation on failure. + */ +static int smb3_fs_context_parse_monolithic(struct fs_context *fc, + void *data) +{ + struct smb3_fs_context *ctx = smb3_fc2context(fc); + char *options = data, *key; + int ret = 0; + + if (!options) + return 0; + + ctx->mount_options = kstrdup(data, GFP_KERNEL); + if (ctx->mount_options == NULL) + return -ENOMEM; + + ret = security_sb_eat_lsm_opts(options, &fc->security); + if (ret) + return ret; + + /* BB Need to add support for sep= here TBD */ + while ((key = strsep(&options, ",")) != NULL) { + if (*key) { + size_t v_len = 0; + char *value = strchr(key, '='); + + if (value) { + if (value == key) + continue; + *value++ = 0; + v_len = strlen(value); + } + ret = vfs_parse_fs_string(fc, key, value, v_len); + if (ret < 0) + break; + } + } + + return ret; +} + +/* + * Validate the preparsed information in the config. + */ +static int smb3_fs_context_validate(struct fs_context *fc) +{ + struct smb3_fs_context *ctx = smb3_fc2context(fc); + + if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) { + cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n"); + return -1; + } + +#ifndef CONFIG_KEYS + /* Muliuser mounts require CONFIG_KEYS support */ + if (ctx->multiuser) { + cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); + return -1; + } +#endif + + if (ctx->got_version == false) + pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n"); + + + if (!ctx->UNC) { + cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n"); + return -1; + } + + /* make sure UNC has a share name */ + if (strlen(ctx->UNC) < 3 || !strchr(ctx->UNC + 3, '\\')) { + cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n"); + return -1; + } + + if (!ctx->got_ip) { + int len; + const char *slash; + + /* No ip= option specified? Try to get it from UNC */ + /* Use the address part of the UNC. */ + slash = strchr(&ctx->UNC[2], '\\'); + len = slash - &ctx->UNC[2]; + if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr, + &ctx->UNC[2], len)) { + pr_err("Unable to determine destination address\n"); + return -1; + } + } + + /* set the port that we got earlier */ + cifs_set_port((struct sockaddr *)&ctx->dstaddr, ctx->port); + + if (ctx->override_uid && !ctx->uid_specified) { + ctx->override_uid = 0; + pr_notice("ignoring forceuid mount option specified with no uid= option\n"); + } + + if (ctx->override_gid && !ctx->gid_specified) { + ctx->override_gid = 0; + pr_notice("ignoring forcegid mount option specified with no gid= option\n"); + } + + return 0; +} + +static int smb3_get_tree_common(struct fs_context *fc) +{ + struct smb3_fs_context *ctx = smb3_fc2context(fc); + struct dentry *root; + int rc = 0; + + root = cifs_smb3_do_mount(fc->fs_type, 0, ctx); + if (IS_ERR(root)) + return PTR_ERR(root); + + fc->root = root; + + return rc; +} + +/* + * Create an SMB3 superblock from the parameters passed. + */ +static int smb3_get_tree(struct fs_context *fc) +{ + int err = smb3_fs_context_validate(fc); + + if (err) + return err; + return smb3_get_tree_common(fc); +} + +static void smb3_fs_context_free(struct fs_context *fc) +{ + struct smb3_fs_context *ctx = smb3_fc2context(fc); + + cifs_cleanup_volume_info(ctx); +} + +static int smb3_reconfigure(struct fs_context *fc) +{ + // TODO: struct smb3_fs_context *ctx = smb3_fc2context(fc); + + /* FIXME : add actual reconfigure */ + return 0; +} + +static int smb3_fs_context_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + struct fs_parse_result result; + struct smb3_fs_context *ctx = smb3_fc2context(fc); + int i, opt; + bool is_smb3 = !strcmp(fc->fs_type->name, "smb3"); + bool skip_parsing = false; + + cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key); + + /* + * fs_parse can not handle string options with an empty value so + * we will need special handling of them. + */ + if (param->type == fs_value_is_string && param->string[0] == 0) { + if (!strcmp("pass", param->key) || !strcmp("password", param->key)) + skip_parsing = true; + } + + if (!skip_parsing) { + opt = fs_parse(fc, smb3_fs_parameters, param, &result); + if (opt < 0) + return ctx->sloppy ? 1 : opt; + } + + switch (opt) { + case Opt_compress: + ctx->compression = UNKNOWN_TYPE; + cifs_dbg(VFS, + "SMB3 compression support is experimental\n"); + break; + case Opt_nodfs: + ctx->nodfs = 1; + break; + case Opt_hard: + if (result.negated) + ctx->retry = 0; + else + ctx->retry = 1; + break; + case Opt_soft: + if (result.negated) + ctx->retry = 1; + else + ctx->retry = 0; + break; + case Opt_mapposix: + if (result.negated) + ctx->remap = false; + else { + ctx->remap = true; + ctx->sfu_remap = false; /* disable SFU mapping */ + } + break; + case Opt_user_xattr: + if (result.negated) + ctx->no_xattr = 1; + else + ctx->no_xattr = 0; + break; + case Opt_forceuid: + if (result.negated) + ctx->override_uid = 0; + else + ctx->override_uid = 1; + break; + case Opt_forcegid: + if (result.negated) + ctx->override_gid = 0; + else + ctx->override_gid = 1; + break; + case Opt_perm: + if (result.negated) + ctx->noperm = 1; + else + ctx->noperm = 0; + break; + case Opt_dynperm: + if (result.negated) + ctx->dynperm = 0; + else + ctx->dynperm = 1; + break; + case Opt_sfu: + if (result.negated) + ctx->sfu_emul = 0; + else + ctx->sfu_emul = 1; + break; + case Opt_noblocksend: + ctx->noblocksnd = 1; + break; + case Opt_noautotune: + ctx->noautotune = 1; + break; + case Opt_nolease: + ctx->no_lease = 1; + break; + case Opt_nodelete: + ctx->nodelete = 1; + break; + case Opt_multichannel: + if (result.negated) { + ctx->multichannel = false; + ctx->max_channels = 1; + } else { + ctx->multichannel = true; + /* if number of channels not specified, default to 2 */ + if (ctx->max_channels < 2) + ctx->max_channels = 2; + } + break; + case Opt_uid: + ctx->linux_uid.val = result.uint_32; + ctx->uid_specified = true; + break; + case Opt_cruid: + ctx->cred_uid.val = result.uint_32; + break; + case Opt_backupgid: + ctx->backupgid.val = result.uint_32; + ctx->backupgid_specified = true; + break; + case Opt_gid: + ctx->linux_gid.val = result.uint_32; + ctx->gid_specified = true; + break; + case Opt_port: + ctx->port = result.uint_32; + break; + case Opt_file_mode: + ctx->file_mode = result.uint_32; + break; + case Opt_dirmode: + ctx->dir_mode = result.uint_32; + break; + case Opt_min_enc_offload: + ctx->min_offload = result.uint_32; + break; + case Opt_blocksize: + /* + * inode blocksize realistically should never need to be + * less than 16K or greater than 16M and default is 1MB. + * Note that small inode block sizes (e.g. 64K) can lead + * to very poor performance of common tools like cp and scp + */ + if ((result.uint_32 < CIFS_MAX_MSGSIZE) || + (result.uint_32 > (4 * SMB3_DEFAULT_IOSIZE))) { + cifs_dbg(VFS, "%s: Invalid blocksize\n", + __func__); + goto cifs_parse_mount_err; + } + ctx->bsize = result.uint_32; + break; + case Opt_rsize: + ctx->rsize = result.uint_32; + break; + case Opt_wsize: + ctx->wsize = result.uint_32; + break; + case Opt_actimeo: + ctx->actimeo = HZ * result.uint_32; + if (ctx->actimeo > CIFS_MAX_ACTIMEO) { + cifs_dbg(VFS, "attribute cache timeout too large\n"); + goto cifs_parse_mount_err; + } + break; + case Opt_echo_interval: + ctx->echo_interval = result.uint_32; + break; + case Opt_snapshot: + ctx->snapshot_time = result.uint_32; + break; + case Opt_max_credits: + if (result.uint_32 < 20 || result.uint_32 > 60000) { + cifs_dbg(VFS, "%s: Invalid max_credits value\n", + __func__); + goto cifs_parse_mount_err; + } + ctx->max_credits = result.uint_32; + break; + case Opt_max_channels: + if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) { + cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n", + __func__, CIFS_MAX_CHANNELS); + goto cifs_parse_mount_err; + } + ctx->max_channels = result.uint_32; + break; + case Opt_handletimeout: + ctx->handle_timeout = result.uint_32; + if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { + cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); + goto cifs_parse_mount_err; + } + break; + case Opt_source: + kfree(ctx->UNC); + ctx->UNC = NULL; + switch (smb3_parse_devname(param->string, ctx)) { + case 0: + break; + case -ENOMEM: + cifs_dbg(VFS, "Unable to allocate memory for devname\n"); + goto cifs_parse_mount_err; + case -EINVAL: + cifs_dbg(VFS, "Malformed UNC in devname\n"); + goto cifs_parse_mount_err; + default: + cifs_dbg(VFS, "Unknown error parsing devname\n"); + goto cifs_parse_mount_err; + } + fc->source = kstrdup(param->string, GFP_KERNEL); + if (fc->source == NULL) { + cifs_dbg(VFS, "OOM when copying UNC string\n"); + goto cifs_parse_mount_err; + } + break; + case Opt_user: + kfree(ctx->username); + ctx->username = NULL; + if (strlen(param->string) == 0) { + /* null user, ie. anonymous authentication */ + ctx->nullauth = 1; + break; + } + + if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) > + CIFS_MAX_USERNAME_LEN) { + pr_warn("username too long\n"); + goto cifs_parse_mount_err; + } + ctx->username = kstrdup(param->string, GFP_KERNEL); + if (ctx->username == NULL) { + cifs_dbg(VFS, "OOM when copying username string\n"); + goto cifs_parse_mount_err; + } + break; + case Opt_pass: + kfree(ctx->password); + ctx->password = NULL; + if (strlen(param->string) == 0) + break; + + ctx->password = kstrdup(param->string, GFP_KERNEL); + if (ctx->password == NULL) { + cifs_dbg(VFS, "OOM when copying password string\n"); + goto cifs_parse_mount_err; + } + break; + case Opt_ip: + if (strlen(param->string) == 0) { + ctx->got_ip = false; + break; + } + if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr, + param->string, + strlen(param->string))) { + pr_err("bad ip= option (%s)\n", param->string); + goto cifs_parse_mount_err; + } + ctx->got_ip = true; + break; + case Opt_domain: + if (strnlen(param->string, CIFS_MAX_DOMAINNAME_LEN) + == CIFS_MAX_DOMAINNAME_LEN) { + pr_warn("domain name too long\n"); + goto cifs_parse_mount_err; + } + + kfree(ctx->domainname); + ctx->domainname = kstrdup(param->string, GFP_KERNEL); + if (ctx->domainname == NULL) { + cifs_dbg(VFS, "OOM when copying domainname string\n"); + goto cifs_parse_mount_err; + } + cifs_dbg(FYI, "Domain name set\n"); + break; + case Opt_srcaddr: + if (!cifs_convert_address( + (struct sockaddr *)&ctx->srcaddr, + param->string, strlen(param->string))) { + pr_warn("Could not parse srcaddr: %s\n", + param->string); + goto cifs_parse_mount_err; + } + break; + case Opt_iocharset: + if (strnlen(param->string, 1024) >= 65) { + pr_warn("iocharset name too long\n"); + goto cifs_parse_mount_err; + } + + if (strncasecmp(param->string, "default", 7) != 0) { + kfree(ctx->iocharset); + ctx->iocharset = kstrdup(param->string, GFP_KERNEL); + if (ctx->iocharset == NULL) { + cifs_dbg(VFS, "OOM when copying iocharset string\n"); + goto cifs_parse_mount_err; + } + } + /* if iocharset not set then load_nls_default + * is used by caller + */ + cifs_dbg(FYI, "iocharset set to %s\n", ctx->iocharset); + break; + case Opt_netbiosname: + memset(ctx->source_rfc1001_name, 0x20, + RFC1001_NAME_LEN); + /* + * FIXME: are there cases in which a comma can + * be valid in workstation netbios name (and + * need special handling)? + */ + for (i = 0; i < RFC1001_NAME_LEN; i++) { + /* don't ucase netbiosname for user */ + if (param->string[i] == 0) + break; + ctx->source_rfc1001_name[i] = param->string[i]; + } + /* The string has 16th byte zero still from + * set at top of the function + */ + if (i == RFC1001_NAME_LEN && param->string[i] != 0) + pr_warn("netbiosname longer than 15 truncated\n"); + break; + case Opt_servern: + /* last byte, type, is 0x20 for servr type */ + memset(ctx->target_rfc1001_name, 0x20, + RFC1001_NAME_LEN_WITH_NULL); + /* + * BB are there cases in which a comma can be valid in this + * workstation netbios name (and need special handling)? + */ + + /* user or mount helper must uppercase the netbios name */ + for (i = 0; i < 15; i++) { + if (param->string[i] == 0) + break; + ctx->target_rfc1001_name[i] = param->string[i]; + } + + /* The string has 16th byte zero still from set at top of function */ + if (i == RFC1001_NAME_LEN && param->string[i] != 0) + pr_warn("server netbiosname longer than 15 truncated\n"); + break; + case Opt_ver: + /* version of mount userspace tools, not dialect */ + /* If interface changes in mount.cifs bump to new ver */ + if (strncasecmp(param->string, "1", 1) == 0) { + if (strlen(param->string) > 1) { + pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n", + param->string); + goto cifs_parse_mount_err; + } + /* This is the default */ + break; + } + /* For all other value, error */ + pr_warn("Invalid mount helper version specified\n"); + goto cifs_parse_mount_err; + case Opt_vers: + /* protocol version (dialect) */ + if (cifs_parse_smb_version(param->string, ctx, is_smb3) != 0) + goto cifs_parse_mount_err; + ctx->got_version = true; + break; + case Opt_sec: + if (cifs_parse_security_flavors(param->string, ctx) != 0) + goto cifs_parse_mount_err; + break; + case Opt_cache: + if (cifs_parse_cache_flavor(param->string, ctx) != 0) + goto cifs_parse_mount_err; + break; + case Opt_rootfs: +#ifdef CONFIG_CIFS_ROOT + ctx->rootfs = true; +#endif + break; + case Opt_posixpaths: + if (result.negated) + ctx->posix_paths = 0; + else + ctx->posix_paths = 1; + break; + case Opt_unix: + if (result.negated) + ctx->linux_ext = 0; + else + ctx->no_linux_ext = 1; + break; + case Opt_nocase: + ctx->nocase = 1; + break; + case Opt_brl: + if (result.negated) { + /* + * turn off mandatory locking in mode + * if remote locking is turned off since the + * local vfs will do advisory + */ + if (ctx->file_mode == + (S_IALLUGO & ~(S_ISUID | S_IXGRP))) + ctx->file_mode = S_IALLUGO; + ctx->nobrl = 1; + } else + ctx->nobrl = 0; + break; + case Opt_handlecache: + if (result.negated) + ctx->nohandlecache = 1; + else + ctx->nohandlecache = 0; + break; + case Opt_forcemandatorylock: + ctx->mand_lock = 1; + break; + case Opt_setuids: + ctx->setuids = result.negated; + break; + case Opt_intr: + ctx->intr = !result.negated; + break; + case Opt_setuidfromacl: + ctx->setuidfromacl = 1; + break; + case Opt_strictsync: + ctx->nostrictsync = result.negated; + break; + case Opt_serverino: + ctx->server_ino = !result.negated; + break; + case Opt_rwpidforward: + ctx->rwpidforward = 1; + break; + case Opt_modesid: + ctx->mode_ace = 1; + break; + case Opt_cifsacl: + ctx->cifs_acl = !result.negated; + break; + case Opt_acl: + ctx->no_psx_acl = result.negated; + break; + case Opt_locallease: + ctx->local_lease = 1; + break; + case Opt_sign: + ctx->sign = true; + break; + case Opt_ignore_signature: + ctx->sign = true; + ctx->ignore_signature = true; + break; + case Opt_seal: + /* we do not do the following in secFlags because seal + * is a per tree connection (mount) not a per socket + * or per-smb connection option in the protocol + * vol->secFlg |= CIFSSEC_MUST_SEAL; + */ + ctx->seal = 1; + break; + case Opt_noac: + pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); + break; + case Opt_fsc: +#ifndef CONFIG_CIFS_FSCACHE + cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); + goto cifs_parse_mount_err; +#endif + ctx->fsc = true; + break; + case Opt_mfsymlinks: + ctx->mfsymlinks = true; + break; + case Opt_multiuser: + ctx->multiuser = true; + break; + case Opt_sloppy: + ctx->sloppy = true; + break; + case Opt_nosharesock: + ctx->nosharesock = true; + break; + case Opt_persistent: + if (result.negated) { + if ((ctx->nopersistent) || (ctx->resilient)) { + cifs_dbg(VFS, + "persistenthandles mount options conflict\n"); + goto cifs_parse_mount_err; + } + } else { + ctx->nopersistent = true; + if (ctx->persistent) { + cifs_dbg(VFS, + "persistenthandles mount options conflict\n"); + goto cifs_parse_mount_err; + } + } + break; + case Opt_resilient: + if (result.negated) { + ctx->resilient = false; /* already the default */ + } else { + ctx->resilient = true; + if (ctx->persistent) { + cifs_dbg(VFS, + "persistenthandles mount options conflict\n"); + goto cifs_parse_mount_err; + } + } + break; + case Opt_domainauto: + ctx->domainauto = true; + break; + case Opt_rdma: + ctx->rdma = true; + break; + } + + return 0; + + cifs_parse_mount_err: + return 1; +} + +int smb3_init_fs_context(struct fs_context *fc) +{ + struct smb3_fs_context *ctx; + char *nodename = utsname()->nodename; + int i; + + ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL); + if (unlikely(!ctx)) + return -ENOMEM; + + /* + * does not have to be perfect mapping since field is + * informational, only used for servers that do not support + * port 445 and it can be overridden at mount time + */ + memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); + for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) + ctx->source_rfc1001_name[i] = toupper(nodename[i]); + + ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0; + /* + * null target name indicates to use *SMBSERVR default called name + * if we end up sending RFC1001 session initialize + */ + ctx->target_rfc1001_name[0] = 0; + ctx->cred_uid = current_uid(); + ctx->linux_uid = current_uid(); + ctx->linux_gid = current_gid(); + ctx->bsize = 1024 * 1024; /* can improve cp performance significantly */ + + /* + * default to SFM style remapping of seven reserved characters + * unless user overrides it or we negotiate CIFS POSIX where + * it is unnecessary. Can not simultaneously use more than one mapping + * since then readdir could list files that open could not open + */ + ctx->remap = true; + + /* default to only allowing write access to owner of the mount */ + ctx->dir_mode = ctx->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; + + /* ctx->retry default is 0 (i.e. "soft" limited retry not hard retry) */ + /* default is always to request posix paths. */ + ctx->posix_paths = 1; + /* default to using server inode numbers where available */ + ctx->server_ino = 1; + + /* default is to use strict cifs caching semantics */ + ctx->strict_io = true; + + ctx->actimeo = CIFS_DEF_ACTIMEO; + + /* Most clients set timeout to 0, allows server to use its default */ + ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ + + /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ + ctx->ops = &smb30_operations; + ctx->vals = &smbdefault_values; + + ctx->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; + + /* default to no multichannel (single server connection) */ + ctx->multichannel = false; + ctx->max_channels = 1; + + ctx->backupuid_specified = false; /* no backup intent for a user */ + ctx->backupgid_specified = false; /* no backup intent for a group */ + +/* + * short int override_uid = -1; + * short int override_gid = -1; + * char *nodename = strdup(utsname()->nodename); + * struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr; + */ + + fc->fs_private = ctx; + fc->ops = &smb3_fs_context_ops; + return 0; +} diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 3a66199f3cb7..d4a905a80883 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -9,8 +9,11 @@ #ifndef _FS_CONTEXT_H #define _FS_CONTEXT_H -#include #include "cifsglob.h" +#include +#include + +#define cifs_invalf(fc, fmt, ...) invalf(fc, fmt, ## __VA_ARGS__) enum smb_version { Smb_1 = 1, @@ -24,8 +27,6 @@ enum smb_version { Smb_version_err }; -int cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3); - enum { Opt_cache_loose, Opt_cache_strict, @@ -35,8 +36,6 @@ enum { Opt_cache_err }; -int cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx); - enum cifs_sec_param { Opt_sec_krb5, Opt_sec_krb5i, @@ -55,36 +54,36 @@ enum cifs_sec_param { enum cifs_param { /* Mount options that take no arguments */ - Opt_user_xattr, Opt_nouser_xattr, - Opt_forceuid, Opt_noforceuid, - Opt_forcegid, Opt_noforcegid, + Opt_user_xattr, + Opt_forceuid, + Opt_forcegid, Opt_noblocksend, Opt_noautotune, Opt_nolease, - Opt_hard, Opt_nohard, - Opt_soft, Opt_nosoft, - Opt_perm, Opt_noperm, + Opt_hard, + Opt_soft, + Opt_perm, Opt_nodelete, - Opt_mapposix, Opt_nomapposix, + Opt_mapposix, Opt_mapchars, Opt_nomapchars, - Opt_sfu, Opt_nosfu, + Opt_sfu, Opt_nodfs, - Opt_posixpaths, Opt_noposixpaths, - Opt_unix, Opt_nounix, + Opt_posixpaths, + Opt_unix, Opt_nocase, - Opt_brl, Opt_nobrl, - Opt_handlecache, Opt_nohandlecache, + Opt_brl, + Opt_handlecache, Opt_forcemandatorylock, Opt_setuidfromacl, - Opt_setuids, Opt_nosetuids, - Opt_dynperm, Opt_nodynperm, - Opt_intr, Opt_nointr, - Opt_strictsync, Opt_nostrictsync, - Opt_serverino, Opt_noserverino, + Opt_setuids, + Opt_dynperm, + Opt_intr, + Opt_strictsync, + Opt_serverino, Opt_rwpidforward, - Opt_cifsacl, Opt_nocifsacl, - Opt_acl, Opt_noacl, + Opt_cifsacl, + Opt_acl, Opt_locallease, Opt_sign, Opt_ignore_signature, @@ -95,13 +94,13 @@ enum cifs_param { Opt_multiuser, Opt_sloppy, Opt_nosharesock, - Opt_persistent, Opt_nopersistent, - Opt_resilient, Opt_noresilient, + Opt_persistent, + Opt_resilient, Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, - Opt_multichannel, Opt_nomultichannel, + Opt_multichannel, Opt_compress, /* Mount options which take numeric value */ @@ -142,11 +141,6 @@ enum cifs_param { /* Mount options to be ignored */ Opt_ignore, - /* Options which could be blank */ - Opt_blank_pass, - Opt_blank_user, - Opt_blank_ip, - Opt_err }; @@ -247,9 +241,23 @@ struct smb3_fs_context { unsigned int max_channels; __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */ bool rootfs:1; /* if it's a SMB root file system */ + + char *mount_options; }; -extern int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx); +extern const struct fs_parameter_spec smb3_fs_parameters[]; + +extern int cifs_parse_cache_flavor(char *value, + struct smb3_fs_context *ctx); +extern int cifs_parse_security_flavors(char *value, + struct smb3_fs_context *ctx); +extern int smb3_init_fs_context(struct fs_context *fc); + +static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fc) +{ + return fc->fs_private; +} + extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx); #endif diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 5c71f2730166..00ca687a17dd 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -195,7 +195,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) * We need to setup at least the fields used for negprot and * sesssetup. * - * We only need the volume here, so we can reuse memory from + * We only need the ctx here, so we can reuse memory from * the session and server without caring about memory * management. */ -- cgit v1.2.3 From 4deb075985ec52961cf43666cd9e12af1241b3cf Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 10 Dec 2020 00:08:43 -0600 Subject: cifs: remove the devname argument to cifs_compose_mount_options none of the callers use this argument any more. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 11 +++-------- fs/cifs/cifsproto.h | 3 +-- fs/cifs/connect.c | 11 +++-------- fs/cifs/dfs_cache.c | 6 ++---- 4 files changed, 9 insertions(+), 22 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 4b0b9cfe2ab1..81f6066d5865 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -124,7 +124,6 @@ cifs_build_devname(char *nodename, const char *prepath) * @sb_mountdata: parent/root DFS mount options (template) * @fullpath: full path in UNC format * @ref: optional server's referral - * @devname: optional pointer for saving device name * * creates mount options for submount based on template options sb_mountdata * and replacing unc,ip,prefixpath options with ones we've got form ref_unc. @@ -134,8 +133,7 @@ cifs_build_devname(char *nodename, const char *prepath) */ char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, - const struct dfs_info3_param *ref, - char **devname) + const struct dfs_info3_param *ref) { int rc; char *name; @@ -232,10 +230,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, strcat(mountdata, "ip="); strcat(mountdata, srvIP); - if (devname) - *devname = name; - else - kfree(name); + kfree(name); /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ @@ -281,7 +276,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt, /* strip first '\' from fullpath */ mountdata = cifs_compose_mount_options(cifs_sb->mountdata, - fullpath + 1, NULL, NULL); + fullpath + 1, NULL); if (IS_ERR(mountdata)) { kfree(devname); return (struct vfsmount *)mountdata; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 8dde386d4893..aa7a717c34ab 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -78,8 +78,7 @@ extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx, int add_treename); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *cifs_compose_mount_options(const char *sb_mountdata, - const char *fullpath, const struct dfs_info3_param *ref, - char **devname); + const char *fullpath, const struct dfs_info3_param *ref); /* extern void renew_parental_timestamps(struct dentry *direntry);*/ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1c463ca16226..ec3c952b90f2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3032,11 +3032,8 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ref_path, &referral, NULL); if (!rc) { - char *fake_devname = NULL; - mdata = cifs_compose_mount_options(cifs_sb->mountdata, - full_path + 1, &referral, - &fake_devname); + full_path + 1, &referral); free_dfs_info_param(&referral); if (IS_ERR(mdata)) { @@ -3046,7 +3043,6 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, cifs_cleanup_volume_info_contents(ctx); rc = cifs_setup_volume_info(ctx); } - kfree(fake_devname); kfree(cifs_sb->mountdata); cifs_sb->mountdata = mdata; } @@ -3098,7 +3094,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, { int rc; struct dfs_info3_param ref = {0}; - char *mdata = NULL, *fake_devname = NULL; + char *mdata = NULL; struct smb3_fs_context fake_ctx = {NULL}; cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); @@ -3107,7 +3103,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, if (rc) return rc; - mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref, &fake_devname); + mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref); free_dfs_info_param(&ref); if (IS_ERR(mdata)) { @@ -3117,7 +3113,6 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, rc = cifs_setup_volume_info(&fake_ctx); kfree(mdata); - kfree(fake_devname); if (!rc) { /* diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index dde859c21f1a..6bccff4596bf 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -1416,7 +1416,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, int rc; struct cache_entry *ce; struct dfs_info3_param ref = {0}; - char *mdata = NULL, *devname = NULL; + char *mdata = NULL; struct TCP_Server_Info *server; struct cifs_ses *ses; struct smb3_fs_context ctx = {NULL}; @@ -1443,8 +1443,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, up_read(&htable_rw_lock); - mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref, - &devname); + mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref); free_dfs_info_param(&ref); if (IS_ERR(mdata)) { @@ -1454,7 +1453,6 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, } rc = cifs_setup_volume_info(&ctx); - kfree(devname); if (rc) { ses = ERR_PTR(rc); -- cgit v1.2.3 From d17abdf7566566fc402c31899b353044a7ff3cf4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 10 Nov 2020 08:59:26 +1000 Subject: cifs: add an smb3_fs_context to cifs_sb and populate it during mount in cifs_smb3_do_mount() Signed-off-by: Ronnie Sahlberg Reviewed-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsfs.c | 60 +++++++++++++++++++++++++--------------------------- fs/cifs/connect.c | 14 +++++++++--- 3 files changed, 41 insertions(+), 34 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 6e7c4427369d..34d0229c0519 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -61,6 +61,7 @@ struct cifs_sb_info { spinlock_t tlink_tree_lock; struct tcon_link *master_tlink; struct nls_table *local_nls; + struct smb3_fs_context *ctx; unsigned int bsize; unsigned int rsize; unsigned int wsize; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 907c82428c42..7fe6502e1672 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -776,8 +776,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, { int rc; struct super_block *sb; - struct cifs_sb_info *cifs_sb; - struct smb3_fs_context *ctx; + struct cifs_sb_info *cifs_sb = NULL; struct cifs_mnt_data mnt_data; struct dentry *root; @@ -790,49 +789,51 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, else cifs_info("Attempting to mount %s\n", old_ctx->UNC); - ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); - rc = smb3_fs_context_dup(ctx, old_ctx); - if (rc) { - root = ERR_PTR(rc); + cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); + if (cifs_sb == NULL) { + root = ERR_PTR(-ENOMEM); goto out; } - rc = cifs_setup_volume_info(ctx); + cifs_sb->ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL); + if (!cifs_sb->ctx) { + root = ERR_PTR(-ENOMEM); + goto out; + } + rc = smb3_fs_context_dup(cifs_sb->ctx, old_ctx); if (rc) { root = ERR_PTR(rc); goto out; } - cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); - if (cifs_sb == NULL) { - root = ERR_PTR(-ENOMEM); - goto out_nls; + rc = cifs_setup_volume_info(cifs_sb->ctx); + if (rc) { + root = ERR_PTR(rc); + goto out; } - cifs_sb->mountdata = kstrndup(ctx->mount_options, PAGE_SIZE, GFP_KERNEL); + cifs_sb->mountdata = kstrndup(cifs_sb->ctx->mount_options, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { root = ERR_PTR(-ENOMEM); - goto out_free; + goto out; } - rc = cifs_setup_cifs_sb(ctx, cifs_sb); + rc = cifs_setup_cifs_sb(cifs_sb->ctx, cifs_sb); if (rc) { root = ERR_PTR(rc); - goto out_free; + goto out; } - rc = cifs_mount(cifs_sb, ctx); + rc = cifs_mount(cifs_sb, cifs_sb->ctx); if (rc) { if (!(flags & SB_SILENT)) cifs_dbg(VFS, "cifs_mount failed w/return code = %d\n", rc); root = ERR_PTR(rc); - goto out_free; + goto out; } - mnt_data.ctx = ctx; + mnt_data.ctx = cifs_sb->ctx; mnt_data.cifs_sb = cifs_sb; mnt_data.flags = flags; @@ -859,26 +860,23 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, sb->s_flags |= SB_ACTIVE; } - root = cifs_get_root(ctx, sb); + root = cifs_get_root(cifs_sb->ctx, sb); if (IS_ERR(root)) goto out_super; cifs_dbg(FYI, "dentry root is: %p\n", root); - goto out; + return root; out_super: deactivate_locked_super(sb); out: - cifs_cleanup_volume_info(ctx); + if (cifs_sb) { + kfree(cifs_sb->prepath); + kfree(cifs_sb->mountdata); + cifs_cleanup_volume_info(cifs_sb->ctx); + kfree(cifs_sb); + } return root; - -out_free: - kfree(cifs_sb->prepath); - kfree(cifs_sb->mountdata); - kfree(cifs_sb); -out_nls: - unload_nls(ctx->local_nls); - goto out; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ec3c952b90f2..5146c4645537 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2799,6 +2799,9 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, void cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx) { + if (ctx == NULL) + return; + /* * Make sure this stays in sync with smb3_fs_context_dup() */ @@ -2818,6 +2821,9 @@ cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx) ctx->iocharset = NULL; kfree(ctx->prepath); ctx->prepath = NULL; + + unload_nls(ctx->local_nls); + ctx->local_nls = NULL; } void @@ -3739,9 +3745,11 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, static void delayed_free(struct rcu_head *p) { - struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu); - unload_nls(sbi->local_nls); - kfree(sbi); + struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); + + unload_nls(cifs_sb->local_nls); + cifs_cleanup_volume_info(cifs_sb->ctx); + kfree(cifs_sb); } void -- cgit v1.2.3 From a2a52a8a3601c37a68b31b734f5a06af8a7903f1 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 10 Nov 2020 09:12:31 +1000 Subject: cifs: get rid of cifs_sb->mountdata as we now have a full smb3_fs_context as part of the cifs superblock we no longer need a local copy of the mount options and can just reference the copy in the smb3_fs_context. Signed-off-by: Ronnie Sahlberg Reviewed-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 3 ++- fs/cifs/cifs_fs_sb.h | 1 - fs/cifs/cifsfs.c | 7 ------- fs/cifs/connect.c | 19 ++++++++++--------- 4 files changed, 12 insertions(+), 18 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 81f6066d5865..6f7187b90fda 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -23,6 +23,7 @@ #include "cifs_debug.h" #include "cifs_unicode.h" #include "dfs_cache.h" +#include "fs_context.h" static LIST_HEAD(cifs_dfs_automount_list); @@ -275,7 +276,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt, /* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */ /* strip first '\' from fullpath */ - mountdata = cifs_compose_mount_options(cifs_sb->mountdata, + mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, fullpath + 1, NULL); if (IS_ERR(mountdata)) { kfree(devname); diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 34d0229c0519..8ee37c80880a 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -74,7 +74,6 @@ struct cifs_sb_info { umode_t mnt_file_mode; umode_t mnt_dir_mode; unsigned int mnt_cifs_flags; - char *mountdata; /* options received at mount time or via DFS refs */ struct delayed_work prune_tlinks; struct rcu_head rcu; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7fe6502e1672..4f27f77d3053 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -812,12 +812,6 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out; } - cifs_sb->mountdata = kstrndup(cifs_sb->ctx->mount_options, PAGE_SIZE, GFP_KERNEL); - if (cifs_sb->mountdata == NULL) { - root = ERR_PTR(-ENOMEM); - goto out; - } - rc = cifs_setup_cifs_sb(cifs_sb->ctx, cifs_sb); if (rc) { root = ERR_PTR(rc); @@ -872,7 +866,6 @@ out_super: out: if (cifs_sb) { kfree(cifs_sb->prepath); - kfree(cifs_sb->mountdata); cifs_cleanup_volume_info(cifs_sb->ctx); kfree(cifs_sb); } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5146c4645537..95b12f148735 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3012,7 +3012,7 @@ build_unc_path_to_root(const struct smb3_fs_context *ctx, * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb * * - * If a referral is found, cifs_sb->mountdata will be (re-)allocated + * If a referral is found, cifs_sb->ctx->mount_options will be (re-)allocated * to a string containing updated options for the submount. Otherwise it * will be left untouched. * @@ -3038,7 +3038,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ref_path, &referral, NULL); if (!rc) { - mdata = cifs_compose_mount_options(cifs_sb->mountdata, + mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, &referral); free_dfs_info_param(&referral); @@ -3049,8 +3049,8 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, cifs_cleanup_volume_info_contents(ctx); rc = cifs_setup_volume_info(ctx); } - kfree(cifs_sb->mountdata); - cifs_sb->mountdata = mdata; + kfree(cifs_sb->ctx->mount_options); + cifs_sb->ctx->mount_options = mdata; } kfree(full_path); return rc; @@ -3109,7 +3109,8 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, if (rc) return rc; - mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref); + mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, + full_path + 1, &ref); free_dfs_info_param(&ref); if (IS_ERR(mdata)) { @@ -3438,7 +3439,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) goto error; } /* Save mount options */ - mntdata = kstrndup(cifs_sb->mountdata, strlen(cifs_sb->mountdata), GFP_KERNEL); + mntdata = kstrndup(cifs_sb->ctx->mount_options, + strlen(cifs_sb->ctx->mount_options), GFP_KERNEL); if (!mntdata) { rc = -ENOMEM; goto error; @@ -3462,12 +3464,12 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) break; } /* Chase referral */ - oldmnt = cifs_sb->mountdata; + oldmnt = cifs_sb->ctx->mount_options; rc = expand_dfs_referral(xid, root_ses, ctx, cifs_sb, ref_path + 1); if (rc) break; /* Connect to new DFS target only if we were redirected */ - if (oldmnt != cifs_sb->mountdata) { + if (oldmnt != cifs_sb->ctx->mount_options) { mount_put_conns(cifs_sb, xid, server, ses, tcon); rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); } @@ -3774,7 +3776,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb) } spin_unlock(&cifs_sb->tlink_tree_lock); - kfree(cifs_sb->mountdata); kfree(cifs_sb->prepath); #ifdef CONFIG_CIFS_DFS_UPCALL dfs_cache_del_vol(cifs_sb->origin_fullpath); -- cgit v1.2.3 From a87e67254bc5da9ca6f3899e354fcf03d12cfd10 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:47 +0100 Subject: cifs: Make extract_hostname function public Move the function to misc.c and give it a public header. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 1 + fs/cifs/connect.c | 34 ---------------------------------- fs/cifs/misc.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 34 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index aa7a717c34ab..3fe0c4a0d36d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -617,6 +617,7 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov, struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server); void cifs_put_tcp_super(struct super_block *sb); int update_super_prepath(struct cifs_tcon *tcon, char *prefix); +char *extract_hostname(const char *unc); #ifdef CONFIG_CIFS_DFS_UPCALL static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 95b12f148735..d3836db33e7c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -77,7 +77,6 @@ static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); static void cifs_prune_tlinks(struct work_struct *work); -static char *extract_hostname(const char *unc); /* * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may @@ -1025,39 +1024,6 @@ next_pdu: module_put_and_exit(0); } -/* extract the host portion of the UNC string */ -static char * -extract_hostname(const char *unc) -{ - const char *src; - char *dst, *delim; - unsigned int len; - - /* skip double chars at beginning of string */ - /* BB: check validity of these bytes? */ - if (strlen(unc) < 3) - return ERR_PTR(-EINVAL); - for (src = unc; *src && *src == '\\'; src++) - ; - if (!*src) - return ERR_PTR(-EINVAL); - - /* delimiter between hostname and sharename is always '\\' now */ - delim = strchr(src, '\\'); - if (!delim) - return ERR_PTR(-EINVAL); - - len = delim - src; - dst = kmalloc((len + 1), GFP_KERNEL); - if (dst == NULL) - return ERR_PTR(-ENOMEM); - - memcpy(dst, src, len); - dst[len] = '\0'; - - return dst; -} - /** Returns true if srcaddr isn't specified and rhs isn't * specified, or if srcaddr is specified and * matches the IP address of the rhs argument. diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c14cf01dbef..3d5cc25c167f 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1195,3 +1195,35 @@ out: cifs_put_tcon_super(sb); return rc; } + +/* extract the host portion of the UNC string */ +char *extract_hostname(const char *unc) +{ + const char *src; + char *dst, *delim; + unsigned int len; + + /* skip double chars at beginning of string */ + /* BB: check validity of these bytes? */ + if (strlen(unc) < 3) + return ERR_PTR(-EINVAL); + for (src = unc; *src && *src == '\\'; src++) + ; + if (!*src) + return ERR_PTR(-EINVAL); + + /* delimiter between hostname and sharename is always '\\' now */ + delim = strchr(src, '\\'); + if (!delim) + return ERR_PTR(-EINVAL); + + len = delim - src; + dst = kmalloc((len + 1), GFP_KERNEL); + if (dst == NULL) + return ERR_PTR(-ENOMEM); + + memcpy(dst, src, len); + dst[len] = '\0'; + + return dst; +} -- cgit v1.2.3 From e73a42e07a2246ecd8b0cad70824d26ab07985c2 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:48 +0100 Subject: cifs: Make extract_sharename function public Move the function to misc.c Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cache.c | 24 ------------------------ fs/cifs/cifsproto.h | 1 + fs/cifs/fscache.c | 1 + fs/cifs/fscache.h | 1 - fs/cifs/misc.c | 24 ++++++++++++++++++++++++ 5 files changed, 26 insertions(+), 25 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 0f2adecb94f2..488fe0ffc1ef 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -53,30 +53,6 @@ const struct fscache_cookie_def cifs_fscache_server_index_def = { .type = FSCACHE_COOKIE_TYPE_INDEX, }; -char *extract_sharename(const char *treename) -{ - const char *src; - char *delim, *dst; - int len; - - /* skip double chars at the beginning */ - src = treename + 2; - - /* share name is always preceded by '\\' now */ - delim = strchr(src, '\\'); - if (!delim) - return ERR_PTR(-EINVAL); - delim++; - len = strlen(delim); - - /* caller has to free the memory */ - dst = kstrndup(delim, len, GFP_KERNEL); - if (!dst) - return ERR_PTR(-ENOMEM); - - return dst; -} - static enum fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, const void *data, diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 3fe0c4a0d36d..b80b57a66804 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -618,6 +618,7 @@ struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server); void cifs_put_tcp_super(struct super_block *sb); int update_super_prepath(struct cifs_tcon *tcon, char *prefix); char *extract_hostname(const char *unc); +char *extract_sharename(const char *unc); #ifdef CONFIG_CIFS_DFS_UPCALL static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index da688185403c..20d24af33ee2 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -22,6 +22,7 @@ #include "cifsglob.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" +#include "cifsproto.h" /* * Key layout of CIFS server cache index object diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 1091633d2adb..e811f2dd7619 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -57,7 +57,6 @@ extern const struct fscache_cookie_def cifs_fscache_inode_object_def; extern int cifs_fscache_register(void); extern void cifs_fscache_unregister(void); -extern char *extract_sharename(const char *); /* * fscache.c diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3d5cc25c167f..f0a1c24751b2 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1227,3 +1227,27 @@ char *extract_hostname(const char *unc) return dst; } + +char *extract_sharename(const char *unc) +{ + const char *src; + char *delim, *dst; + int len; + + /* skip double chars at the beginning */ + src = unc + 2; + + /* share name is always preceded by '\\' now */ + delim = strchr(src, '\\'); + if (!delim) + return ERR_PTR(-EINVAL); + delim++; + len = strlen(delim); + + /* caller has to free the memory */ + dst = kstrndup(delim, len, GFP_KERNEL); + if (!dst) + return ERR_PTR(-ENOMEM); + + return dst; +} -- cgit v1.2.3 From bc04499477d9f01034c2afb6097e835c705ac3bd Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 11 Dec 2020 19:48:26 -0600 Subject: cifs: minor kernel style fixes for comments Trivial fix for a few comments which didn't follow kernel style Signed-off-by: Steve French --- fs/cifs/connect.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d3836db33e7c..ec80b6c3e20f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1024,9 +1024,9 @@ next_pdu: module_put_and_exit(0); } -/** Returns true if srcaddr isn't specified and rhs isn't - * specified, or if srcaddr is specified and - * matches the IP address of the rhs argument. +/** + * Returns true if srcaddr isn't specified and rhs isn't specified, or + * if srcaddr is specified and matches the IP address of the rhs argument */ bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs) @@ -2544,7 +2544,8 @@ ip_connect(struct TCP_Server_Info *server) void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) { - /* if we are reconnecting then should we check to see if + /* + * If we are reconnecting then should we check to see if * any requested capabilities changed locally e.g. via * remount but we can not do much about it here * if they have (even if we could detect it by the following) @@ -2552,7 +2553,8 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, * or if we change to make all sb to same share the same * sb as NFS - then we only have one backpointer to sb. * What if we wanted to mount the server share twice once with - * and once without posixacls or posix paths? */ + * and once without posixacls or posix paths? + */ __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); if (ctx && ctx->no_linux_ext) { @@ -2571,11 +2573,15 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, if (!CIFSSMBQFSUnixInfo(xid, tcon)) { __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); - /* check for reconnect case in which we do not - want to change the mount behavior if we can avoid it */ + /* + * check for reconnect case in which we do not + * want to change the mount behavior if we can avoid it + */ if (ctx == NULL) { - /* turn off POSIX ACL and PATHNAMES if not set - originally at mount time */ + /* + * turn off POSIX ACL and PATHNAMES if not set + * originally at mount time + */ if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) cap &= ~CIFS_UNIX_POSIX_ACL_CAP; if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) { @@ -2977,7 +2983,6 @@ build_unc_path_to_root(const struct smb3_fs_context *ctx, /** * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb * - * * If a referral is found, cifs_sb->ctx->mount_options will be (re-)allocated * to a string containing updated options for the submount. Otherwise it * will be left untouched. -- cgit v1.2.3 From 047092ffe2b1774ab456e0eff0e40e0eb4b6600e Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 11 Dec 2020 20:22:04 -0600 Subject: cifs: cleanup misc.c misc.c was getting a little large, move two of the UNC parsing relating functions to a new C file unc.c which makes the coding of the upcoming witness protocol patch series a little cleaner as well. Suggested-by: Rafal Szczesniak Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/Makefile | 2 +- fs/cifs/misc.c | 56 ---------------------------------------------- fs/cifs/unc.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 57 deletions(-) create mode 100644 fs/cifs/unc.c (limited to 'fs/cifs') diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index cd17d0e50f2a..848ebad6af7d 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_CIFS) += cifs.o cifs-y := trace.o cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o \ inode.o link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ cifs_unicode.o nterr.o cifsencrypt.o \ - readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o \ + readdir.o ioctl.o sess.o export.o smb1ops.o unc.o winucase.o \ smb2ops.o smb2maperror.o smb2transport.o \ smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index f0a1c24751b2..1c14cf01dbef 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1195,59 +1195,3 @@ out: cifs_put_tcon_super(sb); return rc; } - -/* extract the host portion of the UNC string */ -char *extract_hostname(const char *unc) -{ - const char *src; - char *dst, *delim; - unsigned int len; - - /* skip double chars at beginning of string */ - /* BB: check validity of these bytes? */ - if (strlen(unc) < 3) - return ERR_PTR(-EINVAL); - for (src = unc; *src && *src == '\\'; src++) - ; - if (!*src) - return ERR_PTR(-EINVAL); - - /* delimiter between hostname and sharename is always '\\' now */ - delim = strchr(src, '\\'); - if (!delim) - return ERR_PTR(-EINVAL); - - len = delim - src; - dst = kmalloc((len + 1), GFP_KERNEL); - if (dst == NULL) - return ERR_PTR(-ENOMEM); - - memcpy(dst, src, len); - dst[len] = '\0'; - - return dst; -} - -char *extract_sharename(const char *unc) -{ - const char *src; - char *delim, *dst; - int len; - - /* skip double chars at the beginning */ - src = unc + 2; - - /* share name is always preceded by '\\' now */ - delim = strchr(src, '\\'); - if (!delim) - return ERR_PTR(-EINVAL); - delim++; - len = strlen(delim); - - /* caller has to free the memory */ - dst = kstrndup(delim, len, GFP_KERNEL); - if (!dst) - return ERR_PTR(-ENOMEM); - - return dst; -} diff --git a/fs/cifs/unc.c b/fs/cifs/unc.c new file mode 100644 index 000000000000..2c5665f5543a --- /dev/null +++ b/fs/cifs/unc.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020, Microsoft Corporation. + * + * Author(s): Steve French + * Suresh Jayaraman + * Jeff Layton + */ + +#include +#include "cifsproto.h" + +/* extract the host portion of the UNC string */ +char *extract_hostname(const char *unc) +{ + const char *src; + char *dst, *delim; + unsigned int len; + + /* skip double chars at beginning of string */ + /* BB: check validity of these bytes? */ + if (strlen(unc) < 3) + return ERR_PTR(-EINVAL); + for (src = unc; *src && *src == '\\'; src++) + ; + if (!*src) + return ERR_PTR(-EINVAL); + + /* delimiter between hostname and sharename is always '\\' now */ + delim = strchr(src, '\\'); + if (!delim) + return ERR_PTR(-EINVAL); + + len = delim - src; + dst = kmalloc((len + 1), GFP_KERNEL); + if (dst == NULL) + return ERR_PTR(-ENOMEM); + + memcpy(dst, src, len); + dst[len] = '\0'; + + return dst; +} + +char *extract_sharename(const char *unc) +{ + const char *src; + char *delim, *dst; + int len; + + /* skip double chars at the beginning */ + src = unc + 2; + + /* share name is always preceded by '\\' now */ + delim = strchr(src, '\\'); + if (!delim) + return ERR_PTR(-EINVAL); + delim++; + len = strlen(delim); + + /* caller has to free the memory */ + dst = kstrndup(delim, len, GFP_KERNEL); + if (!dst) + return ERR_PTR(-ENOMEM); + + return dst; +} -- cgit v1.2.3 From 06f08dab3ca726b86431889495c45049616d6a15 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:49 +0100 Subject: cifs: Register generic netlink family Register a new generic netlink family to talk to the witness service userspace daemon. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/Kconfig | 11 ++++++ fs/cifs/Makefile | 2 + fs/cifs/cifsfs.c | 17 ++++++++- fs/cifs/netlink.c | 69 ++++++++++++++++++++++++++++++++++ fs/cifs/netlink.h | 16 ++++++++ include/uapi/linux/cifs/cifs_netlink.h | 31 +++++++++++++++ 6 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 fs/cifs/netlink.c create mode 100644 fs/cifs/netlink.h create mode 100644 include/uapi/linux/cifs/cifs_netlink.h (limited to 'fs/cifs') diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 604f65f4b6c5..664ac5c63d39 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -190,6 +190,17 @@ config CIFS_DFS_UPCALL servers if their addresses change or for implicit mounts of DFS junction points. If unsure, say Y. +config CIFS_SWN_UPCALL + bool "SWN feature support" + depends on CIFS + help + The Service Witness Protocol (SWN) is used to get notifications + from a highly available server of resource state changes. This + feature enables an upcall mechanism for CIFS which contacts an + userspace daemon to establish the DCE/RPC connection to retrieve + the cluster available interfaces and resource change notifications. + If unsure, say Y. + config CIFS_NFSD_EXPORT bool "Allow nfsd to export CIFS file system" depends on CIFS && BROKEN diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 848ebad6af7d..9e398d227b0e 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -18,6 +18,8 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o +cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o + cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4f27f77d3053..5d32561ae2ed 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -55,6 +55,9 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" #endif +#ifdef CONFIG_CIFS_SWN_UPCALL +#include "netlink.h" +#endif #include "fs_context.h" /* @@ -1601,10 +1604,15 @@ init_cifs(void) if (rc) goto out_destroy_dfs_cache; #endif /* CONFIG_CIFS_UPCALL */ +#ifdef CONFIG_CIFS_SWN_UPCALL + rc = cifs_genl_init(); + if (rc) + goto out_register_key_type; +#endif /* CONFIG_CIFS_SWN_UPCALL */ rc = init_cifs_idmap(); if (rc) - goto out_register_key_type; + goto out_cifs_swn_init; rc = register_filesystem(&cifs_fs_type); if (rc) @@ -1620,7 +1628,11 @@ init_cifs(void) out_init_cifs_idmap: exit_cifs_idmap(); +out_cifs_swn_init: +#ifdef CONFIG_CIFS_SWN_UPCALL + cifs_genl_exit(); out_register_key_type: +#endif #ifdef CONFIG_CIFS_UPCALL exit_cifs_spnego(); out_destroy_dfs_cache: @@ -1657,6 +1669,9 @@ exit_cifs(void) unregister_filesystem(&smb3_fs_type); cifs_dfs_release_automount_timer(); exit_cifs_idmap(); +#ifdef CONFIG_CIFS_SWN_UPCALL + cifs_genl_exit(); +#endif #ifdef CONFIG_CIFS_UPCALL exit_cifs_spnego(); #endif diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c new file mode 100644 index 000000000000..b9154661fa85 --- /dev/null +++ b/fs/cifs/netlink.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#include +#include + +#include "netlink.h" +#include "cifsglob.h" +#include "cifs_debug.h" + +static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { +}; + +static struct genl_ops cifs_genl_ops[] = { +}; + +static const struct genl_multicast_group cifs_genl_mcgrps[] = { + [CIFS_GENL_MCGRP_SWN] = { .name = CIFS_GENL_MCGRP_SWN_NAME }, +}; + +struct genl_family cifs_genl_family = { + .name = CIFS_GENL_NAME, + .version = CIFS_GENL_VERSION, + .hdrsize = 0, + .maxattr = CIFS_GENL_ATTR_MAX, + .module = THIS_MODULE, + .policy = cifs_genl_policy, + .ops = cifs_genl_ops, + .n_ops = ARRAY_SIZE(cifs_genl_ops), + .mcgrps = cifs_genl_mcgrps, + .n_mcgrps = ARRAY_SIZE(cifs_genl_mcgrps), +}; + +/** + * cifs_genl_init - Register generic netlink family + * + * Return zero if initialized successfully, otherwise non-zero. + */ +int cifs_genl_init(void) +{ + int ret; + + ret = genl_register_family(&cifs_genl_family); + if (ret < 0) { + cifs_dbg(VFS, "%s: failed to register netlink family\n", + __func__); + return ret; + } + + return 0; +} + +/** + * cifs_genl_exit - Unregister generic netlink family + */ +void cifs_genl_exit(void) +{ + int ret; + + ret = genl_unregister_family(&cifs_genl_family); + if (ret < 0) { + cifs_dbg(VFS, "%s: failed to unregister netlink family\n", + __func__); + } +} diff --git a/fs/cifs/netlink.h b/fs/cifs/netlink.h new file mode 100644 index 000000000000..e2fa8ed24c54 --- /dev/null +++ b/fs/cifs/netlink.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#ifndef _CIFS_NETLINK_H +#define _CIFS_NETLINK_H + +extern struct genl_family cifs_genl_family; + +extern int cifs_genl_init(void); +extern void cifs_genl_exit(void); + +#endif /* _CIFS_NETLINK_H */ diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h new file mode 100644 index 000000000000..cdb1bd78fbc7 --- /dev/null +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ +/* + * Netlink routines for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + + +#ifndef _UAPILINUX_CIFS_NETLINK_H +#define _UAPILINUX_CIFS_NETLINK_H + +#define CIFS_GENL_NAME "cifs" +#define CIFS_GENL_VERSION 0x1 + +#define CIFS_GENL_MCGRP_SWN_NAME "cifs_mcgrp_swn" + +enum cifs_genl_multicast_groups { + CIFS_GENL_MCGRP_SWN, +}; + +enum cifs_genl_attributes { + __CIFS_GENL_ATTR_MAX, +}; +#define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) + +enum cifs_genl_commands { + __CIFS_GENL_CMD_MAX +}; +#define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) + +#endif /* _UAPILINUX_CIFS_NETLINK_H */ -- cgit v1.2.3 From 0ac4e2919aa408dfd0fb9ce08ac331a9deeea807 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Fri, 11 Dec 2020 22:59:29 -0600 Subject: cifs: add witness mount option and data structs Add 'witness' mount option to register for witness notifications. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 5 +++++ fs/cifs/cifsglob.h | 3 +++ fs/cifs/connect.c | 25 +++++++++++++++++++++++++ fs/cifs/fs_context.c | 8 ++++++++ fs/cifs/fs_context.h | 2 ++ 5 files changed, 43 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5d32561ae2ed..f810b25dfeb8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -638,6 +638,11 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",multichannel,max_channels=%zu", tcon->ses->chan_max); +#ifdef CONFIG_CIFS_SWN_UPCALL + if (tcon->use_witness) + seq_puts(s, ",witness"); +#endif + return 0; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b46809260e79..78438102f091 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1086,6 +1086,9 @@ struct cifs_tcon { int remap:2; struct list_head ulist; /* cache update list */ #endif +#ifdef CONFIG_CIFS_SWN_UPCALL + bool use_witness:1; /* use witness protocol */ +#endif }; /* diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ec80b6c3e20f..ead1c086b88d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1944,6 +1944,8 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } + /* TODO witness unregister */ + list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2104,6 +2106,26 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) } tcon->use_resilient = true; } +#ifdef CONFIG_CIFS_SWN_UPCALL + tcon->use_witness = false; + if (ctx->witness) { + if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { + if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { + /* TODO witness register */ + tcon->use_witness = true; + } else { + /* TODO: try to extend for non-cluster uses (eg multichannel) */ + cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } + } else { + cifs_dbg(VFS, "SMB3 or later required for witness option\n"); + rc = -EOPNOTSUPP; + goto out_fail; + } + } +#endif /* If the user really knows what they are doing they can override */ if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { @@ -3856,6 +3878,9 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ctx->sectype = master_tcon->ses->sectype; ctx->sign = master_tcon->ses->sign; ctx->seal = master_tcon->seal; +#ifdef CONFIG_CIFS_SWN_UPCALL + ctx->witness = master_tcon->use_witness; +#endif rc = cifs_set_vol_auth(ctx, master_tcon->ses); if (rc) { diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 9120d148c5f1..fe5cc60f4393 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -119,6 +119,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("modesid", Opt_modesid), fsparam_flag("rootfs", Opt_rootfs), fsparam_flag("compress", Opt_compress), + fsparam_flag("witness", Opt_witness), /* Mount options which take numeric value */ fsparam_u32("backupuid", Opt_backupuid), @@ -1004,6 +1005,13 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (cifs_parse_cache_flavor(param->string, ctx) != 0) goto cifs_parse_mount_err; break; + case Opt_witness: +#ifndef CONFIG_CIFS_SWN_UPCALL + cifs_dbg(VFS, "Witness support needs CONFIG_CIFS_SWN_UPCALL config option\n"); + goto cifs_parse_mount_err; +#endif + ctx->witness = true; + break; case Opt_rootfs: #ifdef CONFIG_CIFS_ROOT ctx->rootfs = true; diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index d4a905a80883..aaec8a819d34 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -102,6 +102,7 @@ enum cifs_param { Opt_rootfs, Opt_multichannel, Opt_compress, + Opt_witness, /* Mount options which take numeric value */ Opt_backupuid, @@ -241,6 +242,7 @@ struct smb3_fs_context { unsigned int max_channels; __u16 compression; /* compression algorithm 0xFFFF default 0=disabled */ bool rootfs:1; /* if it's a SMB root file system */ + bool witness:1; /* use witness protocol */ char *mount_options; }; -- cgit v1.2.3 From e68f4a7bf006af0cc1809bce76785d2811b7de65 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 11 Dec 2020 23:31:16 -0600 Subject: cifs: minor updates to Kconfig Correct references to fs/cifs/README which has been replaced by Documentation/filesystems/admin-guide/cifs/usage.rst, and also correct a typo. Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 664ac5c63d39..fe03cbdae959 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -60,9 +60,9 @@ config CIFS_STATS2 Enabling this option will allow more detailed statistics on SMB request timing to be displayed in /proc/fs/cifs/DebugData and also allow optional logging of slow responses to dmesg (depending on the - value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details). - These additional statistics may have a minor effect on performance - and memory utilization. + value of /proc/fs/cifs/cifsFYI). See Documentation/admin-guide/cifs/usage.rst + for more details. These additional statistics may have a minor effect + on performance and memory utilization. Unless you are a developer or are doing network performance analysis or tuning, say N. @@ -102,10 +102,10 @@ config CIFS_WEAK_PW_HASH is enabled in the kernel build, LANMAN authentication will not be used automatically. At runtime LANMAN mounts are disabled but can be set to required (or optional) either in - /proc/fs/cifs (see fs/cifs/README for more detail) or via an - option on the mount command. This support is disabled by - default in order to reduce the possibility of a downgrade - attack. + /proc/fs/cifs (see Documentation/admin-guide/cifs/usage.rst for + more detail) or via an option on the mount command. This support + is disabled by default in order to reduce the possibility of a + downgrade attack. If unsure, say N. @@ -196,7 +196,7 @@ config CIFS_SWN_UPCALL help The Service Witness Protocol (SWN) is used to get notifications from a highly available server of resource state changes. This - feature enables an upcall mechanism for CIFS which contacts an + feature enables an upcall mechanism for CIFS which contacts a userspace daemon to establish the DCE/RPC connection to retrieve the cluster available interfaces and resource change notifications. If unsure, say Y. -- cgit v1.2.3 From bf80e5d4259a192d6b06ae17e79a5e9dab48bf51 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:51 +0100 Subject: cifs: Send witness register and unregister commands to userspace daemon + Define the generic netlink family commands and message attributes to communicate with the userspace daemon + The register and unregister commands are sent when connecting or disconnecting a tree. The witness registration keeps a pointer to the tcon and has the same lifetime. + Each registration has an id allocated by an IDR. This id is sent to the userspace daemon in the register command, and will be included in the notification messages from the userspace daemon to retrieve from the IDR the matching registration. + The authentication information is bundled in the register message. If kerberos is used the message just carries a flag. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/Makefile | 2 +- fs/cifs/cifs_swn.c | 421 +++++++++++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 17 ++ fs/cifs/connect.c | 26 +- fs/cifs/netlink.c | 11 + include/uapi/linux/cifs/cifs_netlink.h | 15 ++ 6 files changed, 489 insertions(+), 3 deletions(-) create mode 100644 fs/cifs/cifs_swn.c create mode 100644 fs/cifs/cifs_swn.h (limited to 'fs/cifs') diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 9e398d227b0e..5213b20843b5 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -18,7 +18,7 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o -cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o +cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c new file mode 100644 index 000000000000..c0af03955d0c --- /dev/null +++ b/fs/cifs/cifs_swn.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Witness Service client for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#include +#include +#include + +#include "cifs_swn.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "fscache.h" +#include "cifs_debug.h" +#include "netlink.h" + +static DEFINE_IDR(cifs_swnreg_idr); +static DEFINE_MUTEX(cifs_swnreg_idr_mutex); + +struct cifs_swn_reg { + int id; + struct kref ref_count; + + const char *net_name; + const char *share_name; + bool net_name_notify; + bool share_name_notify; + bool ip_notify; + + struct cifs_tcon *tcon; +}; + +static int cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb) +{ + int ret; + + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); + if (ret < 0) + return ret; + + return 0; +} + +static int cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb) +{ + int ret; + + if (tcon->ses->user_name != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); + if (ret < 0) + return ret; + } + + if (tcon->ses->password != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); + if (ret < 0) + return ret; + } + + if (tcon->ses->domainName != NULL) { + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + * Sends a register message to the userspace daemon based on the registration. + * The authentication information to connect to the witness service is bundled + * into the message. + */ +static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) +{ + struct sk_buff *skb; + struct genlmsghdr *hdr; + enum securityEnum authtype; + int ret; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb == NULL) { + ret = -ENOMEM; + goto fail; + } + + hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); + if (hdr == NULL) { + ret = -ENOMEM; + goto nlmsg_fail; + } + + ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), + &swnreg->tcon->ses->server->dstaddr); + if (ret < 0) + goto nlmsg_fail; + + if (swnreg->net_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->share_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->ip_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype); + switch (authtype) { + case Kerberos: + ret = cifs_swn_auth_info_krb(swnreg->tcon, skb); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); + goto nlmsg_fail; + } + break; + case LANMAN: + case NTLM: + case NTLMv2: + case RawNTLMSSP: + ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); + goto nlmsg_fail; + } + break; + default: + cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype); + ret = -EINVAL; + goto nlmsg_fail; + } + + genlmsg_end(skb, hdr); + genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); + + cifs_dbg(FYI, "%s: Message to register for network name %s with id %d sent\n", __func__, + swnreg->net_name, swnreg->id); + + return 0; + +nlmsg_fail: + genlmsg_cancel(skb, hdr); + nlmsg_free(skb); +fail: + return ret; +} + +/* + * Sends an uregister message to the userspace daemon based on the registration + */ +static int cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg) +{ + struct sk_buff *skb; + struct genlmsghdr *hdr; + int ret; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (skb == NULL) + return -ENOMEM; + + hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); + if (hdr == NULL) { + ret = -ENOMEM; + goto nlmsg_fail; + } + + ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); + if (ret < 0) + goto nlmsg_fail; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), + &swnreg->tcon->ses->server->dstaddr); + if (ret < 0) + goto nlmsg_fail; + + if (swnreg->net_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->share_name_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + if (swnreg->ip_notify) { + ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); + if (ret < 0) + goto nlmsg_fail; + } + + genlmsg_end(skb, hdr); + genlmsg_multicast(&cifs_genl_family, skb, 0, CIFS_GENL_MCGRP_SWN, GFP_ATOMIC); + + cifs_dbg(FYI, "%s: Message to unregister for network name %s with id %d sent\n", __func__, + swnreg->net_name, swnreg->id); + + return 0; + +nlmsg_fail: + genlmsg_cancel(skb, hdr); + nlmsg_free(skb); + return ret; +} + +/* + * Try to find a matching registration for the tcon's server name and share name. + * Calls to this funciton must be protected by cifs_swnreg_idr_mutex. + * TODO Try to avoid memory allocations + */ +static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + int id; + const char *share_name; + const char *net_name; + + net_name = extract_hostname(tcon->treeName); + if (IS_ERR_OR_NULL(net_name)) { + int ret; + + ret = PTR_ERR(net_name); + cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", + __func__, tcon->treeName, ret); + return NULL; + } + + share_name = extract_sharename(tcon->treeName); + if (IS_ERR_OR_NULL(share_name)) { + int ret; + + ret = PTR_ERR(net_name); + cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", + __func__, tcon->treeName, ret); + kfree(net_name); + return NULL; + } + + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + if (strcasecmp(swnreg->net_name, net_name) != 0 + || strcasecmp(swnreg->share_name, share_name) != 0) { + continue; + } + + mutex_unlock(&cifs_swnreg_idr_mutex); + + cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name, + swnreg->share_name); + + kfree(net_name); + kfree(share_name); + + return swnreg; + } + + kfree(net_name); + kfree(share_name); + + return NULL; +} + +/* + * Get a registration for the tcon's server and share name, allocating a new one if it does not + * exists + */ +static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *reg = NULL; + int ret; + + mutex_lock(&cifs_swnreg_idr_mutex); + + /* Check if we are already registered for this network and share names */ + reg = cifs_find_swn_reg(tcon); + if (IS_ERR(reg)) { + return reg; + } else if (reg != NULL) { + kref_get(®->ref_count); + mutex_unlock(&cifs_swnreg_idr_mutex); + return reg; + } + + reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC); + if (reg == NULL) { + mutex_unlock(&cifs_swnreg_idr_mutex); + return ERR_PTR(-ENOMEM); + } + + kref_init(®->ref_count); + + reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); + if (reg->id < 0) { + cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__); + ret = reg->id; + goto fail; + } + + reg->net_name = extract_hostname(tcon->treeName); + if (IS_ERR(reg->net_name)) { + ret = PTR_ERR(reg->net_name); + cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); + goto fail_idr; + } + + reg->share_name = extract_sharename(tcon->treeName); + if (IS_ERR(reg->share_name)) { + ret = PTR_ERR(reg->share_name); + cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); + goto fail_net_name; + } + + reg->net_name_notify = true; + reg->share_name_notify = true; + reg->ip_notify = (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT); + + reg->tcon = tcon; + + mutex_unlock(&cifs_swnreg_idr_mutex); + + return reg; + +fail_net_name: + kfree(reg->net_name); +fail_idr: + idr_remove(&cifs_swnreg_idr, reg->id); +fail: + kfree(reg); + mutex_unlock(&cifs_swnreg_idr_mutex); + return ERR_PTR(ret); +} + +static void cifs_swn_reg_release(struct kref *ref) +{ + struct cifs_swn_reg *swnreg = container_of(ref, struct cifs_swn_reg, ref_count); + int ret; + + ret = cifs_swn_send_unregister_message(swnreg); + if (ret < 0) + cifs_dbg(VFS, "%s: Failed to send unregister message: %d\n", __func__, ret); + + idr_remove(&cifs_swnreg_idr, swnreg->id); + kfree(swnreg->net_name); + kfree(swnreg->share_name); + kfree(swnreg); +} + +static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) +{ + mutex_lock(&cifs_swnreg_idr_mutex); + kref_put(&swnreg->ref_count, cifs_swn_reg_release); + mutex_unlock(&cifs_swnreg_idr_mutex); +} + +int cifs_swn_register(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + int ret; + + swnreg = cifs_get_swn_reg(tcon); + if (IS_ERR(swnreg)) + return PTR_ERR(swnreg); + + ret = cifs_swn_send_register_message(swnreg); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); + /* Do not put the swnreg or return error, the echo task will retry */ + } + + return 0; +} + +int cifs_swn_unregister(struct cifs_tcon *tcon) +{ + struct cifs_swn_reg *swnreg; + + mutex_lock(&cifs_swnreg_idr_mutex); + + swnreg = cifs_find_swn_reg(tcon); + if (swnreg == NULL) { + mutex_unlock(&cifs_swnreg_idr_mutex); + return -EEXIST; + } + + mutex_unlock(&cifs_swnreg_idr_mutex); + + cifs_put_swn_reg(swnreg); + + return 0; +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h new file mode 100644 index 000000000000..69c7bd1035da --- /dev/null +++ b/fs/cifs/cifs_swn.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Witness Service client for CIFS + * + * Copyright (c) 2020 Samuel Cabrero + */ + +#ifndef _CIFS_SWN_H +#define _CIFS_SWN_H + +struct cifs_tcon; + +extern int cifs_swn_register(struct cifs_tcon *tcon); + +extern int cifs_swn_unregister(struct cifs_tcon *tcon); + +#endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ead1c086b88d..68ef2da7c74b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -62,6 +62,9 @@ #include "dfs_cache.h" #endif #include "fs_context.h" +#ifdef CONFIG_CIFS_SWN_UPCALL +#include "cifs_swn.h" +#endif extern mempool_t *cifs_req_poolp; extern bool disable_legacy_dialects; @@ -1944,7 +1947,17 @@ cifs_put_tcon(struct cifs_tcon *tcon) return; } - /* TODO witness unregister */ +#ifdef CONFIG_CIFS_SWN_UPCALL + if (tcon->use_witness) { + int rc; + + rc = cifs_swn_unregister(tcon); + if (rc < 0) { + cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", + __func__, rc); + } + } +#endif list_del_init(&tcon->tcon_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2111,8 +2124,17 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) if (ctx->witness) { if (ses->server->vals->protocol_id >= SMB30_PROT_ID) { if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) { - /* TODO witness register */ + /* + * Set witness in use flag in first place + * to retry registration in the echo task + */ tcon->use_witness = true; + /* And try to register immediately */ + rc = cifs_swn_register(tcon); + if (rc < 0) { + cifs_dbg(VFS, "Failed to register for witness notifications: %d\n", rc); + goto out_fail; + } } else { /* TODO: try to extend for non-cluster uses (eg multichannel) */ cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n"); diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c index b9154661fa85..83008a56def5 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -13,6 +13,17 @@ #include "cifs_debug.h" static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { + [CIFS_GENL_ATTR_SWN_REGISTRATION_ID] = { .type = NLA_U32 }, + [CIFS_GENL_ATTR_SWN_NET_NAME] = { .type = NLA_STRING }, + [CIFS_GENL_ATTR_SWN_SHARE_NAME] = { .type = NLA_STRING }, + [CIFS_GENL_ATTR_SWN_IP] = { .len = sizeof(struct sockaddr_storage) }, + [CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY] = { .type = NLA_FLAG }, + [CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY] = { .type = NLA_FLAG }, + [CIFS_GENL_ATTR_SWN_IP_NOTIFY] = { .type = NLA_FLAG }, + [CIFS_GENL_ATTR_SWN_KRB_AUTH] = { .type = NLA_FLAG }, + [CIFS_GENL_ATTR_SWN_USER_NAME] = { .type = NLA_STRING }, + [CIFS_GENL_ATTR_SWN_PASSWORD] = { .type = NLA_STRING }, + [CIFS_GENL_ATTR_SWN_DOMAIN_NAME] = { .type = NLA_STRING }, }; static struct genl_ops cifs_genl_ops[] = { diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h index cdb1bd78fbc7..5662e2774513 100644 --- a/include/uapi/linux/cifs/cifs_netlink.h +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -19,11 +19,26 @@ enum cifs_genl_multicast_groups { }; enum cifs_genl_attributes { + CIFS_GENL_ATTR_UNSPEC, + CIFS_GENL_ATTR_SWN_REGISTRATION_ID, + CIFS_GENL_ATTR_SWN_NET_NAME, + CIFS_GENL_ATTR_SWN_SHARE_NAME, + CIFS_GENL_ATTR_SWN_IP, + CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY, + CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY, + CIFS_GENL_ATTR_SWN_IP_NOTIFY, + CIFS_GENL_ATTR_SWN_KRB_AUTH, + CIFS_GENL_ATTR_SWN_USER_NAME, + CIFS_GENL_ATTR_SWN_PASSWORD, + CIFS_GENL_ATTR_SWN_DOMAIN_NAME, __CIFS_GENL_ATTR_MAX, }; #define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) enum cifs_genl_commands { + CIFS_GENL_CMD_UNSPEC, + CIFS_GENL_CMD_SWN_REGISTER, + CIFS_GENL_CMD_SWN_UNREGISTER, __CIFS_GENL_CMD_MAX }; #define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) -- cgit v1.2.3 From fed979a7e082bd9f25f9002c3c4f8740dacd0bc8 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:52 +0100 Subject: cifs: Set witness notification handler for messages from userspace daemon + Set a handler for the witness notification messages received from the userspace daemon. + Handle the resource state change notification. When the resource becomes unavailable or available set the tcp status to CifsNeedReconnect for all channels. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifs_swn.c | 86 ++++++++++++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 4 ++ fs/cifs/netlink.c | 9 ++++ include/uapi/linux/cifs/cifs_netlink.h | 17 +++++++ 4 files changed, 116 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index c0af03955d0c..63b0764af5d5 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -383,6 +383,92 @@ static void cifs_put_swn_reg(struct cifs_swn_reg *swnreg) mutex_unlock(&cifs_swnreg_idr_mutex); } +static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const char *name, int state) +{ + int i; + + switch (state) { + case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE: + cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name); + for (i = 0; i < swnreg->tcon->ses->chan_count; i++) { + spin_lock(&GlobalMid_Lock); + if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting) + swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + break; + case CIFS_SWN_RESOURCE_STATE_AVAILABLE: + cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name); + for (i = 0; i < swnreg->tcon->ses->chan_count; i++) { + spin_lock(&GlobalMid_Lock); + if (swnreg->tcon->ses->chans[i].server->tcpStatus != CifsExiting) + swnreg->tcon->ses->chans[i].server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + break; + case CIFS_SWN_RESOURCE_STATE_UNKNOWN: + cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name); + break; + } + return 0; +} + +int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) +{ + struct cifs_swn_reg *swnreg; + char name[256]; + int type; + + if (info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]) { + int swnreg_id; + + swnreg_id = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_REGISTRATION_ID]); + mutex_lock(&cifs_swnreg_idr_mutex); + swnreg = idr_find(&cifs_swnreg_idr, swnreg_id); + mutex_unlock(&cifs_swnreg_idr_mutex); + if (swnreg == NULL) { + cifs_dbg(FYI, "%s: registration id %d not found\n", __func__, swnreg_id); + return -EINVAL; + } + } else { + cifs_dbg(FYI, "%s: missing registration id attribute\n", __func__); + return -EINVAL; + } + + if (info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]) { + type = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE]); + } else { + cifs_dbg(FYI, "%s: missing notification type attribute\n", __func__); + return -EINVAL; + } + + switch (type) { + case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE: { + int state; + + if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME]) { + nla_strlcpy(name, info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_NAME], + sizeof(name)); + } else { + cifs_dbg(FYI, "%s: missing resource name attribute\n", __func__); + return -EINVAL; + } + if (info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]) { + state = nla_get_u32(info->attrs[CIFS_GENL_ATTR_SWN_RESOURCE_STATE]); + } else { + cifs_dbg(FYI, "%s: missing resource state attribute\n", __func__); + return -EINVAL; + } + return cifs_swn_resource_state_changed(swnreg, name, state); + } + default: + cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); + break; + } + + return 0; +} + int cifs_swn_register(struct cifs_tcon *tcon) { struct cifs_swn_reg *swnreg; diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 69c7bd1035da..7ef9ecedbd05 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -9,9 +9,13 @@ #define _CIFS_SWN_H struct cifs_tcon; +struct sk_buff; +struct genl_info; extern int cifs_swn_register(struct cifs_tcon *tcon); extern int cifs_swn_unregister(struct cifs_tcon *tcon); +extern int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info); + #endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/netlink.c b/fs/cifs/netlink.c index 83008a56def5..5aaabe4cc0a7 100644 --- a/fs/cifs/netlink.c +++ b/fs/cifs/netlink.c @@ -11,6 +11,7 @@ #include "netlink.h" #include "cifsglob.h" #include "cifs_debug.h" +#include "cifs_swn.h" static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { [CIFS_GENL_ATTR_SWN_REGISTRATION_ID] = { .type = NLA_U32 }, @@ -24,9 +25,17 @@ static const struct nla_policy cifs_genl_policy[CIFS_GENL_ATTR_MAX + 1] = { [CIFS_GENL_ATTR_SWN_USER_NAME] = { .type = NLA_STRING }, [CIFS_GENL_ATTR_SWN_PASSWORD] = { .type = NLA_STRING }, [CIFS_GENL_ATTR_SWN_DOMAIN_NAME] = { .type = NLA_STRING }, + [CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE] = { .type = NLA_U32 }, + [CIFS_GENL_ATTR_SWN_RESOURCE_STATE] = { .type = NLA_U32 }, + [CIFS_GENL_ATTR_SWN_RESOURCE_NAME] = { .type = NLA_STRING}, }; static struct genl_ops cifs_genl_ops[] = { + { + .cmd = CIFS_GENL_CMD_SWN_NOTIFY, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = cifs_swn_notify, + }, }; static const struct genl_multicast_group cifs_genl_mcgrps[] = { diff --git a/include/uapi/linux/cifs/cifs_netlink.h b/include/uapi/linux/cifs/cifs_netlink.h index 5662e2774513..da3107582f49 100644 --- a/include/uapi/linux/cifs/cifs_netlink.h +++ b/include/uapi/linux/cifs/cifs_netlink.h @@ -31,6 +31,9 @@ enum cifs_genl_attributes { CIFS_GENL_ATTR_SWN_USER_NAME, CIFS_GENL_ATTR_SWN_PASSWORD, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, + CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE, + CIFS_GENL_ATTR_SWN_RESOURCE_STATE, + CIFS_GENL_ATTR_SWN_RESOURCE_NAME, __CIFS_GENL_ATTR_MAX, }; #define CIFS_GENL_ATTR_MAX (__CIFS_GENL_ATTR_MAX - 1) @@ -39,8 +42,22 @@ enum cifs_genl_commands { CIFS_GENL_CMD_UNSPEC, CIFS_GENL_CMD_SWN_REGISTER, CIFS_GENL_CMD_SWN_UNREGISTER, + CIFS_GENL_CMD_SWN_NOTIFY, __CIFS_GENL_CMD_MAX }; #define CIFS_GENL_CMD_MAX (__CIFS_GENL_CMD_MAX - 1) +enum cifs_swn_notification_type { + CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE = 0x01, + CIFS_SWN_NOTIFICATION_CLIENT_MOVE = 0x02, + CIFS_SWN_NOTIFICATION_SHARE_MOVE = 0x03, + CIFS_SWN_NOTIFICATION_IP_CHANGE = 0x04, +}; + +enum cifs_swn_resource_state { + CIFS_SWN_RESOURCE_STATE_UNKNOWN = 0x00, + CIFS_SWN_RESOURCE_STATE_AVAILABLE = 0x01, + CIFS_SWN_RESOURCE_STATE_UNAVAILABLE = 0xFF +}; + #endif /* _UAPILINUX_CIFS_NETLINK_H */ -- cgit v1.2.3 From 20fab0da2f2df6de9acdfbdec622f6f2a24da422 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:53 +0100 Subject: cifs: Add witness information to debug data dump + Indicate if witness feature is supported + Indicate if witness is used when dumping tcons + Dumps witness registrations. Example: Witness registrations: Id: 1 Refs: 1 Network name: 'fs.fover.ad'(y) Share name: 'share1'(y) \ Ip address: 192.168.103.200(n) Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 13 +++++++++++++ fs/cifs/cifs_swn.c | 35 +++++++++++++++++++++++++++++++++++ fs/cifs/cifs_swn.h | 2 ++ 3 files changed, 50 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 53588d7517b4..b231dcf1d1f9 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -23,6 +23,9 @@ #ifdef CONFIG_CIFS_SMB_DIRECT #include "smbdirect.h" #endif +#ifdef CONFIG_CIFS_SWN_UPCALL +#include "cifs_swn.h" +#endif void cifs_dump_mem(char *label, void *data, int length) @@ -115,6 +118,10 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon) seq_printf(m, " POSIX Extensions"); if (tcon->ses->server->ops->dump_share_caps) tcon->ses->server->ops->dump_share_caps(m, tcon); +#ifdef CONFIG_CIFS_SWN_UPCALL + if (tcon->use_witness) + seq_puts(m, " Witness"); +#endif if (tcon->need_reconnect) seq_puts(m, "\tDISCONNECTED "); @@ -262,6 +269,9 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, ",XATTR"); #endif seq_printf(m, ",ACL"); +#ifdef CONFIG_CIFS_SWN_UPCALL + seq_puts(m, ",WITNESS"); +#endif seq_putc(m, '\n'); seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize); seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); @@ -462,6 +472,9 @@ skip_rdma: spin_unlock(&cifs_tcp_ses_lock); seq_putc(m, '\n'); +#ifdef CONFIG_CIFS_SWN_UPCALL + cifs_swn_dump(m); +#endif /* BB add code to dump additional info such as TCP session info now */ return 0; } diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 63b0764af5d5..140a53a19aa0 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -505,3 +505,38 @@ int cifs_swn_unregister(struct cifs_tcon *tcon) return 0; } + +void cifs_swn_dump(struct seq_file *m) +{ + struct cifs_swn_reg *swnreg; + struct sockaddr_in *sa; + struct sockaddr_in6 *sa6; + int id; + + seq_puts(m, "Witness registrations:"); + + mutex_lock(&cifs_swnreg_idr_mutex); + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + seq_printf(m, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ", + id, kref_read(&swnreg->ref_count), + swnreg->net_name, swnreg->net_name_notify ? "(y)" : "(n)", + swnreg->share_name, swnreg->share_name_notify ? "(y)" : "(n)"); + switch (swnreg->tcon->ses->server->dstaddr.ss_family) { + case AF_INET: + sa = (struct sockaddr_in *) &swnreg->tcon->ses->server->dstaddr; + seq_printf(m, "%pI4", &sa->sin_addr.s_addr); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *) &swnreg->tcon->ses->server->dstaddr; + seq_printf(m, "%pI6", &sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + seq_printf(m, "%%%u", sa6->sin6_scope_id); + break; + default: + seq_puts(m, "(unknown)"); + } + seq_printf(m, "%s", swnreg->ip_notify ? "(y)" : "(n)"); + } + mutex_unlock(&cifs_swnreg_idr_mutex); + seq_puts(m, "\n"); +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 7ef9ecedbd05..13b25cdc9295 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -18,4 +18,6 @@ extern int cifs_swn_unregister(struct cifs_tcon *tcon); extern int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info); +extern void cifs_swn_dump(struct seq_file *m); + #endif /* _CIFS_SWN_H */ -- cgit v1.2.3 From 21077c62e178e637e6291c669d2681c9570f7a08 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:54 +0100 Subject: cifs: Send witness register messages to userspace daemon in echo task If the daemon starts after mounting a share, or if it crashes, this provides a mechanism to register again. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifs_swn.c | 15 +++++++++++++++ fs/cifs/cifs_swn.h | 2 ++ fs/cifs/connect.c | 5 +++++ 3 files changed, 22 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 140a53a19aa0..642c9eedc8ab 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -540,3 +540,18 @@ void cifs_swn_dump(struct seq_file *m) mutex_unlock(&cifs_swnreg_idr_mutex); seq_puts(m, "\n"); } + +void cifs_swn_check(void) +{ + struct cifs_swn_reg *swnreg; + int id; + int ret; + + mutex_lock(&cifs_swnreg_idr_mutex); + idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { + ret = cifs_swn_send_register_message(swnreg); + if (ret < 0) + cifs_dbg(FYI, "%s: Failed to send register message: %d\n", __func__, ret); + } + mutex_unlock(&cifs_swnreg_idr_mutex); +} diff --git a/fs/cifs/cifs_swn.h b/fs/cifs/cifs_swn.h index 13b25cdc9295..236ecd4959d5 100644 --- a/fs/cifs/cifs_swn.h +++ b/fs/cifs/cifs_swn.h @@ -20,4 +20,6 @@ extern int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info); extern void cifs_swn_dump(struct seq_file *m); +extern void cifs_swn_check(void); + #endif /* _CIFS_SWN_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 68ef2da7c74b..584eddbbbb36 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -405,6 +405,11 @@ cifs_echo_request(struct work_struct *work) cifs_dbg(FYI, "Unable to send echo request to server: %s\n", server->hostname); +#ifdef CONFIG_CIFS_SWN_UPCALL + /* Check witness registrations */ + cifs_swn_check(); +#endif + requeue_echo: queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); } -- cgit v1.2.3 From 7d6535b720421d58886d5590ffc3617d359aa871 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:55 +0100 Subject: cifs: Simplify reconnect code when dfs upcall is enabled Some witness notifications, like client move, tell the client to reconnect to a specific IP address. In this situation the DFS failover code path has to be skipped so clean up as much as possible the cifs_reconnect() code. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/connect.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 584eddbbbb36..156c18bf40d2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -88,7 +88,7 @@ static void cifs_prune_tlinks(struct work_struct *work); * This should be called with server->srv_mutex held. */ #ifdef CONFIG_CIFS_DFS_UPCALL -static int reconn_set_ipaddr(struct TCP_Server_Info *server) +static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server) { int rc; int len; @@ -123,14 +123,7 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server) return !rc ? -1 : 0; } -#else -static inline int reconn_set_ipaddr(struct TCP_Server_Info *server) -{ - return 0; -} -#endif -#ifdef CONFIG_CIFS_DFS_UPCALL /* These functions must be called with server->srv_mutex held */ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, struct cifs_sb_info *cifs_sb, @@ -138,6 +131,7 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, struct dfs_cache_tgt_iterator **tgt_it) { const char *name; + int rc; if (!cifs_sb || !cifs_sb->origin_fullpath) return; @@ -162,6 +156,12 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server, "%s: failed to extract hostname from target: %ld\n", __func__, PTR_ERR(server->hostname)); } + + rc = reconn_set_ipaddr_from_hostname(server); + if (rc) { + cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", + __func__, rc); + } } static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb, @@ -320,11 +320,6 @@ cifs_reconnect(struct TCP_Server_Info *server) */ reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); #endif - rc = reconn_set_ipaddr(server); - if (rc) { - cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", - __func__, rc); - } if (cifs_rdma_enabled(server)) rc = smbd_reconnect(server); -- cgit v1.2.3 From 607dfc79c37a0eb1320485ae9336aba0fd8b7723 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 12 Dec 2020 12:08:58 -0600 Subject: cifs: remove various function description warnings When compiling with W=1 I noticed various functions that did not follow proper style in describing (in the comments) the parameters passed in to the function. For example: fs/cifs/inode.c:2236: warning: Function parameter or member 'mode' not described in 'cifs_wait_bit_killable' I did not address the style warnings in two of the six files (connect.c and misc.c) in order to reduce risk of merge conflict with pending patches. We can update those later. Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 1 + fs/cifs/file.c | 9 +++++++-- fs/cifs/inode.c | 16 +++++++++++----- fs/cifs/smb2misc.c | 4 ++++ 4 files changed, 23 insertions(+), 7 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 6f7187b90fda..e4c6ae47a796 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -254,6 +254,7 @@ compose_mount_options_err: * to perform failover in case we failed to connect to the first target in the * referral. * + * @mntpt: directory entry for the path we are trying to automount * @cifs_sb: parent/root superblock * @fullpath: full path in UNC format */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index be46fab4c96d..29176a56229f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -416,6 +416,8 @@ static void cifsFileInfo_put_work(struct work_struct *work) * cifsFileInfo_put - release a reference of file priv data * * Always potentially wait for oplock handler. See _cifsFileInfo_put(). + * + * @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file */ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) { @@ -431,8 +433,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) * * If @wait_for_oplock_handler is true and we are releasing the last * reference, wait for any running oplock break handler of the file - * and cancel any pending one. If calling this function from the - * oplock break handler, you need to pass false. + * and cancel any pending one. + * + * @cifs_file: cifs/smb3 specific info (eg refcounts) for an open file + * @wait_oplock_handler: must be false if called from oplock_break_handler + * @offload: not offloaded on close and oplock breaks * */ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8debd4c18faf..eb3c88671508 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -804,11 +804,15 @@ static __u64 simple_hashstr(const char *str) * cifs_backup_query_path_info - SMB1 fallback code to get ino * * Fallback code to get file metadata when we don't have access to - * @full_path (EACCES) and have backup creds. + * full_path (EACCES) and have backup creds. * - * @data will be set to search info result buffer - * @resp_buf will be set to cifs resp buf and needs to be freed with - * cifs_buf_release() when done with @data. + * @xid: transaction id used to identify original request in logs + * @tcon: information about the server share we have mounted + * @sb: the superblock stores info such as disk space available + * @full_path: name of the file we are getting the metadata for + * @resp_buf: will be set to cifs resp buf and needs to be freed with + * cifs_buf_release() when done with @data + * @data: will be set to search info result buffer */ static int cifs_backup_query_path_info(int xid, @@ -2229,7 +2233,9 @@ cifs_invalidate_mapping(struct inode *inode) /** * cifs_wait_bit_killable - helper for functions that are sleeping on bit locks - * @word: long word containing the bit lock + * + * @key: currently unused + * @mode: the task state to sleep in */ static int cifs_wait_bit_killable(struct wait_bit_key *key, int mode) diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index c2c5e4122a04..60d4bd1eae2b 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -876,6 +876,10 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) * * Assumes @iov does not contain the rfc1002 length and iov[0] has the * SMB2 header. + * + * @ses: server session structure + * @iov: array containing the SMB request we will send to the server + * @nvec: number of array entries for the iov */ int smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec) -- cgit v1.2.3 From ee0dce4926b95c3c96217c076550216eb6dcd90b Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 12 Dec 2020 12:49:28 -0600 Subject: cifs: remove some minor warnings pointed out by kernel test robot Correct some trivial warnings caused when new file unc.c was created. For example: In file included from fs/cifs/unc.c:11: >> fs/cifs/cifsproto.h:44:28: warning: 'struct TCP_Server_Info' declared inside parameter list will not be visible outside of this definition or declaration 44 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, Reported-by: kernel test robot Signed-off-by: Steve French --- fs/cifs/unc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/unc.c b/fs/cifs/unc.c index 2c5665f5543a..394aa00cea40 100644 --- a/fs/cifs/unc.c +++ b/fs/cifs/unc.c @@ -7,7 +7,11 @@ * Jeff Layton */ +#include #include +#include +#include +#include "cifsglob.h" #include "cifsproto.h" /* extract the host portion of the UNC string */ -- cgit v1.2.3 From 8401e93678933a140cebfa2e7122c1a6b687c355 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 12 Dec 2020 13:40:50 -0600 Subject: cifs: remove [gu]id/backup[gu]id/file_mode/dir_mode from cifs_sb We can already access these from cifs_sb->ctx so we no longer need a local copy in cifs_sb. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 6 ------ fs/cifs/cifsacl.c | 7 ++++--- fs/cifs/cifsfs.c | 12 ++++++------ fs/cifs/connect.c | 15 +++++---------- fs/cifs/file.c | 5 +++-- fs/cifs/inode.c | 39 ++++++++++++++++++++------------------- fs/cifs/misc.c | 5 +++-- fs/cifs/readdir.c | 19 ++++++++++--------- 8 files changed, 51 insertions(+), 57 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 8ee37c80880a..3f4f1487f714 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -67,12 +67,6 @@ struct cifs_sb_info { unsigned int wsize; unsigned long actimeo; /* attribute cache timeout (jiffies) */ atomic_t active; - kuid_t mnt_uid; - kgid_t mnt_gid; - kuid_t mnt_backupuid; - kgid_t mnt_backupgid; - umode_t mnt_file_mode; - umode_t mnt_dir_mode; unsigned int mnt_cifs_flags; struct delayed_work prune_tlinks; struct rcu_head rcu; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c3954bfcb666..2f21f89871cc 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -32,6 +32,7 @@ #include "cifsacl.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "fs_context.h" /* security id for everyone/world system group */ static const struct cifs_sid sid_everyone = { @@ -346,8 +347,8 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, struct key *sidkey; char *sidstr; const struct cred *saved_cred; - kuid_t fuid = cifs_sb->mnt_uid; - kgid_t fgid = cifs_sb->mnt_gid; + kuid_t fuid = cifs_sb->ctx->linux_uid; + kgid_t fgid = cifs_sb->ctx->linux_gid; /* * If we have too many subauthorities, then something is really wrong. @@ -448,7 +449,7 @@ out_revert_creds: /* * Note that we return 0 here unconditionally. If the mapping - * fails then we just fall back to using the mnt_uid/mnt_gid. + * fails then we just fall back to using the ctx->linux_uid/linux_gid. */ got_valid_id: rc = 0; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f810b25dfeb8..3af22c09d8de 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -518,14 +518,14 @@ cifs_show_options(struct seq_file *s, struct dentry *root) } seq_printf(s, ",uid=%u", - from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid)); + from_kuid_munged(&init_user_ns, cifs_sb->ctx->linux_uid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) seq_puts(s, ",forceuid"); else seq_puts(s, ",noforceuid"); seq_printf(s, ",gid=%u", - from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid)); + from_kgid_munged(&init_user_ns, cifs_sb->ctx->linux_gid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) seq_puts(s, ",forcegid"); else @@ -535,8 +535,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) if (!tcon->unix_ext) seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho", - cifs_sb->mnt_file_mode, - cifs_sb->mnt_dir_mode); + cifs_sb->ctx->file_mode, + cifs_sb->ctx->dir_mode); cifs_show_nls(s, cifs_sb->local_nls); @@ -609,11 +609,11 @@ cifs_show_options(struct seq_file *s, struct dentry *root) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) seq_printf(s, ",backupuid=%u", from_kuid_munged(&init_user_ns, - cifs_sb->mnt_backupuid)); + cifs_sb->ctx->backupuid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) seq_printf(s, ",backupgid=%u", from_kgid_munged(&init_user_ns, - cifs_sb->mnt_backupgid)); + cifs_sb->ctx->backupgid)); seq_printf(s, ",rsize=%u", cifs_sb->rsize); seq_printf(s, ",wsize=%u", cifs_sb->wsize); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 156c18bf40d2..f6aa37aa3bf0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2240,11 +2240,12 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) if (new->rsize && new->rsize < old->rsize) return 0; - if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid)) + if (!uid_eq(old->ctx->linux_uid, new->ctx->linux_uid) || + !gid_eq(old->ctx->linux_gid, new->ctx->linux_gid)) return 0; - if (old->mnt_file_mode != new->mnt_file_mode || - old->mnt_dir_mode != new->mnt_dir_mode) + if (old->ctx->file_mode != new->ctx->file_mode || + old->ctx->dir_mode != new->ctx->dir_mode) return 0; if (strcmp(old->local_nls->charset, new->local_nls->charset)) @@ -2707,12 +2708,8 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, cifs_sb->rsize = ctx->rsize; cifs_sb->wsize = ctx->wsize; - cifs_sb->mnt_uid = ctx->linux_uid; - cifs_sb->mnt_gid = ctx->linux_gid; - cifs_sb->mnt_file_mode = ctx->file_mode; - cifs_sb->mnt_dir_mode = ctx->dir_mode; cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", - cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); + cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); cifs_sb->actimeo = ctx->actimeo; cifs_sb->local_nls = ctx->local_nls; @@ -2751,11 +2748,9 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; if (ctx->backupuid_specified) { cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; - cifs_sb->mnt_backupuid = ctx->backupuid; } if (ctx->backupgid_specified) { cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; - cifs_sb->mnt_backupgid = ctx->backupgid; } if (ctx->override_uid) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 29176a56229f..583074546e6f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -44,6 +44,7 @@ #include "cifs_fs_sb.h" #include "fscache.h" #include "smbdirect.h" +#include "fs_context.h" static inline int cifs_convert_flags(unsigned int flags) { @@ -571,7 +572,7 @@ int cifs_open(struct inode *inode, struct file *file) le64_to_cpu(tcon->fsUnixInfo.Capability))) { /* can not refresh inode info since size could be stale */ rc = cifs_posix_open(full_path, &inode, inode->i_sb, - cifs_sb->mnt_file_mode /* ignored */, + cifs_sb->ctx->file_mode /* ignored */, file->f_flags, &oplock, &fid.netfid, xid); if (rc == 0) { cifs_dbg(FYI, "posix open succeeded\n"); @@ -740,7 +741,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) ~(O_CREAT | O_EXCL | O_TRUNC); rc = cifs_posix_open(full_path, NULL, inode->i_sb, - cifs_sb->mnt_file_mode /* ignored */, + cifs_sb->ctx->file_mode /* ignored */, oflags, &oplock, &cfile->fid.netfid, xid); if (rc == 0) { cifs_dbg(FYI, "posix reopen succeeded\n"); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index eb3c88671508..bbdce32e978f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -37,6 +37,7 @@ #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "fscache.h" +#include "fs_context.h" static void cifs_set_ops(struct inode *inode) @@ -294,7 +295,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, break; } - fattr->cf_uid = cifs_sb->mnt_uid; + fattr->cf_uid = cifs_sb->ctx->linux_uid; if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { u64 id = le64_to_cpu(info->Uid); if (id < ((uid_t)-1)) { @@ -304,7 +305,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, } } - fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { u64 id = le64_to_cpu(info->Gid); if (id < ((gid_t)-1)) { @@ -333,8 +334,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) memset(fattr, 0, sizeof(*fattr)); fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; - fattr->cf_uid = cifs_sb->mnt_uid; - fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; ktime_get_coarse_real_ts64(&fattr->cf_mtime); fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; fattr->cf_nlink = 2; @@ -644,8 +645,8 @@ smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo * } /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ - fattr->cf_uid = cifs_sb->mnt_uid; /* TODO: map uid and gid from SID */ - fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_uid = cifs_sb->ctx->linux_uid; /* TODO: map uid and gid from SID */ + fattr->cf_gid = cifs_sb->ctx->linux_gid; cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); @@ -685,25 +686,25 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) { - fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_LNK; } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) { - fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_FIFO; } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) { - fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_SOCK; } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) { - fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_CHR; } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) { - fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_BLK; } else if (symlink) { /* TODO add more reparse tag checks */ fattr->cf_mode = S_IFLNK; fattr->cf_dtype = DT_LNK; } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { - fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; + fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; fattr->cf_dtype = DT_DIR; /* * Server can return wrong NumberOfLinks value for directories @@ -712,7 +713,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, if (!tcon->unix_ext) fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; } else { - fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; + fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_REG; /* clear write bits if ATTR_READONLY is set */ @@ -731,8 +732,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, } } - fattr->cf_uid = cifs_sb->mnt_uid; - fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; } static int @@ -1391,8 +1392,8 @@ iget_no_retry: set_nlink(inode, 2); inode->i_op = &cifs_ipc_inode_ops; inode->i_fop = &simple_dir_operations; - inode->i_uid = cifs_sb->mnt_uid; - inode->i_gid = cifs_sb->mnt_gid; + inode->i_uid = cifs_sb->ctx->linux_uid; + inode->i_gid = cifs_sb->ctx->linux_gid; spin_unlock(&inode->i_lock); } else if (rc) { iget_failed(inode); @@ -2877,10 +2878,10 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) attrs->ia_mode &= ~(S_IALLUGO); if (S_ISDIR(inode->i_mode)) attrs->ia_mode |= - cifs_sb->mnt_dir_mode; + cifs_sb->ctx->dir_mode; else attrs->ia_mode |= - cifs_sb->mnt_file_mode; + cifs_sb->ctx->file_mode; } } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { /* ignore mode change - ATTR_READONLY hasn't changed */ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c14cf01dbef..82e176720ca6 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -35,6 +35,7 @@ #ifdef CONFIG_CIFS_DFS_UPCALL #include "dns_resolve.h" #endif +#include "fs_context.h" extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; @@ -632,11 +633,11 @@ bool backup_cred(struct cifs_sb_info *cifs_sb) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) { - if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid())) + if (uid_eq(cifs_sb->ctx->backupuid, current_fsuid())) return true; } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) { - if (in_group_p(cifs_sb->mnt_backupgid)) + if (in_group_p(cifs_sb->ctx->backupgid)) return true; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 799be3a5d25e..80bf4c6f4c7b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -33,6 +33,7 @@ #include "cifs_fs_sb.h" #include "cifsfs.h" #include "smb2proto.h" +#include "fs_context.h" /* * To be safe - for UCS to UTF-8 with strings loaded with the rare long @@ -165,8 +166,8 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr) static void cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) { - fattr->cf_uid = cifs_sb->mnt_uid; - fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; /* * The IO_REPARSE_TAG_LX_ tags originally were used by WSL but they @@ -177,25 +178,25 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) * reasonably map some of them to directories vs. files vs. symlinks */ if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { - fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; + fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode; fattr->cf_dtype = DT_DIR; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) { - fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_LNK; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) { - fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_FIFO; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) { - fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_SOCK; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) { - fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_CHR; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) { - fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode; + fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_BLK; } else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */ - fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; + fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode; fattr->cf_dtype = DT_REG; } -- cgit v1.2.3 From af1e40d9ac8417839d955ca1ac42f754588937a9 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 10 Nov 2020 12:34:48 +1000 Subject: cifs: remove actimeo from cifs_sb Can now be accessed via the ctx Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 - fs/cifs/cifsfs.c | 2 +- fs/cifs/connect.c | 3 +-- fs/cifs/inode.c | 4 ++-- 4 files changed, 4 insertions(+), 6 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 3f4f1487f714..69d26313d350 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -65,7 +65,6 @@ struct cifs_sb_info { unsigned int bsize; unsigned int rsize; unsigned int wsize; - unsigned long actimeo; /* attribute cache timeout (jiffies) */ atomic_t active; unsigned int mnt_cifs_flags; struct delayed_work prune_tlinks; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3af22c09d8de..0932a3b225be 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -632,7 +632,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) if (tcon->handle_timeout) seq_printf(s, ",handletimeout=%u", tcon->handle_timeout); /* convert actimeo and display it in seconds */ - seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); + seq_printf(s, ",actimeo=%lu", cifs_sb->ctx->actimeo / HZ); if (tcon->ses->chan_max > 1) seq_printf(s, ",multichannel,max_channels=%zu", diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f6aa37aa3bf0..1c8b08c06ad7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2251,7 +2251,7 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) if (strcmp(old->local_nls->charset, new->local_nls->charset)) return 0; - if (old->actimeo != new->actimeo) + if (old->ctx->actimeo != new->ctx->actimeo) return 0; return 1; @@ -2711,7 +2711,6 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); - cifs_sb->actimeo = ctx->actimeo; cifs_sb->local_nls = ctx->local_nls; if (ctx->nodfs) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index bbdce32e978f..240d79e3aa14 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2198,11 +2198,11 @@ cifs_inode_needs_reval(struct inode *inode) if (!lookupCacheEnabled) return true; - if (!cifs_sb->actimeo) + if (!cifs_sb->ctx->actimeo) return true; if (!time_in_range(jiffies, cifs_i->time, - cifs_i->time + cifs_sb->actimeo)) + cifs_i->time + cifs_sb->ctx->actimeo)) return true; /* hardlinked files w/ noserverino get "special" treatment */ -- cgit v1.2.3 From 121d947d4fe15bcec90bcfc1249ee9b739cb9258 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 30 Nov 2020 19:02:56 +0100 Subject: cifs: Handle witness client move notification This message is sent to tell a client to close its current connection and connect to the specified address. Signed-off-by: Samuel Cabrero Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifs_swn.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/cifsglob.h | 4 ++ fs/cifs/connect.c | 26 +++++++--- 3 files changed, 162 insertions(+), 8 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 642c9eedc8ab..a172769c239f 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -78,6 +78,7 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) struct sk_buff *skb; struct genlmsghdr *hdr; enum securityEnum authtype; + struct sockaddr_storage *addr; int ret; skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -104,8 +105,18 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) if (ret < 0) goto nlmsg_fail; - ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), - &swnreg->tcon->ses->server->dstaddr); + /* + * If there is an address stored use it instead of the server address, because we are + * in the process of reconnecting to it after a share has been moved or we have been + * told to switch to it (client move message). In these cases we unregister from the + * server address and register to the new address when we receive the notification. + */ + if (swnreg->tcon->ses->server->use_swn_dstaddr) + addr = &swnreg->tcon->ses->server->swn_dstaddr; + else + addr = &swnreg->tcon->ses->server->dstaddr; + + ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); if (ret < 0) goto nlmsg_fail; @@ -413,6 +424,120 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch return 0; } +static bool cifs_sockaddr_equal(struct sockaddr_storage *addr1, struct sockaddr_storage *addr2) +{ + if (addr1->ss_family != addr2->ss_family) + return false; + + if (addr1->ss_family == AF_INET) { + return (memcmp(&((const struct sockaddr_in *)addr1)->sin_addr, + &((const struct sockaddr_in *)addr2)->sin_addr, + sizeof(struct in_addr)) == 0); + } + + if (addr1->ss_family == AF_INET6) { + return (memcmp(&((const struct sockaddr_in6 *)addr1)->sin6_addr, + &((const struct sockaddr_in6 *)addr2)->sin6_addr, + sizeof(struct in6_addr)) == 0); + } + + return false; +} + +static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new, + const struct sockaddr_storage *old, + struct sockaddr_storage *dst) +{ + __be16 port; + + if (old->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)old; + + port = ipv4->sin_port; + } + + if (old->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)old; + + port = ipv6->sin6_port; + } + + if (new->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)new; + + ipv4->sin_port = port; + } + + if (new->ss_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)new; + + ipv6->sin6_port = port; + } + + *dst = *new; + + return 0; +} + +static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr) +{ + /* Store the reconnect address */ + mutex_lock(&tcon->ses->server->srv_mutex); + if (!cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) { + int ret; + + ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr, + &tcon->ses->server->swn_dstaddr); + if (ret < 0) { + cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); + return ret; + } + tcon->ses->server->use_swn_dstaddr = true; + + /* + * Unregister to stop receiving notifications for the old IP address. + */ + ret = cifs_swn_unregister(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n", + __func__, ret); + return ret; + } + + /* + * And register to receive notifications for the new IP address now that we have + * stored the new address. + */ + ret = cifs_swn_register(tcon); + if (ret < 0) { + cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n", + __func__, ret); + return ret; + } + + spin_lock(&GlobalMid_Lock); + if (tcon->ses->server->tcpStatus != CifsExiting) + tcon->ses->server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + } + mutex_unlock(&tcon->ses->server->srv_mutex); + + return 0; +} + +static int cifs_swn_client_move(struct cifs_swn_reg *swnreg, struct sockaddr_storage *addr) +{ + struct sockaddr_in *ipv4 = (struct sockaddr_in *)addr; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)addr; + + if (addr->ss_family == AF_INET) + cifs_dbg(FYI, "%s: move to %pI4\n", __func__, &ipv4->sin_addr); + else if (addr->ss_family == AF_INET6) + cifs_dbg(FYI, "%s: move to %pI6\n", __func__, &ipv6->sin6_addr); + + return cifs_swn_reconnect(swnreg->tcon, addr); +} + int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) { struct cifs_swn_reg *swnreg; @@ -461,6 +586,17 @@ int cifs_swn_notify(struct sk_buff *skb, struct genl_info *info) } return cifs_swn_resource_state_changed(swnreg, name, state); } + case CIFS_SWN_NOTIFICATION_CLIENT_MOVE: { + struct sockaddr_storage addr; + + if (info->attrs[CIFS_GENL_ATTR_SWN_IP]) { + nla_memcpy(&addr, info->attrs[CIFS_GENL_ATTR_SWN_IP], sizeof(addr)); + } else { + cifs_dbg(FYI, "%s: missing IP address attribute\n", __func__); + return -EINVAL; + } + return cifs_swn_client_move(swnreg, &addr); + } default: cifs_dbg(FYI, "%s: unknown notification type %d\n", __func__, type); break; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 78438102f091..720d0f6a982d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -687,6 +687,10 @@ struct TCP_Server_Info { int nr_targets; bool noblockcnt; /* use non-blocking connect() */ bool is_channel; /* if a session channel */ +#ifdef CONFIG_CIFS_SWN_UPCALL + bool use_swn_dstaddr; + struct sockaddr_storage swn_dstaddr; +#endif }; struct cifs_credits { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1c8b08c06ad7..9f59fe2a03e6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -312,13 +312,24 @@ cifs_reconnect(struct TCP_Server_Info *server) try_to_freeze(); mutex_lock(&server->srv_mutex); + +#ifdef CONFIG_CIFS_SWN_UPCALL + if (server->use_swn_dstaddr) { + server->dstaddr = server->swn_dstaddr; + } else { +#endif + #ifdef CONFIG_CIFS_DFS_UPCALL - /* - * Set up next DFS target server (if any) for reconnect. If DFS - * feature is disabled, then we will retry last server we - * connected to before. - */ - reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); + /* + * Set up next DFS target server (if any) for reconnect. If DFS + * feature is disabled, then we will retry last server we + * connected to before. + */ + reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); +#endif + +#ifdef CONFIG_CIFS_SWN_UPCALL + } #endif if (cifs_rdma_enabled(server)) @@ -336,6 +347,9 @@ cifs_reconnect(struct TCP_Server_Info *server) if (server->tcpStatus != CifsExiting) server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); +#ifdef CONFIG_CIFS_SWN_UPCALL + server->use_swn_dstaddr = false; +#endif mutex_unlock(&server->srv_mutex); } } while (server->tcpStatus == CifsNeedReconnect); -- cgit v1.2.3 From 427c4f004e173732ab0eb248e6ec89ef79524cd5 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 14 Dec 2020 14:37:45 +0300 Subject: cifs: Add missing sentinel to smb3_fs_parameters Add missing sentinel to smb3_fs_parameters. This fixes ARM32 kernel crashing once CIFS is registered. Unable to handle kernel paging request at virtual address 33626d73 ... (strcmp) from (fs_validate_description) (fs_validate_description) from (register_filesystem) (register_filesystem) from (init_cifs [cifs]) (init_cifs [cifs]) from (do_one_initcall) (do_one_initcall) from (do_init_module) (do_init_module) from (load_module) (load_module) from (sys_finit_module) (sys_finit_module) from (ret_fast_syscal) Fixes: e07724d1cf38 ("cifs: switch to new mount api") Signed-off-by: Dmitry Osipenko Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/fs_context.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index fe5cc60f4393..c41e87af77b6 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -173,6 +173,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag_no("mand", Opt_ignore), fsparam_string("cred", Opt_ignore), fsparam_string("credentials", Opt_ignore), + {} }; int -- cgit v1.2.3 From c741cba2cd1d145c71f928c329cac007e6f99e42 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:16 +1000 Subject: cifs: move cifs_cleanup_volume_info[_content] to fs_context.c and rename it to smb3_cleanup_fs_context[_content] Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsproto.h | 3 --- fs/cifs/connect.c | 47 ++++------------------------------------------- fs/cifs/dfs_cache.c | 4 ++-- fs/cifs/fs_context.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/fs_context.h | 2 ++ 6 files changed, 51 insertions(+), 52 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0932a3b225be..9c2959f552e0 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -874,7 +874,7 @@ out_super: out: if (cifs_sb) { kfree(cifs_sb->prepath); - cifs_cleanup_volume_info(cifs_sb->ctx); + smb3_cleanup_fs_context(cifs_sb->ctx); kfree(cifs_sb); } return root; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b80b57a66804..891c8d8c2bb5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -237,7 +237,6 @@ extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, extern int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb); extern int cifs_match_super(struct super_block *, void *); -extern void cifs_cleanup_volume_info(struct smb3_fs_context *ctx); extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); @@ -552,8 +551,6 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, extern int cifs_setup_volume_info(struct smb3_fs_context *ctx); -extern void -cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx); extern struct TCP_Server_Info * cifs_find_tcp_session(struct smb3_fs_context *ctx); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9f59fe2a03e6..16d92ff4ae5e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2820,45 +2820,6 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, return 0; } -void -cifs_cleanup_volume_info_contents(struct smb3_fs_context *ctx) -{ - if (ctx == NULL) - return; - - /* - * Make sure this stays in sync with smb3_fs_context_dup() - */ - kfree(ctx->mount_options); - ctx->mount_options = NULL; - kfree(ctx->username); - ctx->username = NULL; - kfree_sensitive(ctx->password); - ctx->password = NULL; - kfree(ctx->UNC); - ctx->UNC = NULL; - kfree(ctx->domainname); - ctx->domainname = NULL; - kfree(ctx->nodename); - ctx->nodename = NULL; - kfree(ctx->iocharset); - ctx->iocharset = NULL; - kfree(ctx->prepath); - ctx->prepath = NULL; - - unload_nls(ctx->local_nls); - ctx->local_nls = NULL; -} - -void -cifs_cleanup_volume_info(struct smb3_fs_context *ctx) -{ - if (!ctx) - return; - cifs_cleanup_volume_info_contents(ctx); - kfree(ctx); -} - /* Release all succeed connections */ static inline void mount_put_conns(struct cifs_sb_info *cifs_sb, unsigned int xid, @@ -3069,7 +3030,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, rc = PTR_ERR(mdata); mdata = NULL; } else { - cifs_cleanup_volume_info_contents(ctx); + smb3_cleanup_fs_context_contents(ctx); rc = cifs_setup_volume_info(ctx); } kfree(cifs_sb->ctx->mount_options); @@ -3161,7 +3122,7 @@ static int setup_dfs_tgt_conn(const char *path, const char *full_path, rc = update_vol_info(tgt_it, &fake_ctx, ctx); } } - cifs_cleanup_volume_info_contents(&fake_ctx); + smb3_cleanup_fs_context_contents(&fake_ctx); return rc; } @@ -3409,7 +3370,7 @@ static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_contex break; rc = -EREMOTE; npath = build_unc_path_to_root(&v, cifs_sb, true); - cifs_cleanup_volume_info_contents(&v); + smb3_cleanup_fs_context_contents(&v); } else { v.UNC = ctx->UNC; v.prepath = path + 1; @@ -3773,7 +3734,7 @@ static void delayed_free(struct rcu_head *p) struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu); unload_nls(cifs_sb->local_nls); - cifs_cleanup_volume_info(cifs_sb->ctx); + smb3_cleanup_fs_context(cifs_sb->ctx); kfree(cifs_sb); } diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index 6bccff4596bf..6ad6ba5f6ebe 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -587,7 +587,7 @@ static void __vol_release(struct vol_info *vi) { kfree(vi->fullpath); kfree(vi->mntdata); - cifs_cleanup_volume_info_contents(&vi->ctx); + smb3_cleanup_fs_context_contents(&vi->ctx); kfree(vi); } @@ -1468,7 +1468,7 @@ static struct cifs_ses *find_root_ses(struct vol_info *vi, ses = cifs_get_smb_ses(server, &ctx); out: - cifs_cleanup_volume_info_contents(&ctx); + smb3_cleanup_fs_context_contents(&ctx); kfree(mdata); kfree(rpath); diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index c41e87af77b6..4d8caf5b9519 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -290,7 +290,7 @@ do { \ if (ctx->field) { \ new_ctx->field = kstrdup(ctx->field, GFP_ATOMIC); \ if (new_ctx->field == NULL) { \ - cifs_cleanup_volume_info_contents(new_ctx); \ + smb3_cleanup_fs_context_contents(new_ctx); \ return -ENOMEM; \ } \ } \ @@ -313,7 +313,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx new_ctx->iocharset = NULL; /* - * Make sure to stay in sync with cifs_cleanup_volume_info_contents() + * Make sure to stay in sync with smb3_cleanup_fs_context_contents() */ DUP_CTX_STR(prepath); DUP_CTX_STR(mount_options); @@ -618,7 +618,7 @@ static void smb3_fs_context_free(struct fs_context *fc) { struct smb3_fs_context *ctx = smb3_fc2context(fc); - cifs_cleanup_volume_info(ctx); + smb3_cleanup_fs_context(ctx); } static int smb3_reconfigure(struct fs_context *fc) @@ -1244,3 +1244,42 @@ int smb3_init_fs_context(struct fs_context *fc) fc->ops = &smb3_fs_context_ops; return 0; } + +void +smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx) +{ + if (ctx == NULL) + return; + + /* + * Make sure this stays in sync with smb3_fs_context_dup() + */ + kfree(ctx->mount_options); + ctx->mount_options = NULL; + kfree(ctx->username); + ctx->username = NULL; + kfree_sensitive(ctx->password); + ctx->password = NULL; + kfree(ctx->UNC); + ctx->UNC = NULL; + kfree(ctx->domainname); + ctx->domainname = NULL; + kfree(ctx->nodename); + ctx->nodename = NULL; + kfree(ctx->iocharset); + ctx->iocharset = NULL; + kfree(ctx->prepath); + ctx->prepath = NULL; + + unload_nls(ctx->local_nls); + ctx->local_nls = NULL; +} + +void +smb3_cleanup_fs_context(struct smb3_fs_context *ctx) +{ + if (!ctx) + return; + smb3_cleanup_fs_context_contents(ctx); + kfree(ctx); +} diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index aaec8a819d34..4c4c392b9767 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -254,6 +254,8 @@ extern int cifs_parse_cache_flavor(char *value, extern int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx); extern int smb3_init_fs_context(struct fs_context *fc); +extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx); +extern void smb3_cleanup_fs_context(struct smb3_fs_context *ctx); static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *fc) { -- cgit v1.2.3 From 522aa3b575322597efdd64a517c65b2f43fb6b9c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:17 +1000 Subject: cifs: move [brw]size from cifs_sb to cifs_sb->ctx Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 3 --- fs/cifs/cifsfs.c | 11 +++++++---- fs/cifs/connect.c | 21 +++++++++------------ fs/cifs/file.c | 12 ++++++------ fs/cifs/fs_context.c | 3 +++ fs/cifs/fs_context.h | 3 +++ fs/cifs/inode.c | 2 +- fs/cifs/smb1ops.c | 2 +- fs/cifs/smb2ops.c | 2 +- 9 files changed, 31 insertions(+), 28 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 69d26313d350..aa77edc12212 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -62,9 +62,6 @@ struct cifs_sb_info { struct tcon_link *master_tlink; struct nls_table *local_nls; struct smb3_fs_context *ctx; - unsigned int bsize; - unsigned int rsize; - unsigned int wsize; atomic_t active; unsigned int mnt_cifs_flags; struct delayed_work prune_tlinks; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9c2959f552e0..6a3cb192d75a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -218,7 +218,7 @@ cifs_read_super(struct super_block *sb) if (rc) goto out_no_root; /* tune readahead according to rsize */ - sb->s_bdi->ra_pages = cifs_sb->rsize / PAGE_SIZE; + sb->s_bdi->ra_pages = cifs_sb->ctx->rsize / PAGE_SIZE; sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ @@ -615,9 +615,12 @@ cifs_show_options(struct seq_file *s, struct dentry *root) from_kgid_munged(&init_user_ns, cifs_sb->ctx->backupgid)); - seq_printf(s, ",rsize=%u", cifs_sb->rsize); - seq_printf(s, ",wsize=%u", cifs_sb->wsize); - seq_printf(s, ",bsize=%u", cifs_sb->bsize); + if (cifs_sb->ctx->got_rsize) + seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); + if (cifs_sb->ctx->got_wsize) + seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize); + if (cifs_sb->ctx->got_bsize) + seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize); if (tcon->ses->server->min_offload) seq_printf(s, ",esize=%u", tcon->ses->server->min_offload); seq_printf(s, ",echo_interval=%lu", diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 16d92ff4ae5e..eb036cf0f631 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2248,10 +2248,10 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) * We want to share sb only if we don't specify an r/wsize or * specified r/wsize is greater than or equal to existing one. */ - if (new->wsize && new->wsize < old->wsize) + if (new->ctx->wsize && new->ctx->wsize < old->ctx->wsize) return 0; - if (new->rsize && new->rsize < old->rsize) + if (new->ctx->rsize && new->ctx->rsize < old->ctx->rsize) return 0; if (!uid_eq(old->ctx->linux_uid, new->ctx->linux_uid) || @@ -2714,14 +2714,6 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; - cifs_sb->bsize = ctx->bsize; - /* - * Temporarily set r/wsize for matching superblock. If we end up using - * new sb then client will later negotiate it downward if needed. - */ - cifs_sb->rsize = ctx->rsize; - cifs_sb->wsize = ctx->wsize; - cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); @@ -2925,8 +2917,13 @@ static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cif } } - cifs_sb->wsize = server->ops->negotiate_wsize(tcon, ctx); - cifs_sb->rsize = server->ops->negotiate_rsize(tcon, ctx); + /* + * Clamp the rsize/wsize mount arguments if they are too big for the server + */ + if (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx)) + cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); + if (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)) + cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); return 0; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 583074546e6f..6d001905c8e5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2336,7 +2336,7 @@ static int cifs_writepages(struct address_space *mapping, * If wsize is smaller than the page cache size, default to writing * one page at a time via cifs_writepage */ - if (cifs_sb->wsize < PAGE_SIZE) + if (cifs_sb->ctx->wsize < PAGE_SIZE) return generic_writepages(mapping, wbc); xid = get_xid(); @@ -2369,7 +2369,7 @@ retry: if (rc) get_file_rc = rc; - rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, + rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize, &wsize, credits); if (rc != 0) { done = true; @@ -2911,7 +2911,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, break; } - rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, + rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->wsize, &wsize, credits); if (rc) break; @@ -3642,7 +3642,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, break; } - rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, + rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize, credits); if (rc) break; @@ -4028,7 +4028,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) cifs_sb = CIFS_FILE_SB(file); /* FIXME: set up handlers for larger reads and/or convert to async */ - rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize); + rsize = min_t(unsigned int, cifs_sb->ctx->rsize, CIFSMaxBufSize); if (file->private_data == NULL) { rc = -EBADF; @@ -4413,7 +4413,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, break; } - rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, + rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize, &rsize, credits); if (rc) break; diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 4d8caf5b9519..b7f5633a1c64 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -784,12 +784,15 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, goto cifs_parse_mount_err; } ctx->bsize = result.uint_32; + ctx->got_bsize = true; break; case Opt_rsize: ctx->rsize = result.uint_32; + ctx->got_rsize = true; break; case Opt_wsize: ctx->wsize = result.uint_32; + ctx->got_wsize = true; break; case Opt_actimeo: ctx->actimeo = HZ * result.uint_32; diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 4c4c392b9767..7c794df7a874 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -152,6 +152,9 @@ struct smb3_fs_context { char *nodename; bool got_ip; bool got_version; + bool got_rsize; + bool got_wsize; + bool got_bsize; unsigned short port; char *username; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 240d79e3aa14..a83b3a8ffaac 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2409,7 +2409,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat, } generic_fillattr(inode, stat); - stat->blksize = cifs_sb->bsize; + stat->blksize = cifs_sb->ctx->bsize; stat->ino = CIFS_I(inode)->uniqueid; /* old CIFS Unix Extensions doesn't return create time */ diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 359a0ef796de..e31b939e628c 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -1006,7 +1006,7 @@ cifs_is_read_op(__u32 oplock) static unsigned int cifs_wp_retry_size(struct inode *inode) { - return CIFS_SB(inode->i_sb)->wsize; + return CIFS_SB(inode->i_sb)->ctx->wsize; } static bool diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 940e61e92a8c..a505cc3e58da 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3951,7 +3951,7 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key) static unsigned int smb2_wp_retry_size(struct inode *inode) { - return min_t(unsigned int, CIFS_SB(inode->i_sb)->wsize, + return min_t(unsigned int, CIFS_SB(inode->i_sb)->ctx->wsize, SMB2_MAX_BUFFER_SIZE); } -- cgit v1.2.3 From d6a78783407cdf9f8dcf677f7e5a26b1aa22bc0e Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:18 +1000 Subject: cifs: add initial reconfigure support Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/fs_context.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index b7f5633a1c64..18b469fab521 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -621,14 +621,44 @@ static void smb3_fs_context_free(struct fs_context *fc) smb3_cleanup_fs_context(ctx); } -static int smb3_reconfigure(struct fs_context *fc) +/* + * Compare the old and new proposed context during reconfigure + * and check if the changes are compatible. + */ +static int smb3_verify_reconfigure_ctx(struct smb3_fs_context *new_ctx, + struct smb3_fs_context *old_ctx) { - // TODO: struct smb3_fs_context *ctx = smb3_fc2context(fc); + if (new_ctx->sectype != old_ctx->sectype) { + cifs_dbg(VFS, "can not change sec during remount\n"); + return -EINVAL; + } - /* FIXME : add actual reconfigure */ return 0; } +static int smb3_reconfigure(struct fs_context *fc) +{ + struct smb3_fs_context *ctx = smb3_fc2context(fc); + struct dentry *root = fc->root; + struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); + int rc; + + rc = smb3_verify_reconfigure_ctx(ctx, cifs_sb->ctx); + if (rc) + return rc; + + /* + * Steal the UNC from the old and to be destroyed context. + */ + ctx->UNC = cifs_sb->ctx->UNC; + cifs_sb->ctx->UNC = NULL; + + smb3_cleanup_fs_context_contents(cifs_sb->ctx); + rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); + + return rc; +} + static int smb3_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { -- cgit v1.2.3 From 9ccecae8d1d7131439fb4849f51e614ef7395298 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:19 +1000 Subject: cifs: we do not allow changing username/password/unc/... during remount Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/fs_context.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/fs_context.h | 2 +- 3 files changed, 52 insertions(+), 5 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6a3cb192d75a..276b0659c238 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -493,7 +493,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) if (tcon->no_lease) seq_puts(s, ",nolease"); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) + if (cifs_sb->ctx->multiuser) seq_puts(s, ",multiuser"); else if (tcon->ses->user_name) seq_show_option(s, "username", tcon->ses->user_name); diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 18b469fab521..b807f8a78adc 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -632,10 +632,51 @@ static int smb3_verify_reconfigure_ctx(struct smb3_fs_context *new_ctx, cifs_dbg(VFS, "can not change sec during remount\n"); return -EINVAL; } + if (new_ctx->multiuser != old_ctx->multiuser) { + cifs_dbg(VFS, "can not change multiuser during remount\n"); + return -EINVAL; + } + if (new_ctx->UNC && + (!old_ctx->UNC || strcmp(new_ctx->UNC, old_ctx->UNC))) { + cifs_dbg(VFS, "can not change UNC during remount\n"); + return -EINVAL; + } + if (new_ctx->username && + (!old_ctx->username || strcmp(new_ctx->username, old_ctx->username))) { + cifs_dbg(VFS, "can not change username during remount\n"); + return -EINVAL; + } + if (new_ctx->password && + (!old_ctx->password || strcmp(new_ctx->password, old_ctx->password))) { + cifs_dbg(VFS, "can not change password during remount\n"); + return -EINVAL; + } + if (new_ctx->domainname && + (!old_ctx->domainname || strcmp(new_ctx->domainname, old_ctx->domainname))) { + cifs_dbg(VFS, "can not change domainname during remount\n"); + return -EINVAL; + } + if (new_ctx->nodename && + (!old_ctx->nodename || strcmp(new_ctx->nodename, old_ctx->nodename))) { + cifs_dbg(VFS, "can not change nodename during remount\n"); + return -EINVAL; + } + if (new_ctx->iocharset && + (!old_ctx->iocharset || strcmp(new_ctx->iocharset, old_ctx->iocharset))) { + cifs_dbg(VFS, "can not change iocharset during remount\n"); + return -EINVAL; + } return 0; } +#define STEAL_STRING(cifs_sb, ctx, field) \ +do { \ + kfree(ctx->field); \ + ctx->field = cifs_sb->ctx->field; \ + cifs_sb->ctx->field = NULL; \ +} while (0) + static int smb3_reconfigure(struct fs_context *fc) { struct smb3_fs_context *ctx = smb3_fc2context(fc); @@ -648,10 +689,16 @@ static int smb3_reconfigure(struct fs_context *fc) return rc; /* - * Steal the UNC from the old and to be destroyed context. + * We can not change UNC/username/password/domainname/nodename/iocharset + * during reconnect so ignore what we have in the new context and + * just use what we already have in cifs_sb->ctx. */ - ctx->UNC = cifs_sb->ctx->UNC; - cifs_sb->ctx->UNC = NULL; + STEAL_STRING(cifs_sb, ctx, UNC); + STEAL_STRING(cifs_sb, ctx, username); + STEAL_STRING(cifs_sb, ctx, password); + STEAL_STRING(cifs_sb, ctx, domainname); + STEAL_STRING(cifs_sb, ctx, nodename); + STEAL_STRING(cifs_sb, ctx, iocharset); smb3_cleanup_fs_context_contents(cifs_sb->ctx); rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 7c794df7a874..1680d0ceed38 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -149,7 +149,6 @@ struct smb3_fs_context { bool uid_specified; bool gid_specified; bool sloppy; - char *nodename; bool got_ip; bool got_version; bool got_rsize; @@ -161,6 +160,7 @@ struct smb3_fs_context { char *password; char *domainname; char *UNC; + char *nodename; char *iocharset; /* local code page for mapping to and from Unicode */ char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ -- cgit v1.2.3 From 387ec58f339b0c45e3767395f11fa8dd3772131e Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:20 +1000 Subject: cifs: simplify handling of cifs_sb/ctx->local_nls Only load/unload local_nls from cifs_sb and just make the ctx contain a pointer to cifs_sb->ctx. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 4 +--- fs/cifs/connect.c | 29 ++++++++++++++--------------- fs/cifs/fs_context.c | 4 ---- fs/cifs/fs_context.h | 2 +- fs/cifs/sess.c | 23 +++++++++++------------ 5 files changed, 27 insertions(+), 35 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 891c8d8c2bb5..313d252bbbe9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -598,9 +598,7 @@ extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, unsigned int *len, unsigned int *offset); struct cifs_chan * cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server); -int cifs_try_adding_channels(struct cifs_ses *ses); -int cifs_ses_add_channel(struct cifs_ses *ses, - struct cifs_server_iface *iface); +int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses); bool is_server_using_iface(struct TCP_Server_Info *server, struct cifs_server_iface *iface); bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index eb036cf0f631..2d43c313f13d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2717,7 +2717,19 @@ int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); - cifs_sb->local_nls = ctx->local_nls; + /* this is needed for ASCII cp to Unicode converts */ + if (ctx->iocharset == NULL) { + /* load_nls_default cannot return null */ + cifs_sb->local_nls = load_nls_default(); + } else { + cifs_sb->local_nls = load_nls(ctx->iocharset); + if (cifs_sb->local_nls == NULL) { + cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n", + ctx->iocharset); + return -ELIBACC; + } + } + ctx->local_nls = cifs_sb->local_nls; if (ctx->nodfs) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; @@ -3187,19 +3199,6 @@ cifs_setup_volume_info(struct smb3_fs_context *ctx) return -EINVAL; } - /* this is needed for ASCII cp to Unicode converts */ - if (ctx->iocharset == NULL) { - /* load_nls_default cannot return null */ - ctx->local_nls = load_nls_default(); - } else { - ctx->local_nls = load_nls(ctx->iocharset); - if (ctx->local_nls == NULL) { - cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n", - ctx->iocharset); - return -ELIBACC; - } - } - return rc; } @@ -3521,7 +3520,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) out: free_xid(xid); - cifs_try_adding_channels(ses); + cifs_try_adding_channels(cifs_sb, ses); return mount_setup_tlink(cifs_sb, ses, tcon); error: diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index b807f8a78adc..c3c6d0cd291b 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -304,7 +304,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx memcpy(new_ctx, ctx, sizeof(*ctx)); new_ctx->prepath = NULL; new_ctx->mount_options = NULL; - new_ctx->local_nls = NULL; new_ctx->nodename = NULL; new_ctx->username = NULL; new_ctx->password = NULL; @@ -1350,9 +1349,6 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx) ctx->iocharset = NULL; kfree(ctx->prepath); ctx->prepath = NULL; - - unload_nls(ctx->local_nls); - ctx->local_nls = NULL; } void diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 1680d0ceed38..2519108eeb29 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -237,7 +237,7 @@ struct smb3_fs_context { char *prepath; struct sockaddr_storage dstaddr; /* destination address */ struct sockaddr_storage srcaddr; /* allow binding to a local IP */ - struct nls_table *local_nls; + struct nls_table *local_nls; /* This is a copy of the pointer in cifs_sb */ unsigned int echo_interval; /* echo interval in secs */ __u64 snapshot_time; /* needed for timewarp tokens */ __u32 handle_timeout; /* persistent and durable handle timeout in ms */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 00ca687a17dd..213465718fa8 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -34,6 +34,10 @@ #include "smb2proto.h" #include "fs_context.h" +static int +cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, + struct cifs_server_iface *iface); + bool is_server_using_iface(struct TCP_Server_Info *server, struct cifs_server_iface *iface) @@ -71,7 +75,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface) } /* returns number of channels added */ -int cifs_try_adding_channels(struct cifs_ses *ses) +int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) { int old_chan_count = ses->chan_count; int left = ses->chan_max - ses->chan_count; @@ -134,7 +138,7 @@ int cifs_try_adding_channels(struct cifs_ses *ses) continue; } - rc = cifs_ses_add_channel(ses, iface); + rc = cifs_ses_add_channel(cifs_sb, ses, iface); if (rc) { cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n", i, rc); @@ -167,8 +171,9 @@ cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server) return NULL; } -int -cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) +static int +cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, + struct cifs_server_iface *iface) { struct cifs_chan *chan; struct smb3_fs_context ctx = {NULL}; @@ -229,13 +234,8 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) /* * This will be used for encoding/decoding user/domain/pw * during sess setup auth. - * - * XXX: We use the default for simplicity but the proper way - * would be to use the one that ses used, which is not - * stored. This might break when dealing with non-ascii - * strings. */ - ctx.local_nls = load_nls_default(); + ctx.local_nls = cifs_sb->local_nls; /* Use RDMA if possible */ ctx.rdma = iface->rdma_capable; @@ -275,7 +275,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) if (rc) goto out; - rc = cifs_setup_session(xid, ses, ctx.local_nls); + rc = cifs_setup_session(xid, ses, cifs_sb->local_nls); if (rc) goto out; @@ -298,7 +298,6 @@ out: if (rc && chan->server) cifs_put_tcp_session(chan->server, 0); - unload_nls(ctx.local_nls); return rc; } -- cgit v1.2.3 From 6fd4ea88b59acaf2bffdaa14da313d1140b9c7c4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:21 +1000 Subject: cifs: don't create a temp nls in cifs_setup_ipc just use the one that is already available in ctx Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/connect.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2d43c313f13d..5ed7403ad5f2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1478,7 +1478,6 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) { int rc = 0, xid; struct cifs_tcon *tcon; - struct nls_table *nls_codepage; char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0}; bool seal = false; struct TCP_Server_Info *server = ses->server; @@ -1503,14 +1502,11 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); - /* cannot fail */ - nls_codepage = load_nls_default(); - xid = get_xid(); tcon->ses = ses; tcon->ipc = true; tcon->seal = seal; - rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage); + rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls); free_xid(xid); if (rc) { @@ -1523,7 +1519,6 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) ses->tcon_ipc = tcon; out: - unload_nls(nls_codepage); return rc; } -- cgit v1.2.3 From 7c7ee628f8e94720727709424b3afdae7e73d028 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:22 +1000 Subject: cifs: uncomplicate printing the iocharset parameter There is no need to load the default nls to check if the iocharset argument was specified or not since we have it in cifs_sb->ctx Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 276b0659c238..229e5cbcaf18 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -462,18 +462,6 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) seq_puts(s, "loose"); } -static void -cifs_show_nls(struct seq_file *s, struct nls_table *cur) -{ - struct nls_table *def; - - /* Display iocharset= option if it's not default charset */ - def = load_nls_default(); - if (def != cur) - seq_printf(s, ",iocharset=%s", cur->charset); - unload_nls(def); -} - /* * cifs_show_options() is for displaying mount options in /proc/mounts. * Not all settable options are displayed but most of the important @@ -537,9 +525,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho", cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); - - cifs_show_nls(s, cifs_sb->local_nls); - + if (cifs_sb->ctx->iocharset) + seq_printf(s, ",iocharset=%s", cifs_sb->ctx->iocharset); if (tcon->seal) seq_puts(s, ",seal"); else if (tcon->ses->server->ignore_signature) -- cgit v1.2.3 From 531f03bc6d0509f2e7a5852e3f1819166e0f364c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:23 +1000 Subject: cifs: do not allow changing posix_paths during remount Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/fs_context.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index c3c6d0cd291b..58da674c0365 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -627,6 +627,10 @@ static void smb3_fs_context_free(struct fs_context *fc) static int smb3_verify_reconfigure_ctx(struct smb3_fs_context *new_ctx, struct smb3_fs_context *old_ctx) { + if (new_ctx->posix_paths != old_ctx->posix_paths) { + cifs_dbg(VFS, "can not change posixpaths during remount\n"); + return -EINVAL; + } if (new_ctx->sectype != old_ctx->sectype) { cifs_dbg(VFS, "can not change sec during remount\n"); return -EINVAL; -- cgit v1.2.3 From 51acd208bd57c82eaa2fda3cab03d62436c6a2ae Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:24 +1000 Subject: cifs: remove ctx argument from cifs_setup_cifs_sb Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsproto.h | 3 +-- fs/cifs/connect.c | 7 ++++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 229e5cbcaf18..4c385eeecc05 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -810,7 +810,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, goto out; } - rc = cifs_setup_cifs_sb(cifs_sb->ctx, cifs_sb); + rc = cifs_setup_cifs_sb(cifs_sb); if (rc) { root = ERR_PTR(rc); goto out; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 313d252bbbe9..bd1c9b038568 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -234,8 +234,7 @@ extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, unsigned int page_offset, unsigned int to_read); -extern int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, - struct cifs_sb_info *cifs_sb); +extern int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb); extern int cifs_match_super(struct super_block *, void *); extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx); extern void cifs_umount(struct cifs_sb_info *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5ed7403ad5f2..e0864ae42d0d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2701,16 +2701,17 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, } } -int cifs_setup_cifs_sb(struct smb3_fs_context *ctx, - struct cifs_sb_info *cifs_sb) +int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb) { + struct smb3_fs_context *ctx = cifs_sb->ctx; + INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", - cifs_sb->ctx->file_mode, cifs_sb->ctx->dir_mode); + ctx->file_mode, ctx->dir_mode); /* this is needed for ASCII cp to Unicode converts */ if (ctx->iocharset == NULL) { -- cgit v1.2.3 From 2d39f50c2b15bfd197451a967e371dea19f9600b Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:25 +1000 Subject: cifs: move update of flags into a separate function This function will set/clear flags that can be changed during mount or remount Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/connect.c | 74 +----------------------- fs/cifs/fs_context.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/fs_context.h | 1 + 3 files changed, 159 insertions(+), 71 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e0864ae42d0d..de747ee40e87 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2727,61 +2727,10 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb) } ctx->local_nls = cifs_sb->local_nls; - if (ctx->nodfs) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; - if (ctx->noperm) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; - if (ctx->setuids) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; - if (ctx->setuidfromacl) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL; - if (ctx->server_ino) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; - if (ctx->remap) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR; - if (ctx->sfu_remap) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; - if (ctx->no_xattr) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; - if (ctx->sfu_emul) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; - if (ctx->nobrl) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; - if (ctx->nohandlecache) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE; - if (ctx->nostrictsync) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; - if (ctx->mand_lock) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; - if (ctx->rwpidforward) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; - if (ctx->mode_ace) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID; - if (ctx->cifs_acl) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; - if (ctx->backupuid_specified) { - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; - } - if (ctx->backupgid_specified) { - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; - } - if (ctx->override_uid) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; - if (ctx->override_gid) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; - if (ctx->dynperm) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; - if (ctx->fsc) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; - if (ctx->multiuser) - cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | - CIFS_MOUNT_NO_PERM); - if (ctx->strict_io) - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO; - if (ctx->direct_io) { + smb3_update_mnt_flags(cifs_sb); + + if (ctx->direct_io) cifs_dbg(FYI, "mounting share using direct i/o\n"); - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; - } if (ctx->cache_ro) { cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n"); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE; @@ -2790,23 +2739,6 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb) cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE | CIFS_MOUNT_RW_CACHE); } - if (ctx->mfsymlinks) { - if (ctx->sfu_emul) { - /* - * Our SFU ("Services for Unix" emulation does not allow - * creating symlinks but does allow reading existing SFU - * symlinks (it does allow both creating and reading SFU - * style mknod and FIFOs though). When "mfsymlinks" and - * "sfu" are both enabled at the same time, it allows - * reading both types of symlinks, but will only create - * them with mfsymlinks format. This allows better - * Apple compatibility (probably better for Samba too) - * while still recognizing old Windows style symlinks. - */ - cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n"); - } - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; - } if ((ctx->cifs_acl) && (ctx->dynperm)) cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n"); diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 58da674c0365..29b1dd2b9681 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -1363,3 +1363,158 @@ smb3_cleanup_fs_context(struct smb3_fs_context *ctx) smb3_cleanup_fs_context_contents(ctx); kfree(ctx); } + +void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb) +{ + struct smb3_fs_context *ctx = cifs_sb->ctx; + + if (ctx->nodfs) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_DFS; + + if (ctx->noperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_PERM; + + if (ctx->setuids) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SET_UID; + + if (ctx->setuidfromacl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UID_FROM_ACL; + + if (ctx->server_ino) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; + + if (ctx->remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SFM_CHR; + + if (ctx->sfu_remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR; + + if (ctx->no_xattr) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_XATTR; + + if (ctx->sfu_emul) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UNX_EMUL; + + if (ctx->nobrl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_BRL; + + if (ctx->nohandlecache) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_HANDLE_CACHE; + + if (ctx->nostrictsync) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOSSYNC; + + if (ctx->mand_lock) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOPOSIXBRL; + + if (ctx->rwpidforward) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_RWPIDFORWARD; + + if (ctx->mode_ace) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MODE_FROM_SID; + + if (ctx->cifs_acl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_ACL; + + if (ctx->backupuid_specified) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPUID; + + if (ctx->backupgid_specified) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPGID; + + if (ctx->override_uid) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_UID; + + if (ctx->override_gid) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_GID; + + if (ctx->dynperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DYNPERM; + + if (ctx->fsc) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_FSCACHE; + + if (ctx->multiuser) + cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | + CIFS_MOUNT_NO_PERM); + else + cifs_sb->mnt_cifs_flags &= ~(CIFS_MOUNT_MULTIUSER | + CIFS_MOUNT_NO_PERM); + + if (ctx->strict_io) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_STRICT_IO; + + if (ctx->direct_io) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DIRECT_IO; + + if (ctx->mfsymlinks) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; + else + cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MF_SYMLINKS; + if (ctx->mfsymlinks) { + if (ctx->sfu_emul) { + /* + * Our SFU ("Services for Unix" emulation does not allow + * creating symlinks but does allow reading existing SFU + * symlinks (it does allow both creating and reading SFU + * style mknod and FIFOs though). When "mfsymlinks" and + * "sfu" are both enabled at the same time, it allows + * reading both types of symlinks, but will only create + * them with mfsymlinks format. This allows better + * Apple compatibility (probably better for Samba too) + * while still recognizing old Windows style symlinks. + */ + cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n"); + } + } + + return; +} diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index 2519108eeb29..3358b33abcd0 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -266,5 +266,6 @@ static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *f } extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx); +extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb); #endif -- cgit v1.2.3 From 1cb6c3d62ca9cfdb103470e7eb60c332475b186f Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:26 +1000 Subject: cifs: update mnt_cifs_flags during reconfigure Many mount flags (e.g. for noperm, noxattr, nobrl, cifsacl, mfsymlinks and more) can be updated now. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/fs_context.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 29b1dd2b9681..a309e494577c 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -705,6 +705,7 @@ static int smb3_reconfigure(struct fs_context *fc) smb3_cleanup_fs_context_contents(cifs_sb->ctx); rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); + smb3_update_mnt_flags(cifs_sb); return rc; } -- cgit v1.2.3 From 5c4b642141eb3576213ab59d06ba12e1fa989046 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 14 Dec 2020 16:40:27 +1000 Subject: cifs: fix uninitialized variable in smb3_fs_context_parse_param Addresses an issue noted by the kernel test robot Reported-by: kernel test robot Signed-off-by: Steve French Signed-off-by: Ronnie Sahlberg --- fs/cifs/fs_context.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index a309e494577c..ca745fa6c4a1 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -726,8 +726,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, * we will need special handling of them. */ if (param->type == fs_value_is_string && param->string[0] == 0) { - if (!strcmp("pass", param->key) || !strcmp("password", param->key)) + if (!strcmp("pass", param->key) || !strcmp("password", param->key)) { skip_parsing = true; + opt = Opt_pass; + } } if (!skip_parsing) { -- cgit v1.2.3 From 653a5efb849aea1706648257c3c23ece82997f44 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 14 Dec 2020 20:08:10 -0600 Subject: cifs: update super_operations to show_devname This is needed so that we display the correct //server/share vs \\server\share in /proc/mounts for the device name (in the new mount API). Signed-off-by: Steve French Reviewed-by: Shyam Prasad N --- fs/cifs/cifsfs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4c385eeecc05..a19387fe8b47 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -462,6 +462,25 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) seq_puts(s, "loose"); } +/* + * cifs_show_devname() is used so we show the mount device name with correct + * format (e.g. forward slashes vs. back slashes) in /proc/mounts + */ +static int cifs_show_devname(struct seq_file *m, struct dentry *root) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb); + char *devname = kstrdup(cifs_sb->ctx->UNC, GFP_KERNEL); + + if (devname == NULL) + seq_puts(m, "none"); + else { + convert_delimiter(devname, '/'); + seq_puts(m, devname); + kfree(devname); + } + return 0; +} + /* * cifs_show_options() is for displaying mount options in /proc/mounts. * Not all settable options are displayed but most of the important @@ -695,6 +714,8 @@ static const struct super_operations cifs_super_ops = { .free_inode = cifs_free_inode, .drop_inode = cifs_drop_inode, .evict_inode = cifs_evict_inode, +/* .show_path = cifs_show_path, */ /* Would we ever need show path? */ + .show_devname = cifs_show_devname, /* .delete_inode = cifs_delete_inode, */ /* Do not need above function unless later we add lazy close of inodes or unless the kernel forgets to call us with the same number of releases (closes) -- cgit v1.2.3 From dd538034f84fa4ea670420aac19adcceef45d057 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 14 Dec 2020 20:15:12 -0600 Subject: smb3: remind users that witness protocol is experimental warn_once when using the witness protocol that it is experimental Signed-off-by: Steve French Reviewed-by: Samuel Cabrero Reviewed-by: Shyam Prasad N --- fs/cifs/fs_context.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index ca745fa6c4a1..c427e494ea56 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -1098,6 +1098,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, goto cifs_parse_mount_err; #endif ctx->witness = true; + pr_warn_once("Witness protocol support is experimental\n"); break; case Opt_rootfs: #ifdef CONFIG_CIFS_ROOT -- cgit v1.2.3 From 09a8361e3b681ef6b56cc56f7b2905b4455d6774 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Tue, 15 Dec 2020 17:46:56 +0100 Subject: cifs: Fix some error pointers handling detected by static checker * extract_hostname() and extract_sharename() never return NULL, so use IS_ERR() instead of IS_ERR_OR_NULL() in cifs_find_swn_reg(). If any of these functions return an error, then return an error pointer instead of NULL. * Change cifs_find_swn_reg() function to always return a valid pointer or an error pointer, instead of returning NULL if the registration is not found. * Finally update cifs_find_swn_reg() callers to check for -EEXIST instead of NULL. * In cifs_get_swn_reg() the swnreg idr mutex was not unlocked in the error path of cifs_find_swn_reg() call. Reported-by: Dan Carpenter Signed-off-by: Samuel Cabrero Reviewed-by: Dan Carpenter Signed-off-by: Steve French --- fs/cifs/cifs_swn.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index a172769c239f..69b7571010a6 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -259,24 +259,24 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) const char *net_name; net_name = extract_hostname(tcon->treeName); - if (IS_ERR_OR_NULL(net_name)) { + if (IS_ERR(net_name)) { int ret; ret = PTR_ERR(net_name); cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n", __func__, tcon->treeName, ret); - return NULL; + return ERR_PTR(-EINVAL); } share_name = extract_sharename(tcon->treeName); - if (IS_ERR_OR_NULL(share_name)) { + if (IS_ERR(share_name)) { int ret; ret = PTR_ERR(net_name); cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n", __func__, tcon->treeName, ret); kfree(net_name); - return NULL; + return ERR_PTR(-EINVAL); } idr_for_each_entry(&cifs_swnreg_idr, swnreg, id) { @@ -299,7 +299,7 @@ static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon) kfree(net_name); kfree(share_name); - return NULL; + return ERR_PTR(-EEXIST); } /* @@ -315,12 +315,13 @@ static struct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon) /* Check if we are already registered for this network and share names */ reg = cifs_find_swn_reg(tcon); - if (IS_ERR(reg)) { - return reg; - } else if (reg != NULL) { + if (!IS_ERR(reg)) { kref_get(®->ref_count); mutex_unlock(&cifs_swnreg_idr_mutex); return reg; + } else if (PTR_ERR(reg) != -EEXIST) { + mutex_unlock(&cifs_swnreg_idr_mutex); + return reg; } reg = kmalloc(sizeof(struct cifs_swn_reg), GFP_ATOMIC); @@ -630,9 +631,9 @@ int cifs_swn_unregister(struct cifs_tcon *tcon) mutex_lock(&cifs_swnreg_idr_mutex); swnreg = cifs_find_swn_reg(tcon); - if (swnreg == NULL) { + if (IS_ERR(swnreg)) { mutex_unlock(&cifs_swnreg_idr_mutex); - return -EEXIST; + return PTR_ERR(swnreg); } mutex_unlock(&cifs_swnreg_idr_mutex); -- cgit v1.2.3 From 0c2b5f7ce50c24099e8ed7d35936e89fe9ca26ff Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 15 Dec 2020 13:28:50 -0600 Subject: cifs: fix rsize/wsize to be negotiated values Also make sure these are displayed in /proc/mounts Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/cifsfs.c | 9 +++------ fs/cifs/connect.c | 8 ++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a19387fe8b47..4c9e12b46810 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -621,12 +621,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root) from_kgid_munged(&init_user_ns, cifs_sb->ctx->backupgid)); - if (cifs_sb->ctx->got_rsize) - seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); - if (cifs_sb->ctx->got_wsize) - seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize); - if (cifs_sb->ctx->got_bsize) - seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize); + seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); + seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize); + seq_printf(s, ",bsize=%u", cifs_sb->ctx->bsize); if (tcon->ses->server->min_offload) seq_printf(s, ",esize=%u", tcon->ses->server->min_offload); seq_printf(s, ",echo_interval=%lu", diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index de747ee40e87..64a41b32fbb1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2859,10 +2859,14 @@ static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cif /* * Clamp the rsize/wsize mount arguments if they are too big for the server + * and set the rsize/wsize to the negotiated values if not passed in by + * the user on mount */ - if (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx)) + if ((cifs_sb->ctx->wsize == 0) || + (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); - if (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)) + if ((cifs_sb->ctx->rsize == 0) || + (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx))) cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); return 0; -- cgit v1.2.3 From 6cf5abbfa8c8a2826d56e38ed1956a0e2f0c85b9 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 16 Dec 2020 08:51:33 +1000 Subject: cifs: fix use after free in cifs_smb3_do_mount() Reported-by: Dan Carpenter Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4c9e12b46810..ce0d0037fd0a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -854,12 +854,14 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, if (IS_ERR(sb)) { root = ERR_CAST(sb); cifs_umount(cifs_sb); + cifs_sb = NULL; goto out; } if (sb->s_root) { cifs_dbg(FYI, "Use existing superblock\n"); cifs_umount(cifs_sb); + cifs_sb = NULL; } else { rc = cifs_read_super(sb); if (rc) { @@ -870,7 +872,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type, sb->s_flags |= SB_ACTIVE; } - root = cifs_get_root(cifs_sb->ctx, sb); + root = cifs_get_root(cifs_sb ? cifs_sb->ctx : old_ctx, sb); if (IS_ERR(root)) goto out_super; -- cgit v1.2.3 From cd7b699b0198a7fc24f6dc79985f6151f589518c Mon Sep 17 00:00:00 2001 From: Shyam Prasad N Date: Thu, 12 Nov 2020 08:56:49 -0800 Subject: cifs: Tracepoints and logs for tracing credit changes. There is at least one suspected bug in crediting changes in cifs.ko which has come up a few times in the discussions and in a customer case. This change adds tracepoints to the code which modifies the server credit values in any way. The goal is to be able to track the changes to the credit values of the session to be able to catch when there is a crediting bug. Signed-off-by: Shyam Prasad N Signed-off-by: Steve French --- fs/cifs/connect.c | 8 ++++++++ fs/cifs/smb2ops.c | 41 +++++++++++++++++++++++++++++++++++++---- fs/cifs/trace.h | 4 ++++ fs/cifs/transport.c | 15 +++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 64a41b32fbb1..509a41ff56b8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -845,6 +845,7 @@ static void smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) { struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; + int scredits = server->credits; /* * SMB1 does not use credits. @@ -857,6 +858,13 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) server->credits += le16_to_cpu(shdr->CreditRequest); spin_unlock(&server->req_lock); wake_up(&server->request_q); + + trace_smb3_add_credits(server->CurrentMid, + server->hostname, scredits, + le16_to_cpu(shdr->CreditRequest)); + cifs_server_dbg(FYI, "%s: added %u credits total=%d\n", + __func__, le16_to_cpu(shdr->CreditRequest), + scredits); } } diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a505cc3e58da..949cd1177147 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -100,9 +100,10 @@ smb2_add_credits(struct TCP_Server_Info *server, spin_unlock(&server->req_lock); wake_up(&server->request_q); - if (reconnect_detected) + if (reconnect_detected) { cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n", add, instance); + } if (server->tcpStatus == CifsNeedReconnect || server->tcpStatus == CifsExiting) @@ -124,7 +125,7 @@ smb2_add_credits(struct TCP_Server_Info *server, default: trace_smb3_add_credits(server->CurrentMid, server->hostname, rc, add); - cifs_dbg(FYI, "add %u credits total=%d\n", add, rc); + cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, rc); } } @@ -136,6 +137,11 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val) if (val == 1) server->reconnect_instance++; spin_unlock(&server->req_lock); + + trace_smb3_set_credits(server->CurrentMid, + server->hostname, val, val); + cifs_dbg(FYI, "%s: set %u credits\n", __func__, val); + /* don't log while holding the lock */ if (val == 1) cifs_dbg(FYI, "set credits to 1 due to smb2 reconnect\n"); @@ -202,6 +208,7 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); credits->instance = server->reconnect_instance; server->credits -= credits->value; + scredits = server->credits; server->in_flight++; if (server->in_flight > server->max_in_flight) server->max_in_flight = server->in_flight; @@ -209,6 +216,12 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, } } spin_unlock(&server->req_lock); + + trace_smb3_add_credits(server->CurrentMid, + server->hostname, scredits, -(credits->value)); + cifs_dbg(FYI, "%s: removed %u credits total=%d\n", + __func__, credits->value, scredits); + return rc; } @@ -218,13 +231,17 @@ smb2_adjust_credits(struct TCP_Server_Info *server, const unsigned int payload_size) { int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); + int scredits; if (!credits->value || credits->value == new_val) return 0; if (credits->value < new_val) { - WARN_ONCE(1, "request has less credits (%d) than required (%d)", - credits->value, new_val); + trace_smb3_too_many_credits(server->CurrentMid, + server->hostname, 0, credits->value - new_val); + cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)", + credits->value, new_val); + return -ENOTSUPP; } @@ -232,15 +249,24 @@ smb2_adjust_credits(struct TCP_Server_Info *server, if (server->reconnect_instance != credits->instance) { spin_unlock(&server->req_lock); + trace_smb3_reconnect_detected(server->CurrentMid, + server->hostname, 0, 0); cifs_server_dbg(VFS, "trying to return %d credits to old session\n", credits->value - new_val); return -EAGAIN; } server->credits += credits->value - new_val; + scredits = server->credits; spin_unlock(&server->req_lock); wake_up(&server->request_q); credits->value = new_val; + + trace_smb3_add_credits(server->CurrentMid, + server->hostname, scredits, credits->value - new_val); + cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n", + __func__, credits->value - new_val, scredits); + return 0; } @@ -2343,6 +2369,7 @@ static bool smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) { struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; + int scredits; if (shdr->Status != STATUS_PENDING) return false; @@ -2350,8 +2377,14 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) if (shdr->CreditRequest) { spin_lock(&server->req_lock); server->credits += le16_to_cpu(shdr->CreditRequest); + scredits = server->credits; spin_unlock(&server->req_lock); wake_up(&server->request_q); + + trace_smb3_add_credits(server->CurrentMid, + server->hostname, scredits, le16_to_cpu(shdr->CreditRequest)); + cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n", + __func__, le16_to_cpu(shdr->CreditRequest), scredits); } return true; diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 90e0fab69bb8..c3d1a584f251 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -909,8 +909,12 @@ DEFINE_EVENT(smb3_credit_class, smb3_##name, \ TP_ARGS(currmid, hostname, credits, credits_to_add)) DEFINE_SMB3_CREDIT_EVENT(reconnect_with_invalid_credits); +DEFINE_SMB3_CREDIT_EVENT(reconnect_detected); DEFINE_SMB3_CREDIT_EVENT(credit_timeout); +DEFINE_SMB3_CREDIT_EVENT(insufficient_credits); +DEFINE_SMB3_CREDIT_EVENT(too_many_credits); DEFINE_SMB3_CREDIT_EVENT(add_credits); +DEFINE_SMB3_CREDIT_EVENT(set_credits); #endif /* _CIFS_TRACE_H */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 36b2ece43403..e9abb41aa89b 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -527,6 +527,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, int *credits; int optype; long int t; + int scredits = server->credits; if (timeout < 0) t = MAX_JIFFY_OFFSET; @@ -624,12 +625,18 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int num_credits, /* update # of requests on the wire to server */ if ((flags & CIFS_TIMEOUT_MASK) != CIFS_BLOCKING_OP) { *credits -= num_credits; + scredits = *credits; server->in_flight += num_credits; if (server->in_flight > server->max_in_flight) server->max_in_flight = server->in_flight; *instance = server->reconnect_instance; } spin_unlock(&server->req_lock); + + trace_smb3_add_credits(server->CurrentMid, + server->hostname, scredits, -(num_credits)); + cifs_dbg(FYI, "%s: remove %u credits total=%d\n", + __func__, num_credits, scredits); break; } } @@ -649,10 +656,14 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num, const int flags, unsigned int *instance) { int *credits; + int scredits, sin_flight; credits = server->ops->get_credits_field(server, flags & CIFS_OP_MASK); spin_lock(&server->req_lock); + scredits = *credits; + sin_flight = server->in_flight; + if (*credits < num) { /* * Return immediately if not too many requests in flight since @@ -660,6 +671,10 @@ wait_for_compound_request(struct TCP_Server_Info *server, int num, */ if (server->in_flight < num - *credits) { spin_unlock(&server->req_lock); + trace_smb3_insufficient_credits(server->CurrentMid, + server->hostname, scredits, sin_flight); + cifs_dbg(FYI, "%s: %d requests in flight, needed %d total=%d\n", + __func__, sin_flight, num, scredits); return -ENOTSUPP; } } -- cgit v1.2.3 From 27cf94853e6d2b5c981ed4d9f798912027352584 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 16 Dec 2020 01:22:54 -0600 Subject: cifs: correct four aliased mount parms to allow use of previous names The updates to the new mount API created aliases for some mount parms e.g. esize, idsfromsid, modefromsid, signloosely as "min_enc_offload", "setuidfromacl", "modesid", "ignore_signature" but did not add back in the original name expected by test cases and current users. It also had incorrect names for a few less used mount parms. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/fs_context.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index c427e494ea56..29b99e68ec80 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -94,6 +94,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("forcemandatorylock", Opt_forcemandatorylock), fsparam_flag("forcemand", Opt_forcemandatorylock), fsparam_flag("setuidfromacl", Opt_setuidfromacl), + fsparam_flag("idsfromsid", Opt_setuidfromacl), fsparam_flag_no("setuids", Opt_setuids), fsparam_flag_no("dynperm", Opt_dynperm), fsparam_flag_no("intr", Opt_intr), @@ -105,6 +106,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("locallease", Opt_locallease), fsparam_flag("sign", Opt_sign), fsparam_flag("ignore_signature", Opt_ignore_signature), + fsparam_flag("signloosely", Opt_ignore_signature), fsparam_flag("seal", Opt_seal), fsparam_flag("noac", Opt_noac), fsparam_flag("fsc", Opt_fsc), @@ -112,11 +114,12 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("multiuser", Opt_multiuser), fsparam_flag("sloppy", Opt_sloppy), fsparam_flag("nosharesock", Opt_nosharesock), - fsparam_flag_no("persistent", Opt_persistent), - fsparam_flag_no("resilient", Opt_resilient), + fsparam_flag_no("persistenthandles", Opt_persistent), + fsparam_flag_no("resilienthandles", Opt_resilient), fsparam_flag("domainauto", Opt_domainauto), fsparam_flag("rdma", Opt_rdma), fsparam_flag("modesid", Opt_modesid), + fsparam_flag("modefromsid", Opt_modesid), fsparam_flag("rootfs", Opt_rootfs), fsparam_flag("compress", Opt_compress), fsparam_flag("witness", Opt_witness), @@ -132,6 +135,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_u32("dir_mode", Opt_dirmode), fsparam_u32("port", Opt_port), fsparam_u32("min_enc_offload", Opt_min_enc_offload), + fsparam_u32("esize", Opt_min_enc_offload), fsparam_u32("bsize", Opt_blocksize), fsparam_u32("rsize", Opt_rsize), fsparam_u32("wsize", Opt_wsize), @@ -1212,14 +1216,15 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; case Opt_persistent: if (result.negated) { - if ((ctx->nopersistent) || (ctx->resilient)) { + ctx->nopersistent = true; + if (ctx->persistent) { cifs_dbg(VFS, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; } } else { - ctx->nopersistent = true; - if (ctx->persistent) { + ctx->persistent = true; + if ((ctx->nopersistent) || (ctx->resilient)) { cifs_dbg(VFS, "persistenthandles mount options conflict\n"); goto cifs_parse_mount_err; -- cgit v1.2.3 From 31f6551ad75608d9c71fd4d3548c33f1abc52093 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 16 Dec 2020 16:26:35 -0600 Subject: cifs: handle "guest" mount parameter With the new mount API it can not handle empty strings for mount parms ("guest" is mapped in userspace mount helper to "user=") so we have to special case it as we do for the password mount parm. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/fs_context.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 29b99e68ec80..734b30db580f 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -733,6 +733,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (!strcmp("pass", param->key) || !strcmp("password", param->key)) { skip_parsing = true; opt = Opt_pass; + } else if (!strcmp("user", param->key) || !strcmp("username", param->key)) { + skip_parsing = true; + opt = Opt_user; } } @@ -1250,6 +1253,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ctx->rdma = true; break; } + /* case Opt_ignore: - is ignored as expected ... */ return 0; -- cgit v1.2.3 From 2d0604934f507b8b4799f3c1dff41cca3dd85239 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 16 Dec 2020 18:04:27 -0600 Subject: cifs: Fix support for remount when not changing rsize/wsize When remounting with the new mount API, we need to set rsize and wsize to the previous values if they are not passed in on the remount. Otherwise they get set to zero which breaks xfstest 452 for example. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Shyam Prasad N --- fs/cifs/fs_context.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 734b30db580f..0afccbbed2e6 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -707,6 +707,13 @@ static int smb3_reconfigure(struct fs_context *fc) STEAL_STRING(cifs_sb, ctx, nodename); STEAL_STRING(cifs_sb, ctx, iocharset); + /* if rsize or wsize not passed in on remount, use previous values */ + if (ctx->rsize == 0) + ctx->rsize = cifs_sb->ctx->rsize; + if (ctx->wsize == 0) + ctx->wsize = cifs_sb->ctx->wsize; + + smb3_cleanup_fs_context_contents(cifs_sb->ctx); rc = smb3_fs_context_dup(cifs_sb->ctx, ctx); smb3_update_mnt_flags(cifs_sb); -- cgit v1.2.3 From afee4410bc6c50e1422c5a45d633ad0e478ea960 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 15 Dec 2020 15:17:43 -0600 Subject: cifs: update internal module version number To 2.30 Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d6976c28970d..2307bb0f6147 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -160,5 +160,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "2.29" +#define CIFS_VERSION "2.30" #endif /* _CIFSFS_H */ -- cgit v1.2.3