cifs: multichannel: try to rebind when reconnecting a channel
authorAurelien Aptel <aaptel@suse.com>
Fri, 24 Apr 2020 14:55:31 +0000 (16:55 +0200)
committerSteve French <stfrench@microsoft.com>
Thu, 4 Jun 2020 18:50:55 +0000 (13:50 -0500)
first steps in trying to make channels properly reconnect.

* add cifs_ses_find_chan() function to find the enclosing cifs_chan
  struct it belongs to
* while we have the session lock and are redoing negprot and
  sess.setup in smb2_reconnect() redo the binding of channels.

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifsproto.h
fs/cifs/sess.c
fs/cifs/smb2pdu.c

index a25a462..bd92070 100644 (file)
@@ -593,6 +593,8 @@ void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
 
 extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
                                unsigned int *len, unsigned int *offset);
+struct cifs_chan *
+cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
 int cifs_try_adding_channels(struct cifs_ses *ses);
 int cifs_ses_add_channel(struct cifs_ses *ses,
                                struct cifs_server_iface *iface);
index 1ffdd7d..5d05bd2 100644 (file)
@@ -150,6 +150,22 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
        return ses->chan_count - old_chan_count;
 }
 
+/*
+ * If server is a channel of ses, return the corresponding enclosing
+ * cifs_chan otherwise return NULL.
+ */
+struct cifs_chan *
+cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server)
+{
+       int i;
+
+       for (i = 0; i < ses->chan_count; i++) {
+               if (ses->chans[i].server == server)
+                       return &ses->chans[i];
+       }
+       return NULL;
+}
+
 int
 cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface)
 {
index 2497e0e..ded96b5 100644 (file)
@@ -375,15 +375,31 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
                goto out;
        }
 
+       /*
+        * If we are reconnecting an extra channel, bind
+        */
+       if (server->is_channel) {
+               ses->binding = true;
+               ses->binding_chan = cifs_ses_find_chan(ses, server);
+       }
+
        rc = cifs_negotiate_protocol(0, tcon->ses);
        if (!rc && tcon->ses->need_reconnect) {
                rc = cifs_setup_session(0, tcon->ses, nls_codepage);
                if ((rc == -EACCES) && !tcon->retry) {
                        rc = -EHOSTDOWN;
+                       ses->binding = false;
+                       ses->binding_chan = NULL;
                        mutex_unlock(&tcon->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);
                goto out;