]> git.baikalelectronics.ru Git - kernel.git/commitdiff
cifs: use the chans_need_reconnect bitmap for reconnect status
authorShyam Prasad N <sprasad@microsoft.com>
Mon, 19 Jul 2021 13:54:16 +0000 (13:54 +0000)
committerSteve French <stfrench@microsoft.com>
Mon, 3 Jan 2022 02:38:46 +0000 (20:38 -0600)
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: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
15 files changed:
fs/cifs/cifs_spnego.c
fs/cifs/cifs_spnego.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/ntlmssp.h
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/transport.c

index 353bd0dd702606114b8ced486c0212235cf82018..342717bf1dc28dc885a44815b460726961fa3d16 100644 (file)
@@ -84,9 +84,9 @@ struct key_type cifs_spnego_key_type = {
 
 /* get a key struct with a SPNEGO security blob, suitable for session setup */
 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_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
        char *description, *dp;
index e6a0451877d4790a2bab3f5e50786df285c6fecf..7f102ffeb675014985a16108596d6ee61b4517be 100644 (file)
@@ -29,7 +29,8 @@ struct cifs_spnego_msg {
 
 #ifdef __KERNEL__
 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 /* _CIFS_SPNEGO_H */
index 91878e84c637347c440968179effaface8be271b..76b4adc7d7388e108e82b691f889d0f46200ea31 100644 (file)
@@ -263,13 +263,16 @@ struct smb_version_operations {
        /* check if we need to negotiate */
        bool (*need_neg)(struct TCP_Server_Info *);
        /* 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 */
        unsigned int (*negotiate_wsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
        /* set negotiated read size */
        unsigned int (*negotiate_rsize)(struct cifs_tcon *tcon, struct smb3_fs_context *ctx);
        /* setup smb sessionn */
        int (*sess_setup)(const unsigned int, struct cifs_ses *,
+                         struct TCP_Server_Info *server,
                          const struct nls_table *);
        /* close smb session */
        int (*logoff)(const unsigned int, struct cifs_ses *);
@@ -414,7 +417,8 @@ struct smb_version_operations {
        void (*set_lease_key)(struct inode *, struct cifs_fid *);
        /* generate new lease key */
        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 *,
                                bool allocate_crypto);
        int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon,
@@ -940,15 +944,12 @@ struct cifs_ses {
        enum securityEnum sectype; /* what security flavor was specified? */
        bool sign;              /* is signing required? */
        bool domainAuto:1;
-       bool binding:1; /* are we binding the session? */
        __u16 session_flags;
        __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
        __u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE];
        __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_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
         * connected to.
@@ -976,7 +977,6 @@ struct cifs_ses {
        test_bit((index), &(ses)->chans_need_reconnect)
 
        struct cifs_chan chans[CIFS_MAX_CHANNELS];
-       struct cifs_chan *binding_chan;
        size_t chan_count;
        size_t chan_max;
        atomic_t chan_seq; /* round robin state */
@@ -985,42 +985,16 @@ struct cifs_ses {
         * chans_need_reconnect is a bitmap indicating which of the channels
         * under this smb session needs to be reconnected.
         * 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;
        /* ========= 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
 cap_unix(struct cifs_ses *ses)
 {
index 2a821a8801d2a5faa595d177ec56a5744e315e06..09356a9abe9ce0a439839860613a5ef08e253ac7 100644 (file)
@@ -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,
                                enum securityEnum requested);
 extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
+                         struct TCP_Server_Info *server,
                          const struct nls_table *nls_cp);
 extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec64);
@@ -293,11 +294,15 @@ extern int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon,
                             const struct nls_table *nlsc);
 
 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,
+                             struct TCP_Server_Info *server,
                              struct nls_table *nls_info);
 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,
                    const char *tree, struct cifs_tcon *tcon,
@@ -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 void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
 extern int calc_seckey(struct cifs_ses *);
-extern int generate_smb30signingkey(struct cifs_ses *);
-extern int generate_smb311signingkey(struct cifs_ses *);
+extern int generate_smb30signingkey(struct cifs_ses *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,
                        struct cifs_tcon *source_tcon,
index cbb0d55c1267d6498674386d0e6e842012a87b43..8b3e5be483bc3270713702681df1afdb79b6e556 100644 (file)
@@ -199,7 +199,8 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
        spin_lock(&ses->chan_lock);
        if (!cifs_chan_needs_reconnect(ses, server)) {
                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)
                        goto skip_sess_setup;
 
@@ -209,9 +210,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
        }
        spin_unlock(&ses->chan_lock);
 
-       rc = cifs_negotiate_protocol(0, ses);
+       rc = cifs_negotiate_protocol(0, ses, server);
        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? */
        if (rc || !tcon->need_reconnect) {
@@ -503,14 +504,15 @@ should_set_ext_sec_flag(enum securityEnum sectype)
 }
 
 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_RSP *pSMBr;
        int rc = 0;
        int bytes_returned;
        int i;
-       struct TCP_Server_Info *server = ses->server;
        u16 count;
 
        if (!server) {
index fa80a23f9fcfa8680e54a2acaeebdcc7c9f3630f..9ee5856d63cc92791c2f7a3c62f08a53c3f93cbd 100644 (file)
@@ -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)
 {
+       unsigned int num_sessions = 0;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
        struct mid_q_entry *mid, *nmid;
@@ -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))
                        goto next_session;
 
+               num_sessions++;
+
                list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
                        tcon->need_reconnect = true;
                if (ses->tcon_ipc)
@@ -211,6 +214,14 @@ next_session:
        }
        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 */
        cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
        mutex_lock(&server->srv_mutex);
@@ -2005,7 +2016,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
                        spin_unlock(&ses->chan_lock);
                        cifs_dbg(FYI, "Session needs reconnect\n");
 
-                       rc = cifs_negotiate_protocol(xid, ses);
+                       rc = cifs_negotiate_protocol(xid, ses, server);
                        if (rc) {
                                mutex_unlock(&ses->session_mutex);
                                /* problem -- put our ses reference */
@@ -2014,7 +2025,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
                                return ERR_PTR(rc);
                        }
 
-                       rc = cifs_setup_session(xid, ses,
+                       rc = cifs_setup_session(xid, ses, server,
                                                ctx->local_nls);
                        if (rc) {
                                mutex_unlock(&ses->session_mutex);
@@ -2086,9 +2097,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
        ses->chans_need_reconnect = 1;
        spin_unlock(&ses->chan_lock);
 
-       rc = cifs_negotiate_protocol(xid, ses);
+       rc = cifs_negotiate_protocol(xid, ses, server);
        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 */
        memcpy(ses->chans[0].signkey, ses->smb3signingkey,
@@ -3820,10 +3831,10 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
 }
 
 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;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
 
        if (!server->ops->need_neg || !server->ops->negotiate)
                return -ENOSYS;
@@ -3832,7 +3843,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
        if (!server->ops->need_neg(server))
                return 0;
 
-       rc = server->ops->negotiate(xid, ses);
+       rc = server->ops->negotiate(xid, ses, server);
        if (rc == 0) {
                spin_lock(&GlobalMid_Lock);
                if (server->tcpStatus == CifsNeedNegotiate)
@@ -3847,12 +3858,17 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
 
 int
 cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
+                  struct TCP_Server_Info *server,
                   struct nls_table *nls_info)
 {
        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;
                if (!linuxExtEnabled)
                        ses->capabilities &= (~server->vals->cap_unix);
@@ -3870,7 +3886,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                 server->sec_mode, server->capabilities, server->timeAdj);
 
        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)
                cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
index fe707f45da890291d8027b5a5951f54d1be443b6..6d242af536cbff1a5ed830ec281cdb349c5518a9 100644 (file)
@@ -121,7 +121,9 @@ typedef struct _AUTHENTICATE_MESSAGE {
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
 int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
                                 struct cifs_ses *ses,
+                                struct TCP_Server_Info *server,
                                 const struct nls_table *nls_cp);
 int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
                        struct cifs_ses *ses,
+                       struct TCP_Server_Info *server,
                        const struct nls_table *nls_cp);
index ba8543ccb29892a8019d79b46eb143c1f827f2af..b121a2591e696dad00cdfdf07e9f82c6debf30cb 100644 (file)
@@ -310,7 +310,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 
        mutex_lock(&ses->session_mutex);
        spin_lock(&ses->chan_lock);
-       chan = ses->binding_chan = &ses->chans[ses->chan_count];
+       chan = &ses->chans[ses->chan_count];
        chan->server = chan_server;
        if (IS_ERR(chan->server)) {
                rc = PTR_ERR(chan->server);
@@ -318,6 +318,12 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
                spin_unlock(&ses->chan_lock);
                goto out;
        }
+       ses->chan_count++;
+       atomic_set(&ses->chan_seq, 0);
+
+       /* Mark this channel as needing connect/setup */
+       cifs_chan_set_need_reconnect(ses, chan->server);
+
        spin_unlock(&ses->chan_lock);
 
        /*
@@ -331,41 +337,17 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
                goto out;
        }
 
-       ses->binding = true;
-       rc = cifs_negotiate_protocol(xid, ses);
-       if (rc)
-               goto out;
-
-       rc = cifs_setup_session(xid, ses, cifs_sb->local_nls);
-       if (rc)
-               goto out;
-
-       /* success, put it on the list
-        * XXX: sharing ses between 2 tcp servers is not possible, the
-        * way "internal" linked lists works in linux makes element
-        * only able to belong to one list
-        *
-        * the binding session is already established so the rest of
-        * the code should be able to look it up, no need to add the
-        * ses to the new server.
-        */
-
-       spin_lock(&ses->chan_lock);
-       ses->chan_count++;
-       atomic_set(&ses->chan_seq, 0);
-
-       /* Mark this channel as needing connect/setup */
-       cifs_chan_set_need_reconnect(ses, chan->server);
-       spin_unlock(&ses->chan_lock);
+       rc = cifs_negotiate_protocol(xid, ses, chan->server);
+       if (!rc)
+               rc = cifs_setup_session(xid, ses, chan->server, cifs_sb->local_nls);
 
 out:
-       ses->binding = false;
-       ses->binding_chan = NULL;
-
        if (rc && chan->server) {
+               spin_lock(&ses->chan_lock);
                /* we rely on all bits beyond chan_count to be clear */
                cifs_chan_clear_need_reconnect(ses, chan->server);
                ses->chan_count--;
+               spin_unlock(&ses->chan_lock);
        }
 
        mutex_unlock(&ses->session_mutex);
@@ -389,7 +371,9 @@ void cifs_ses_mark_for_reconnect(struct cifs_ses *ses)
        }
 }
 
-static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
+static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
+                            struct TCP_Server_Info *server,
+                            SESSION_SETUP_ANDX *pSMB)
 {
        __u32 capabilities = 0;
 
@@ -402,7 +386,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
        pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32,
                                        CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
                                        USHRT_MAX));
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+       pSMB->req.MaxMpxCount = cpu_to_le16(server->maxReq);
        pSMB->req.VcNumber = cpu_to_le16(1);
 
        /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
