]> git.baikalelectronics.ru Git - kernel.git/commitdiff
cifs: reconnect only the connection and not smb session where possible
authorShyam Prasad N <sprasad@microsoft.com>
Mon, 19 Jul 2021 14:14:46 +0000 (14:14 +0000)
committerSteve French <stfrench@microsoft.com>
Mon, 3 Jan 2022 02:38:46 +0000 (20:38 -0600)
With the new per-channel bitmask for reconnect, we have an option to
reconnect the tcp session associated with the channel without reconnecting
the smb session. i.e. if there are still channels to operate on, we can
continue to use the smb session and tcon.

However, there are cases where it makes sense to reconnect the smb session
even when there are active channels underneath. For example for
SMB session expiry.

With this patch, we'll have an option to do either, and use the correct
option for specific cases.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/smb2ops.c

index 76b4adc7d7388e108e82b691f889d0f46200ea31..23d76ae713f0962c95622c84e738a78b0bfd7a72 100644 (file)
@@ -973,6 +973,8 @@ struct cifs_ses {
        ((1UL << (ses)->chan_count) - 1)
 #define CIFS_ALL_CHANS_NEED_RECONNECT(ses)     \
        ((ses)->chans_need_reconnect == CIFS_ALL_CHANNELS_SET(ses))
+#define CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses) \
+       ((ses)->chans_need_reconnect = CIFS_ALL_CHANNELS_SET(ses))
 #define CIFS_CHAN_NEEDS_RECONNECT(ses, index)  \
        test_bit((index), &(ses)->chans_need_reconnect)
 
index 09356a9abe9ce0a439839860613a5ef08e253ac7..e0dc147e69a85820b2c2a60cbba8496b2ab76cd8 100644 (file)
@@ -131,7 +131,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct smb_hdr *in_buf ,
                        struct smb_hdr *out_buf,
                        int *bytes_returned);
-extern int cifs_reconnect(struct TCP_Server_Info *server);
+extern int cifs_reconnect(struct TCP_Server_Info *server,
+                         bool mark_smb_session);
 extern int checkSMB(char *buf, unsigned int len, struct TCP_Server_Info *srvr);
 extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
 extern bool backup_cred(struct cifs_sb_info *);
index 8b3e5be483bc3270713702681df1afdb79b6e556..7b1d0d71f3f14130de4008896063dc4e62cd737f 100644 (file)
@@ -1439,7 +1439,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        if (server->ops->is_session_expired &&
            server->ops->is_session_expired(buf)) {
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                return -1;
        }
 
index 9ee5856d63cc92791c2f7a3c62f08a53c3f93cbd..7b478f5db9d619bb8f3870595457a4d97fa17d84 100644 (file)
@@ -166,8 +166,11 @@ static void cifs_resolve_server(struct work_struct *work)
  * Mark all sessions and tcons for reconnect.
  *
  * @server needs to be previously set to CifsNeedReconnect.
+ *
  */
-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,
+                                     bool mark_smb_session)
 {
        unsigned int num_sessions = 0;
        struct cifs_ses *ses;
@@ -193,13 +196,16 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
                spin_lock(&ses->chan_lock);
-               if (cifs_chan_needs_reconnect(ses, server))
+               if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
                        goto next_session;
 
-               cifs_chan_set_need_reconnect(ses, server);
+               if (mark_smb_session)
+                       CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
+               else
+                       cifs_chan_set_need_reconnect(ses, server);
 
                /* If all channels need reconnect, then tcon needs reconnect */
-               if (!CIFS_ALL_CHANS_NEED_RECONNECT(ses))
+               if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
                        goto next_session;
 
                num_sessions++;
@@ -271,16 +277,16 @@ next_session:
 
 static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets)
 {
-       spin_lock(&GlobalMid_Lock);
+       spin_lock(&cifs_tcp_ses_lock);
        server->nr_targets = num_targets;
        if (server->tcpStatus == CifsExiting) {
                /* the demux thread will exit normally next time through the loop */
-               spin_unlock(&GlobalMid_Lock);
+               spin_unlock(&cifs_tcp_ses_lock);
                wake_up(&server->response_q);
                return false;
        }
        server->tcpStatus = CifsNeedReconnect;
-       spin_unlock(&GlobalMid_Lock);
+       spin_unlock(&cifs_tcp_ses_lock);
        return true;
 }
 
@@ -291,15 +297,21 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num
  * mark all smb sessions as reconnecting for tcp session
  * reconnect tcp session
  * wake up waiters on reconnection? - (not needed currently)
+ *
+ * if mark_smb_session is passed as true, unconditionally mark
+ * the smb session (and tcon) for reconnect as well. This value
+ * doesn't really matter for non-multichannel scenario.
+ *
  */
