cifs: fix the connection state transitions with multichannel
authorShyam Prasad N <sprasad@microsoft.com>
Wed, 17 Nov 2021 15:57:22 +0000 (15:57 +0000)
committerSteve French <stfrench@microsoft.com>
Wed, 19 Jan 2022 17:10:54 +0000 (11:10 -0600)
Recent changes to multichannel required some adjustments in
the way connection states transitioned during/after reconnect.

Also some minor fixes:
1. A pending switch of GlobalMid_Lock to cifs_tcp_ses_lock
2. Relocations of the code that logs reconnect
3. Changed some code in allocate_mid to suit the new scheme

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c
fs/cifs/transport.c

index 804ffcd..9fba2ec 100644 (file)
@@ -181,17 +181,16 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
        server->maxBuf = 0;
        server->max_read = 0;
 
-       cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
-       trace_smb3_reconnect(server->CurrentMid, server->conn_id, server->hostname);
        /*
         * 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__);
+       cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__);
 
        /* If server is a channel, select the primary channel */
        pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
 
+
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                spin_lock(&ses->chan_lock);
@@ -218,13 +217,8 @@ next_session:
        }
        spin_unlock(&cifs_tcp_ses_lock);
 
-       /*
-        * 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 and tearing down socket\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);
        if (server->ssocket) {
                cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", server->ssocket->state,
@@ -280,7 +274,12 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num
                wake_up(&server->response_q);
                return false;
        }
+
+       cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
+       trace_smb3_reconnect(server->CurrentMid, server->conn_id,
+                            server->hostname);
        server->tcpStatus = CifsNeedReconnect;
+
        spin_unlock(&cifs_tcp_ses_lock);
        return true;
 }
@@ -634,7 +633,6 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 
                if (server->tcpStatus == CifsNeedReconnect) {
                        spin_unlock(&cifs_tcp_ses_lock);
-                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
                spin_unlock(&cifs_tcp_ses_lock);
@@ -3885,6 +3883,11 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
                else
                        rc = -EHOSTDOWN;
                spin_unlock(&cifs_tcp_ses_lock);
+       } else {
+               spin_lock(&cifs_tcp_ses_lock);
+               if (server->tcpStatus == CifsInNegotiate)
+                       server->tcpStatus = CifsNeedNegotiate;
+               spin_unlock(&cifs_tcp_ses_lock);
        }
 
        return rc;
@@ -3931,8 +3934,18 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
        if (server->ops->sess_setup)
                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);
+               spin_lock(&cifs_tcp_ses_lock);
+               if (server->tcpStatus == CifsInSessSetup)
+                       server->tcpStatus = CifsNeedSessSetup;
+               spin_unlock(&cifs_tcp_ses_lock);
+       } else {
+               spin_lock(&cifs_tcp_ses_lock);
+               if (server->tcpStatus == CifsInSessSetup)
+                       server->tcpStatus = CifsGood;
+               spin_unlock(&cifs_tcp_ses_lock);
+       }
 
        return rc;
 }
@@ -4279,9 +4292,8 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
 
        /* only send once per connect */
        spin_lock(&cifs_tcp_ses_lock);
-       if (tcon->ses->status != CifsGood ||
-           (tcon->tidStatus != CifsNew &&
-           tcon->tidStatus != CifsNeedTcon)) {
+       if (tcon->tidStatus != CifsNew &&
+           tcon->tidStatus != CifsNeedTcon) {
                spin_unlock(&cifs_tcp_ses_lock);
                return 0;
        }
index 50ca479..e7fddd4 100644 (file)
@@ -1054,7 +1054,6 @@ sess_establish_session(struct sess_data *sess_data)
 
        /* Even if one channel is active, session is in good state */
        spin_lock(&cifs_tcp_ses_lock);
-       server->tcpStatus = CifsGood;
        ses->status = CifsGood;
        spin_unlock(&cifs_tcp_ses_lock);
 
index 41b6dff..6d8cfe1 100644 (file)
@@ -1393,7 +1393,6 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
 
        /* Even if one channel is active, session is in good state */
        spin_lock(&cifs_tcp_ses_lock);
-       server->tcpStatus = CifsGood;
        ses->status = CifsGood;
        spin_unlock(&cifs_tcp_ses_lock);
 
index 93f0e8c..548cb37 100644 (file)
@@ -431,7 +431,8 @@ unmask:
                 * socket so the server throws away the partial SMB
                 */
                spin_lock(&cifs_tcp_ses_lock);
-               server->tcpStatus = CifsNeedReconnect;
+               if (server->tcpStatus != CifsExiting)
+                       server->tcpStatus = CifsNeedReconnect;
                spin_unlock(&cifs_tcp_ses_lock);
                trace_smb3_partial_send_reconnect(server->CurrentMid,
                                                  server->conn_id, server->hostname);
@@ -729,17 +730,6 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
                        struct mid_q_entry **ppmidQ)
 {
        spin_lock(&cifs_tcp_ses_lock);
-       if (ses->server->tcpStatus == CifsExiting) {
-               spin_unlock(&cifs_tcp_ses_lock);
-               return -ENOENT;
-       }
-
-       if (ses->server->tcpStatus == CifsNeedReconnect) {
-               spin_unlock(&cifs_tcp_ses_lock);
-               cifs_dbg(FYI, "tcp session dead - return to caller to retry\n");
-               return -EAGAIN;
-       }
-
        if (ses->status == CifsNew) {
                if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
                        (in_buf->Command != SMB_COM_NEGOTIATE)) {