From a347ecb209b58a1b37f20d8299ab552f7d3ee8c3 Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Fri, 17 Sep 2010 19:43:10 +0530 Subject: cifs: use type __u32 instead of int for the oplock parameter ... and avoid implicit casting from a signed type. Also, pass oplock by value instead by reference as we don't intend to change the value in cifs_open_inode_helper(). Thanks to Jeff Layton for spotting this. Reviewed-by: Jeff Layton Signed-off-by: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index de748c652d11..d33da45fe987 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -165,7 +165,7 @@ psx_client_can_cache: /* all arguments to this function must be checked for validity in caller */ static inline int cifs_open_inode_helper(struct inode *inode, - struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, + struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf, char *full_path, int xid) { struct cifsInodeInfo *pCifsInode = CIFS_I(inode); @@ -207,11 +207,11 @@ client_can_cache: rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, xid, NULL); - if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { + if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = true; pCifsInode->clientCanCacheRead = true; cFYI(1, "Exclusive Oplock granted on inode %p", inode); - } else if ((*oplock & 0xF) == OPLOCK_READ) + } else if ((oplock & 0xF) == OPLOCK_READ) pCifsInode->clientCanCacheRead = true; return rc; @@ -365,7 +365,7 @@ int cifs_open(struct inode *inode, struct file *file) goto out; } - rc = cifs_open_inode_helper(inode, tcon, &oplock, buf, full_path, xid); + rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid); if (rc != 0) goto out; -- cgit v1.2.3 From aa91c7e4ab9b0842b7d7a7cbf8cca18b20df89b5 Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Fri, 17 Sep 2010 18:56:39 +0530 Subject: cifs: fix broken oplock handling cifs_new_fileinfo() does not use the 'oplock' value from the callers. Instead, it sets it to REQ_OPLOCK which seems wrong. We should be using the oplock value obtained from the Server to set the inode's clientCanCacheAll or clientCanCacheRead flags. Fix this by passing oplock from the callers to cifs_new_fileinfo(). This change dates back to commit a6ce4932 (2.6.30-rc3). So, all the affected versions will need this fix. Please Cc stable once reviewed and accepted. Cc: Stable Reviewed-by: Jeff Layton Signed-off-by: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 3 ++- fs/cifs/dir.c | 12 +++++------- fs/cifs/file.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1d60c655e3e0..f110e0e7e947 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -107,7 +107,8 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, - struct vfsmount *mnt, unsigned int oflags); + struct vfsmount *mnt, unsigned int oflags, + __u32 oplock); extern int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f9ed0751cc12..0f947bf73f8e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -132,9 +132,9 @@ cifs_bp_rename_retry: struct cifsFileInfo * cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, - struct file *file, struct vfsmount *mnt, unsigned int oflags) + struct file *file, struct vfsmount *mnt, unsigned int oflags, + __u32 oplock) { - int oplock = 0; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); @@ -143,9 +143,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, if (pCifsFile == NULL) return pCifsFile; - if (oplockEnabled) - oplock = REQ_OPLOCK; - pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; pCifsFile->pInode = igrab(newinode); @@ -468,7 +465,7 @@ cifs_create_set_dentry: } pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, - nd->path.mnt, oflags); + nd->path.mnt, oflags, oplock); if (pfile_info == NULL) { fput(filp); CIFSSMBClose(xid, tcon, fileHandle); @@ -729,7 +726,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, cfile = cifs_new_fileinfo(newInode, fileHandle, filp, nd->path.mnt, - nd->intent.open.flags); + nd->intent.open.flags, + oplock); if (cfile == NULL) { fput(filp); CIFSSMBClose(xid, pTcon, fileHandle); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d33da45fe987..60061b9c2f67 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -277,7 +277,7 @@ int cifs_open(struct inode *inode, struct file *file) pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - oflags); + oflags, oplock); if (pCifsFile == NULL) { CIFSSMBClose(xid, tcon, netfid); rc = -ENOMEM; @@ -370,7 +370,7 @@ int cifs_open(struct inode *inode, struct file *file) goto out; pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - file->f_flags); + file->f_flags, oplock); if (pCifsFile == NULL) { rc = -ENOMEM; goto out; -- cgit v1.2.3 From 5f98ca9afb9c004f8948c0d40920503de447918a Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Sat, 18 Sep 2010 22:01:58 -0500 Subject: cifs NTLMv2/NTLMSSP Change variable name mac_key to session key to reflect the key it holds Change name of variable mac_key to session key. The reason mac_key was changed to session key is, this structure does not hold message authentication code, it holds the session key (for ntlmv2, ntlmv1 etc.). mac is generated as a signature in cifs_calc* functions. Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 22 +++++++++++----------- fs/cifs/cifsglob.h | 4 ++-- fs/cifs/cifsproto.h | 4 ++-- fs/cifs/sess.c | 10 +++++----- fs/cifs/transport.c | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 35042d8f7338..eed70cae1275 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -42,7 +42,7 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, - const struct mac_key *key, char *signature) + const struct session_key *key, char *signature) { struct MD5Context context; @@ -78,7 +78,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, + rc = cifs_calculate_signature(cifs_pdu, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); @@ -89,7 +89,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, - const struct mac_key *key, char *signature) + const struct session_key *key, char *signature) { struct MD5Context context; int i; @@ -145,7 +145,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, + rc = cifs_calc_signature2(iov, n_vec, &server->session_key, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); @@ -156,14 +156,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, - const struct mac_key *mac_key, + const struct session_key *session_key, __u32 expected_sequence_number) { unsigned int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if ((cifs_pdu == NULL) || (mac_key == NULL)) + if (cifs_pdu == NULL || session_key == NULL) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) @@ -192,7 +192,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, mac_key, + rc = cifs_calculate_signature(cifs_pdu, session_key, what_we_think_sig_should_be); if (rc) @@ -209,7 +209,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* We fill in key by putting in 40 byte array which was allocated by caller */ -int cifs_calculate_mac_key(struct mac_key *key, const char *rn, +int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *password) { char temp_key[16]; @@ -347,11 +347,11 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, /* now calculate the MAC key for NTLMv2 */ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); hmac_md5_update(resp_buf, 16, &context); - hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); + hmac_md5_final(ses->server->session_key.data.ntlmv2.key, &context); - memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, + memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, sizeof(struct ntlmv2_resp)); - ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); + ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); } void CalcNTLMv2_response(const struct cifsSesInfo *ses, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0cdfb8c32ac6..14dfa9a067e5 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -97,7 +97,7 @@ enum protocolEnum { /* Netbios frames protocol not supported at this time */ }; -struct mac_key { +struct session_key { unsigned int len; union { char ntlm[CIFS_SESS_KEY_SIZE + 16]; @@ -182,7 +182,7 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - struct mac_key mac_signing_key; + struct session_key session_key; char ntlmv2_hash[16]; unsigned long lstrp; /* when we got last response from this server */ u16 dialect; /* dialect index that server chose */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f110e0e7e947..099fd6173e01 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -363,9 +363,9 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_hdr *, - const struct mac_key *mac_key, + const struct session_key *session_key, __u32 expected_sequence_number); -extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, +extern int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *pass); extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 0a57cb7db5dd..88820127650e 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -480,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, /* calculate session key, BB what about adding similar ntlmv2 path? */ SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); if (first) - cifs_calculate_mac_key(&ses->server->mac_signing_key, + cifs_calculate_session_key(&ses->server->session_key, ntlm_session_key, ses->password); memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); @@ -690,7 +690,7 @@ ssetup_ntlmssp_authenticate: if (first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key(&ses->server->mac_signing_key, + cifs_calculate_session_key(&ses->server->session_key, ntlm_session_key, ses->password); /* copy session key */ @@ -765,15 +765,15 @@ ssetup_ntlmssp_authenticate: } /* bail out if key is too long */ if (msg->sesskey_len > - sizeof(ses->server->mac_signing_key.data.krb5)) { + sizeof(ses->server->session_key.data.krb5)) { cERROR(1, "Kerberos signing key too long (%u bytes)", msg->sesskey_len); rc = -EOVERFLOW; goto ssetup_exit; } if (first_time) { - ses->server->mac_signing_key.len = msg->sesskey_len; - memcpy(ses->server->mac_signing_key.data.krb5, + ses->server->session_key.len = msg->sesskey_len; + memcpy(ses->server->session_key.data.krb5, msg->data, msg->sesskey_len); } pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 82f78c4d6978..a66c91eb6eb4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, - &ses->server->mac_signing_key, + &ses->server->session_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, + &ses->server->session_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, + &ses->server->session_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); -- cgit v1.2.3 From 2b149f11978b44199954710d32c0eecf6c9efd9c Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Sat, 18 Sep 2010 22:02:18 -0500 Subject: cifs NTLMv2/NTLMSSP ntlmv2 within ntlmssp autentication code Attribue Value (AV) pairs or Target Info (TI) pairs are part of ntlmv2 authentication. Structure ntlmv2_resp had only definition for two av pairs. So removed it, and now allocation of av pairs is dynamic. For servers like Windows 7/2008, av pairs sent by server in challege packet (type 2 in the ntlmssp exchange/negotiation) can vary. Server sends them during ntlmssp negotiation. So when ntlmssp is used as an authentication mechanism, type 2 challenge packet from server has this information. Pluck it and use the entire blob for authenticaiton purpose. If user has not specified, extract (netbios) domain name from the av pairs which is used to calculate ntlmv2 hash. Servers like Windows 7 are particular about the AV pair blob. Servers like Windows 2003, are not very strict about the contents of av pair blob used during ntlmv2 authentication. So when security mechanism such as ntlmv2 is used (not ntlmv2 in ntlmssp), there is no negotiation and so genereate a minimal blob that gets used in ntlmv2 authentication as well as gets sent. Fields tilen and tilbob are session specific. AV pair values are defined. To calculate ntlmv2 response we need ti/av pair blob. For sec mech like ntlmssp, the blob is plucked from type 2 response from the server. From this blob, netbios name of the domain is retrieved, if user has not already provided, to be included in the Target String as part of ntlmv2 hash calculations. For sec mech like ntlmv2, create a minimal, two av pair blob. The allocated blob is freed in case of error. In case there is no error, this blob is used in calculating ntlmv2 response (in CalcNTLMv2_response) and is also copied on the response to the server, and then freed. The type 3 ntlmssp response is prepared on a buffer, 5 * sizeof of struct _AUTHENTICATE_MESSAGE, an empirical value large enough to hold _AUTHENTICATE_MESSAGE plus a blob with max possible 10 values as part of ntlmv2 response and lmv2 keys and domain, user, workstation names etc. Also, kerberos gets selected as a default mechanism if server supports it, over the other security mechanisms. Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/cifsglob.h | 2 + fs/cifs/cifspdu.h | 1 - fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 16 ++++--- fs/cifs/connect.c | 2 + fs/cifs/ntlmssp.h | 15 +++++++ fs/cifs/sess.c | 119 +++++++++++++++++++++++++++++++++---------------- 8 files changed, 225 insertions(+), 53 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index eed70cae1275..730038a12982 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,6 +27,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" +#include "ntlmssp.h" #include #include @@ -262,6 +263,87 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, } #endif /* CIFS_WEAK_PW_HASH */ +/* This is just a filler for ntlmv2 type of security mechanisms. + * Older servers are not very particular about the contents of av pairs + * in the blob and for sec mechs like ntlmv2, there is no negotiation + * as in ntlmssp, so unless domain and server netbios and dns names + * are specified, there is no way to obtain name. In case of ntlmssp, + * server provides that info in type 2 challenge packet + */ +static int +build_avpair_blob(struct cifsSesInfo *ses) +{ + struct ntlmssp2_name *attrptr; + + ses->tilen = 2 * sizeof(struct ntlmssp2_name); + ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); + if (!ses->tiblob) { + ses->tilen = 0; + cERROR(1, "Challenge target info allocation failure"); + return -ENOMEM; + } + attrptr = (struct ntlmssp2_name *) ses->tiblob; + attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); + + return 0; +} + +/* Server has provided av pairs/target info in the type 2 challenge + * packet and we have plucked it and stored within smb session. + * We parse that blob here to find netbios domain name to be used + * as part of ntlmv2 authentication (in Target String), if not already + * specified on the command line. + * If this function returns without any error but without fetching + * domain name, authentication may fail against some server but + * may not fail against other (those who are not very particular + * about target string i.e. for some, just user name might suffice. + */ +static int +find_domain_name(struct cifsSesInfo *ses) +{ + unsigned int attrsize; + unsigned int type; + unsigned int onesize = sizeof(struct ntlmssp2_name); + unsigned char *blobptr; + unsigned char *blobend; + struct ntlmssp2_name *attrptr; + + if (!ses->tilen || !ses->tiblob) + return 0; + + blobptr = ses->tiblob; + blobend = ses->tiblob + ses->tilen; + + while (blobptr + onesize < blobend) { + attrptr = (struct ntlmssp2_name *) blobptr; + type = le16_to_cpu(attrptr->type); + if (type == NTLMSSP_AV_EOL) + break; + blobptr += 2; /* advance attr type */ + attrsize = le16_to_cpu(attrptr->length); + blobptr += 2; /* advance attr size */ + if (blobptr + attrsize > blobend) + break; + if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { + if (!attrsize) + break; + if (!ses->domainName) { + ses->domainName = + kmalloc(attrsize + 1, GFP_KERNEL); + if (!ses->domainName) + return -ENOMEM; + cifs_from_ucs2(ses->domainName, + (__le16 *)blobptr, attrsize, attrsize, + load_nls_default(), false); + break; + } + } + blobptr += attrsize; /* advance attr value */ + } + + return 0; +} + static int calc_ntlmv2_hash(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { @@ -321,7 +403,8 @@ calc_exit_2: return rc; } -void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, +int +setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, const struct nls_table *nls_cp) { int rc; @@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; - buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); - buf->names[0].length = 0; - buf->names[1].type = 0; - buf->names[1].length = 0; + + if (ses->server->secType == RawNTLMSSP) { + if (!ses->domainName) { + rc = find_domain_name(ses); + if (rc) { + cERROR(1, "error %d finding domain name", rc); + goto setup_ntlmv2_rsp_ret; + } + } + } else { + rc = build_avpair_blob(ses); + if (rc) { + cERROR(1, "error %d building av pair blob", rc); + return rc; + } + } /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); - if (rc) + if (rc) { cERROR(1, "could not get v2 hash rc %d", rc); + goto setup_ntlmv2_rsp_ret; + } CalcNTLMv2_response(ses, resp_buf); /* now calculate the MAC key for NTLMv2 */ @@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, sizeof(struct ntlmv2_resp)); ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); + + return 0; + +setup_ntlmv2_rsp_ret: + kfree(ses->tiblob); + ses->tiblob = NULL; + ses->tilen = 0; + + return rc; } void CalcNTLMv2_response(const struct cifsSesInfo *ses, @@ -365,6 +471,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses, hmac_md5_update(v2_session_response+8, sizeof(struct ntlmv2_resp) - 8, &context); + if (ses->tilen) + hmac_md5_update(ses->tiblob, ses->tilen, &context); + hmac_md5_final(v2_session_response, &context); /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 14dfa9a067e5..c68f31cf4550 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -222,6 +222,8 @@ struct cifsSesInfo { char userName[MAX_USERNAME_SIZE + 1]; char *domainName; char *password; + unsigned int tilen; /* length of the target info blob */ + unsigned char *tiblob; /* target info blob in challenge response */ bool need_reconnect:1; /* connection reset, uid now invalid */ }; /* no more than one of the following three session flags may be set */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d8db11..b0f4b5656d4c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -663,7 +663,6 @@ struct ntlmv2_resp { __le64 time; __u64 client_chal; /* random */ __u32 reserved2; - struct ntlmssp2_name names[2]; /* array of name entries could follow ending in minimum 4 byte struct */ } __attribute__((packed)); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 099fd6173e01..588612867451 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -368,7 +368,7 @@ extern int cifs_verify_signature(struct smb_hdr *, extern int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *pass); extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); -extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, +extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(const char *password, const char *cryptkey, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index c65c3419dd37..13c854e41073 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -603,13 +603,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) rc = 0; else rc = -EINVAL; - - if (server->sec_kerberos || server->sec_mskerberos) - server->secType = Kerberos; - else if (server->sec_ntlmssp) - server->secType = RawNTLMSSP; - else - rc = -EOPNOTSUPP; + if (server->secType == Kerberos) { + if (!server->sec_kerberos && + !server->sec_mskerberos) + rc = -EOPNOTSUPP; + } else if (server->secType == RawNTLMSSP) { + if (!server->sec_ntlmssp) + rc = -EOPNOTSUPP; + } else + rc = -EOPNOTSUPP; } } else server->capabilities &= ~CAP_EXTENDED_SECURITY; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 88c84a38bccb..c99760a523bf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1740,6 +1740,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) if (ses == NULL) goto get_ses_fail; + ses->tilen = 0; + ses->tiblob = NULL; /* new SMB session uses our server ref */ ses->server = server; if (server->addr.sockAddr6.sin6_family == AF_INET6) diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 49c9a4e75319..5d52e4a3b1ed 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -61,6 +61,21 @@ #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 +/* Define AV Pair Field IDs */ +enum av_field_type { + NTLMSSP_AV_EOL = 0, + NTLMSSP_AV_NB_COMPUTER_NAME, + NTLMSSP_AV_NB_DOMAIN_NAME, + NTLMSSP_AV_DNS_COMPUTER_NAME, + NTLMSSP_AV_DNS_DOMAIN_NAME, + NTLMSSP_AV_DNS_TREE_NAME, + NTLMSSP_AV_FLAGS, + NTLMSSP_AV_TIMESTAMP, + NTLMSSP_AV_RESTRICTION, + NTLMSSP_AV_TARGET_NAME, + NTLMSSP_AV_CHANNEL_BINDINGS +}; + /* Although typedefs are not commonly used for structure definitions */ /* in the Linux kernel, in this particular case they are useful */ /* to more closely match the standards document for NTLMSSP from */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 88820127650e..af18a500f7e0 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifsSesInfo *ses) { + unsigned int tioffset; /* challenge message target info area */ + unsigned int tilen; /* challenge message target info area length */ + CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; if (blob_len < sizeof(CHALLENGE_MESSAGE)) { @@ -405,6 +408,19 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ + tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); + tilen = cpu_to_le16(pblob->TargetInfoArray.Length); + ses->tilen = tilen; + if (ses->tilen) { + ses->tiblob = kmalloc(tilen, GFP_KERNEL); + if (!ses->tiblob) { + cERROR(1, "Challenge target info allocation failure"); + ses->tilen = 0; + return -ENOMEM; + } + memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen); + } + return 0; } @@ -425,7 +441,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, /* BB is NTLMV2 session security format easier to use here? */ flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) flags |= NTLMSSP_NEGOTIATE_SIGN; @@ -449,12 +465,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, This function returns the length of the data in the blob */ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, struct cifsSesInfo *ses, - const struct nls_table *nls_cp, bool first) + const struct nls_table *nls_cp) { + int rc; + unsigned int size; AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; __u32 flags; unsigned char *tmp; - char ntlm_session_key[CIFS_SESS_KEY_SIZE]; + struct ntlmv2_resp ntlmv2_response = {}; memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); sec_blob->MessageType = NtLmAuthenticate; @@ -462,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) flags |= NTLMSSP_NEGOTIATE_SIGN; @@ -477,19 +495,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.Length = 0; sec_blob->LmChallengeResponse.MaximumLength = 0; - /* calculate session key, BB what about adding similar ntlmv2 path? */ - SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); - if (first) - cifs_calculate_session_key(&ses->server->session_key, - ntlm_session_key, ses->password); - - memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); - sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(CIFS_SESS_KEY_SIZE); + rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); + if (rc) { + cERROR(1, "Error %d during NTLMSSP authentication", rc); + goto setup_ntlmv2_ret; + } + size = sizeof(struct ntlmv2_resp); + memcpy(tmp, (char *)&ntlmv2_response, size); + tmp += size; + if (ses->tilen > 0) { + memcpy(tmp, ses->tiblob, ses->tilen); + tmp += ses->tilen; + } - tmp += CIFS_SESS_KEY_SIZE; + sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen); + sec_blob->NtChallengeResponse.MaximumLength = + cpu_to_le16(size + ses->tilen); + kfree(ses->tiblob); + ses->tiblob = NULL; + ses->tilen = 0; if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); @@ -501,7 +526,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ - len += 2; /* trailing null */ sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.Length = cpu_to_le16(len); sec_blob->DomainName.MaximumLength = cpu_to_le16(len); @@ -518,7 +542,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->userName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ - len += 2; /* trailing null */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = cpu_to_le16(len); sec_blob->UserName.MaximumLength = cpu_to_le16(len); @@ -533,6 +556,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->SessionKey.Length = 0; sec_blob->SessionKey.MaximumLength = 0; + +setup_ntlmv2_ret: return tmp - pbuffer; } @@ -545,19 +570,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, return; } - -static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, - struct cifsSesInfo *ses, - const struct nls_table *nls, bool first_time) -{ - int bloblen; - - bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, - first_time); - pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); - - return bloblen; -} #endif int @@ -580,6 +592,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ bool first_time; + int blob_len; + char *ntlmsspblob = NULL; if (ses == NULL) return -EINVAL; @@ -729,12 +743,24 @@ ssetup_ntlmssp_authenticate: cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); - /* FIXME: calculate MAC key */ + rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); + if (rc) { + cERROR(1, "Error %d during NTLMv2 authentication", rc); + kfree(v2_sess_key); + goto ssetup_exit; + } memcpy(bcc_ptr, (char *)v2_sess_key, - sizeof(struct ntlmv2_resp)); + sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); + if (ses->tilen > 0) { + memcpy(bcc_ptr, ses->tiblob, ses->tilen); + bcc_ptr += ses->tilen; + /* we never did allocate ses->domainName to free */ + kfree(ses->tiblob); + ses->tiblob = NULL; + ses->tilen = 0; + } if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; @@ -815,12 +841,28 @@ ssetup_ntlmssp_authenticate: if (phase == NtLmNegotiate) { setup_ntlmssp_neg_req(pSMB, ses); iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); + iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { - int blob_len; - blob_len = setup_ntlmssp_auth_req(pSMB, ses, - nls_cp, - first_time); + /* 5 is an empirical value, large enought to + * hold authenticate message, max 10 of + * av paris, doamin,user,workstation mames, + * flags etc.. + */ + ntlmsspblob = kmalloc( + 5*sizeof(struct _AUTHENTICATE_MESSAGE), + GFP_KERNEL); + if (!ntlmsspblob) { + cERROR(1, "Can't allocate NTLMSSP"); + rc = -ENOMEM; + goto ssetup_exit; + } + + blob_len = build_ntlmssp_auth_blob(ntlmsspblob, + ses, nls_cp); iov[1].iov_len = blob_len; + iov[1].iov_base = ntlmsspblob; + pSMB->req.SecurityBlobLength = + cpu_to_le16(blob_len); /* Make sure that we tell the server that we are using the uid that it just gave us back on the response (challenge) */ @@ -830,7 +872,6 @@ ssetup_ntlmssp_authenticate: rc = -ENOSYS; goto ssetup_exit; } - iov[1].iov_base = &pSMB->req.SecurityBlob[0]; /* unicode strings must be word aligned */ if ((iov[0].iov_len + iov[1].iov_len) % 2) { *bcc_ptr = 0; @@ -931,6 +972,8 @@ ssetup_exit: key_put(spnego_key); } kfree(str_area); + kfree(ntlmsspblob); + ntlmsspblob = NULL; if (resp_buf_type == CIFS_SMALL_BUFFER) { cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); cifs_small_buf_release(iov[0].iov_base); -- cgit v1.2.3 From 3eb9a8893a76cf1cda3b41c3212eb2cfe83eae0e Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 1 Sep 2010 17:06:02 -0700 Subject: cifs: Allow binding to local IP address. When using multi-homed machines, it's nice to be able to specify the local IP to use for outbound connections. This patch gives cifs the ability to bind to a particular IP address. Usage: mount -t cifs -o srcaddr=192.168.1.50,user=foo, ... Usage: mount -t cifs -o srcaddr=2002::100:1,user=foo, ... Acked-by: Jeff Layton Acked-by: Dr. David Holder Signed-off-by: Ben Greear Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 19 ++++++++++++ fs/cifs/cifsglob.h | 1 + fs/cifs/connect.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b7431afdd76d..1b6ddd6f760f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "cifsfs.h" #include "cifspdu.h" #define DECLARE_GLOBALS_HERE @@ -367,6 +368,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) { struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); struct cifsTconInfo *tcon = cifs_sb->tcon; + struct sockaddr *srcaddr; + srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; seq_printf(s, ",unc=%s", tcon->treeName); if (tcon->ses->userName) @@ -374,6 +377,22 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) if (tcon->ses->domainName) seq_printf(s, ",domain=%s", tcon->ses->domainName); + if (srcaddr->sa_family != AF_UNSPEC) { + struct sockaddr_in *saddr4; + struct sockaddr_in6 *saddr6; + saddr4 = (struct sockaddr_in *)srcaddr; + saddr6 = (struct sockaddr_in6 *)srcaddr; + if (srcaddr->sa_family == AF_INET6) + seq_printf(s, ",srcaddr=%pI6c", + &saddr6->sin6_addr); + else if (srcaddr->sa_family == AF_INET) + seq_printf(s, ",srcaddr=%pI4", + &saddr4->sin_addr.s_addr); + else + seq_printf(s, ",srcaddr=BAD-AF:%i", + (int)(srcaddr->sa_family)); + } + seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) seq_printf(s, ",forceuid"); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c68f31cf4550..6ef0efaf68d4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -139,6 +139,7 @@ struct TCP_Server_Info { struct sockaddr_in sockAddr; struct sockaddr_in6 sockAddr6; } addr; + struct sockaddr_storage srcaddr; /* locally bind to this IP */ wait_queue_head_t response_q; wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ struct list_head pending_mid_q; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c99760a523bf..fa884520fb84 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -105,6 +105,7 @@ struct smb_vol { bool sockopt_tcp_nodelay:1; unsigned short int port; char *prepath; + struct sockaddr_storage srcaddr; /* allow binding to a local IP */ struct nls_table *local_nls; }; @@ -1046,6 +1047,22 @@ cifs_parse_mount_options(char *options, const char *devname, "long\n"); return 1; } + } else if (strnicmp(data, "srcaddr", 7) == 0) { + vol->srcaddr.ss_family = AF_UNSPEC; + + if (!value || !*value) { + printk(KERN_WARNING "CIFS: srcaddr value" + " not specified.\n"); + return 1; /* needs_arg; */ + } + i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, + value, strlen(value)); + if (i < 0) { + printk(KERN_WARNING "CIFS: Could not parse" + " srcaddr: %s\n", + value); + return 1; + } } else if (strnicmp(data, "prefixpath", 10) == 0) { if (!value || !*value) { printk(KERN_WARNING @@ -1374,8 +1391,36 @@ cifs_parse_mount_options(char *options, const char *devname, return 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. + */ +static bool +srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) +{ + switch (srcaddr->sa_family) { + case AF_UNSPEC: + return (rhs->sa_family == AF_UNSPEC); + case AF_INET: { + struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; + struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; + return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); + } + case AF_INET6: { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; + struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs; + return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); + } + default: + WARN_ON(1); + return false; /* don't expect to be here */ + } +} + + static bool -match_address(struct TCP_Server_Info *server, struct sockaddr *addr) +match_address(struct TCP_Server_Info *server, struct sockaddr *addr, + struct sockaddr *srcaddr) { struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; @@ -1402,6 +1447,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr) break; } + if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) + return false; + return true; } @@ -1469,7 +1517,8 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) if (server->tcpStatus == CifsNew) continue; - if (!match_address(server, addr)) + if (!match_address(server, addr, + (struct sockaddr *)&vol->srcaddr)) continue; if (!match_security(server, vol)) @@ -1584,6 +1633,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) * no need to spinlock this init of tcpStatus or srv_count */ tcp_ses->tcpStatus = CifsNew; + memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, + sizeof(tcp_ses->srcaddr)); ++tcp_ses->srv_count; if (addr.ss_family == AF_INET6) { @@ -1999,6 +2050,33 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) } +static int +bind_socket(struct TCP_Server_Info *server) +{ + int rc = 0; + if (server->srcaddr.ss_family != AF_UNSPEC) { + /* Bind to the specified local IP address */ + struct socket *socket = server->ssocket; + rc = socket->ops->bind(socket, + (struct sockaddr *) &server->srcaddr, + sizeof(server->srcaddr)); + if (rc < 0) { + struct sockaddr_in *saddr4; + struct sockaddr_in6 *saddr6; + saddr4 = (struct sockaddr_in *)&server->srcaddr; + saddr6 = (struct sockaddr_in6 *)&server->srcaddr; + if (saddr6->sin6_family == AF_INET6) + cERROR(1, "cifs: " + "Failed to bind to: %pI6c, error: %d\n", + &saddr6->sin6_addr, rc); + else + cERROR(1, "cifs: " + "Failed to bind to: %pI4, error: %d\n", + &saddr4->sin_addr.s_addr, rc); + } + } + return rc; +} static int ipv4_connect(struct TCP_Server_Info *server) @@ -2024,6 +2102,10 @@ ipv4_connect(struct TCP_Server_Info *server) cifs_reclassify_socket4(socket); } + rc = bind_socket(server); + if (rc < 0) + return rc; + /* user overrode default port */ if (server->addr.sockAddr.sin_port) { rc = socket->ops->connect(socket, (struct sockaddr *) @@ -2186,6 +2268,10 @@ ipv6_connect(struct TCP_Server_Info *server) cifs_reclassify_socket6(socket); } + rc = bind_socket(server); + if (rc < 0) + return rc; + /* user overrode default port */ if (server->addr.sockAddr6.sin6_port) { rc = socket->ops->connect(socket, -- cgit v1.2.3 From c69c1b6eaea1b3e1eecf7ad2fba0208ac4a11131 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 31 Jul 2010 09:14:16 +0200 Subject: cifs: implement CIFSParseMFSymlink() Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/link.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'fs') diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 473ca8033656..12eb491d4c52 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -28,6 +28,68 @@ #include "cifsproto.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" +#include "md5.h" + +#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) +#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) +#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) +#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024) +#define CIFS_MF_SYMLINK_FILE_SIZE \ + (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) + +#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" +#define CIFS_MF_SYMLINK_MD5_FORMAT \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" +#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \ + md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \ + md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \ + md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\ + md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15] + +static int +CIFSParseMFSymlink(const u8 *buf, + unsigned int buf_len, + unsigned int *_link_len, + char **_link_str) +{ + int rc; + unsigned int link_len; + const char *md5_str1; + const char *link_str; + struct MD5Context md5_ctx; + u8 md5_hash[16]; + char md5_str2[34]; + + if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) + return -EINVAL; + + md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET]; + link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET]; + + rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len); + if (rc != 1) + return -EINVAL; + + cifs_MD5_init(&md5_ctx); + cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len); + cifs_MD5_final(md5_hash, &md5_ctx); + + snprintf(md5_str2, sizeof(md5_str2), + CIFS_MF_SYMLINK_MD5_FORMAT, + CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); + + if (strncmp(md5_str1, md5_str2, 17) != 0) + return -EINVAL; + + if (_link_str) { + *_link_str = kstrndup(link_str, link_len, GFP_KERNEL); + if (!*_link_str) + return -ENOMEM; + } + + *_link_len = link_len; + return 0; +} int cifs_hardlink(struct dentry *old_file, struct inode *inode, -- cgit v1.2.3 From 8bfb50a882ccd9804929876470f74edcb23d2326 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 31 Jul 2010 09:15:10 +0200 Subject: cifs: implement CIFSCouldBeMFSymlink() and CIFSCheckMFSymlink() Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 4 +++ fs/cifs/link.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 588612867451..8604a45c1107 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -409,4 +409,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, const int netfid, __u64 *pExtAttrBits, __u64 *pMask); extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); +extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); +extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid); #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 12eb491d4c52..bec212b09a02 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -91,6 +91,85 @@ CIFSParseMFSymlink(const u8 *buf, return 0; } +bool +CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) +{ + if (!(fattr->cf_mode & S_IFREG)) + /* it's not a symlink */ + return false; + + if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) + /* it's not a symlink */ + return false; + + return true; +} + +int +CIFSCheckMFSymlink(struct cifs_fattr *fattr, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ + int rc; + int oplock = 0; + __u16 netfid = 0; + struct cifsTconInfo *pTcon = cifs_sb->tcon; + u8 *buf; + char *pbuf; + unsigned int bytes_read = 0; + int buf_type = CIFS_NO_BUFFER; + unsigned int link_len = 0; + FILE_ALL_INFO file_info; + + if (!CIFSCouldBeMFSymlink(fattr)) + /* it's not a symlink */ + return 0; + + rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, &netfid, &oplock, &file_info, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc != 0) + return rc; + + if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { + CIFSSMBClose(xid, pTcon, netfid); + /* it's not a symlink */ + return 0; + } + + buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pbuf = buf; + + rc = CIFSSMBRead(xid, pTcon, netfid, + CIFS_MF_SYMLINK_FILE_SIZE /* length */, + 0 /* offset */, + &bytes_read, &pbuf, &buf_type); + CIFSSMBClose(xid, pTcon, netfid); + if (rc != 0) { + kfree(buf); + return rc; + } + + rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); + kfree(buf); + if (rc == -EINVAL) + /* it's not a symlink */ + return 0; + if (rc != 0) + return rc; + + /* it is a symlink */ + fattr->cf_eof = link_len; + fattr->cf_mode &= ~S_IFMT; + fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + fattr->cf_dtype = DT_LNK; + return 0; +} + int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) -- cgit v1.2.3 From 0fd43ae4758b2841656afda4439b80e8a3603af2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Aug 2010 21:13:44 +0200 Subject: cifs: implement CIFSQueryMFSymLink() Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/link.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'fs') diff --git a/fs/cifs/link.c b/fs/cifs/link.c index bec212b09a02..6e4e8957595d 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -91,6 +91,56 @@ CIFSParseMFSymlink(const u8 *buf, return 0; } +static int +CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, char **symlinkinfo, + const struct nls_table *nls_codepage, int remap) +{ + int rc; + int oplock = 0; + __u16 netfid = 0; + u8 *buf; + char *pbuf; + unsigned int bytes_read = 0; + int buf_type = CIFS_NO_BUFFER; + unsigned int link_len = 0; + FILE_ALL_INFO file_info; + + rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, &netfid, &oplock, &file_info, + nls_codepage, remap); + if (rc != 0) + return rc; + + if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { + CIFSSMBClose(xid, tcon, netfid); + /* it's not a symlink */ + return -EINVAL; + } + + buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pbuf = buf; + + rc = CIFSSMBRead(xid, tcon, netfid, + CIFS_MF_SYMLINK_FILE_SIZE /* length */, + 0 /* offset */, + &bytes_read, &pbuf, &buf_type); + CIFSSMBClose(xid, tcon, netfid); + if (rc != 0) { + kfree(buf); + return rc; + } + + rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo); + kfree(buf); + if (rc != 0) + return rc; + + return 0; +} + bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) { -- cgit v1.2.3 From 18bddd1059c5d1e17ad6e49c514c95484aa80a33 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 3 Aug 2010 11:24:22 +0200 Subject: cifs: implement CIFSFormatMFSymlink() Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/link.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'fs') diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 6e4e8957595d..0473a86031a5 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -92,6 +92,47 @@ CIFSParseMFSymlink(const u8 *buf, } static int +CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) +{ + unsigned int link_len; + unsigned int ofs; + struct MD5Context md5_ctx; + u8 md5_hash[16]; + + if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) + return -EINVAL; + + link_len = strlen(link_str); + + if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) + return -ENAMETOOLONG; + + cifs_MD5_init(&md5_ctx); + cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len); + cifs_MD5_final(md5_hash, &md5_ctx); + + snprintf(buf, buf_len, + CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, + link_len, + CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); + + ofs = CIFS_MF_SYMLINK_LINK_OFFSET; + memcpy(buf + ofs, link_str, link_len); + + ofs += link_len; + if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { + buf[ofs] = '\n'; + ofs++; + } + + while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { + buf[ofs] = ' '; + ofs++; + } + + return 0; +} + CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char **symlinkinfo, const struct nls_table *nls_codepage, int remap) -- cgit v1.2.3 From 8713d01db8bf948eb9632726f529ec4f821bb025 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Aug 2010 21:15:22 +0200 Subject: cifs: implement CIFSCreateMFSymLink() Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/link.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'fs') diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 0473a86031a5..1b2a8c971995 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -133,6 +133,51 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) return 0; } +static int +CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage, int remap) +{ + int rc; + int oplock = 0; + __u16 netfid = 0; + u8 *buf; + unsigned int bytes_written = 0; + + buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); + if (rc != 0) { + kfree(buf); + return rc; + } + + rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, + CREATE_NOT_DIR, &netfid, &oplock, NULL, + nls_codepage, remap); + if (rc != 0) { + kfree(buf); + return rc; + } + + rc = CIFSSMBWrite(xid, tcon, netfid, + CIFS_MF_SYMLINK_FILE_SIZE /* length */, + 0 /* offset */, + &bytes_written, buf, NULL, 0); + CIFSSMBClose(xid, tcon, netfid); + kfree(buf); + if (rc != 0) + return rc; + + if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) + return -EIO; + + return 0; +} + +static int CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char **symlinkinfo, const struct nls_table *nls_codepage, int remap) -- cgit v1.2.3 From 1b12b9c15b4371d83b729b8fc18c670e78a1479b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Aug 2010 21:19:56 +0200 Subject: cifs: use Minshall+French symlink functions If configured, Minshall+French Symlinks are used against all servers. If the server supports UNIX Extensions, we still create Minshall+French Symlinks on write, but on read we fallback to UNIX Extension symlinks. Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/inode.c | 14 ++++++++++++++ fs/cifs/link.c | 27 +++++++++++++++++++++++---- fs/cifs/readdir.c | 9 +++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 9e771450c3b8..7fde52969896 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -36,6 +36,7 @@ #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ +#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 93f77d438d3c..016975b8e6dd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -332,6 +332,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, return rc; } + /* check for Minshall+French symlinks */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); + if (tmprc) + cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); + } + if (*pinode == NULL) { /* get new inode */ cifs_fill_uniqueid(sb, &fattr); @@ -661,6 +668,13 @@ int cifs_get_inode_info(struct inode **pinode, if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); + /* check for Minshall+French symlinks */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { + tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); + if (tmprc) + cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); + } + if (!*pinode) { *pinode = cifs_iget(sb, &fattr); if (!*pinode) diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1b2a8c971995..cbf7b112287b 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -407,7 +407,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) * but there doesn't seem to be any harm in allowing the client to * read them. */ - if (!(tcon->ses->capabilities & CAP_UNIX)) { + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) + && !(tcon->ses->capabilities & CAP_UNIX)) { rc = -EACCES; goto out; } @@ -418,8 +419,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); - rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, - cifs_sb->local_nls); + rc = -EACCES; + /* + * First try Minshall+French Symlinks, if configured + * and fallback to UNIX Extensions Symlinks. + */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) + rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + + if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX)) + rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, + cifs_sb->local_nls); + kfree(full_path); out: if (rc != 0) { @@ -459,7 +473,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) cFYI(1, "symname is %s", symname); /* BB what if DFS and this volume is on different share? BB */ - if (pTcon->unix_ext) + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) + rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + else if (pTcon->unix_ext) rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, cifs_sb->local_nls); /* else diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d5e591fab475..6a8b417babab 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -738,6 +738,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, cifs_autodisable_serverino(cifs_sb); } + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && + CIFSCouldBeMFSymlink(&fattr)) + /* + * trying to get the type and mode can be slow, + * so just call those regular files for now, and mark + * for reval + */ + fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; + ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); -- cgit v1.2.3 From 736a33205969c16f81d747db14ff4c0f133609a6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 30 Jul 2010 14:56:00 +0200 Subject: cifs: add "mfsymlinks" mount option This is the start for an implementation of "Minshall+French Symlinks" (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks). Signed-off-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/README | 5 +++++ fs/cifs/cifsfs.c | 2 ++ fs/cifs/connect.c | 11 +++++++++++ 3 files changed, 18 insertions(+) (limited to 'fs') diff --git a/fs/cifs/README b/fs/cifs/README index 7099a526f775..ee68d1036544 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -527,6 +527,11 @@ A partial list of the supported mount options follows: SFU does). In the future the bottom 9 bits of the mode also will be emulated using queries of the security descriptor (ACL). + mfsymlinks Enable support for Minshall+French symlinks + (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) + This option is ignored when specified together with the + 'sfu' option. Minshall+French symlinks are used even if + the server supports the CIFS Unix Extensions. sign Must use packet signing (helps avoid unwanted data modification by intermediate systems in the route). Note that signing does not work with lanman or plaintext authentication. diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1b6ddd6f760f..52e89ea07458 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -441,6 +441,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",dynperm"); if (m->mnt_sb->s_flags & MS_POSIXACL) seq_printf(s, ",acl"); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) + seq_printf(s, ",mfsymlinks"); seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index fa884520fb84..435b912f5de5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -100,6 +100,7 @@ struct smb_vol { bool noautotune:1; bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ bool fsc:1; /* enable fscache */ + bool mfsymlinks:1; /* use Minshall+French Symlinks */ unsigned int rsize; unsigned int wsize; bool sockopt_tcp_nodelay:1; @@ -1342,6 +1343,8 @@ cifs_parse_mount_options(char *options, const char *devname, "/proc/fs/cifs/LookupCacheEnabled to 0\n"); } else if (strnicmp(data, "fsc", 3) == 0) { vol->fsc = true; + } else if (strnicmp(data, "mfsymlinks", 10) == 0) { + vol->mfsymlinks = true; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n", data); @@ -2554,6 +2557,14 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cFYI(1, "mounting share using direct i/o"); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; } + if (pvolume_info->mfsymlinks) { + if (pvolume_info->sfu_emul) { + cERROR(1, "mount option mfsymlinks ignored if sfu " + "mount option is used"); + } else { + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; + } + } if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) cERROR(1, "mount option dynperm ignored if cifsacl " -- cgit v1.2.3 From 5fe97cfddc426f3145e8673b68faab7e54462173 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:30 -0700 Subject: cifs: add tcon field to cifsFileInfo struct Eventually, we'll have more than one tcon per superblock. At that point, we'll need to know which one is associated with a particular fid. For now, this is just set from the cifs_sb->tcon pointer, but eventually the caller of cifs_new_fileinfo will pass a tcon pointer in. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 1 + fs/cifs/dir.c | 1 + 2 files changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6ef0efaf68d4..6f3968a5fea4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -351,6 +351,7 @@ struct cifsFileInfo { struct file *pfile; /* needed for writepage */ struct inode *pInode; /* needed for oplock break */ struct vfsmount *mnt; + struct cifsTconInfo *tcon; struct mutex lock_mutex; struct list_head llist; /* list of byte range locks we have. */ bool closePend:1; /* file is marked to close */ diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 0f947bf73f8e..613589cf5172 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -150,6 +150,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, pCifsFile->pfile = file; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; + pCifsFile->tcon = cifs_sb->tcon; mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); -- cgit v1.2.3 From ab9db8b737210bec365593a04dd1c534220bb311 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 21 Sep 2010 08:14:46 -0700 Subject: cifs: allow matching of tcp sessions in CifsNew state With commit 7332f2a6217ee6925f83ef0e725013067ed316ba, cifsd will no longer exit when the socket abends and the tcpStatus is CifsNew. With that change, there's no reason to avoid matching an existing session in this state. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 435b912f5de5..271038b6ec0e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1511,15 +1511,6 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) write_lock(&cifs_tcp_ses_lock); list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { - /* - * the demux thread can exit on its own while still in CifsNew - * so don't accept any sockets in that state. Since the - * tcpStatus never changes back to CifsNew it's safe to check - * for this without a lock. - */ - if (server->tcpStatus == CifsNew) - continue; - if (!match_address(server, addr, (struct sockaddr *)&vol->srcaddr)) continue; -- cgit v1.2.3 From 17edec6f563ba6b5630329fbe9473557bb475c3d Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 22 Sep 2010 02:01:59 +0000 Subject: [CIFS] Remove obsolete header We decided not to use connector to do the upcalls so cn_cifs.h is obsolete - remove it. Signed-off-by: Steve French --- fs/cifs/cn_cifs.h | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 fs/cifs/cn_cifs.h (limited to 'fs') diff --git a/fs/cifs/cn_cifs.h b/fs/cifs/cn_cifs.h deleted file mode 100644 index ea59ccac2eb1..000000000000 --- a/fs/cifs/cn_cifs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * fs/cifs/cn_cifs.h - * - * Copyright (c) International Business Machines Corp., 2002 - * Author(s): Steve French (sfrench@us.ibm.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _CN_CIFS_H -#define _CN_CIFS_H -#ifdef CONFIG_CIFS_UPCALL -#include -#include - -struct cifs_upcall { - char signature[4]; /* CIFS */ - enum command { - CIFS_GET_IP = 0x00000001, /* get ip address for hostname */ - CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */ - } command; - /* union cifs upcall data follows */ -}; -#endif /* CIFS_UPCALL */ -#endif /* _CN_CIFS_H */ -- cgit v1.2.3 From d3bf5221d3274b5015ad18a55060b074cca8d2f0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 22 Sep 2010 19:15:36 +0000 Subject: [CIFS] Fix ordering of cleanup on module init failure If registering fs cache failed, we weren't cleaning up proc. Acked-by: Jeff Layton CC: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 18 +++++++++--------- fs/cifs/connect.c | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 52e89ea07458..eeb8c67a3f29 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -933,11 +933,11 @@ init_cifs(void) rc = cifs_fscache_register(); if (rc) - goto out; + goto out_clean_proc; rc = cifs_init_inodecache(); if (rc) - goto out_clean_proc; + goto out_unreg_fscache; rc = cifs_init_mids(); if (rc) @@ -959,19 +959,19 @@ init_cifs(void) return 0; #ifdef CONFIG_CIFS_UPCALL - out_unregister_filesystem: +out_unregister_filesystem: unregister_filesystem(&cifs_fs_type); #endif - out_destroy_request_bufs: +out_destroy_request_bufs: cifs_destroy_request_bufs(); - out_destroy_mids: +out_destroy_mids: cifs_destroy_mids(); - out_destroy_inodecache: +out_destroy_inodecache: cifs_destroy_inodecache(); - out_clean_proc: - cifs_proc_clean(); +out_unreg_fscache: cifs_fscache_unregister(); - out: +out_clean_proc: + cifs_proc_clean(); return rc; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 271038b6ec0e..230410e0a453 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -47,7 +47,6 @@ #include "ntlmssp.h" #include "nterr.h" #include "rfc1002pdu.h" -#include "cn_cifs.h" #include "fscache.h" #define CIFS_PORT 445 -- cgit v1.2.3 From ba00ba64cf0895e4c2ac507e56306363dc125a90 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:31 -0700 Subject: cifs: make various routines use the cifsFileInfo->tcon pointer ...where it's available and appropriate. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 4 ++-- fs/cifs/file.c | 39 ++++++++++++++++----------------------- fs/cifs/inode.c | 22 ++++++++++++++++------ fs/cifs/ioctl.c | 17 +++-------------- fs/cifs/readdir.c | 19 ++++++++----------- 5 files changed, 45 insertions(+), 56 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index eeb8c67a3f29..7193494efc03 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -589,6 +589,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) /* note that this is called by vfs setlease with the BKL held although I doubt that BKL is needed here in cifs */ struct inode *inode = file->f_path.dentry->d_inode; + struct cifsFileInfo *cfile = file->private_data; if (!(S_ISREG(inode->i_mode))) return -EINVAL; @@ -599,8 +600,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) ((arg == F_WRLCK) && (CIFS_I(inode)->clientCanCacheAll))) return generic_setlease(file, arg, lease); - else if (CIFS_SB(inode->i_sb)->tcon->local_lease && - !CIFS_I(inode)->clientCanCacheRead) + else if (cfile->tcon->local_lease && !CIFS_I(inode)->clientCanCacheRead) /* If the server claims to support oplock on this file, then we still need to check oplock even if the local_lease mount option is set, but there diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 60061b9c2f67..84979fc77862 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -461,7 +461,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) } cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb->tcon; + tcon = pCifsFile->tcon; /* can not grab rename sem here because various ops, including those that already have the rename sem can end up causing writepage @@ -575,7 +575,7 @@ int cifs_close(struct inode *inode, struct file *file) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = pSMBFile->tcon; if (pSMBFile) { struct cifsLockInfo *li, *tmp; write_lock(&GlobalSMBSeslock); @@ -653,11 +653,7 @@ int cifs_closedir(struct inode *inode, struct file *file) xid = GetXid(); if (pCFileStruct) { - struct cifsTconInfo *pTcon; - struct cifs_sb_info *cifs_sb = - CIFS_SB(file->f_path.dentry->d_sb); - - pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = pCFileStruct->tcon; cFYI(1, "Freeing private data in close dir"); write_lock(&GlobalSMBSeslock); @@ -767,7 +763,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) cFYI(1, "Unknown type of lock"); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - tcon = cifs_sb->tcon; + tcon = ((struct cifsFileInfo *)file->private_data)->tcon; if (file->private_data == NULL) { rc = -EBADF; @@ -960,14 +956,14 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; - /* cFYI(1, " write %d bytes to offset %lld of %s", write_size, *poffset, file->f_path.dentry->d_name.name); */ if (file->private_data == NULL) return -EBADF; + open_file = file->private_data; + pTcon = open_file->tcon; rc = generic_write_checks(file, poffset, &write_size, 0); if (rc) @@ -1062,14 +1058,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data, cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; - cFYI(1, "write %zd bytes to offset %lld of %s", write_size, *poffset, file->f_path.dentry->d_name.name); if (file->private_data == NULL) return -EBADF; open_file = file->private_data; + pTcon = open_file->tcon; xid = GetXid(); @@ -1284,7 +1279,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) int rc = -EFAULT; int bytes_written = 0; struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; struct inode *inode; struct cifsFileInfo *open_file; @@ -1293,7 +1287,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) inode = page->mapping->host; cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; offset += (loff_t)from; write_data = kmap(page); @@ -1352,6 +1345,7 @@ static int cifs_writepages(struct address_space *mapping, int nr_pages; __u64 offset = 0; struct cifsFileInfo *open_file; + struct cifsTconInfo *tcon; struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); struct page *page; struct pagevec pvec; @@ -1501,8 +1495,9 @@ retry: cERROR(1, "No writable handles for inode"); rc = -EBADF; } else { + tcon = open_file->tcon; long_op = cifs_write_timeout(cifsi, offset); - rc = CIFSSMBWrite2(xid, cifs_sb->tcon, + rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, bytes_to_write, offset, &bytes_written, iov, n_iov, @@ -1520,8 +1515,7 @@ retry: else set_bit(AS_EIO, &mapping->flags); } else { - cifs_stats_bytes_written(cifs_sb->tcon, - bytes_written); + cifs_stats_bytes_written(tcon, bytes_written); } } for (i = 0; i < n_iov; i++) { @@ -1665,7 +1659,7 @@ int cifs_fsync(struct file *file, int datasync) if (rc == 0) { rc = CIFS_I(inode)->write_behind_rc; CIFS_I(inode)->write_behind_rc = 0; - tcon = CIFS_SB(inode->i_sb)->tcon; + tcon = smbfile->tcon; if (!rc && tcon && smbfile && !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); @@ -1750,7 +1744,6 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, xid = GetXid(); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; if (file->private_data == NULL) { rc = -EBADF; @@ -1758,6 +1751,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, return rc; } open_file = file->private_data; + pTcon = open_file->tcon; if ((file->f_flags & O_ACCMODE) == O_WRONLY) cFYI(1, "attempting read on write only file instance"); @@ -1831,7 +1825,6 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, xid = GetXid(); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; if (file->private_data == NULL) { rc = -EBADF; @@ -1839,6 +1832,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, return rc; } open_file = file->private_data; + pTcon = open_file->tcon; if ((file->f_flags & O_ACCMODE) == O_WRONLY) cFYI(1, "attempting read on write only file instance"); @@ -1974,7 +1968,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, } open_file = file->private_data; cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; + pTcon = open_file->tcon; /* * Reads as many pages as possible from fscache. Returns -ENOBUFS @@ -2312,7 +2306,6 @@ void cifs_oplock_break(struct work_struct *work) oplock_break); struct inode *inode = cfile->pInode; struct cifsInodeInfo *cinode = CIFS_I(inode); - struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb); int rc, waitrc = 0; if (inode && S_ISREG(inode->i_mode)) { @@ -2339,7 +2332,7 @@ void cifs_oplock_break(struct work_struct *work) * disconnected since oplock already released by the server */ if (!cfile->closePend && !cfile->oplock_break_cancelled) { - rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0, + rc = CIFSSMBLock(0, cfile->tcon, cfile->netfid, 0, 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); cFYI(1, "Oplock release rc = %d", rc); } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 016975b8e6dd..0fa145596fcf 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -288,8 +288,8 @@ int cifs_get_file_info_unix(struct file *filp) struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsFileInfo *cfile = filp->private_data; + struct cifsTconInfo *tcon = cfile->tcon; xid = GetXid(); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -522,8 +522,8 @@ int cifs_get_file_info(struct file *filp) struct cifs_fattr fattr; struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; struct cifsFileInfo *cfile = filp->private_data; + struct cifsTconInfo *tcon = cfile->tcon; xid = GetXid(); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -891,7 +891,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon; FILE_BASIC_INFO info_buf; if (attrs == NULL) @@ -934,9 +934,12 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; + pTcon = open_file->tcon; goto set_via_filehandle; } + pTcon = cifs_sb->tcon; + /* * NT4 apparently returns success on this call, but it doesn't * really work. @@ -1611,11 +1614,12 @@ int cifs_revalidate_file(struct file *filp) { int rc = 0; struct inode *inode = filp->f_path.dentry->d_inode; + struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; if (!cifs_inode_needs_reval(inode)) goto check_inval; - if (CIFS_SB(inode->i_sb)->tcon->unix_ext) + if (cfile->tcon->unix_ext) rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); @@ -1720,7 +1724,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = NULL; /* * To avoid spurious oplock breaks from server, in the case of @@ -1735,6 +1739,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; + pTcon = open_file->tcon; rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, false); cifsFileInfo_put(open_file); @@ -1749,6 +1754,9 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, rc = -EINVAL; if (rc != 0) { + if (pTcon == NULL) + pTcon = cifs_sb->tcon; + /* Set file size by pathname rather than by handle either because no valid, writeable file handle for it was found or because there was an error setting @@ -1798,7 +1806,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) struct inode *inode = direntry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon; struct cifs_unix_set_info_args *args = NULL; struct cifsFileInfo *open_file; @@ -1889,9 +1897,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid; + pTcon = open_file->tcon; rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); cifsFileInfo_put(open_file); } else { + pTcon = cifs_sb->tcon; rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 9d38a71c8e14..cc70a61a47d2 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -37,11 +37,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) int xid; struct cifs_sb_info *cifs_sb; #ifdef CONFIG_CIFS_POSIX + struct cifsFileInfo *pSMBFile = filep->private_data; + struct cifsTconInfo *tcon = pSMBFile->tcon; __u64 ExtAttrBits = 0; __u64 ExtAttrMask = 0; - __u64 caps; - struct cifsTconInfo *tcon; - struct cifsFileInfo *pSMBFile = filep->private_data; + __u64 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); #endif /* CONFIG_CIFS_POSIX */ xid = GetXid(); @@ -50,17 +50,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) cifs_sb = CIFS_SB(inode->i_sb); -#ifdef CONFIG_CIFS_POSIX - tcon = cifs_sb->tcon; - if (tcon) - caps = le64_to_cpu(tcon->fsUnixInfo.Capability); - else { - rc = -EIO; - FreeXid(xid); - return -EIO; - } -#endif /* CONFIG_CIFS_POSIX */ - switch (command) { case CIFS_IOC_CHECKUMOUNT: cFYI(1, "User unmount attempted"); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 6a8b417babab..d7784a95134f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -228,22 +228,21 @@ static int initiate_cifs_search(const int xid, struct file *file) struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - if (file->private_data == NULL) { + cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); + if (cifs_sb == NULL) + return -EINVAL; + + if (file->private_data == NULL) file->private_data = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); - } if (file->private_data == NULL) return -ENOMEM; cifsFile = file->private_data; cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - - cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - if (cifs_sb == NULL) - return -EINVAL; - - pTcon = cifs_sb->tcon; + cifsFile->tcon = cifs_sb->tcon; + pTcon = cifsFile->tcon; if (pTcon == NULL) return -EINVAL; @@ -786,9 +785,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) xid = GetXid(); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = cifs_sb->tcon; - if (pTcon == NULL) - return -EINVAL; switch ((int) file->f_pos) { case 0: @@ -838,6 +834,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) CIFSFindClose(xid, pTcon, cifsFile->netfid); } */ + pTcon = cifsFile->tcon; rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); if (rc) { -- cgit v1.2.3 From a6e8a8455c94565c53e1a1756d2ab9d9e3a902b8 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:33 -0700 Subject: cifs: add function to get a tcon from cifs_sb When we convert cifs to do multiple sessions per mount, we'll need more than one tcon per superblock. At that point "cifs_sb->tcon" will make no sense. Add a new accessor function that gets a tcon given a cifs_sb. For now, it just returns cifs_sb->tcon. Later it'll do more. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 2 +- fs/cifs/cifsacl.c | 16 ++++++++-------- fs/cifs/cifsfs.c | 11 +++-------- fs/cifs/cifsglob.h | 6 ++++++ fs/cifs/connect.c | 4 ++-- fs/cifs/dir.c | 20 ++++++++++---------- fs/cifs/file.c | 4 ++-- fs/cifs/fscache.c | 7 ++++--- fs/cifs/inode.c | 49 +++++++++++++++++++++++++------------------------ fs/cifs/link.c | 8 ++++---- fs/cifs/misc.c | 2 +- fs/cifs/readdir.c | 8 ++++---- fs/cifs/xattr.c | 8 ++++---- 13 files changed, 74 insertions(+), 71 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index d6ced7aa23cf..f1e13ea45a17 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -316,7 +316,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); - ses = cifs_sb->tcon->ses; + ses = cifs_sb_tcon(cifs_sb)->ses; if (!ses) { rc = -EINVAL; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 85d7cf7ff2c8..32f244909a0d 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -559,7 +559,7 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, int xid, rc; xid = GetXid(); - rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen); FreeXid(xid); @@ -577,7 +577,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, xid = GetXid(); - rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0, + rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, READ_CONTROL, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { @@ -585,10 +585,10 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, goto out; } - rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); - CIFSSMBClose(xid, cifs_sb->tcon, fid); + CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid); out: FreeXid(xid); return pntsd; @@ -618,7 +618,7 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, int xid, rc; xid = GetXid(); - rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); + rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen); FreeXid(xid); cFYI(DBG2, "SetCIFSACL rc = %d", rc); @@ -634,7 +634,7 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, xid = GetXid(); - rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, + rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, WRITE_DAC, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { @@ -642,10 +642,10 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, goto out; } - rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); + rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen); cFYI(DBG2, "SetCIFSACL rc = %d", rc); - CIFSSMBClose(xid, cifs_sb->tcon, fid); + CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid); out: FreeXid(xid); return rc; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7193494efc03..b9624abb7261 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -137,9 +137,6 @@ cifs_read_super(struct super_block *sb, void *data, sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_op = &cifs_super_ops; sb->s_bdi = &cifs_sb->bdi; -/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) - sb->s_blocksize = - cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ inode = cifs_root_iget(sb, ROOT_I); @@ -225,7 +222,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); int rc = -EOPNOTSUPP; int xid; @@ -367,7 +364,7 @@ static int cifs_show_options(struct seq_file *s, struct vfsmount *m) { struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); struct sockaddr *srcaddr; srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; @@ -458,9 +455,7 @@ static void cifs_umount_begin(struct super_block *sb) if (cifs_sb == NULL) return; - tcon = cifs_sb->tcon; - if (tcon == NULL) - return; + tcon = cifs_sb_tcon(cifs_sb); read_lock(&cifs_tcp_ses_lock); if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6f3968a5fea4..c3510168438e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -413,6 +413,12 @@ CIFS_SB(struct super_block *sb) return sb->s_fs_info; } +static inline struct cifsTconInfo * +cifs_sb_tcon(struct cifs_sb_info *cifs_sb) +{ + return cifs_sb->tcon; +} + static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 230410e0a453..c42d37fb5b7c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3026,8 +3026,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) int rc = 0; char *tmp; - if (cifs_sb->tcon) - cifs_put_tcon(cifs_sb->tcon); + if (cifs_sb_tcon(cifs_sb)) + cifs_put_tcon(cifs_sb_tcon(cifs_sb)); cifs_sb->tcon = NULL; tmp = cifs_sb->prepath; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 613589cf5172..f660a15eb14f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -64,8 +64,8 @@ build_path_from_dentry(struct dentry *direntry) cifs_sb = CIFS_SB(direntry->d_sb); dirsep = CIFS_DIR_SEP(cifs_sb); pplen = cifs_sb->prepathlen; - if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) - dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); + if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS)) + dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; cifs_bp_rename_retry: @@ -117,7 +117,7 @@ cifs_bp_rename_retry: /* BB test paths to Windows with '/' in the midst of prepath */ if (dfsplen) { - strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); + strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { int i; for (i = 0; i < dfsplen; i++) { @@ -150,7 +150,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, pCifsFile->pfile = file; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; - pCifsFile->tcon = cifs_sb->tcon; + pCifsFile->tcon = cifs_sb_tcon(cifs_sb); mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); @@ -158,7 +158,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); write_lock(&GlobalSMBSeslock); - list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); + list_add(&pCifsFile->tlist, &cifs_sb_tcon(cifs_sb)->openFileList); pCifsInode = CIFS_I(newinode); if (pCifsInode) { /* if readable file instance put first in list*/ @@ -225,7 +225,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, posix_flags |= SMB_O_DIRECT; mode &= ~current_umask(); - rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, + rc = CIFSPOSIXCreate(xid, cifs_sb_tcon(cifs_sb), posix_flags, mode, pnetfid, presp_data, poplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -298,7 +298,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb->tcon; + tcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -373,7 +373,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, if (!tcon->unix_ext && (mode & S_IWUGO) == 0) create_options |= CREATE_OPTION_READONLY; - if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + if (tcon->ses->capabilities & CAP_NT_SMBS) rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, create_options, &fileHandle, &oplock, buf, cifs_sb->local_nls, @@ -504,7 +504,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -631,7 +631,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, /* check whether path exists */ cifs_sb = CIFS_SB(parent_dir_inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); /* * Don't allow the separator character in a path component. diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 84979fc77862..6712c2b0a0ae 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -235,7 +235,7 @@ int cifs_open(struct inode *inode, struct file *file) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb->tcon; + tcon = cifs_sb_tcon(cifs_sb); pCifsInode = CIFS_I(file->f_path.dentry->d_inode); @@ -345,7 +345,7 @@ int cifs_open(struct inode *inode, struct file *file) goto out; } - if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + if (tcon->ses->capabilities & CAP_NT_SMBS) rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 9f3f5c4be161..ec4318b019cc 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -66,11 +66,11 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) if (cifsi->fscache) return; - cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, + cifsi->fscache = fscache_acquire_cookie(cifs_sb_tcon(cifs_sb)->fscache, &cifs_fscache_inode_object_def, cifsi); cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", - cifs_sb->tcon->fscache, cifsi->fscache); + cifs_sb_tcon(cifs_sb)->fscache, cifsi->fscache); } void cifs_fscache_release_inode_cookie(struct inode *inode) @@ -117,7 +117,8 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode) /* retire the current fscache cache and get a new one */ fscache_relinquish_cookie(cifsi->fscache, 1); - cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, + cifsi->fscache = fscache_acquire_cookie( + cifs_sb_tcon(cifs_sb)->fscache, &cifs_fscache_inode_object_def, cifsi); cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0fa145596fcf..dce2d598927e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -52,7 +52,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) /* check if server can support readpages */ - if (cifs_sb->tcon->ses->server->maxBuf < + if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf < PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else @@ -315,7 +315,8 @@ int cifs_get_inode_info_unix(struct inode **pinode, struct cifsTconInfo *tcon; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - tcon = cifs_sb->tcon; + tcon = cifs_sb_tcon(cifs_sb); + cFYI(1, "Getting info on %s", full_path); /* could have done a find first instead but this returns more info */ @@ -360,7 +361,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, int rc; int oplock = 0; __u16 netfid; - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); char buf[24]; unsigned int bytes_read; char *pbuf; @@ -449,7 +450,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, char ea_value[4]; __u32 mode; - rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS", + rc = CIFSSMBQAllEAs(xid, cifs_sb_tcon(cifs_sb), path, "SETFILEBITS", ea_value, 4 /* size of buf */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -489,8 +490,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); if (adjust_tz) { - fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; - fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; + fattr->cf_ctime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; + fattr->cf_mtime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; } fattr->cf_eof = le64_to_cpu(info->EndOfFile); @@ -566,7 +567,7 @@ int cifs_get_inode_info(struct inode **pinode, bool adjustTZ = false; struct cifs_fattr fattr; - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); cFYI(1, "Getting info on %s", full_path); if ((pfindData == NULL) && (*pinode != NULL)) { @@ -706,8 +707,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; } - if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) - dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); + if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS)) + dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; @@ -716,7 +717,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; if (dfsplen) { - strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); + strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen); /* switch slash direction in prepath depending on whether * windows or posix style path names */ @@ -841,7 +842,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(-ENOMEM); xid = GetXid(); - if (cifs_sb->tcon->unix_ext) + if (cifs_sb_tcon(cifs_sb)->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, @@ -852,10 +853,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) #ifdef CONFIG_CIFS_FSCACHE /* populate tcon->resource_id */ - cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; + cifs_sb_tcon(cifs_sb)->resource_id = CIFS_I(inode)->uniqueid; #endif - if (rc && cifs_sb->tcon->ipc) { + if (rc && cifs_sb_tcon(cifs_sb)->ipc) { cFYI(1, "ipc connection - fake read inode"); inode->i_mode |= S_IFDIR; inode->i_nlink = 2; @@ -938,7 +939,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, goto set_via_filehandle; } - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); /* * NT4 apparently returns success on this call, but it doesn't @@ -1000,7 +1001,7 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) struct inode *inode = dentry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); __u32 dosattr, origattr; FILE_BASIC_INFO *info_buf = NULL; @@ -1111,7 +1112,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); struct iattr *attrs = NULL; __u32 dosattr = 0, origattr = 0; @@ -1213,7 +1214,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -1394,7 +1395,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -1435,7 +1436,7 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, struct dentry *to_dentry, const char *toPath) { struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); __u16 srcfid; int oplock, rc; @@ -1486,7 +1487,7 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, int xid, rc, tmprc; cifs_sb = CIFS_SB(source_dir->i_sb); - tcon = cifs_sb->tcon; + tcon = cifs_sb_tcon(cifs_sb); xid = GetXid(); @@ -1660,7 +1661,7 @@ int cifs_revalidate_dentry(struct dentry *dentry) "jiffies %ld", full_path, inode, inode->i_count.counter, dentry, dentry->d_time, jiffies); - if (CIFS_SB(sb)->tcon->unix_ext) + if (cifs_sb_tcon(CIFS_SB(sb))->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, @@ -1755,7 +1756,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, if (rc != 0) { if (pTcon == NULL) - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); /* Set file size by pathname rather than by handle either because no valid, writeable file handle for @@ -1901,7 +1902,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); cifsFileInfo_put(open_file); } else { - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -2086,7 +2087,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) { struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); if (pTcon->unix_ext) return cifs_setattr_unix(direntry, attrs); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index cbf7b112287b..66db2d61fa43 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -249,7 +249,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, int rc; int oplock = 0; __u16 netfid = 0; - struct cifsTconInfo *pTcon = cifs_sb->tcon; + struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); u8 *buf; char *pbuf; unsigned int bytes_read = 0; @@ -321,7 +321,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, xid = GetXid(); cifs_sb_target = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_target->tcon; + pTcon = cifs_sb_tcon(cifs_sb_target); /* No need to check for cross device links since server will do that BB note DFS case in future though (when we may have to check) */ @@ -390,7 +390,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb->tcon; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); xid = GetXid(); @@ -459,7 +459,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3ccadc1326d6..c5cbfdb2a58b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -729,6 +729,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) "properly. Hardlinks will not be recognized on this " "mount. Consider mounting with the \"noserverino\" " "option to silence this message.", - cifs_sb->tcon->treeName); + cifs_sb_tcon(cifs_sb)->treeName); } } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d7784a95134f..3efc2424964f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, return NULL; } - if (CIFS_SB(sb)->tcon->nocase) + if (cifs_sb_tcon(CIFS_SB(sb))->nocase) dentry->d_op = &cifs_ci_dentry_ops; else dentry->d_op = &cifs_dentry_ops; @@ -171,7 +171,7 @@ static void cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, struct cifs_sb_info *cifs_sb) { - int offset = cifs_sb->tcon->ses->server->timeAdj; + int offset = cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; memset(fattr, 0, sizeof(*fattr)); fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, @@ -199,7 +199,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, int len; int oplock = 0; int rc; - struct cifsTconInfo *ptcon = cifs_sb->tcon; + struct cifsTconInfo *ptcon = cifs_sb_tcon(cifs_sb); char *tmpbuffer; rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, @@ -241,7 +241,7 @@ static int initiate_cifs_search(const int xid, struct file *file) cifsFile = file->private_data; cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - cifsFile->tcon = cifs_sb->tcon; + cifsFile->tcon = cifs_sb_tcon(cifs_sb); pTcon = cifsFile->tcon; if (pTcon == NULL) return -EINVAL; diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a1509207bfa6..41f95bf67977 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -61,7 +61,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) xid = GetXid(); cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -116,7 +116,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, xid = GetXid(); cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -224,7 +224,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, xid = GetXid(); cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -346,7 +346,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) return -EIO; cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb->tcon; + pTcon = cifs_sb_tcon(cifs_sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) return -EOPNOTSUPP; -- cgit v1.2.3 From f6acb9d0596889a774e142ed76cb05b90d9763d2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:34 -0700 Subject: cifs: temporarily rename cifs_sb->tcon to ptcon to catch stragglers Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 2 +- fs/cifs/cifsglob.h | 2 +- fs/cifs/connect.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 7fde52969896..ba0afd3acff4 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -39,7 +39,7 @@ #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ struct cifs_sb_info { - struct cifsTconInfo *tcon; /* primary mount */ + struct cifsTconInfo *ptcon; /* primary mount */ struct list_head nested_tcon_q; struct nls_table *local_nls; unsigned int rsize; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c3510168438e..cc8300c741b6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -416,7 +416,7 @@ CIFS_SB(struct super_block *sb) static inline struct cifsTconInfo * cifs_sb_tcon(struct cifs_sb_info *cifs_sb) { - return cifs_sb->tcon; + return cifs_sb->ptcon; } static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c42d37fb5b7c..b4bacea54626 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2727,7 +2727,7 @@ try_mount_again: goto remote_path_check; } - cifs_sb->tcon = tcon; + cifs_sb->ptcon = tcon; /* do not care if following two calls succeed - informational */ if (!tcon->ipc) { @@ -3029,7 +3029,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) if (cifs_sb_tcon(cifs_sb)) cifs_put_tcon(cifs_sb_tcon(cifs_sb)); - cifs_sb->tcon = NULL; + cifs_sb->ptcon = NULL; tmp = cifs_sb->prepath; cifs_sb->prepathlen = 0; cifs_sb->prepath = NULL; -- cgit v1.2.3 From 0d424ad0a4b8c08e45928bccfa5b4b240097b01b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:35 -0700 Subject: cifs: add cifs_sb_master_tcon and convert some callers to use it At mount time, we'll always need to create a tcon that will serve as a template for others that are associated with the mount. This tcon is known as the "master" tcon. In some cases, we'll need to use that tcon regardless of who's accessing the mount. Add an accessor function for the master tcon and go ahead and switch the appropriate places to use it. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 6 +++--- fs/cifs/cifsglob.h | 7 +++++++ fs/cifs/connect.c | 4 ++-- fs/cifs/dir.c | 10 +++++----- fs/cifs/fscache.c | 12 ++++++------ fs/cifs/inode.c | 29 ++++++++++++++++------------- fs/cifs/misc.c | 2 +- fs/cifs/readdir.c | 4 ++-- 8 files changed, 42 insertions(+), 32 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b9624abb7261..898d2a5cfad2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -222,7 +222,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); int rc = -EOPNOTSUPP; int xid; @@ -364,7 +364,7 @@ static int cifs_show_options(struct seq_file *s, struct vfsmount *m) { struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); struct sockaddr *srcaddr; srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; @@ -455,7 +455,7 @@ static void cifs_umount_begin(struct super_block *sb) if (cifs_sb == NULL) return; - tcon = cifs_sb_tcon(cifs_sb); + tcon = cifs_sb_master_tcon(cifs_sb); read_lock(&cifs_tcp_ses_lock); if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cc8300c741b6..c265ebdcd177 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -419,6 +419,13 @@ cifs_sb_tcon(struct cifs_sb_info *cifs_sb) return cifs_sb->ptcon; } +/* This function is always expected to succeed */ +static inline struct cifsTconInfo * +cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) +{ + return cifs_sb->ptcon; +} + static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b4bacea54626..f6a3091c2874 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3025,9 +3025,9 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) { int rc = 0; char *tmp; + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - if (cifs_sb_tcon(cifs_sb)) - cifs_put_tcon(cifs_sb_tcon(cifs_sb)); + cifs_put_tcon(tcon); cifs_sb->ptcon = NULL; tmp = cifs_sb->prepath; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f660a15eb14f..fe02435acb3c 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -54,18 +54,18 @@ build_path_from_dentry(struct dentry *direntry) int dfsplen; char *full_path; char dirsep; - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); if (direntry == NULL) return NULL; /* not much we can do if dentry is freed and we need to reopen the file after it was closed implicitly when the server crashed */ - cifs_sb = CIFS_SB(direntry->d_sb); dirsep = CIFS_DIR_SEP(cifs_sb); pplen = cifs_sb->prepathlen; - if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS)) - dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1); + if (tcon->Flags & SMB_SHARE_IS_IN_DFS) + dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; cifs_bp_rename_retry: @@ -117,7 +117,7 @@ cifs_bp_rename_retry: /* BB test paths to Windows with '/' in the midst of prepath */ if (dfsplen) { - strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen); + strncpy(full_path, tcon->treeName, dfsplen); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { int i; for (i = 0; i < dfsplen; i++) { diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index ec4318b019cc..a2ad94efcfe6 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -62,15 +62,15 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); if (cifsi->fscache) return; - cifsi->fscache = fscache_acquire_cookie(cifs_sb_tcon(cifs_sb)->fscache, - &cifs_fscache_inode_object_def, - cifsi); - cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", - cifs_sb_tcon(cifs_sb)->fscache, cifsi->fscache); + cifsi->fscache = fscache_acquire_cookie(tcon->fscache, + &cifs_fscache_inode_object_def, cifsi); + cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache, + cifsi->fscache); } void cifs_fscache_release_inode_cookie(struct inode *inode) @@ -118,7 +118,7 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode) fscache_relinquish_cookie(cifsi->fscache, 1); cifsi->fscache = fscache_acquire_cookie( - cifs_sb_tcon(cifs_sb)->fscache, + cifs_sb_master_tcon(cifs_sb)->fscache, &cifs_fscache_inode_object_def, cifsi); cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index dce2d598927e..da716d96dae6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -52,7 +52,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) /* check if server can support readpages */ - if (cifs_sb_tcon(cifs_sb)->ses->server->maxBuf < + if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops = &cifs_addr_ops_smallbuf; else @@ -476,6 +476,8 @@ static void cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, struct cifs_sb_info *cifs_sb, bool adjust_tz) { + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); + memset(fattr, 0, sizeof(*fattr)); fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); if (info->DeletePending) @@ -490,8 +492,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); if (adjust_tz) { - fattr->cf_ctime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; - fattr->cf_mtime.tv_sec += cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; + fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; + fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; } fattr->cf_eof = le64_to_cpu(info->EndOfFile); @@ -698,6 +700,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) int pplen = cifs_sb->prepathlen; int dfsplen; char *full_path = NULL; + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); /* if no prefix path, simply set path to the root of share to "" */ if (pplen == 0) { @@ -707,8 +710,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; } - if (cifs_sb_tcon(cifs_sb) && (cifs_sb_tcon(cifs_sb)->Flags & SMB_SHARE_IS_IN_DFS)) - dfsplen = strnlen(cifs_sb_tcon(cifs_sb)->treeName, MAX_TREE_SIZE + 1); + if (tcon->Flags & SMB_SHARE_IS_IN_DFS) + dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; @@ -717,7 +720,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; if (dfsplen) { - strncpy(full_path, cifs_sb_tcon(cifs_sb)->treeName, dfsplen); + strncpy(full_path, tcon->treeName, dfsplen); /* switch slash direction in prepath depending on whether * windows or posix style path names */ @@ -831,18 +834,18 @@ retry_iget5_locked: struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) { int xid; - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct inode *inode = NULL; long rc; char *full_path; + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); - cifs_sb = CIFS_SB(sb); full_path = cifs_build_path_to_root(cifs_sb); if (full_path == NULL) return ERR_PTR(-ENOMEM); xid = GetXid(); - if (cifs_sb_tcon(cifs_sb)->unix_ext) + if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, @@ -853,10 +856,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) #ifdef CONFIG_CIFS_FSCACHE /* populate tcon->resource_id */ - cifs_sb_tcon(cifs_sb)->resource_id = CIFS_I(inode)->uniqueid; + tcon->resource_id = CIFS_I(inode)->uniqueid; #endif - if (rc && cifs_sb_tcon(cifs_sb)->ipc) { + if (rc && tcon->ipc) { cFYI(1, "ipc connection - fake read inode"); inode->i_mode |= S_IFDIR; inode->i_nlink = 2; @@ -1661,7 +1664,7 @@ int cifs_revalidate_dentry(struct dentry *dentry) "jiffies %ld", full_path, inode, inode->i_count.counter, dentry, dentry->d_time, jiffies); - if (cifs_sb_tcon(CIFS_SB(sb))->unix_ext) + if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else rc = cifs_get_inode_info(&inode, full_path, NULL, sb, @@ -2087,7 +2090,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) { struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); + struct cifsTconInfo *pTcon = cifs_sb_master_tcon(cifs_sb); if (pTcon->unix_ext) return cifs_setattr_unix(direntry, attrs); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index c5cbfdb2a58b..252f2768db84 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -729,6 +729,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) "properly. Hardlinks will not be recognized on this " "mount. Consider mounting with the \"noserverino\" " "option to silence this message.", - cifs_sb_tcon(cifs_sb)->treeName); + cifs_sb_master_tcon(cifs_sb)->treeName); } } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 3efc2424964f..887a7e230376 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, return NULL; } - if (cifs_sb_tcon(CIFS_SB(sb))->nocase) + if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase) dentry->d_op = &cifs_ci_dentry_ops; else dentry->d_op = &cifs_dentry_ops; @@ -171,7 +171,7 @@ static void cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, struct cifs_sb_info *cifs_sb) { - int offset = cifs_sb_tcon(cifs_sb)->ses->server->timeAdj; + int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; memset(fattr, 0, sizeof(*fattr)); fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, -- cgit v1.2.3 From f7a40689fd1e963cb1006349e050c07584895db5 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 20 Sep 2010 16:01:36 -0700 Subject: cifs: have cifs_new_fileinfo take a tcon arg To minimize calls to cifs_sb_tcon and to allow for a clear error path if a tcon can't be acquired. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 4 ++-- fs/cifs/dir.c | 22 ++++++++++++---------- fs/cifs/file.c | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 8604a45c1107..610b2263c9f3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -107,8 +107,8 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, - struct vfsmount *mnt, unsigned int oflags, - __u32 oplock); + struct vfsmount *mnt, struct cifsTconInfo *tcon, + unsigned int oflags, __u32 oplock); extern int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index fe02435acb3c..23ec28a4c11f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -131,9 +131,9 @@ cifs_bp_rename_retry: } struct cifsFileInfo * -cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, - struct file *file, struct vfsmount *mnt, unsigned int oflags, - __u32 oplock) +cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, + struct vfsmount *mnt, struct cifsTconInfo *tcon, + unsigned int oflags, __u32 oplock) { struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; @@ -150,7 +150,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, pCifsFile->pfile = file; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; - pCifsFile->tcon = cifs_sb_tcon(cifs_sb); + pCifsFile->tcon = tcon; mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); @@ -158,7 +158,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); write_lock(&GlobalSMBSeslock); - list_add(&pCifsFile->tlist, &cifs_sb_tcon(cifs_sb)->openFileList); + list_add(&pCifsFile->tlist, &tcon->openFileList); pCifsInode = CIFS_I(newinode); if (pCifsInode) { /* if readable file instance put first in list*/ @@ -191,6 +191,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, __u32 posix_flags = 0; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_fattr fattr; + struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); cFYI(1, "posix open %s", full_path); @@ -225,9 +226,9 @@ int cifs_posix_open(char *full_path, struct inode **pinode, posix_flags |= SMB_O_DIRECT; mode &= ~current_umask(); - rc = CIFSPOSIXCreate(xid, cifs_sb_tcon(cifs_sb), posix_flags, mode, - pnetfid, presp_data, poplock, full_path, - cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & + rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, + poplock, full_path, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto posix_open_ret; @@ -466,7 +467,8 @@ cifs_create_set_dentry: } pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, - nd->path.mnt, oflags, oplock); + nd->path.mnt, tcon, oflags, + oplock); if (pfile_info == NULL) { fput(filp); CIFSSMBClose(xid, tcon, fileHandle); @@ -726,7 +728,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } cfile = cifs_new_fileinfo(newInode, fileHandle, filp, - nd->path.mnt, + nd->path.mnt, pTcon, nd->intent.open.flags, oplock); if (cfile == NULL) { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 6712c2b0a0ae..e5f463e15c9b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -277,7 +277,7 @@ int cifs_open(struct inode *inode, struct file *file) pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - oflags, oplock); + tcon, oflags, oplock); if (pCifsFile == NULL) { CIFSSMBClose(xid, tcon, netfid); rc = -ENOMEM; @@ -370,7 +370,7 @@ int cifs_open(struct inode *inode, struct file *file) goto out; pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - file->f_flags, oplock); + tcon, file->f_flags, oplock); if (pCifsFile == NULL) { rc = -ENOMEM; goto out; -- cgit v1.2.3 From f3983c2133e9bea9c8b4f690737d15e3e9b02491 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 22 Sep 2010 16:17:40 -0700 Subject: cifs: fix handling of signing with writepages (try #6) Get a reference to the file early so we can eventually base the decision about signing on the correct tcon. If that doesn't work for some reason, then fall back to generic_writepages. That's just as likely to fail, but it simplifies the error handling. In truth, I'm not sure how that could occur anyway, so maybe a NULL open_file here ought to be a BUG()? After that, we drop the reference to the open_file and then we re-get one prior to each WriteAndX call. This helps ensure that the filehandle isn't held open any longer than necessary and that open files are reclaimed prior to each write call. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/file.c | 68 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'fs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e5f463e15c9b..de046e183d12 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1353,6 +1353,15 @@ static int cifs_writepages(struct address_space *mapping, int scanned = 0; int xid, long_op; + /* + * BB: Is this meaningful for a non-block-device file system? + * If it is, we should test it again after we do I/O + */ + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + return 0; + } + cifs_sb = CIFS_SB(mapping->host->i_sb); /* @@ -1362,26 +1371,28 @@ static int cifs_writepages(struct address_space *mapping, if (cifs_sb->wsize < PAGE_CACHE_SIZE) return generic_writepages(mapping, wbc); - if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) - if (cifs_sb->tcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - if (!experimEnabled) - return generic_writepages(mapping, wbc); - iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); if (iov == NULL) return generic_writepages(mapping, wbc); - /* - * BB: Is this meaningful for a non-block-device file system? - * If it is, we should test it again after we do I/O + * if there's no open file, then this is likely to fail too, + * but it'll at least handle the return. Maybe it should be + * a BUG() instead? */ - if (wbc->nonblocking && bdi_write_congested(bdi)) { - wbc->encountered_congestion = 1; + open_file = find_writable_file(CIFS_I(mapping->host)); + if (!open_file) { kfree(iov); - return 0; + return generic_writepages(mapping, wbc); + } + + tcon = open_file->tcon; + if (!experimEnabled && tcon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { + cifsFileInfo_put(open_file); + return generic_writepages(mapping, wbc); } + cifsFileInfo_put(open_file); xid = GetXid(); @@ -1486,38 +1497,33 @@ retry: break; } if (n_iov) { - /* Search for a writable handle every time we call - * CIFSSMBWrite2. We can't rely on the last handle - * we used to still be valid - */ open_file = find_writable_file(CIFS_I(mapping->host)); if (!open_file) { cERROR(1, "No writable handles for inode"); rc = -EBADF; } else { - tcon = open_file->tcon; long_op = cifs_write_timeout(cifsi, offset); - rc = CIFSSMBWrite2(xid, tcon, - open_file->netfid, + rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, bytes_to_write, offset, &bytes_written, iov, n_iov, long_op); cifsFileInfo_put(open_file); cifs_update_eof(cifsi, offset, bytes_written); + } - if (rc || bytes_written < bytes_to_write) { - cERROR(1, "Write2 ret %d, wrote %d", - rc, bytes_written); - /* BB what if continued retry is - requested via mount flags? */ - if (rc == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else - set_bit(AS_EIO, &mapping->flags); - } else { - cifs_stats_bytes_written(tcon, bytes_written); - } + if (rc || bytes_written < bytes_to_write) { + cERROR(1, "Write2 ret %d, wrote %d", + rc, bytes_written); + /* BB what if continued retry is + requested via mount flags? */ + if (rc == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else + set_bit(AS_EIO, &mapping->flags); + } else { + cifs_stats_bytes_written(tcon, bytes_written); } + for (i = 0; i < n_iov; i++) { page = pvec.pages[first + i]; /* Should we also set page error on -- cgit v1.2.3 From 7ffec372458d163492e56e663a1b3a2d7be0a0a2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 29 Sep 2010 19:51:11 -0400 Subject: cifs: add refcounted and timestamped container for holding tcons Eventually, we'll need to track the use of tcons on a per-sb basis, so that we know when it's ok to tear them down. Begin this conversion by adding a new "tcon_link" struct and accessors that get it. For now, the core data structures are untouched -- cifs_sb still just points to a single tcon and the pointers are just cast to deal with the accessor functions. A later patch will flesh this out. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_dfs_ref.c | 21 ++++--- fs/cifs/cifsacl.c | 42 ++++++++++--- fs/cifs/cifsglob.h | 51 ++++++++++++---- fs/cifs/dir.c | 65 ++++++++++++++------ fs/cifs/file.c | 9 ++- fs/cifs/inode.c | 157 ++++++++++++++++++++++++++++++++++++++----------- fs/cifs/link.c | 87 ++++++++++++++++++--------- fs/cifs/readdir.c | 32 +++++----- fs/cifs/xattr.c | 60 ++++++++++++------- 9 files changed, 376 insertions(+), 148 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index f1e13ea45a17..f4aab6f01174 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -306,6 +306,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) int xid, i; int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); + struct tcon_link *tlink; cFYI(1, "in %s", __func__); BUG_ON(IS_ROOT(dentry)); @@ -315,14 +316,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) dput(nd->path.dentry); nd->path.dentry = dget(dentry); - cifs_sb = CIFS_SB(dentry->d_inode->i_sb); - ses = cifs_sb_tcon(cifs_sb)->ses; - - if (!ses) { - rc = -EINVAL; - goto out_err; - } - /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of @@ -335,10 +328,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; } - rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls, + cifs_sb = CIFS_SB(dentry->d_inode->i_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto out_err; + } + ses = tlink_tcon(tlink)->ses; + + rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); + for (i = 0; i < num_referrals; i++) { int len; dump_referral(referrals+i); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 32f244909a0d..2647ea410c4c 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, { struct cifs_ntsd *pntsd = NULL; int xid, rc; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + + if (IS_ERR(tlink)) + return NULL; xid = GetXid(); - rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); FreeXid(xid); + cifs_put_tlink(tlink); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); return pntsd; @@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, int oplock = 0; int xid, rc; __u16 fid; + struct cifsTconInfo *tcon; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + + if (IS_ERR(tlink)) + return NULL; + tcon = tlink_tcon(tlink); xid = GetXid(); - rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, READ_CONTROL, 0, + rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { @@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, goto out; } - rc = CIFSSMBGetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); - CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid); + CIFSSMBClose(xid, tcon, fid); out: + cifs_put_tlink(tlink); FreeXid(xid); return pntsd; } @@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, struct cifs_ntsd *pnntsd, u32 acllen) { int xid, rc; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + + if (IS_ERR(tlink)) + return PTR_ERR(tlink); xid = GetXid(); - rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen); + rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen); FreeXid(xid); + cifs_put_tlink(tlink); cFYI(DBG2, "SetCIFSACL rc = %d", rc); return rc; @@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, int oplock = 0; int xid, rc; __u16 fid; + struct cifsTconInfo *tcon; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + + tcon = tlink_tcon(tlink); xid = GetXid(); - rc = CIFSSMBOpen(xid, cifs_sb_tcon(cifs_sb), path, FILE_OPEN, WRITE_DAC, 0, + rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { @@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, goto out; } - rc = CIFSSMBSetCIFSACL(xid, cifs_sb_tcon(cifs_sb), fid, pnntsd, acllen); + rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); cFYI(DBG2, "SetCIFSACL rc = %d", rc); - CIFSSMBClose(xid, cifs_sb_tcon(cifs_sb), fid); - out: + CIFSSMBClose(xid, tcon, fid); +out: FreeXid(xid); + cifs_put_tlink(tlink); return rc; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c265ebdcd177..cdfd2db4e70d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -310,6 +310,44 @@ struct cifsTconInfo { /* BB add field for back pointer to sb struct(s)? */ }; +/* + * This is a refcounted and timestamped container for a tcon pointer. The + * container holds a tcon reference. It is considered safe to free one of + * these when the tl_count goes to 0. The tl_time is the time of the last + * "get" on the container. + */ +struct tcon_link { + spinlock_t tl_lock; + u32 tl_count; + u64 tl_time; + struct cifsTconInfo *tl_tcon; +}; + +static inline struct tcon_link * +cifs_sb_tlink(struct cifs_sb_info *cifs_sb) +{ + return (struct tcon_link *)cifs_sb->ptcon; +} + +static inline struct cifsTconInfo * +tlink_tcon(struct tcon_link *tlink) +{ + return (struct cifsTconInfo *)tlink; +} + +static inline void +cifs_put_tlink(struct tcon_link *tlink) +{ + return; +} + +/* This function is always expected to succeed */ +static inline struct cifsTconInfo * +cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) +{ + return cifs_sb->ptcon; +} + /* * This info hangs off the cifsFileInfo structure, pointed to by llist. * This is used to track byte stream locks on the file @@ -413,19 +451,6 @@ CIFS_SB(struct super_block *sb) return sb->s_fs_info; } -static inline struct cifsTconInfo * -cifs_sb_tcon(struct cifs_sb_info *cifs_sb) -{ - return cifs_sb->ptcon; -} - -/* This function is always expected to succeed */ -static inline struct cifsTconInfo * -cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) -{ - return cifs_sb->ptcon; -} - static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 23ec28a4c11f..bb3ea06ca6f4 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -137,7 +137,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, { struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; - struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) @@ -191,7 +190,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode, __u32 posix_flags = 0; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_fattr fattr; - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *tcon; cFYI(1, "posix open %s", full_path); @@ -226,10 +226,20 @@ int cifs_posix_open(char *full_path, struct inode **pinode, posix_flags |= SMB_O_DIRECT; mode &= ~current_umask(); + + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto posix_open_ret; + } + + tcon = tlink_tcon(tlink); rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, poplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); + if (rc) goto posix_open_ret; @@ -290,6 +300,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, int desiredAccess = GENERIC_READ | GENERIC_WRITE; __u16 fileHandle; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *tcon; char *full_path = NULL; FILE_ALL_INFO *buf = NULL; @@ -299,13 +310,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb_tcon(cifs_sb); - - full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { - rc = -ENOMEM; - goto cifs_create_out; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + FreeXid(xid); + return PTR_ERR(tlink); } + tcon = tlink_tcon(tlink); if (oplockEnabled) oplock = REQ_OPLOCK; @@ -315,6 +325,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, else oflags = FMODE_READ | SMB_O_CREAT; + full_path = build_path_from_dentry(direntry); + if (full_path == NULL) { + rc = -ENOMEM; + goto cifs_create_out; + } + if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { @@ -481,6 +497,7 @@ cifs_create_set_dentry: cifs_create_out: kfree(buf); kfree(full_path); + cifs_put_tlink(tlink); FreeXid(xid); return rc; } @@ -491,6 +508,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int rc = -EPERM; int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; @@ -503,10 +521,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, if (!old_valid_dev(device_number)) return -EINVAL; - xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { @@ -606,6 +628,7 @@ mknod_out: kfree(full_path); kfree(buf); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -619,6 +642,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, __u16 fileHandle = 0; bool posix_open = false; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct cifsFileInfo *cfile; struct inode *newInode = NULL; @@ -633,7 +657,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, /* check whether path exists */ cifs_sb = CIFS_SB(parent_dir_inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + FreeXid(xid); + return (struct dentry *)tlink; + } + pTcon = tlink_tcon(tlink); /* * Don't allow the separator character in a path component. @@ -644,8 +673,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, for (i = 0; i < direntry->d_name.len; i++) if (direntry->d_name.name[i] == '\\') { cFYI(1, "Invalid file name"); - FreeXid(xid); - return ERR_PTR(-EINVAL); + rc = -EINVAL; + goto lookup_out; } } @@ -655,7 +684,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, */ if (nd && (nd->flags & LOOKUP_EXCL)) { d_instantiate(direntry, NULL); - return NULL; + rc = 0; + goto lookup_out; } /* can not grab the rename sem here since it would @@ -663,8 +693,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, in which we already have the sb rename sem */ full_path = build_path_from_dentry(direntry); if (full_path == NULL) { - FreeXid(xid); - return ERR_PTR(-ENOMEM); + rc = -ENOMEM; + goto lookup_out; } if (direntry->d_inode != NULL) { @@ -760,6 +790,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, lookup_out: kfree(full_path); + cifs_put_tlink(tlink); FreeXid(xid); return ERR_PTR(rc); } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index de046e183d12..1e375abc5eb3 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -224,6 +224,7 @@ int cifs_open(struct inode *inode, struct file *file) __u32 oplock; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *tcon; + struct tcon_link *tlink; struct cifsFileInfo *pCifsFile = NULL; struct cifsInodeInfo *pCifsInode; char *full_path = NULL; @@ -235,7 +236,12 @@ int cifs_open(struct inode *inode, struct file *file) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - tcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + FreeXid(xid); + return PTR_ERR(tlink); + } + tcon = tlink_tcon(tlink); pCifsInode = CIFS_I(file->f_path.dentry->d_inode); @@ -402,6 +408,7 @@ out: kfree(buf); kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index da716d96dae6..aa229692aef1 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -313,16 +313,21 @@ int cifs_get_inode_info_unix(struct inode **pinode, FILE_UNIX_BASIC_INFO find_data; struct cifs_fattr fattr; struct cifsTconInfo *tcon; + struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - tcon = cifs_sb_tcon(cifs_sb); - cFYI(1, "Getting info on %s", full_path); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (!rc) { cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); @@ -361,7 +366,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, int rc; int oplock = 0; __u16 netfid; - struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *tcon; char buf[24]; unsigned int bytes_read; char *pbuf; @@ -380,7 +386,12 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, return -EINVAL; /* EOPNOTSUPP? */ } - rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -388,7 +399,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, if (rc == 0) { int buf_type = CIFS_NO_BUFFER; /* Read header */ - rc = CIFSSMBRead(xid, pTcon, netfid, + rc = CIFSSMBRead(xid, tcon, netfid, 24 /* length */, 0 /* offset */, &bytes_read, &pbuf, &buf_type); if ((rc == 0) && (bytes_read >= 8)) { @@ -430,8 +441,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, fattr->cf_dtype = DT_REG; rc = -EOPNOTSUPP; /* or some unknown SFU type */ } - CIFSSMBClose(xid, pTcon, netfid); + CIFSSMBClose(xid, tcon, netfid); } + cifs_put_tlink(tlink); return rc; } @@ -449,11 +461,19 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, ssize_t rc; char ea_value[4]; __u32 mode; + struct tcon_link *tlink; + struct cifsTconInfo *tcon; - rc = CIFSSMBQAllEAs(xid, cifs_sb_tcon(cifs_sb), path, "SETFILEBITS", + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + + rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS", ea_value, 4 /* size of buf */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (rc < 0) return (int)rc; else if (rc > 3) { @@ -564,26 +584,33 @@ int cifs_get_inode_info(struct inode **pinode, { int rc = 0, tmprc; struct cifsTconInfo *pTcon; + struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *buf = NULL; bool adjustTZ = false; struct cifs_fattr fattr; - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + cFYI(1, "Getting info on %s", full_path); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { cFYI(1, "No need to revalidate cached inode sizes"); - return rc; + goto cgii_exit; } } /* if file info not passed in then get it from server */ if (pfindData == NULL) { buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + if (buf == NULL) { + rc = -ENOMEM; + goto cgii_exit; + } pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ @@ -688,6 +715,7 @@ int cifs_get_inode_info(struct inode **pinode, cgii_exit: kfree(buf); + cifs_put_tlink(tlink); return rc; } @@ -895,6 +923,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink = NULL; struct cifsTconInfo *pTcon; FILE_BASIC_INFO info_buf; @@ -942,7 +971,13 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, goto set_via_filehandle; } - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + tlink = NULL; + goto out; + } + pTcon = tlink_tcon(tlink); /* * NT4 apparently returns success on this call, but it doesn't @@ -987,6 +1022,8 @@ set_via_filehandle: else cifsFileInfo_put(open_file); out: + if (tlink != NULL) + cifs_put_tlink(tlink); return rc; } @@ -1004,10 +1041,16 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) struct inode *inode = dentry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *tcon; __u32 dosattr, origattr; FILE_BASIC_INFO *info_buf = NULL; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, @@ -1076,6 +1119,7 @@ out_close: CIFSSMBClose(xid, tcon, netfid); out: kfree(info_buf); + cifs_put_tlink(tlink); return rc; /* @@ -1115,12 +1159,18 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *tcon; struct iattr *attrs = NULL; __u32 dosattr = 0, origattr = 0; cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + xid = GetXid(); /* Unlink can be called from rename so we can not take the @@ -1128,8 +1178,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto unlink_out; } if ((tcon->ses->capabilities & CAP_UNIX) && @@ -1195,10 +1244,11 @@ out_reval: dir->i_ctime = dir->i_mtime = current_fs_time(sb); cifs_inode = CIFS_I(dir); CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ - +unlink_out: kfree(full_path); kfree(attrs); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1207,6 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) int rc = 0, tmprc; int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; @@ -1214,16 +1265,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); - xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto mkdir_out; } if ((pTcon->ses->capabilities & CAP_UNIX) && @@ -1381,6 +1434,7 @@ mkdir_get_info: mkdir_out: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1389,6 +1443,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) int rc = 0; int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; @@ -1397,18 +1452,23 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb); - full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto rmdir_exit; + } + + cifs_sb = CIFS_SB(inode->i_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto rmdir_exit; } + pTcon = tlink_tcon(tlink); rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); if (!rc) { drop_nlink(inode); @@ -1429,6 +1489,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); +rmdir_exit: kfree(full_path); FreeXid(xid); return rc; @@ -1439,10 +1500,16 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, struct dentry *to_dentry, const char *toPath) { struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); - struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *pTcon; __u16 srcfid; int oplock, rc; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + /* try path-based rename first */ rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -1454,11 +1521,11 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, * rename by filehandle to various Windows servers. */ if (rc == 0 || rc != -ETXTBSY) - return rc; + goto do_rename_exit; /* open-file renames don't work across directories */ if (to_dentry->d_parent != from_dentry->d_parent) - return rc; + goto do_rename_exit; /* open the file to be renamed -- we need DELETE perms */ rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, @@ -1474,7 +1541,8 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, CIFSSMBClose(xid, pTcon, srcfid); } - +do_rename_exit: + cifs_put_tlink(tlink); return rc; } @@ -1484,13 +1552,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *tcon; FILE_UNIX_BASIC_INFO *info_buf_source = NULL; FILE_UNIX_BASIC_INFO *info_buf_target; int xid, rc, tmprc; cifs_sb = CIFS_SB(source_dir->i_sb); - tcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); xid = GetXid(); @@ -1566,6 +1638,7 @@ cifs_rename_exit: kfree(fromName); kfree(toName); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -1728,6 +1801,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, struct cifsFileInfo *open_file; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink = NULL; struct cifsTconInfo *pTcon = NULL; /* @@ -1758,8 +1832,12 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, rc = -EINVAL; if (rc != 0) { - if (pTcon == NULL) - pTcon = cifs_sb_tcon(cifs_sb); + if (pTcon == NULL) { + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + } /* Set file size by pathname rather than by handle either because no valid, writeable file handle for @@ -1790,6 +1868,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, CIFSSMBClose(xid, pTcon, netfid); } } + if (tlink) + cifs_put_tlink(tlink); } if (rc == 0) { @@ -1810,6 +1890,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) struct inode *inode = direntry->d_inode; struct cifsInodeInfo *cifsInode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct cifs_unix_set_info_args *args = NULL; struct cifsFileInfo *open_file; @@ -1905,11 +1986,17 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); cifsFileInfo_put(open_file); } else { - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto out; + } + pTcon = tlink_tcon(tlink); rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + cifs_put_tlink(tlink); } if (rc) diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 66db2d61fa43..b38fe6704ad2 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -249,7 +249,8 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, int rc; int oplock = 0; __u16 netfid = 0; - struct cifsTconInfo *pTcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink; + struct cifsTconInfo *pTcon; u8 *buf; char *pbuf; unsigned int bytes_read = 0; @@ -261,23 +262,30 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, /* it's not a symlink */ return 0; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, CREATE_NOT_DIR, &netfid, &oplock, &file_info, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc != 0) - return rc; + goto out; if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { CIFSSMBClose(xid, pTcon, netfid); /* it's not a symlink */ - return 0; + goto out; } buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + if (!buf) { + rc = -ENOMEM; + goto out; + } pbuf = buf; rc = CIFSSMBRead(xid, pTcon, netfid, @@ -287,23 +295,28 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, CIFSSMBClose(xid, pTcon, netfid); if (rc != 0) { kfree(buf); - return rc; + goto out; } rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); kfree(buf); - if (rc == -EINVAL) + if (rc == -EINVAL) { /* it's not a symlink */ - return 0; + rc = 0; + goto out; + } + if (rc != 0) - return rc; + goto out; /* it is a symlink */ fattr->cf_eof = link_len; fattr->cf_mode &= ~S_IFMT; fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; fattr->cf_dtype = DT_LNK; - return 0; +out: + cifs_put_tlink(tlink); + return rc; } int @@ -314,17 +327,17 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, int xid; char *fromName = NULL; char *toName = NULL; - struct cifs_sb_info *cifs_sb_target; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; - xid = GetXid(); - - cifs_sb_target = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb_target); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); -/* No need to check for cross device links since server will do that - BB note DFS case in future though (when we may have to check) */ + xid = GetXid(); fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); @@ -336,13 +349,13 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, /* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/ if (pTcon->unix_ext) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls, - cifs_sb_target->mnt_cifs_flags & + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, - cifs_sb_target->local_nls, - cifs_sb_target->mnt_cifs_flags & + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if ((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; @@ -378,6 +391,7 @@ cifs_hl_exit: kfree(fromName); kfree(toName); FreeXid(xid); + cifs_put_tlink(tlink); return rc; } @@ -390,10 +404,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) char *full_path = NULL; char *target_path = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsTconInfo *tcon = cifs_sb_tcon(cifs_sb); + struct tcon_link *tlink = NULL; + struct cifsTconInfo *tcon; xid = GetXid(); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + tlink = NULL; + goto out; + } + tcon = tlink_tcon(tlink); + /* * For now, we just handle symlinks with unix extensions enabled. * Eventually we should handle NTFS reparse points, and MacOS @@ -442,6 +465,8 @@ out: } FreeXid(xid); + if (tlink) + cifs_put_tlink(tlink); nd_set_link(nd, target_path); return NULL; } @@ -451,22 +476,25 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) { int rc = -EOPNOTSUPP; int xid; - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct tcon_link *tlink; struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) { + rc = PTR_ERR(tlink); + goto symlink_exit; + } + pTcon = tlink_tcon(tlink); full_path = build_path_from_dentry(direntry); - if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto symlink_exit; } cFYI(1, "Full path: %s", full_path); @@ -504,8 +532,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) d_instantiate(direntry, newinode); } } - +symlink_exit: kfree(full_path); + cifs_put_tlink(tlink); FreeXid(xid); return rc; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 887a7e230376..170047cf4522 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -223,33 +223,35 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, static int initiate_cifs_search(const int xid, struct file *file) { int rc = 0; - char *full_path; + char *full_path = NULL; struct cifsFileInfo *cifsFile; - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); + struct tcon_link *tlink; struct cifsTconInfo *pTcon; - cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - if (cifs_sb == NULL) - return -EINVAL; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); if (file->private_data == NULL) file->private_data = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); + if (file->private_data == NULL) { + rc = -ENOMEM; + goto error_exit; + } - if (file->private_data == NULL) - return -ENOMEM; cifsFile = file->private_data; cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - cifsFile->tcon = cifs_sb_tcon(cifs_sb); - pTcon = cifsFile->tcon; - if (pTcon == NULL) - return -EINVAL; + cifsFile->tcon = pTcon; full_path = build_path_from_dentry(file->f_path.dentry); - - if (full_path == NULL) - return -ENOMEM; + if (full_path == NULL) { + rc = -ENOMEM; + goto error_exit; + } cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); @@ -282,7 +284,9 @@ ffirst_retry: cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; goto ffirst_retry; } +error_exit: kfree(full_path); + cifs_put_tlink(tlink); return rc; } diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 41f95bf67977..a264b744bb41 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -47,9 +47,10 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) #ifdef CONFIG_CIFS_XATTR int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct super_block *sb; - char *full_path; + char *full_path = NULL; if (direntry == NULL) return -EIO; @@ -58,16 +59,19 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) sb = direntry->d_inode->i_sb; if (sb == NULL) return -EIO; - xid = GetXid(); cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto remove_ea_exit; } if (ea_name == NULL) { cFYI(1, "Null xattr names not supported"); @@ -91,6 +95,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) remove_ea_exit: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); #endif return rc; } @@ -102,6 +107,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, #ifdef CONFIG_CIFS_XATTR int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct super_block *sb; char *full_path; @@ -113,16 +119,19 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, sb = direntry->d_inode->i_sb; if (sb == NULL) return -EIO; - xid = GetXid(); cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto set_ea_exit; } /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ @@ -132,9 +141,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, returns as xattrs */ if (value_size > MAX_EA_VALUE_SIZE) { cFYI(1, "size of EA value too large"); - kfree(full_path); - FreeXid(xid); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + goto set_ea_exit; } if (ea_name == NULL) { @@ -198,6 +206,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, set_ea_exit: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); #endif return rc; } @@ -209,6 +218,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, #ifdef CONFIG_CIFS_XATTR int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct super_block *sb; char *full_path; @@ -221,16 +231,18 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, if (sb == NULL) return -EIO; - xid = GetXid(); - cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb_tcon(cifs_sb); + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto get_ea_exit; } /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ @@ -323,6 +335,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, get_ea_exit: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); #endif return rc; } @@ -333,6 +346,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) #ifdef CONFIG_CIFS_XATTR int xid; struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct super_block *sb; char *full_path; @@ -346,18 +360,20 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) return -EIO; cifs_sb = CIFS_SB(sb); - pTcon = cifs_sb_tcon(cifs_sb); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) return -EOPNOTSUPP; + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + pTcon = tlink_tcon(tlink); + xid = GetXid(); full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto list_ea_exit; } /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ @@ -370,8 +386,10 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); +list_ea_exit: kfree(full_path); FreeXid(xid); + cifs_put_tlink(tlink); #endif return rc; } -- cgit v1.2.3 From 13cfb7334eb6fd0fc06da5589aea1e947791f1d6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 29 Sep 2010 19:51:11 -0400 Subject: cifs: have cifsFileInfo hold a reference to a tlink rather than tcon pointer cifsFileInfo needs a pointer to a tcon, but it doesn't currently hold a reference to it. Change it to keep a pointer to a tcon_link instead and hold a reference to it. That will keep the tcon from being freed until the file is closed. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 3 ++- fs/cifs/cifsglob.h | 9 ++++++++- fs/cifs/cifsproto.h | 2 +- fs/cifs/dir.c | 10 +++++----- fs/cifs/file.c | 31 ++++++++++++++++--------------- fs/cifs/inode.c | 12 ++++++------ fs/cifs/ioctl.c | 2 +- fs/cifs/link.c | 1 - fs/cifs/readdir.c | 4 ++-- 9 files changed, 41 insertions(+), 33 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 898d2a5cfad2..b2fd075dc2e6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -595,7 +595,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) ((arg == F_WRLCK) && (CIFS_I(inode)->clientCanCacheAll))) return generic_setlease(file, arg, lease); - else if (cfile->tcon->local_lease && !CIFS_I(inode)->clientCanCacheRead) + else if (tlink_tcon(cfile->tlink)->local_lease && + !CIFS_I(inode)->clientCanCacheRead) /* If the server claims to support oplock on this file, then we still need to check oplock even if the local_lease mount option is set, but there diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cdfd2db4e70d..d5324853203b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -341,6 +341,12 @@ cifs_put_tlink(struct tcon_link *tlink) return; } +static inline struct tcon_link * +cifs_get_tlink(struct tcon_link *tlink) +{ + return tlink; +} + /* This function is always expected to succeed */ static inline struct cifsTconInfo * cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) @@ -389,7 +395,7 @@ struct cifsFileInfo { struct file *pfile; /* needed for writepage */ struct inode *pInode; /* needed for oplock break */ struct vfsmount *mnt; - struct cifsTconInfo *tcon; + struct tcon_link *tlink; struct mutex lock_mutex; struct list_head llist; /* list of byte range locks we have. */ bool closePend:1; /* file is marked to close */ @@ -411,6 +417,7 @@ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file) { if (atomic_dec_and_test(&cifs_file->count)) { + cifs_put_tlink(cifs_file->tlink); iput(cifs_file->pInode); kfree(cifs_file); } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 610b2263c9f3..7294723d0625 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -107,7 +107,7 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, - struct vfsmount *mnt, struct cifsTconInfo *tcon, + struct vfsmount *mnt, struct tcon_link *tlink, unsigned int oflags, __u32 oplock); extern int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index bb3ea06ca6f4..5adf47f28fed 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -132,7 +132,7 @@ cifs_bp_rename_retry: struct cifsFileInfo * cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, - struct vfsmount *mnt, struct cifsTconInfo *tcon, + struct vfsmount *mnt, struct tcon_link *tlink, unsigned int oflags, __u32 oplock) { struct cifsFileInfo *pCifsFile; @@ -149,7 +149,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, pCifsFile->pfile = file; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; - pCifsFile->tcon = tcon; + pCifsFile->tlink = cifs_get_tlink(tlink); mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); @@ -157,7 +157,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); write_lock(&GlobalSMBSeslock); - list_add(&pCifsFile->tlist, &tcon->openFileList); + list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList)); pCifsInode = CIFS_I(newinode); if (pCifsInode) { /* if readable file instance put first in list*/ @@ -483,7 +483,7 @@ cifs_create_set_dentry: } pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, - nd->path.mnt, tcon, oflags, + nd->path.mnt, tlink, oflags, oplock); if (pfile_info == NULL) { fput(filp); @@ -758,7 +758,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } cfile = cifs_new_fileinfo(newInode, fileHandle, filp, - nd->path.mnt, pTcon, + nd->path.mnt, tlink, nd->intent.open.flags, oplock); if (cfile == NULL) { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 1e375abc5eb3..24332d437150 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -283,7 +283,7 @@ int cifs_open(struct inode *inode, struct file *file) pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - tcon, oflags, oplock); + tlink, oflags, oplock); if (pCifsFile == NULL) { CIFSSMBClose(xid, tcon, netfid); rc = -ENOMEM; @@ -376,7 +376,7 @@ int cifs_open(struct inode *inode, struct file *file) goto out; pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, - tcon, file->f_flags, oplock); + tlink, file->f_flags, oplock); if (pCifsFile == NULL) { rc = -ENOMEM; goto out; @@ -468,7 +468,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) } cifs_sb = CIFS_SB(inode->i_sb); - tcon = pCifsFile->tcon; + tcon = tlink_tcon(pCifsFile->tlink); /* can not grab rename sem here because various ops, including those that already have the rename sem can end up causing writepage @@ -582,7 +582,7 @@ int cifs_close(struct inode *inode, struct file *file) xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); - pTcon = pSMBFile->tcon; + pTcon = tlink_tcon(pSMBFile->tlink); if (pSMBFile) { struct cifsLockInfo *li, *tmp; write_lock(&GlobalSMBSeslock); @@ -660,7 +660,7 @@ int cifs_closedir(struct inode *inode, struct file *file) xid = GetXid(); if (pCFileStruct) { - struct cifsTconInfo *pTcon = pCFileStruct->tcon; + struct cifsTconInfo *pTcon = tlink_tcon(pCFileStruct->tlink); cFYI(1, "Freeing private data in close dir"); write_lock(&GlobalSMBSeslock); @@ -684,6 +684,7 @@ int cifs_closedir(struct inode *inode, struct file *file) else cifs_buf_release(ptmp); } + cifs_put_tlink(pCFileStruct->tlink); kfree(file->private_data); file->private_data = NULL; } @@ -770,7 +771,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) cFYI(1, "Unknown type of lock"); cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - tcon = ((struct cifsFileInfo *)file->private_data)->tcon; + tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); if (file->private_data == NULL) { rc = -EBADF; @@ -970,7 +971,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, return -EBADF; open_file = file->private_data; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); rc = generic_write_checks(file, poffset, &write_size, 0); if (rc) @@ -1071,7 +1072,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (file->private_data == NULL) return -EBADF; open_file = file->private_data; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); xid = GetXid(); @@ -1393,7 +1394,7 @@ static int cifs_writepages(struct address_space *mapping, return generic_writepages(mapping, wbc); } - tcon = open_file->tcon; + tcon = tlink_tcon(open_file->tlink); if (!experimEnabled && tcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { cifsFileInfo_put(open_file); @@ -1672,7 +1673,7 @@ int cifs_fsync(struct file *file, int datasync) if (rc == 0) { rc = CIFS_I(inode)->write_behind_rc; CIFS_I(inode)->write_behind_rc = 0; - tcon = smbfile->tcon; + tcon = tlink_tcon(smbfile->tlink); if (!rc && tcon && smbfile && !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); @@ -1764,7 +1765,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, return rc; } open_file = file->private_data; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); if ((file->f_flags & O_ACCMODE) == O_WRONLY) cFYI(1, "attempting read on write only file instance"); @@ -1845,7 +1846,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, return rc; } open_file = file->private_data; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); if ((file->f_flags & O_ACCMODE) == O_WRONLY) cFYI(1, "attempting read on write only file instance"); @@ -1981,7 +1982,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, } open_file = file->private_data; cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); /* * Reads as many pages as possible from fscache. Returns -ENOBUFS @@ -2345,8 +2346,8 @@ void cifs_oplock_break(struct work_struct *work) * disconnected since oplock already released by the server */ if (!cfile->closePend && !cfile->oplock_break_cancelled) { - rc = CIFSSMBLock(0, cfile->tcon, cfile->netfid, 0, 0, 0, 0, - LOCKING_ANDX_OPLOCK_RELEASE, false); + rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, + 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); cFYI(1, "Oplock release rc = %d", rc); } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index aa229692aef1..a39a1c451733 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -289,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp) struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = filp->private_data; - struct cifsTconInfo *tcon = cfile->tcon; + struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink); xid = GetXid(); rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -546,7 +546,7 @@ int cifs_get_file_info(struct file *filp) struct inode *inode = filp->f_path.dentry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = filp->private_data; - struct cifsTconInfo *tcon = cfile->tcon; + struct cifsTconInfo *tcon = tlink_tcon(cfile->tlink); xid = GetXid(); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); @@ -967,7 +967,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); goto set_via_filehandle; } @@ -1696,7 +1696,7 @@ int cifs_revalidate_file(struct file *filp) if (!cifs_inode_needs_reval(inode)) goto check_inval; - if (cfile->tcon->unix_ext) + if (tlink_tcon(cfile->tlink)->unix_ext) rc = cifs_get_file_info_unix(filp); else rc = cifs_get_file_info(filp); @@ -1817,7 +1817,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, npid, false); cifsFileInfo_put(open_file); @@ -1982,7 +1982,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid; - pTcon = open_file->tcon; + pTcon = tlink_tcon(open_file->tlink); rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); cifsFileInfo_put(open_file); } else { diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index cc70a61a47d2..077bf756f342 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -38,7 +38,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) struct cifs_sb_info *cifs_sb; #ifdef CONFIG_CIFS_POSIX struct cifsFileInfo *pSMBFile = filep->private_data; - struct cifsTconInfo *tcon = pSMBFile->tcon; + struct cifsTconInfo *tcon = tlink_tcon(pSMBFile->tlink); __u64 ExtAttrBits = 0; __u64 ExtAttrMask = 0; __u64 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); diff --git a/fs/cifs/link.c b/fs/cifs/link.c index b38fe6704ad2..85cdbf831e7b 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -346,7 +346,6 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, goto cifs_hl_exit; } -/* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/ if (pTcon->unix_ext) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, cifs_sb->local_nls, diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 170047cf4522..1f0bd0f972d4 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -245,7 +245,7 @@ static int initiate_cifs_search(const int xid, struct file *file) cifsFile = file->private_data; cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; - cifsFile->tcon = pTcon; + cifsFile->tlink = cifs_get_tlink(tlink); full_path = build_path_from_dentry(file->f_path.dentry); if (full_path == NULL) { @@ -838,7 +838,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) CIFSFindClose(xid, pTcon, cifsFile->netfid); } */ - pTcon = cifsFile->tcon; + pTcon = tlink_tcon(cifsFile->tlink); rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); if (rc) { -- cgit v1.2.3 From 6508d904e6fb66ce4c34617f72b38d6714c4b9f6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 29 Sep 2010 19:51:11 -0400 Subject: cifs: have find_readable/writable_file filter by fsuid When we implement multiuser mounts, we'll need to filter filehandles by fsuid. Add a flag for multiuser mounts and code to filter by fsuid when it's set. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 3 ++- fs/cifs/cifsacl.c | 4 ++-- fs/cifs/cifsproto.h | 4 ++-- fs/cifs/dir.c | 1 + fs/cifs/file.c | 33 +++++++++++++++++++++++++-------- fs/cifs/inode.c | 6 +++--- 6 files changed, 35 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ba0afd3acff4..e04e6923d354 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -37,6 +37,7 @@ #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ +#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ struct cifs_sb_info { struct cifsTconInfo *ptcon; /* primary mount */ @@ -48,7 +49,7 @@ struct cifs_sb_info { gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; - int mnt_cifs_flags; + unsigned int mnt_cifs_flags; int prepathlen; char *prepath; /* relative path under the share to mount to */ #ifdef CONFIG_CIFS_DFS_UPCALL diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 2647ea410c4c..c9b4792ae825 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -615,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct cifsFileInfo *open_file = NULL; if (inode) - open_file = find_readable_file(CIFS_I(inode)); + open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); @@ -685,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); - open_file = find_readable_file(CIFS_I(inode)); + open_file = find_readable_file(CIFS_I(inode), true); if (!open_file) return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7294723d0625..29a2ee8ae51f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -78,9 +78,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern bool is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); -extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); +extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); #ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *); +extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); #endif extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 5adf47f28fed..e249b561ce8f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -144,6 +144,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; + pCifsFile->uid = current_fsuid(); pCifsFile->pInode = igrab(newinode); pCifsFile->mnt = mnt; pCifsFile->pfile = file; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 24332d437150..80856f180711 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1168,9 +1168,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data, } #ifdef CONFIG_CIFS_EXPERIMENTAL -struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) +struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, + bool fsuid_only) { struct cifsFileInfo *open_file = NULL; + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); + + /* only filter by fsuid on multiuser mounts */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) + fsuid_only = false; read_lock(&GlobalSMBSeslock); /* we could simply get the first_list_entry since write-only entries @@ -1179,6 +1185,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; + if (fsuid_only && open_file->uid != current_fsuid()) + continue; if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_RDONLY))) { if (!open_file->invalidHandle) { @@ -1198,9 +1206,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) } #endif -struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) +struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, + bool fsuid_only) { struct cifsFileInfo *open_file; + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); bool any_available = false; int rc; @@ -1214,13 +1224,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) return NULL; } + /* only filter by fsuid on multiuser mounts */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) + fsuid_only = false; + read_lock(&GlobalSMBSeslock); refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { - if (open_file->closePend || - (!any_available && open_file->pid != current->tgid)) + if (open_file->closePend) + continue; + if (!any_available && open_file->pid != current->tgid) + continue; + if (fsuid_only && open_file->uid != current_fsuid()) continue; - if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { @@ -1315,7 +1331,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) if (mapping->host->i_size - offset < (loff_t)to) to = (unsigned)(mapping->host->i_size - offset); - open_file = find_writable_file(CIFS_I(mapping->host)); + open_file = find_writable_file(CIFS_I(mapping->host), false); if (open_file) { bytes_written = cifs_write(open_file->pfile, write_data, to-from, &offset); @@ -1388,7 +1404,7 @@ static int cifs_writepages(struct address_space *mapping, * but it'll at least handle the return. Maybe it should be * a BUG() instead? */ - open_file = find_writable_file(CIFS_I(mapping->host)); + open_file = find_writable_file(CIFS_I(mapping->host), false); if (!open_file) { kfree(iov); return generic_writepages(mapping, wbc); @@ -1505,7 +1521,8 @@ retry: break; } if (n_iov) { - open_file = find_writable_file(CIFS_I(mapping->host)); + open_file = find_writable_file(CIFS_I(mapping->host), + false); if (!open_file) { cERROR(1, "No writable handles for inode"); rc = -EBADF; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a39a1c451733..df29a3a3d80c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -963,7 +963,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, /* * If the file is already open for write, just use that fileid */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { netfid = open_file->netfid; netpid = open_file->pid; @@ -1813,7 +1813,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, * writebehind data than the SMB timeout for the SetPathInfo * request would allow */ - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { __u16 nfid = open_file->netfid; __u32 npid = open_file->pid; @@ -1978,7 +1978,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) args->ctime = NO_CHANGE_64; args->device = 0; - open_file = find_writable_file(cifsInode); + open_file = find_writable_file(cifsInode, true); if (open_file) { u16 nfid = open_file->netfid; u32 npid = open_file->pid; -- cgit v1.2.3 From 29e07c82a9e8acebbb38ecc22b0b5005a0a5d839 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 29 Sep 2010 19:51:12 -0400 Subject: cifs: fix cifs_show_options to show "username=" or "multiuser" ...based on CIFS_MOUNT_MULTIUSER flag. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b2fd075dc2e6..c96345c3314d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -369,8 +369,12 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; seq_printf(s, ",unc=%s", tcon->treeName); - if (tcon->ses->userName) + + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) + seq_printf(s, ",multiuser"); + else if (tcon->ses->userName) seq_printf(s, ",username=%s", tcon->ses->userName); + if (tcon->ses->domainName) seq_printf(s, ",domain=%s", tcon->ses->domainName); -- cgit v1.2.3 From c9928f7040a6e5f39e028bea500e0fde910d4a96 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Mon, 4 Oct 2010 19:56:13 -0500 Subject: ntlm authentication and signing - Correct response length for ntlmv2 authentication without extended security Fix incorrect calculation of case sensitive response length in the ntlmv2 (without extended security) response. Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/sess.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index af18a500f7e0..c926e6c7c0c6 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -739,9 +739,6 @@ ssetup_ntlmssp_authenticate: pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(sizeof(struct ntlmv2_resp)); - /* calculate session key */ rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); if (rc) { @@ -753,6 +750,11 @@ ssetup_ntlmssp_authenticate: sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); + /* set case sensitive password length after tilen may get + * assigned, tilen is 0 otherwise. + */ + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(sizeof(struct ntlmv2_resp) + ses->tilen); if (ses->tilen > 0) { memcpy(bcc_ptr, ses->tiblob, ses->tilen); bcc_ptr += ses->tilen; @@ -761,6 +763,7 @@ ssetup_ntlmssp_authenticate: ses->tiblob = NULL; ses->tilen = 0; } + if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; -- cgit v1.2.3 From 9d002df492b14c690425d9785530371b6c1ccbca Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 6 Oct 2010 19:51:11 -0400 Subject: cifs: add routines to build sessions and tcons on the fly This patch is rather large, but it's a bit difficult to do piecemeal... For non-multiuser mounts, everything will basically work as it does today. A call to cifs_sb_tlink will return the "master" tcon link. Turn the tcon pointer in the cifs_sb into a radix tree that uses the fsuid of the process as a key. The value is a new "tcon_link" struct that contains info about a tcon that's under construction. When a new process needs a tcon, it'll call cifs_sb_tcon. That will then look up the tcon_link in the radix tree. If it exists and is valid, it's returned. If it doesn't exist, then we stuff a new tcon_link into the tree and mark it as pending and then go and try to build the session/tcon. If that works, the tcon pointer in the tcon_link is updated and the pending flag is cleared. If the construction fails, then we set the tcon pointer to an ERR_PTR and clear the pending flag. If the radix tree is searched and the tcon_link is marked pending then we go to sleep and wait for the pending flag to be cleared. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 7 +- fs/cifs/cifsglob.h | 32 +++--- fs/cifs/connect.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 279 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index e04e6923d354..5ce57bdf1865 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -15,6 +15,8 @@ * the GNU Lesser General Public License for more details. * */ +#include + #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H @@ -40,8 +42,9 @@ #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ struct cifs_sb_info { - struct cifsTconInfo *ptcon; /* primary mount */ - struct list_head nested_tcon_q; + struct radix_tree_root tlink_tree; +#define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */ + spinlock_t tlink_tree_lock; struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d5324853203b..9a7c472a153f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -317,42 +317,36 @@ struct cifsTconInfo { * "get" on the container. */ struct tcon_link { - spinlock_t tl_lock; - u32 tl_count; - u64 tl_time; + unsigned long tl_index; + unsigned long tl_flags; +#define TCON_LINK_MASTER 0 +#define TCON_LINK_PENDING 1 +#define TCON_LINK_IN_TREE 2 + unsigned long tl_time; + atomic_t tl_count; struct cifsTconInfo *tl_tcon; }; -static inline struct tcon_link * -cifs_sb_tlink(struct cifs_sb_info *cifs_sb) -{ - return (struct tcon_link *)cifs_sb->ptcon; -} +extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb); static inline struct cifsTconInfo * tlink_tcon(struct tcon_link *tlink) { - return (struct cifsTconInfo *)tlink; + return tlink->tl_tcon; } -static inline void -cifs_put_tlink(struct tcon_link *tlink) -{ - return; -} +extern void cifs_put_tlink(struct tcon_link *tlink); static inline struct tcon_link * cifs_get_tlink(struct tcon_link *tlink) { + if (tlink && !IS_ERR(tlink)) + atomic_inc(&tlink->tl_count); return tlink; } /* This function is always expected to succeed */ -static inline struct cifsTconInfo * -cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) -{ - return cifs_sb->ptcon; -} +extern struct cifsTconInfo *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); /* * This info hangs off the cifsFileInfo structure, pointed to by llist. diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f6a3091c2874..3156a9de947d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -109,6 +109,9 @@ struct smb_vol { struct nls_table *local_nls; }; +#define TLINK_ERROR_EXPIRE (1 * HZ) + + static int ipv4_connect(struct TCP_Server_Info *server); static int ipv6_connect(struct TCP_Server_Info *server); @@ -1959,6 +1962,23 @@ out_fail: return ERR_PTR(rc); } +void +cifs_put_tlink(struct tcon_link *tlink) +{ + if (!tlink || IS_ERR(tlink)) + return; + + if (!atomic_dec_and_test(&tlink->tl_count) || + test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) { + tlink->tl_time = jiffies; + return; + } + + if (!IS_ERR(tlink_tcon(tlink))) + cifs_put_tcon(tlink_tcon(tlink)); + kfree(tlink); + return; +} int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, @@ -2641,6 +2661,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, struct TCP_Server_Info *srvTcp; char *full_path; char *mount_data = mount_data_global; + struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL struct dfs_info3_param *referrals = NULL; unsigned int num_referrals = 0; @@ -2652,6 +2673,7 @@ try_mount_again: pSesInfo = NULL; srvTcp = NULL; full_path = NULL; + tlink = NULL; xid = GetXid(); @@ -2727,8 +2749,6 @@ try_mount_again: goto remote_path_check; } - cifs_sb->ptcon = tcon; - /* do not care if following two calls succeed - informational */ if (!tcon->ipc) { CIFSSMBQFSDeviceInfo(xid, tcon); @@ -2837,6 +2857,35 @@ remote_path_check: #endif } + if (rc) + goto mount_fail_check; + + /* now, hang the tcon off of the superblock */ + tlink = kzalloc(sizeof *tlink, GFP_KERNEL); + if (tlink == NULL) { + rc = -ENOMEM; + goto mount_fail_check; + } + + tlink->tl_index = pSesInfo->linux_uid; + tlink->tl_tcon = tcon; + tlink->tl_time = jiffies; + set_bit(TCON_LINK_MASTER, &tlink->tl_flags); + set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); + + rc = radix_tree_preload(GFP_KERNEL); + if (rc == -ENOMEM) { + kfree(tlink); + goto mount_fail_check; + } + + spin_lock(&cifs_sb->tlink_tree_lock); + radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink); + radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid, + CIFS_TLINK_MASTER_TAG); + spin_unlock(&cifs_sb->tlink_tree_lock); + radix_tree_preload_end(); + mount_fail_check: /* on error free sesinfo and tcon struct if needed */ if (rc) { @@ -3023,19 +3072,37 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, int cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) { - int rc = 0; + int i, ret; char *tmp; - struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); + struct tcon_link *tlink[8]; + unsigned long index = 0; + + do { + spin_lock(&cifs_sb->tlink_tree_lock); + ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, + (void **)tlink, index, + ARRAY_SIZE(tlink)); + /* increment index for next pass */ + if (ret > 0) + index = tlink[ret - 1]->tl_index + 1; + for (i = 0; i < ret; i++) { + cifs_get_tlink(tlink[i]); + clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); + radix_tree_delete(&cifs_sb->tlink_tree, + tlink[i]->tl_index); + } + spin_unlock(&cifs_sb->tlink_tree_lock); - cifs_put_tcon(tcon); + for (i = 0; i < ret; i++) + cifs_put_tlink(tlink[i]); + } while (ret != 0); - cifs_sb->ptcon = NULL; tmp = cifs_sb->prepath; cifs_sb->prepathlen = 0; cifs_sb->prepath = NULL; kfree(tmp); - return rc; + return 0; } int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) @@ -3096,3 +3163,190 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, return rc; } +struct cifsTconInfo * +cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) +{ + struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb); + struct cifsSesInfo *ses; + struct cifsTconInfo *tcon = NULL; + struct smb_vol *vol_info; + char username[MAX_USERNAME_SIZE + 1]; + + vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); + if (vol_info == NULL) { + tcon = ERR_PTR(-ENOMEM); + goto out; + } + + snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid); + vol_info->username = username; + 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->local_lease = master_tcon->local_lease; + vol_info->no_linux_ext = !master_tcon->unix_ext; + + /* FIXME: allow for other secFlg settings */ + vol_info->secFlg = CIFSSEC_MUST_KRB5; + + /* get a reference for the same TCP session */ + write_lock(&cifs_tcp_ses_lock); + ++master_tcon->ses->server->srv_count; + write_unlock(&cifs_tcp_ses_lock); + + ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); + if (IS_ERR(ses)) { + tcon = (struct cifsTconInfo *)ses; + cifs_put_tcp_session(master_tcon->ses->server); + goto out; + } + + tcon = cifs_get_tcon(ses, vol_info); + if (IS_ERR(tcon)) { + cifs_put_smb_ses(ses); + goto out; + } + + if (ses->capabilities & CAP_UNIX) + reset_cifs_unix_caps(0, tcon, NULL, vol_info); +out: + kfree(vol_info); + + return tcon; +} + +static struct tcon_link * +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) +{ + struct tcon_link *tlink; + unsigned int ret; + + spin_lock(&cifs_sb->tlink_tree_lock); + ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink, + 0, 1, CIFS_TLINK_MASTER_TAG); + spin_unlock(&cifs_sb->tlink_tree_lock); + + /* the master tcon should always be present */ + if (ret == 0) + BUG(); + + return tlink; +} + +struct cifsTconInfo * +cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) +{ + return tlink_tcon(cifs_sb_master_tlink(cifs_sb)); +} + +static int +cifs_sb_tcon_pending_wait(void *unused) +{ + schedule(); + return signal_pending(current) ? -ERESTARTSYS : 0; +} + +/* + * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the + * current task. + * + * If the superblock doesn't refer to a multiuser mount, then just return + * the master tcon for the mount. + * + * First, search the radix tree for an existing tcon for this fsuid. If one + * exists, then check to see if it's pending construction. If it is then wait + * for construction to complete. Once it's no longer pending, check to see if + * it failed and either return an error or retry construction, depending on + * the timeout. + * + * If one doesn't exist then insert a new tcon_link struct into the tree and + * try to construct a new one. + */ +struct tcon_link * +cifs_sb_tlink(struct cifs_sb_info *cifs_sb) +{ + int ret; + unsigned long fsuid = (unsigned long) current_fsuid(); + struct tcon_link *tlink, *newtlink; + + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) + return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); + + spin_lock(&cifs_sb->tlink_tree_lock); + tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); + if (tlink) + cifs_get_tlink(tlink); + spin_unlock(&cifs_sb->tlink_tree_lock); + + if (tlink == NULL) { + newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); + if (newtlink == NULL) + return ERR_PTR(-ENOMEM); + newtlink->tl_index = fsuid; + newtlink->tl_tcon = ERR_PTR(-EACCES); + set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); + set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); + cifs_get_tlink(newtlink); + + ret = radix_tree_preload(GFP_KERNEL); + if (ret != 0) { + kfree(newtlink); + return ERR_PTR(ret); + } + + spin_lock(&cifs_sb->tlink_tree_lock); + /* was one inserted after previous search? */ + tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid); + if (tlink) { + cifs_get_tlink(tlink); + spin_unlock(&cifs_sb->tlink_tree_lock); + radix_tree_preload_end(); + kfree(newtlink); + goto wait_for_construction; + } + ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink); + spin_unlock(&cifs_sb->tlink_tree_lock); + radix_tree_preload_end(); + if (ret) { + kfree(newtlink); + return ERR_PTR(ret); + } + tlink = newtlink; + } else { +wait_for_construction: + ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, + cifs_sb_tcon_pending_wait, + TASK_INTERRUPTIBLE); + if (ret) { + cifs_put_tlink(tlink); + return ERR_PTR(ret); + } + + /* if it's good, return it */ + if (!IS_ERR(tlink->tl_tcon)) + return tlink; + + /* return error if we tried this already recently */ + if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { + cifs_put_tlink(tlink); + return ERR_PTR(-EACCES); + } + + if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) + goto wait_for_construction; + } + + tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid); + clear_bit(TCON_LINK_PENDING, &tlink->tl_flags); + wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); + + if (IS_ERR(tlink->tl_tcon)) { + cifs_put_tlink(tlink); + return ERR_PTR(-EACCES); + } + + return tlink; +} -- cgit v1.2.3 From 0eb8a132c449c755b7a3f18f33365b2040c47347 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 6 Oct 2010 19:51:12 -0400 Subject: cifs: add "multiuser" mount option This allows someone to declare a mount as a multiuser mount. Multiuser mounts also imply "noperm" since we want to allow the server to handle permission checking. It also (for now) requires Kerberos authentication. Eventually, we could expand this to other authtypes, but that requires a scheme to allow per-user credential stashing in some form. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3156a9de947d..e65f72d1f23b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -100,6 +100,7 @@ struct smb_vol { bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ bool fsc:1; /* enable fscache */ bool mfsymlinks:1; /* use Minshall+French Symlinks */ + bool multiuser:1; unsigned int rsize; unsigned int wsize; bool sockopt_tcp_nodelay:1; @@ -1347,6 +1348,8 @@ cifs_parse_mount_options(char *options, const char *devname, vol->fsc = true; } else if (strnicmp(data, "mfsymlinks", 10) == 0) { vol->mfsymlinks = true; + } else if (strnicmp(data, "multiuser", 8) == 0) { + vol->multiuser = true; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n", data); @@ -1378,6 +1381,13 @@ cifs_parse_mount_options(char *options, const char *devname, return 1; } } + + if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { + cERROR(1, "Multiuser mounts currently require krb5 " + "authentication!"); + return 1; + } + if (vol->UNCip == NULL) vol->UNCip = &vol->UNC[2]; @@ -2563,6 +2573,9 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; if (pvolume_info->fsc) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; + if (pvolume_info->multiuser) + cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | + CIFS_MOUNT_NO_PERM); if (pvolume_info->direct_io) { cFYI(1, "mounting share using direct i/o"); cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; -- cgit v1.2.3 From 13cd4b7f7472eea7cbc1ab34e042842fbb902160 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 7 Oct 2010 18:46:32 +0000 Subject: [CIFS] Various small checkpatch cleanups Signed-off-by: Steve French --- fs/cifs/cifs_debug.h | 2 +- fs/cifs/cifsfs.h | 2 +- fs/cifs/cifsglob.h | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index aa316891ac0c..8942b28cf807 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h @@ -34,7 +34,7 @@ void cifs_dump_mids(struct TCP_Server_Info *); extern int traceSMB; /* flag which enables the function below */ void dump_smb(struct smb_hdr *, int); #define CIFS_INFO 0x01 -#define CIFS_RC 0x02 +#define CIFS_RC 0x02 #define CIFS_TIMER 0x04 /* diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d82f5fb4761e..786bdf36aebf 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -104,7 +104,7 @@ extern int cifs_readlink(struct dentry *direntry, char __user *buffer, extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); extern int cifs_removexattr(struct dentry *, const char *); -extern int cifs_setxattr(struct dentry *, const char *, const void *, +extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9a7c472a153f..4f85dfdf197d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -517,16 +517,16 @@ struct oplock_q_entry { /* for pending dnotify requests */ struct dir_notify_req { - struct list_head lhead; - __le16 Pid; - __le16 PidHigh; - __u16 Mid; - __u16 Tid; - __u16 Uid; - __u16 netfid; - __u32 filter; /* CompletionFilter (for multishot) */ - int multishot; - struct file *pfile; + struct list_head lhead; + __le16 Pid; + __le16 PidHigh; + __u16 Mid; + __u16 Tid; + __u16 Uid; + __u16 netfid; + __u32 filter; /* CompletionFilter (for multishot) */ + int multishot; + struct file *pfile; }; struct dfs_info3_param { -- cgit v1.2.3 From 3aa1c8c2900065a51268430ab48a1b42fdfe5b45 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 7 Oct 2010 14:46:28 -0400 Subject: cifs: on multiuser mount, set ownership to current_fsuid/current_fsgid (try #5) ...when unix extensions aren't enabled. This makes everything on the mount appear to be owned by the current user. This version of the patch differs from previous versions however in that the admin can still force the ownership of all files to appear as a single user via the uid=/gid= options. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index df29a3a3d80c..7e5b8c39a07a 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1755,11 +1755,21 @@ check_inval: int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { + struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); + struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); int err = cifs_revalidate_dentry(dentry); + if (!err) { generic_fillattr(dentry->d_inode, stat); stat->blksize = CIFS_MAX_MSGSIZE; stat->ino = CIFS_I(dentry->d_inode)->uniqueid; + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && + !tcon->unix_ext) { + if (!cifs_sb->mnt_uid) + stat->uid = current_fsuid(); + if (!cifs_sb->mnt_uid) + stat->gid = current_fsgid(); + } } return err; } -- cgit v1.2.3 From 2de970ff69bbcc5a4b7440df669a595b2b1acd73 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 6 Oct 2010 19:51:12 -0400 Subject: cifs: implement recurring workqueue job to prune old tcons Create a workqueue job that cleans out unused tlinks. For now, it uses a hardcoded expire time of 10 minutes. When it's done, the work rearms itself. On umount, the work is cancelled before tearing down the tlink tree. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/connect.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 5ce57bdf1865..586ee3d527d2 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -59,5 +59,6 @@ struct cifs_sb_info { char *mountdata; /* mount options received at mount time */ #endif struct backing_dev_info bdi; + struct delayed_work prune_tlinks; }; #endif /* _CIFS_FS_SB_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e65f72d1f23b..1092e9e839c2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -110,11 +110,13 @@ struct smb_vol { struct nls_table *local_nls; }; +/* FIXME: should these be tunable? */ #define TLINK_ERROR_EXPIRE (1 * HZ) - +#define TLINK_IDLE_EXPIRE (600 * HZ) static int ipv4_connect(struct TCP_Server_Info *server); static int ipv6_connect(struct TCP_Server_Info *server); +static void cifs_prune_tlinks(struct work_struct *work); /* * cifs tcp session reconnection @@ -2494,6 +2496,8 @@ convert_delimiter(char *path, char delim) static void setup_cifs_sb(struct smb_vol *pvolume_info, struct cifs_sb_info *cifs_sb) { + INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); + if (pvolume_info->rsize > CIFSMaxBufSize) { cERROR(1, "rsize %d too large, using MaxBufSize", pvolume_info->rsize); @@ -2899,6 +2903,9 @@ remote_path_check: spin_unlock(&cifs_sb->tlink_tree_lock); radix_tree_preload_end(); + queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, + TLINK_IDLE_EXPIRE); + mount_fail_check: /* on error free sesinfo and tcon struct if needed */ if (rc) { @@ -3090,6 +3097,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) struct tcon_link *tlink[8]; unsigned long index = 0; + cancel_delayed_work_sync(&cifs_sb->prune_tlinks); + do { spin_lock(&cifs_sb->tlink_tree_lock); ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, @@ -3363,3 +3372,50 @@ wait_for_construction: return tlink; } + +/* + * periodic workqueue job that scans tcon_tree for a superblock and closes + * out tcons. + */ +static void +cifs_prune_tlinks(struct work_struct *work) +{ + struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, + prune_tlinks.work); + struct tcon_link *tlink[8]; + unsigned long now = jiffies; + unsigned long index = 0; + int i, ret; + + do { + spin_lock(&cifs_sb->tlink_tree_lock); + ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree, + (void **)tlink, index, + ARRAY_SIZE(tlink)); + /* increment index for next pass */ + if (ret > 0) + index = tlink[ret - 1]->tl_index + 1; + for (i = 0; i < ret; i++) { + if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) || + atomic_read(&tlink[i]->tl_count) != 0 || + time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE, + now)) { + tlink[i] = NULL; + continue; + } + cifs_get_tlink(tlink[i]); + clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags); + radix_tree_delete(&cifs_sb->tlink_tree, + tlink[i]->tl_index); + } + spin_unlock(&cifs_sb->tlink_tree_lock); + + for (i = 0; i < ret; i++) { + if (tlink[i] != NULL) + cifs_put_tlink(tlink[i]); + } + } while (ret != 0); + + queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, + TLINK_IDLE_EXPIRE); +} -- cgit v1.2.3 From ccc46a7402200a3b28a8fa1605ea5405a9ef66f7 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 6 Oct 2010 19:51:12 -0400 Subject: cifs: fix module refcount leak in find_domain_name find_domain_name() uses load_nls_default which takes a module reference on the appropriate NLS module, but doesn't put it. Signed-off-by: Jeff Layton Cc: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 730038a12982..89fb94fac4b5 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -328,13 +328,16 @@ find_domain_name(struct cifsSesInfo *ses) if (!attrsize) break; if (!ses->domainName) { + struct nls_table *default_nls; ses->domainName = kmalloc(attrsize + 1, GFP_KERNEL); if (!ses->domainName) return -ENOMEM; + default_nls = load_nls_default(); cifs_from_ucs2(ses->domainName, (__le16 *)blobptr, attrsize, attrsize, - load_nls_default(), false); + default_nls, false); + unload_nls(default_nls); break; } } -- cgit v1.2.3 From d2445556137c38ae15d3191174bfd235630ed7cd Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 8 Oct 2010 03:38:46 +0000 Subject: [CIFS] Remove build warning Signed-off-by: Steve French --- fs/cifs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1092e9e839c2..4944fc84d5ef 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3185,7 +3185,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, return rc; } -struct cifsTconInfo * +static struct cifsTconInfo * cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) { struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb); -- cgit v1.2.3