-static int __cifs_reconnect(struct TCP_Server_Info *server)
+static int __cifs_reconnect(struct TCP_Server_Info *server,
+                           bool mark_smb_session)
 {
        int rc = 0;
 
        if (!cifs_tcp_ses_needs_reconnect(server, 1))
                return 0;
 
-       cifs_mark_tcp_ses_conns_for_reconnect(server);
+       cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
        do {
                try_to_freeze();
@@ -322,10 +334,10 @@ static int __cifs_reconnect(struct TCP_Server_Info *server)
                } else {
                        atomic_inc(&tcpSesReconnectCount);
                        set_credits(server, 1);
-                       spin_lock(&GlobalMid_Lock);
+                       spin_lock(&cifs_tcp_ses_lock);
                        if (server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsNeedNegotiate;
-                       spin_unlock(&GlobalMid_Lock);
+                       spin_unlock(&cifs_tcp_ses_lock);
                        cifs_swn_reset_server_dstaddr(server);
                        mutex_unlock(&server->srv_mutex);
                }
@@ -394,7 +406,9 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_
        return rc;
 }
 
-static int reconnect_dfs_server(struct TCP_Server_Info *server)
+static int
+reconnect_dfs_server(struct TCP_Server_Info *server,
+                    bool mark_smb_session)
 {
        int rc = 0;
        const char *refpath = server->current_fullpath + 1;
@@ -418,7 +432,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
        if (!cifs_tcp_ses_needs_reconnect(server, num_targets))
                return 0;
 
-       cifs_mark_tcp_ses_conns_for_reconnect(server);
+       cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
        do {
                try_to_freeze();
@@ -439,10 +453,10 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
                 */
                atomic_inc(&tcpSesReconnectCount);
                set_credits(server, 1);
-               spin_lock(&GlobalMid_Lock);
+               spin_lock(&cifs_tcp_ses_lock);
                if (server->tcpStatus != CifsExiting)
                        server->tcpStatus = CifsNeedNegotiate;
-               spin_unlock(&GlobalMid_Lock);
+               spin_unlock(&cifs_tcp_ses_lock);
                cifs_swn_reset_server_dstaddr(server);
                mutex_unlock(&server->srv_mutex);
        } while (server->tcpStatus == CifsNeedReconnect);
@@ -460,22 +474,22 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
        return rc;
 }
 
-int cifs_reconnect(struct TCP_Server_Info *server)
+int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session)
 {
        /* If tcp session is not an dfs connection, then reconnect to last target server */
        spin_lock(&cifs_tcp_ses_lock);
        if (!server->is_dfs_conn || !server->origin_fullpath || !server->leaf_fullpath) {
                spin_unlock(&cifs_tcp_ses_lock);
-               return __cifs_reconnect(server);
+               return __cifs_reconnect(server, mark_smb_session);
        }
        spin_unlock(&cifs_tcp_ses_lock);
 
-       return reconnect_dfs_server(server);
+       return reconnect_dfs_server(server, mark_smb_session);
 }
 #else
-int cifs_reconnect(struct TCP_Server_Info *server)
+int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session)
 {
-       return __cifs_reconnect(server);
+       return __cifs_reconnect(server, mark_smb_session);
 }
 #endif
 
@@ -563,7 +577,7 @@ server_unresponsive(struct TCP_Server_Info *server)
            time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
                cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
                         (3 * server->echo_interval) / HZ);
-               cifs_reconnect(server);
+               cifs_reconnect(server, false);
                return true;
        }
 
@@ -599,7 +613,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 
                /* reconnect if no credits and no requests in flight */
                if (zero_credits(server)) {
-                       cifs_reconnect(server);
+                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
 
@@ -614,7 +628,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
                        return -ESHUTDOWN;
 
                if (server->tcpStatus == CifsNeedReconnect) {
-                       cifs_reconnect(server);
+                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
 
@@ -633,7 +647,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 
                if (length <= 0) {
                        cifs_dbg(FYI, "Received no data or error: %d\n", length);
-                       cifs_reconnect(server);
+                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
        }
@@ -712,11 +726,11 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
                 * initialize frame).
                 */
                cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                break;
        default:
                cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
        }
 
        return false;
@@ -889,7 +903,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
                server->vals->header_preamble_size) {
                cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                return -ECONNABORTED;
        }
 
@@ -936,7 +950,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        if (server->ops->is_session_expired &&
            server->ops->is_session_expired(buf)) {
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                return -1;
        }
 
@@ -1040,7 +1054,7 @@ next_pdu:
                    server->vals->header_preamble_size) {
                        cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
                                 server->pdu_size);
-                       cifs_reconnect(server);
+                       cifs_reconnect(server, true);
                        continue;
                }
 
@@ -1092,7 +1106,7 @@ next_pdu:
                    server->ops->is_status_io_timeout(buf)) {
                        num_io_timeout++;
                        if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
-                               cifs_reconnect(server);
+                               cifs_reconnect(server, false);
                                num_io_timeout = 0;
                                continue;
                        }
index c97dd9758c6954561d6d232ebe164aa1829ecf36..b33b0f391a2340ed81f90d677d90249d374481bb 100644 (file)
@@ -4810,7 +4810,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
        if (server->ops->is_session_expired &&
            server->ops->is_session_expired(buf)) {
                if (!is_offloaded)
-                       cifs_reconnect(server);
+                       cifs_reconnect(server, true);
                return -1;
        }
 
@@ -5223,13 +5223,13 @@ smb3_receive_transform(struct TCP_Server_Info *server,
                                                sizeof(struct smb2_hdr)) {
                cifs_server_dbg(VFS, "Transform message is too small (%u)\n",
                         pdu_length);
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                return -ECONNABORTED;
        }
 
        if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
                cifs_server_dbg(VFS, "Transform message is broken\n");
-               cifs_reconnect(server);
+               cifs_reconnect(server, true);
                return -ECONNABORTED;
        }