Commit f486ef8e authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French

cifs: use the chans_need_reconnect bitmap for reconnect status

We use the concept of "binding" when one of the secondary channel
is in the process of connecting/reconnecting to the server. Till this
binding process completes, and the channel is bound to an existing session,
we redirect traffic from other established channels on the binding channel,
effectively blocking all traffic till individual channels get reconnected.

With my last set of commits, we can get rid of this binding serialization.
We now have a bitmap of connection states for each channel. We will use
this bitmap instead for tracking channel status.

Having a bitmap also now enables us to keep the session alive, as long
as even a single channel underneath is alive.

Unfortunately, this also meant that we need to supply the tcp connection
info for the channel during all negotiate and session setup functions.
These changes have resulted in a slightly bigger code churn.
However, I expect perf and robustness improvements in the mchan scenario
after this change.
Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent d1a931ce
...@@ -84,9 +84,9 @@ struct key_type cifs_spnego_key_type = { ...@@ -84,9 +84,9 @@ struct key_type cifs_spnego_key_type = {
/* get a key struct with a SPNEGO security blob, suitable for session setup */ /* get a key struct with a SPNEGO security blob, suitable for session setup */
struct key * struct key *
cifs_get_spnego_key(struct cifs_ses *sesInfo) cifs_get_spnego_key(struct cifs_ses *sesInfo,
struct TCP_Server_Info *server)
{ {
struct TCP_Server_Info *server = cifs_ses_server(sesInfo);
struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
char *description, *dp; char *description, *dp;
......
...@@ -29,7 +29,8 @@ struct cifs_spnego_msg { ...@@ -29,7 +29,8 @@ struct cifs_spnego_msg {
#ifdef __KERNEL__ #ifdef __KERNEL__
extern struct key_type cifs_spnego_key_type; extern struct key_type cifs_spnego_key_type;
extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo); extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo,
struct TCP_Server_Info *server);
#endif /* KERNEL */ #endif /* KERNEL */
#endif /* _CIFS_SPNEGO_H */ #endif /* _CIFS_SPNEGO_H */
...@@ -263,13 +263,16 @@ struct smb_version_operations { ...@@ -263,13 +263,16 @@ struct smb_version_operations {
/* check if we need to negotiate */ /* check if we need to negotiate */
bool (*need_neg)(struct TCP_Server_Info *); bool (*need_neg)(struct TCP_Server_Info *);
/* negotiate to the server */ /* negotiate to the server */
int (*negotiate)(const unsigned int, struct cifs_ses *); int (*negotiate)(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server);
/* set negotiated write size */ /* set negotiated write size */
unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
/* set negotiated read size */ /* set negotiated read size */
unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx); unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
/* setup smb sessionn */ /* setup smb sessionn */
int (*sess_setup)(const unsigned int, struct cifs_ses *, int (*sess_setup)(const unsigned int, struct cifs_ses *,
struct TCP_Server_Info *server,
const struct nls_table *); const struct nls_table *);
/* close smb session */ /* close smb session */
int (*logoff)(const unsigned int, struct cifs_ses *); int (*logoff)(const unsigned int, struct cifs_ses *);
...@@ -414,7 +417,8 @@ struct smb_version_operations { ...@@ -414,7 +417,8 @@ struct smb_version_operations {
void (*set_lease_key)(struct inode *, struct cifs_fid *); void (*set_lease_key)(struct inode *, struct cifs_fid *);
/* generate new lease key */ /* generate new lease key */
void (*new_lease_key)(struct cifs_fid *); void (*new_lease_key)(struct cifs_fid *);
int (*generate_signingkey)(struct cifs_ses *); int (*generate_signingkey)(struct cifs_ses *ses,
struct TCP_Server_Info *server);
int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *, int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *,
bool allocate_crypto); bool allocate_crypto);
int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon, int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
...@@ -940,15 +944,12 @@ struct cifs_ses { ...@@ -940,15 +944,12 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */ enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */ bool sign; /* is signing required? */
bool domainAuto:1; bool domainAuto:1;
bool binding:1; /* are we binding the session? */
__u16 session_flags; __u16 session_flags;
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
__u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE]; __u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE];
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE]; __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
__u8 binding_preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
/* /*
* Network interfaces available on the server this session is * Network interfaces available on the server this session is
* connected to. * connected to.
...@@ -976,7 +977,6 @@ struct cifs_ses { ...@@ -976,7 +977,6 @@ struct cifs_ses {
test_bit((index), &(ses)->chans_need_reconnect) test_bit((index), &(ses)->chans_need_reconnect)
struct cifs_chan chans[CIFS_MAX_CHANNELS]; struct cifs_chan chans[CIFS_MAX_CHANNELS];
struct cifs_chan *binding_chan;
size_t chan_count; size_t chan_count;
size_t chan_max; size_t chan_max;
atomic_t chan_seq; /* round robin state */ atomic_t chan_seq; /* round robin state */
...@@ -985,42 +985,16 @@ struct cifs_ses { ...@@ -985,42 +985,16 @@ struct cifs_ses {
* chans_need_reconnect is a bitmap indicating which of the channels * chans_need_reconnect is a bitmap indicating which of the channels
* under this smb session needs to be reconnected. * under this smb session needs to be reconnected.
* If not multichannel session, only one bit will be used. * If not multichannel session, only one bit will be used.
*
* We will ask for sess and tcon reconnection only if all the
* channels are marked for needing reconnection. This will
* enable the sessions on top to continue to live till any
* of the channels below are active.
*/ */
unsigned long chans_need_reconnect; unsigned long chans_need_reconnect;
/* ========= end: protected by chan_lock ======== */ /* ========= end: protected by chan_lock ======== */
}; };
/*
* When binding a new channel, we need to access the channel which isn't fully
* established yet.
*/
static inline
struct cifs_chan *cifs_ses_binding_channel(struct cifs_ses *ses)
{
if (ses->binding)
return ses->binding_chan;
else
return NULL;
}
/*
* Returns the server pointer of the session. When binding a new
* channel this returns the last channel which isn't fully established
* yet.
*
* This function should be use for negprot/sess.setup codepaths. For
* the other requests see cifs_pick_channel().
*/
static inline
struct TCP_Server_Info *cifs_ses_server(struct cifs_ses *ses)
{
if (ses->binding)
return ses->binding_chan->server;
else
return ses->server;
}
static inline bool static inline bool
cap_unix(struct cifs_ses *ses) cap_unix(struct cifs_ses *ses)
{ {
......
...@@ -164,6 +164,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, ...@@ -164,6 +164,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
extern enum securityEnum select_sectype(struct TCP_Server_Info *server, extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
enum securityEnum requested); enum securityEnum requested);
extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec64); extern u64 cifs_UnixTimeToNT(struct timespec64);
...@@ -293,11 +294,15 @@ extern int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -293,11 +294,15 @@ extern int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon,
const struct nls_table *nlsc); const struct nls_table *nlsc);
extern int cifs_negotiate_protocol(const unsigned int xid, extern int cifs_negotiate_protocol(const unsigned int xid,
struct cifs_ses *ses); struct cifs_ses *ses,
struct TCP_Server_Info *server);
extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server,
struct nls_table *nls_info); struct nls_table *nls_info);
extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required); extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses); extern int CIFSSMBNegotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server);
extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses, extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
const char *tree, struct cifs_tcon *tcon, const char *tree, struct cifs_tcon *tcon,
...@@ -504,8 +509,10 @@ extern int cifs_verify_signature(struct smb_rqst *rqst, ...@@ -504,8 +509,10 @@ extern int cifs_verify_signature(struct smb_rqst *rqst,
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
extern int calc_seckey(struct cifs_ses *); extern int calc_seckey(struct cifs_ses *);
extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *ses,
extern int generate_smb311signingkey(struct cifs_ses *); struct TCP_Server_Info *server);
extern int generate_smb311signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server);
extern int CIFSSMBCopy(unsigned int xid, extern int CIFSSMBCopy(unsigned int xid,
struct cifs_tcon *source_tcon, struct cifs_tcon *source_tcon,
......
...@@ -199,7 +199,8 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -199,7 +199,8 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
if (!cifs_chan_needs_reconnect(ses, server)) { if (!cifs_chan_needs_reconnect(ses, server)) {
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
/* this just means that we only need to tcon */
/* this means that we only need to tree connect */
if (tcon->need_reconnect) if (tcon->need_reconnect)
goto skip_sess_setup; goto skip_sess_setup;
...@@ -209,9 +210,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -209,9 +210,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
} }
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
rc = cifs_negotiate_protocol(0, ses); rc = cifs_negotiate_protocol(0, ses, server);
if (!rc) if (!rc)
rc = cifs_setup_session(0, ses, nls_codepage); rc = cifs_setup_session(0, ses, server, nls_codepage);
/* do we need to reconnect tcon? */ /* do we need to reconnect tcon? */
if (rc || !tcon->need_reconnect) { if (rc || !tcon->need_reconnect) {
...@@ -503,14 +504,15 @@ should_set_ext_sec_flag(enum securityEnum sectype) ...@@ -503,14 +504,15 @@ should_set_ext_sec_flag(enum securityEnum sectype)
} }
int int
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) CIFSSMBNegotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
NEGOTIATE_REQ *pSMB; NEGOTIATE_REQ *pSMB;
NEGOTIATE_RSP *pSMBr; NEGOTIATE_RSP *pSMBr;
int rc = 0; int rc = 0;
int bytes_returned; int bytes_returned;
int i; int i;
struct TCP_Server_Info *server = ses->server;
u16 count; u16 count;
if (!server) { if (!server) {
......
...@@ -169,6 +169,7 @@ static void cifs_resolve_server(struct work_struct *work) ...@@ -169,6 +169,7 @@ static void cifs_resolve_server(struct work_struct *work)
*/ */
static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server) static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server)
{ {
unsigned int num_sessions = 0;
struct cifs_ses *ses; struct cifs_ses *ses;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct mid_q_entry *mid, *nmid; struct mid_q_entry *mid, *nmid;
...@@ -201,6 +202,8 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server ...@@ -201,6 +202,8 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
if (!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) if (!CIFS_ALL_CHANS_NEED_RECONNECT(ses))
goto next_session; goto next_session;
num_sessions++;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
tcon->need_reconnect = true; tcon->need_reconnect = true;
if (ses->tcon_ipc) if (ses->tcon_ipc)
...@@ -211,6 +214,14 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server ...@@ -211,6 +214,14 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
} }
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
if (num_sessions == 0)
return;
/*
* before reconnecting the tcp session, mark the smb session (uid)
* and the tid bad so they are not used until reconnected
*/
cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
__func__);
/* do not want to be sending data on a socket we are freeing */ /* do not want to be sending data on a socket we are freeing */
cifs_dbg(FYI, "%s: tearing down socket\n", __func__); cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
...@@ -2005,7 +2016,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ...@@ -2005,7 +2016,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
cifs_dbg(FYI, "Session needs reconnect\n"); cifs_dbg(FYI, "Session needs reconnect\n");
rc = cifs_negotiate_protocol(xid, ses); rc = cifs_negotiate_protocol(xid, ses, server);
if (rc) { if (rc) {
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
/* problem -- put our ses reference */ /* problem -- put our ses reference */
...@@ -2014,7 +2025,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ...@@ -2014,7 +2025,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
return ERR_PTR(rc); return ERR_PTR(rc);
} }
rc = cifs_setup_session(xid, ses, rc = cifs_setup_session(xid, ses, server,
ctx->local_nls); ctx->local_nls);
if (rc) { if (rc) {
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
...@@ -2086,9 +2097,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ...@@ -2086,9 +2097,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
ses->chans_need_reconnect = 1; ses->chans_need_reconnect = 1;
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
rc = cifs_negotiate_protocol(xid, ses); rc = cifs_negotiate_protocol(xid, ses, server);
if (!rc) if (!rc)
rc = cifs_setup_session(xid, ses, ctx->local_nls); rc = cifs_setup_session(xid, ses, server, ctx->local_nls);
/* each channel uses a different signing key */ /* each channel uses a different signing key */
memcpy(ses->chans[0].signkey, ses->smb3signingkey, memcpy(ses->chans[0].signkey, ses->smb3signingkey,
...@@ -3820,10 +3831,10 @@ cifs_umount(struct cifs_sb_info *cifs_sb) ...@@ -3820,10 +3831,10 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
} }
int int
cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
struct TCP_Server_Info *server = cifs_ses_server(ses);
if (!server->ops->need_neg || !server->ops->negotiate) if (!server->ops->need_neg || !server->ops->negotiate)
return -ENOSYS; return -ENOSYS;
...@@ -3832,7 +3843,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) ...@@ -3832,7 +3843,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
if (!server->ops->need_neg(server)) if (!server->ops->need_neg(server))
return 0; return 0;
rc = server->ops->negotiate(xid, ses); rc = server->ops->negotiate(xid, ses, server);
if (rc == 0) { if (rc == 0) {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if (server->tcpStatus == CifsNeedNegotiate) if (server->tcpStatus == CifsNeedNegotiate)
...@@ -3847,12 +3858,17 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) ...@@ -3847,12 +3858,17 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
int int
cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server,
struct nls_table *nls_info) struct nls_table *nls_info)
{ {
int rc = -ENOSYS; int rc = -ENOSYS;
struct TCP_Server_Info *server = cifs_ses_server(ses); bool is_binding = false;
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
if (!ses->binding) { if (!is_binding) {
ses->capabilities = server->capabilities; ses->capabilities = server->capabilities;
if (!linuxExtEnabled) if (!linuxExtEnabled)
ses->capabilities &= (~server->vals->cap_unix); ses->capabilities &= (~server->vals->cap_unix);
...@@ -3870,7 +3886,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, ...@@ -3870,7 +3886,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
server->sec_mode, server->capabilities, server->timeAdj); server->sec_mode, server->capabilities, server->timeAdj);
if (server->ops->sess_setup) if (server->ops->sess_setup)
rc = server->ops->sess_setup(xid, ses, nls_info); rc = server->ops->sess_setup(xid, ses, server, nls_info);
if (rc) if (rc)
cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc); cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
......
...@@ -121,7 +121,9 @@ typedef struct _AUTHENTICATE_MESSAGE { ...@@ -121,7 +121,9 @@ typedef struct _AUTHENTICATE_MESSAGE {
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen, int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
This diff is collapsed.
...@@ -414,14 +414,16 @@ cifs_need_neg(struct TCP_Server_Info *server) ...@@ -414,14 +414,16 @@ cifs_need_neg(struct TCP_Server_Info *server)
} }
static int static int
cifs_negotiate(const unsigned int xid, struct cifs_ses *ses) cifs_negotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
int rc; int rc;
rc = CIFSSMBNegotiate(xid, ses); rc = CIFSSMBNegotiate(xid, ses, server);
if (rc == -EAGAIN) { if (rc == -EAGAIN) {
/* retry only once on 1st time connection */ /* retry only once on 1st time connection */
set_credits(ses->server, 1); set_credits(server, 1);
rc = CIFSSMBNegotiate(xid, ses); rc = CIFSSMBNegotiate(xid, ses, server);
if (rc == -EAGAIN) if (rc == -EAGAIN)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
} }
......
...@@ -851,12 +851,12 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve ...@@ -851,12 +851,12 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve
* @nvec: number of array entries for the iov * @nvec: number of array entries for the iov
*/ */
int int
smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec) smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
struct kvec *iov, int nvec)
{ {
int i, rc; int i, rc;
struct sdesc *d; struct sdesc *d;
struct smb2_hdr *hdr; struct smb2_hdr *hdr;
struct TCP_Server_Info *server = cifs_ses_server(ses);
hdr = (struct smb2_hdr *)iov[0].iov_base; hdr = (struct smb2_hdr *)iov[0].iov_base;
/* neg prot are always taken */ /* neg prot are always taken */
......
...@@ -384,14 +384,16 @@ smb2_need_neg(struct TCP_Server_Info *server) ...@@ -384,14 +384,16 @@ smb2_need_neg(struct TCP_Server_Info *server)
} }
static int static int
smb2_negotiate(const unsigned int xid, struct cifs_ses *ses) smb2_negotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
int rc; int rc;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
cifs_ses_server(ses)->CurrentMid = 0; server->CurrentMid = 0;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = SMB2_negotiate(xid, ses); rc = SMB2_negotiate(xid, ses, server);
/* BB we probably don't need to retry with modern servers */ /* BB we probably don't need to retry with modern servers */
if (rc == -EAGAIN) if (rc == -EAGAIN)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
......
This diff is collapsed.
...@@ -123,8 +123,11 @@ extern void smb2_set_related(struct smb_rqst *rqst); ...@@ -123,8 +123,11 @@ extern void smb2_set_related(struct smb_rqst *rqst);
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
* are contained within these calls. * are contained within these calls.
*/ */
extern int SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses); extern int SMB2_negotiate(const unsigned int xid,
struct cifs_ses *ses,
struct TCP_Server_Info *server);
extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, extern int SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses); extern int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses);
extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
...@@ -276,6 +279,7 @@ extern void smb2_copy_fs_info_to_kstatfs( ...@@ -276,6 +279,7 @@ extern void smb2_copy_fs_info_to_kstatfs(
struct kstatfs *kst); struct kstatfs *kst);
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
extern int smb311_update_preauth_hash(struct cifs_ses *ses, extern int smb311_update_preauth_hash(struct cifs_ses *ses,
struct TCP_Server_Info *server,
struct kvec *iov, int nvec); struct kvec *iov, int nvec);
extern int smb2_query_info_compound(const unsigned int xid, extern int smb2_query_info_compound(const unsigned int xid,
struct cifs_tcon *tcon, struct cifs_tcon *tcon,
......
...@@ -100,7 +100,8 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ...@@ -100,7 +100,8 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
goto out; goto out;
found: found:
if (ses->binding) { if (cifs_chan_needs_reconnect(ses, server) &&
!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
/* /*
* If we are in the process of binding a new channel * If we are in the process of binding a new channel
* to an existing session, use the master connection * to an existing session, use the master connection
...@@ -390,12 +391,18 @@ struct derivation_triplet { ...@@ -390,12 +391,18 @@ struct derivation_triplet {
static int static int
generate_smb3signingkey(struct cifs_ses *ses, generate_smb3signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server,
const struct derivation_triplet *ptriplet) const struct derivation_triplet *ptriplet)
{ {
int rc; int rc;
#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS bool is_binding = false;
struct TCP_Server_Info *server = ses->server; int chan_index = 0;
#endif
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
chan_index = cifs_ses_get_chan_index(ses, server);
/* TODO: introduce ref counting for channels when the can be freed */
spin_unlock(&ses->chan_lock);
/* /*
* All channels use the same encryption/decryption keys but * All channels use the same encryption/decryption keys but
...@@ -407,10 +414,10 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -407,10 +414,10 @@ generate_smb3signingkey(struct cifs_ses *ses,
* master connection signing key stored in the session * master connection signing key stored in the session
*/ */
if (ses->binding) { if (is_binding) {
rc = generate_key(ses, ptriplet->signing.label, rc = generate_key(ses, ptriplet->signing.label,
ptriplet->signing.context, ptriplet->signing.context,
cifs_ses_binding_channel(ses)->signkey, ses->chans[chan_index].signkey,
SMB3_SIGN_KEY_SIZE); SMB3_SIGN_KEY_SIZE);
if (rc) if (rc)
return rc; return rc;
...@@ -422,6 +429,7 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -422,6 +429,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
if (rc) if (rc)
return rc; return rc;
/* safe to access primary channel, since it will never go away */
memcpy(ses->chans[0].signkey, ses->smb3signingkey, memcpy(ses->chans[0].signkey, ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE); SMB3_SIGN_KEY_SIZE);
...@@ -470,7 +478,8 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -470,7 +478,8 @@ generate_smb3signingkey(struct cifs_ses *ses,
} }
int int
generate_smb30signingkey(struct cifs_ses *ses) generate_smb30signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
struct derivation_triplet triplet; struct derivation_triplet triplet;
...@@ -494,11 +503,12 @@ generate_smb30signingkey(struct cifs_ses *ses) ...@@ -494,11 +503,12 @@ generate_smb30signingkey(struct cifs_ses *ses)
d->context.iov_base = "ServerOut"; d->context.iov_base = "ServerOut";
d->context.iov_len = 10; d->context.iov_len = 10;
return generate_smb3signingkey(ses, &triplet); return generate_smb3signingkey(ses, server, &triplet);
} }
int int
generate_smb311signingkey(struct cifs_ses *ses) generate_smb311signingkey(struct cifs_ses *ses,
struct TCP_Server_Info *server)
{ {
struct derivation_triplet triplet; struct derivation_triplet triplet;
...@@ -522,7 +532,7 @@ generate_smb311signingkey(struct cifs_ses *ses) ...@@ -522,7 +532,7 @@ generate_smb311signingkey(struct cifs_ses *ses)
d->context.iov_base = ses->preauth_sha_hash; d->context.iov_base = ses->preauth_sha_hash;
d->context.iov_len = 64; d->context.iov_len = 64;
return generate_smb3signingkey(ses, &triplet); return generate_smb3signingkey(ses, server, &triplet);
} }
int int
......
...@@ -1045,18 +1045,19 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) ...@@ -1045,18 +1045,19 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
return NULL; return NULL;
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
if (!ses->binding) { /* round robin */
/* round robin */ pick_another:
if (ses->chan_count > 1) { if (ses->chan_count > 1 &&
index = (uint)atomic_inc_return(&ses->chan_seq); !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
index %= ses->chan_count; index = (uint)atomic_inc_return(&ses->chan_seq);
} index %= ses->chan_count;
spin_unlock(&ses->chan_lock);
return ses->chans[index].server; if (CIFS_CHAN_NEEDS_RECONNECT(ses, index))
} else { goto pick_another;
spin_unlock(&ses->chan_lock);
return cifs_ses_server(ses);
} }
spin_unlock(&ses->chan_lock);
return ses->chans[index].server;
} }
int int
...@@ -1190,8 +1191,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1190,8 +1191,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
*/ */
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
smb311_update_preauth_hash(ses, rqst[0].rq_iov, smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
rqst[0].rq_nvec);
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
} }
...@@ -1262,7 +1262,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1262,7 +1262,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
.iov_len = resp_iov[0].iov_len .iov_len = resp_iov[0].iov_len
}; };
mutex_lock(&server->srv_mutex); mutex_lock(&server->srv_mutex);
smb311_update_preauth_hash(ses, &iov, 1); smb311_update_preauth_hash(ses, server, &iov, 1);
mutex_unlock(&server->srv_mutex); mutex_unlock(&server->srv_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment