summaryrefslogtreecommitdiff
path: root/fs/smb/client/sess.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/sess.c')
-rw-r--r--fs/smb/client/sess.c64
1 files changed, 56 insertions, 8 deletions
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index 4e4cc0cd5206..0bb2ac929061 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -297,6 +297,60 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
}
/*
+ * called when multichannel is disabled by the server.
+ * this always gets called from smb2_reconnect
+ * and cannot get called in parallel threads.
+ */
+void
+cifs_disable_secondary_channels(struct cifs_ses *ses)
+{
+ int i, chan_count;
+ struct TCP_Server_Info *server;
+ struct cifs_server_iface *iface;
+
+ spin_lock(&ses->chan_lock);
+ chan_count = ses->chan_count;
+ if (chan_count == 1)
+ goto done;
+
+ ses->chan_count = 1;
+
+ /* for all secondary channels reset the need reconnect bit */
+ ses->chans_need_reconnect &= 1;
+
+ for (i = 1; i < chan_count; i++) {
+ iface = ses->chans[i].iface;
+ server = ses->chans[i].server;
+
+ if (iface) {
+ spin_lock(&ses->iface_lock);
+ kref_put(&iface->refcount, release_iface);
+ ses->chans[i].iface = NULL;
+ iface->num_channels--;
+ if (iface->weight_fulfilled)
+ iface->weight_fulfilled--;
+ spin_unlock(&ses->iface_lock);
+ }
+
+ spin_unlock(&ses->chan_lock);
+ if (server && !server->terminate) {
+ server->terminate = true;
+ cifs_signal_cifsd_for_reconnect(server, false);
+ }
+ spin_lock(&ses->chan_lock);
+
+ if (server) {
+ ses->chans[i].server = NULL;
+ cifs_put_tcp_session(server, false);
+ }
+
+ }
+
+done:
+ spin_unlock(&ses->chan_lock);
+}
+
+/*
* update the iface for the channel if necessary.
* will return 0 when iface is updated, 1 if removed, 2 otherwise
* Must be called with chan_lock held.
@@ -595,14 +649,10 @@ cifs_ses_add_channel(struct cifs_ses *ses,
out:
if (rc && chan->server) {
- /*
- * we should avoid race with these delayed works before we
- * remove this channel
- */
- cancel_delayed_work_sync(&chan->server->echo);
- cancel_delayed_work_sync(&chan->server->reconnect);
+ cifs_put_tcp_session(chan->server, 0);
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--;
@@ -612,8 +662,6 @@ out:
*/
WARN_ON(ses->chan_count < 1);
spin_unlock(&ses->chan_lock);
-
- cifs_put_tcp_session(chan->server, 0);
}
kfree(ctx->UNC);