@@ -413,7 +397,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
                        CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-       if (ses->server->sign)
+       if (server->sign)
                pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_UNICODE) {
@@ -776,10 +760,10 @@ static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf,
 int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
                                 u16 *buflen,
                                 struct cifs_ses *ses,
+                                struct TCP_Server_Info *server,
                                 const struct nls_table *nls_cp)
 {
        int rc = 0;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
        NEGOTIATE_MESSAGE *sec_blob;
        __u32 flags;
        unsigned char *tmp;
@@ -833,6 +817,7 @@ setup_ntlm_neg_ret:
 int build_ntlmssp_auth_blob(unsigned char **pbuffer,
                                        u16 *buflen,
                                   struct cifs_ses *ses,
+                                  struct TCP_Server_Info *server,
                                   const struct nls_table *nls_cp)
 {
        int rc;
@@ -969,6 +954,7 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
 struct sess_data {
        unsigned int xid;
        struct cifs_ses *ses;
+       struct TCP_Server_Info *server;
        struct nls_table *nls_cp;
        void (*func)(struct sess_data *);
        int result;
@@ -1035,35 +1021,34 @@ static int
 sess_establish_session(struct sess_data *sess_data)
 {
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
 
-       mutex_lock(&ses->server->srv_mutex);
-       if (!ses->server->session_estab) {
-               if (ses->server->sign) {
-                       ses->server->session_key.response =
+       mutex_lock(&server->srv_mutex);
+       if (!server->session_estab) {
+               if (server->sign) {
+                       server->session_key.response =
                                kmemdup(ses->auth_key.response,
                                ses->auth_key.len, GFP_KERNEL);
-                       if (!ses->server->session_key.response) {
-                               mutex_unlock(&ses->server->srv_mutex);
+                       if (!server->session_key.response) {
+                               mutex_unlock(&server->srv_mutex);
                                return -ENOMEM;
                        }
-                       ses->server->session_key.len =
+                       server->session_key.len =
                                                ses->auth_key.len;
                }
-               ses->server->sequence_number = 0x2;
-               ses->server->session_estab = true;
+               server->sequence_number = 0x2;
+               server->session_estab = true;
        }
-       mutex_unlock(&ses->server->srv_mutex);
+       mutex_unlock(&server->srv_mutex);
 
        cifs_dbg(FYI, "CIFS session established successfully\n");
-       if (ses->binding)
-               cifs_chan_clear_need_reconnect(ses, ses->binding_chan->server);
-       else
-               cifs_chan_clear_need_reconnect(ses, ses->server);
+       spin_lock(&ses->chan_lock);
+       cifs_chan_clear_need_reconnect(ses, server);
+       spin_unlock(&ses->chan_lock);
 
-       /* keep existing ses state if binding */
+       /* Even if one channel is active, session is in good state */
        spin_lock(&GlobalMid_Lock);
-       if (!ses->binding)
-               ses->status = CifsGood;
+       ses->status = CifsGood;
        spin_unlock(&GlobalMid_Lock);
 
        return 0;
@@ -1099,6 +1084,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
        SESSION_SETUP_ANDX *pSMB;
        char *bcc_ptr;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        __u32 capabilities;
        __u16 bytes_remaining;
 
@@ -1110,7 +1096,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
 
        pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
        bcc_ptr = sess_data->iov[2].iov_base;
-       capabilities = cifs_ssetup_hdr(ses, pSMB);
+       capabilities = cifs_ssetup_hdr(ses, server, pSMB);
 
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
@@ -1208,6 +1194,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
        SESSION_SETUP_ANDX *pSMB;
        char *bcc_ptr;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        __u32 capabilities;
        __u16 bytes_remaining;
        struct key *spnego_key = NULL;
@@ -1222,9 +1209,9 @@ sess_auth_kerberos(struct sess_data *sess_data)
 
        pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
        bcc_ptr = sess_data->iov[2].iov_base;
-       capabilities = cifs_ssetup_hdr(ses, pSMB);
+       capabilities = cifs_ssetup_hdr(ses, server, pSMB);
 
-       spnego_key = cifs_get_spnego_key(ses);
+       spnego_key = cifs_get_spnego_key(ses, server);
        if (IS_ERR(spnego_key)) {
                rc = PTR_ERR(spnego_key);
                spnego_key = NULL;
@@ -1348,12 +1335,13 @@ _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
 {
        SESSION_SETUP_ANDX *pSMB;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        __u32 capabilities;
        char *bcc_ptr;
 
        pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 
-       capabilities = cifs_ssetup_hdr(ses, pSMB);
+       capabilities = cifs_ssetup_hdr(ses, server, pSMB);
        if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
                cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
                return -ENOSYS;
@@ -1387,6 +1375,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
        struct smb_hdr *smb_buf;
        SESSION_SETUP_ANDX *pSMB;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        __u16 bytes_remaining;
        char *bcc_ptr;
        unsigned char *ntlmsspblob = NULL;
@@ -1414,7 +1403,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
 
        /* Build security blob before we assemble the request */
        rc = build_ntlmssp_negotiate_blob(&ntlmsspblob,
-                                    &blob_len, ses,
+                                    &blob_len, ses, server,
                                     sess_data->nls_cp);
        if (rc)
                goto out;
@@ -1489,6 +1478,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
        struct smb_hdr *smb_buf;
        SESSION_SETUP_ANDX *pSMB;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        __u16 bytes_remaining;
        char *bcc_ptr;
        unsigned char *ntlmsspblob = NULL;
@@ -1505,7 +1495,8 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
        pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
        smb_buf = (struct smb_hdr *)pSMB;
        rc = build_ntlmssp_auth_blob(&ntlmsspblob,
-                                       &blob_len, ses, sess_data->nls_cp);
+                                       &blob_len, ses, server,
+                                       sess_data->nls_cp);
        if (rc)
                goto out_free_ntlmsspblob;
        sess_data->iov[1].iov_len = blob_len;
@@ -1589,11 +1580,13 @@ out:
        sess_data->result = rc;
 }
 
-static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
+static int select_sec(struct sess_data *sess_data)
 {
        int type;
+       struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
 
-       type = cifs_select_sectype(ses->server, ses->sectype);
+       type = cifs_select_sectype(server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
        if (type == Unspecified) {
                cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
@@ -1624,7 +1617,8 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
 }
 
 int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
-                   const struct nls_table *nls_cp)
+                  struct TCP_Server_Info *server,
+                  const struct nls_table *nls_cp)
 {
        int rc = 0;
        struct sess_data *sess_data;
@@ -1638,15 +1632,16 @@ int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
        if (!sess_data)
                return -ENOMEM;
 
-       rc = select_sec(ses, sess_data);
-       if (rc)
-               goto out;
-
        sess_data->xid = xid;
        sess_data->ses = ses;
+       sess_data->server = server;
        sess_data->buf0_type = CIFS_NO_BUFFER;
        sess_data->nls_cp = (struct nls_table *) nls_cp;
 
+       rc = select_sec(sess_data);
+       if (rc)
+               goto out;
+
        while (sess_data->func)
                sess_data->func(sess_data);
 
index 3b83839fc2c276d02a5e9e52fdf5f839c2b9465f..5366202d343d883ad24cced48350956d2cea0968 100644 (file)
@@ -414,14 +414,16 @@ cifs_need_neg(struct TCP_Server_Info *server)
 }
 
 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;
-       rc = CIFSSMBNegotiate(xid, ses);
+       rc = CIFSSMBNegotiate(xid, ses, server);
        if (rc == -EAGAIN) {
                /* retry only once on 1st time connection */
-               set_credits(ses->server, 1);
-               rc = CIFSSMBNegotiate(xid, ses);
+               set_credits(server, 1);
+               rc = CIFSSMBNegotiate(xid, ses, server);
                if (rc == -EAGAIN)
                        rc = -EHOSTDOWN;
        }
index cdcdef32759e4230815cf8c9c646d35d05295a58..396d5afa7cf12ab58b9c267ecef743a2f223ae88 100644 (file)
@@ -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
  */
 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;
        struct sdesc *d;
        struct smb2_hdr *hdr;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
 
        hdr = (struct smb2_hdr *)iov[0].iov_base;
        /* neg prot are always taken */
index c5b1dea54ebcdf5f99827f8d62918685deebd07f..c97dd9758c6954561d6d232ebe164aa1829ecf36 100644 (file)
@@ -384,14 +384,16 @@ smb2_need_neg(struct TCP_Server_Info *server)
 }
 
 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;
 
        spin_lock(&GlobalMid_Lock);
-       cifs_ses_server(ses)->CurrentMid = 0;
+       server->CurrentMid = 0;
        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 */
        if (rc == -EAGAIN)
                rc = -EHOSTDOWN;
index f3b2eef36ec150d7a5d631939944f89f80412899..9e7b213dbef5bce405071d015cf6bdcab7e12919 100644 (file)
@@ -248,7 +248,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
         * need to prevent multiple threads trying to simultaneously reconnect
         * the same SMB session
         */
-       mutex_lock(&tcon->ses->session_mutex);
+       mutex_lock(&ses->session_mutex);
 
        /*
         * Recheck after acquire mutex. If another thread is negotiating
@@ -257,18 +257,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
         */
        if (server->tcpStatus == CifsNeedReconnect) {
                rc = -EHOSTDOWN;
-               mutex_unlock(&tcon->ses->session_mutex);
+               mutex_unlock(&ses->session_mutex);
                goto out;
        }
 
-       /*
-        * If we are reconnecting an extra channel, bind
-        */
-       if (CIFS_SERVER_IS_CHAN(server)) {
-               ses->binding = true;
-               ses->binding_chan = cifs_ses_find_chan(ses, server);
-       }
-
        /*
         * need to prevent multiple threads trying to simultaneously
         * reconnect the same SMB session
@@ -277,7 +269,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
        if (!cifs_chan_needs_reconnect(ses, server)) {
                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)
                        goto skip_sess_setup;
 
@@ -287,22 +279,15 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
        }
        spin_unlock(&ses->chan_lock);
 
-       rc = cifs_negotiate_protocol(0, tcon->ses);
+       rc = cifs_negotiate_protocol(0, ses, server);
        if (!rc) {
-               rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+               rc = cifs_setup_session(0, ses, server, nls_codepage);
                if ((rc == -EACCES) && !tcon->retry) {
                        rc = -EHOSTDOWN;
-                       ses->binding = false;
-                       ses->binding_chan = NULL;
-                       mutex_unlock(&tcon->ses->session_mutex);
+                       mutex_unlock(&ses->session_mutex);
                        goto failed;
                }
        }
-       /*
-        * End of channel binding
-        */
-       ses->binding = false;
-       ses->binding_chan = NULL;
 
        if (rc || !tcon->need_reconnect) {
                mutex_unlock(&tcon->ses->session_mutex);
@@ -859,7 +844,9 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
  */
 
 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)
 {
        struct smb_rqst rqst;
        struct smb2_negotiate_req *req;
@@ -868,7 +855,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
        int blob_offset, blob_length;
        char *security_blob;
        int flags = CIFS_NEG_OP;
@@ -1247,6 +1233,7 @@ smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
 struct SMB2_sess_data {
        unsigned int xid;
        struct cifs_ses *ses;
+       struct TCP_Server_Info *server;
        struct nls_table *nls_cp;
        void (*func)(struct SMB2_sess_data *);
        int result;
@@ -1268,9 +1255,10 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
 {
        int rc;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        struct smb2_sess_setup_req *req;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
        unsigned int total_len;
+       bool is_binding = false;
 
        rc = smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server,
                                 (void **) &req,
@@ -1278,11 +1266,16 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
        if (rc)
                return rc;
 
-       if (sess_data->ses->binding) {
-               req->hdr.SessionId = cpu_to_le64(sess_data->ses->Suid);
+       spin_lock(&ses->chan_lock);
+       is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+       spin_unlock(&ses->chan_lock);
+
+       if (is_binding) {
+               req->hdr.SessionId = cpu_to_le64(ses->Suid);
                req->hdr.Flags |= SMB2_FLAGS_SIGNED;
                req->PreviousSessionId = 0;
                req->Flags = SMB2_SESSION_REQ_FLAG_BINDING;
+               cifs_dbg(FYI, "Binding to sess id: %llx\n", ses->Suid);
        } else {
                /* First session, not a reauthenticate */
                req->hdr.SessionId = 0;
@@ -1292,6 +1285,8 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
                 */
                req->PreviousSessionId = cpu_to_le64(sess_data->previous_session);
                req->Flags = 0; /* MBZ */
+               cifs_dbg(FYI, "Fresh session. Previous: %llx\n",
+                        sess_data->previous_session);
        }
 
        /* enough to enable echos and oplocks and one max size write */
@@ -1351,7 +1346,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
 
        /* BB add code to build os and lm fields */
        rc = cifs_send_recv(sess_data->xid, sess_data->ses,
-                           cifs_ses_server(sess_data->ses),
+                           sess_data->server,
                            &rqst,
                            &sess_data->buf0_type,
                            CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov);
@@ -1366,11 +1361,11 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
 {
        int rc = 0;
        struct cifs_ses *ses = sess_data->ses;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
+       struct TCP_Server_Info *server = sess_data->server;
 
        mutex_lock(&server->srv_mutex);
        if (server->ops->generate_signingkey) {
-               rc = server->ops->generate_signingkey(ses);
+               rc = server->ops->generate_signingkey(ses, server);
                if (rc) {
                        cifs_dbg(FYI,
                                "SMB3 session key generation failed\n");
@@ -1387,16 +1382,12 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
        cifs_dbg(FYI, "SMB2/3 session established successfully\n");
 
        spin_lock(&ses->chan_lock);
-       if (ses->binding)
-               cifs_chan_clear_need_reconnect(ses, ses->binding_chan->server);
-       else
-               cifs_chan_clear_need_reconnect(ses, ses->server);
+       cifs_chan_clear_need_reconnect(ses, server);
        spin_unlock(&ses->chan_lock);
 
-       /* keep existing ses state if binding */
+       /* Even if one channel is active, session is in good state */
        spin_lock(&GlobalMid_Lock);
-       if (!ses->binding)
-               ses->status = CifsGood;
+       ses->status = CifsGood;
        spin_unlock(&GlobalMid_Lock);
 
        return rc;
@@ -1408,15 +1399,17 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 {
        int rc;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        struct cifs_spnego_msg *msg;
        struct key *spnego_key = NULL;
        struct smb2_sess_setup_rsp *rsp = NULL;
+       bool is_binding = false;
 
        rc = SMB2_sess_alloc_buffer(sess_data);
        if (rc)
                goto out;
 
-       spnego_key = cifs_get_spnego_key(ses);
+       spnego_key = cifs_get_spnego_key(ses, server);
        if (IS_ERR(spnego_key)) {
                rc = PTR_ERR(spnego_key);
                if (rc == -ENOKEY)
@@ -1437,8 +1430,12 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
                goto out_put_spnego_key;
        }
 
+       spin_lock(&ses->chan_lock);
+       is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+       spin_unlock(&ses->chan_lock);
+
        /* keep session key if binding */
-       if (!ses->binding) {
+       if (!is_binding) {
                ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
                                                 GFP_KERNEL);
                if (!ses->auth_key.response) {
@@ -1459,7 +1456,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 
        rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
        /* keep session id and flags if binding */
-       if (!ses->binding) {
+       if (!is_binding) {
                ses->Suid = le64_to_cpu(rsp->hdr.SessionId);
                ses->session_flags = le16_to_cpu(rsp->SessionFlags);
        }
@@ -1491,10 +1488,12 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 {
        int rc;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        struct smb2_sess_setup_rsp *rsp = NULL;
        unsigned char *ntlmssp_blob = NULL;
        bool use_spnego = false; /* else use raw ntlmssp */
        u16 blob_length = 0;
+       bool is_binding = false;
 
        /*
         * If memory allocation is successful, caller of this function
@@ -1512,7 +1511,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
                goto out_err;
 
        rc = build_ntlmssp_negotiate_blob(&ntlmssp_blob,
-                                         &blob_length, ses,
+                                         &blob_length, ses, server,
                                          sess_data->nls_cp);
        if (rc)
                goto out_err;
@@ -1551,8 +1550,12 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 
        cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
 
+       spin_lock(&ses->chan_lock);
+       is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+       spin_unlock(&ses->chan_lock);
+
        /* keep existing ses id and flags if binding */
-       if (!ses->binding) {
+       if (!is_binding) {
                ses->Suid = le64_to_cpu(rsp->hdr.SessionId);
                ses->session_flags = le16_to_cpu(rsp->SessionFlags);
        }
@@ -1577,11 +1580,13 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 {
        int rc;
        struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
        struct smb2_sess_setup_req *req;
        struct smb2_sess_setup_rsp *rsp = NULL;
        unsigned char *ntlmssp_blob = NULL;
        bool use_spnego = false; /* else use raw ntlmssp */
        u16 blob_length = 0;
+       bool is_binding = false;
 
        rc = SMB2_sess_alloc_buffer(sess_data);
        if (rc)
@@ -1590,8 +1595,9 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
        req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base;
        req->hdr.SessionId = cpu_to_le64(ses->Suid);
 
-       rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
-                                       sess_data->nls_cp);
+       rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length,
+                                    ses, server,
+                                    sess_data->nls_cp);
        if (rc) {
                cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc);
                goto out;
@@ -1612,8 +1618,12 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 
        rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
 
+       spin_lock(&ses->chan_lock);
+       is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+       spin_unlock(&ses->chan_lock);
+
        /* keep existing ses id and flags if binding */
-       if (!ses->binding) {
+       if (!is_binding) {
                ses->Suid = le64_to_cpu(rsp->hdr.SessionId);
                ses->session_flags = le16_to_cpu(rsp->SessionFlags);
        }
@@ -1644,11 +1654,13 @@ out:
 }
 
 static int
-SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
+SMB2_select_sec(struct SMB2_sess_data *sess_data)
 {
        int type;
+       struct cifs_ses *ses = sess_data->ses;
+       struct TCP_Server_Info *server = sess_data->server;
 
-       type = smb2_select_sectype(cifs_ses_server(ses), ses->sectype);
+       type = smb2_select_sectype(server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
        if (type == Unspecified) {
                cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
@@ -1672,10 +1684,10 @@ SMB2_select_sec(struct cifs_ses *ses, struct SMB2_sess_data *sess_data)
 
 int
 SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
+               struct TCP_Server_Info *server,
                const struct nls_table *nls_cp)
 {
        int rc = 0;
-       struct TCP_Server_Info *server = cifs_ses_server(ses);
        struct SMB2_sess_data *sess_data;
 
        cifs_dbg(FYI, "Session Setup\n");
@@ -1689,15 +1701,17 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        if (!sess_data)
                return -ENOMEM;
 
-       rc = SMB2_select_sec(ses, sess_data);
-       if (rc)
-               goto out;
        sess_data->xid = xid;
        sess_data->ses = ses;
+       sess_data->server = server;
        sess_data->buf0_type = CIFS_NO_BUFFER;
        sess_data->nls_cp = (struct nls_table *) nls_cp;
        sess_data->previous_session = ses->Suid;
 
+       rc = SMB2_select_sec(sess_data);
+       if (rc)
+               goto out;
+
        /*
         * Initialize the session hash with the server one.
         */
index 096fada16ebd8c0e84a52a80491aa0ac3339f6c5..4a7062fd1c26b538dd46a2ba46c76a52b1b2ed9c 100644 (file)
@@ -123,8 +123,11 @@ extern void smb2_set_related(struct smb_rqst *rqst);
  * SMB2 Worker functions - most of protocol specific implementation details
  * 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,
+                          struct TCP_Server_Info *server,
                           const struct nls_table *nls_cp);
 extern int SMB2_logoff(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(
         struct kstatfs *kst);
 extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
 extern int smb311_update_preauth_hash(struct cifs_ses *ses,
+                                     struct TCP_Server_Info *server,
                                      struct kvec *iov, int nvec);
 extern int smb2_query_info_compound(const unsigned int xid,
                                    struct cifs_tcon *tcon,
index 2bf047b390a98bcc702ac6a6f1c26948b9499caa..112adf153807d3d926c5a8550250830ed2f95ed1 100644 (file)
@@ -100,7 +100,8 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
        goto out;
 
 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
                 * to an existing session, use the master connection
@@ -390,12 +391,18 @@ struct derivation_triplet {
 
 static int
 generate_smb3signingkey(struct cifs_ses *ses,
+                       struct TCP_Server_Info *server,
                        const struct derivation_triplet *ptriplet)
 {
        int rc;
-#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
-       struct TCP_Server_Info *server = ses->server;
-#endif
+       bool is_binding = false;
+       int chan_index = 0;
+
+       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
@@ -407,10 +414,10 @@ generate_smb3signingkey(struct cifs_ses *ses,
         * master connection signing key stored in the session
         */
 
-       if (ses->binding) {
+       if (is_binding) {
                rc = generate_key(ses, ptriplet->signing.label,
                                  ptriplet->signing.context,
-                                 cifs_ses_binding_channel(ses)->signkey,
+                                 ses->chans[chan_index].signkey,
                                  SMB3_SIGN_KEY_SIZE);
                if (rc)
                        return rc;
@@ -422,6 +429,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
                if (rc)
                        return rc;
 
+               /* safe to access primary channel, since it will never go away */
                memcpy(ses->chans[0].signkey, ses->smb3signingkey,
                       SMB3_SIGN_KEY_SIZE);
 
@@ -470,7 +478,8 @@ generate_smb3signingkey(struct cifs_ses *ses,
 }
 
 int
-generate_smb30signingkey(struct cifs_ses *ses)
+generate_smb30signingkey(struct cifs_ses *ses,
+                        struct TCP_Server_Info *server)
 
 {
        struct derivation_triplet triplet;
@@ -494,11 +503,12 @@ generate_smb30signingkey(struct cifs_ses *ses)
        d->context.iov_base = "ServerOut";
        d->context.iov_len = 10;
 
-       return generate_smb3signingkey(ses, &triplet);
+       return generate_smb3signingkey(ses, server, &triplet);
 }
 
 int
-generate_smb311signingkey(struct cifs_ses *ses)
+generate_smb311signingkey(struct cifs_ses *ses,
+                         struct TCP_Server_Info *server)
 
 {
        struct derivation_triplet triplet;
@@ -522,7 +532,7 @@ generate_smb311signingkey(struct cifs_ses *ses)
        d->context.iov_base = ses->preauth_sha_hash;
        d->context.iov_len = 64;
 
-       return generate_smb3signingkey(ses, &triplet);
+       return generate_smb3signingkey(ses, server, &triplet);
 }
 
 int
index 61ea3d3f95b4a61a5eca77c78dadf7bcebb107b9..1d81681d9b973a9307e027d67ef23b8a19f86418 100644 (file)
@@ -1045,18 +1045,19 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
                return NULL;
 
        spin_lock(&ses->chan_lock);
-       if (!ses->binding) {
-               /* round robin */
-               if (ses->chan_count > 1) {
-                       index = (uint)atomic_inc_return(&ses->chan_seq);
-                       index %= ses->chan_count;
-               }
-               spin_unlock(&ses->chan_lock);
-               return ses->chans[index].server;
-       } else {
-               spin_unlock(&ses->chan_lock);
-               return cifs_ses_server(ses);
+       /* round robin */
+pick_another:
+       if (ses->chan_count > 1 &&
+           !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
+               index = (uint)atomic_inc_return(&ses->chan_seq);
+               index %= ses->chan_count;
+
+               if (CIFS_CHAN_NEEDS_RECONNECT(ses, index))
+                       goto pick_another;
        }
+       spin_unlock(&ses->chan_lock);
+
+       return ses->chans[index].server;
 }
 
 int
@@ -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)) {
                mutex_lock(&server->srv_mutex);
-               smb311_update_preauth_hash(ses, rqst[0].rq_iov,
-                                          rqst[0].rq_nvec);
+               smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec);
                mutex_unlock(&server->srv_mutex);
        }
 
@@ -1262,7 +1262,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                        .iov_len = resp_iov[0].iov_len
                };
                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);
        }