cifs: handle when server starts supporting multichannel
authorShyam Prasad N <sprasad@microsoft.com>
Fri, 13 Oct 2023 11:33:21 +0000 (11:33 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Feb 2024 00:18:48 +0000 (16:18 -0800)
[ Upstream commit 705fc522fe9d58848c253ee0948567060f36e2a7 ]

When the user mounts with multichannel option, but the
server does not support it, there can be a time in future
where it can be supported.

With this change, such a case is handled.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/cifsproto.h
fs/smb/client/connect.c
fs/smb/client/smb2pdu.c

index 0eb62cc..4a28cff 100644 (file)
@@ -132,6 +132,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct smb_hdr *in_buf,
                        struct smb_hdr *out_buf,
                        int *bytes_returned);
+
 void
 cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
                                      bool all_channels);
index 2f5be7d..c0b1f30 100644 (file)
@@ -128,6 +128,9 @@ static void smb2_query_server_interfaces(struct work_struct *work)
         */
        rc = SMB3_request_interfaces(0, tcon, false);
        if (rc) {
+               if (rc == -EOPNOTSUPP)
+                       return;
+
                cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
                                __func__, rc);
        }
index 0274ef6..288f220 100644 (file)
@@ -163,6 +163,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
        int rc = 0;
        struct nls_table *nls_codepage = NULL;
        struct cifs_ses *ses;
+       int xid;
 
        /*
         * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
@@ -307,17 +308,44 @@ skip_sess_setup:
                tcon->need_reopen_files = true;
 
        rc = cifs_tree_connect(0, tcon, nls_codepage);
-       mutex_unlock(&ses->session_mutex);
 
        cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
        if (rc) {
                /* If sess reconnected but tcon didn't, something strange ... */
+               mutex_unlock(&ses->session_mutex);
                cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
                goto out;
        }
 
+       if (!rc &&
+           (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
+               mutex_unlock(&ses->session_mutex);
+
+               /*
+                * query server network interfaces, in case they change
+                */
+               xid = get_xid();
+               rc = SMB3_request_interfaces(xid, tcon, false);
+               free_xid(xid);
+
+               if (rc)
+                       cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
+                                __func__, rc);
+
+               if (ses->chan_max > ses->chan_count &&
+                   !SERVER_IS_CHAN(server)) {
+                       if (ses->chan_count == 1)
+                               cifs_server_dbg(VFS, "supports multichannel now\n");
+
+                       cifs_try_adding_channels(ses);
+               }
+       } else {
+               mutex_unlock(&ses->session_mutex);
+       }
+
        if (smb2_command != SMB2_INTERNAL_CMD)
-               mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+               if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+                       cifs_put_tcp_session(server, false);
 
        atomic_inc(&tconInfoReconnectCount);
 out: