diff options
author | Shyam Prasad N <sprasad@microsoft.com> | 2021-07-19 15:46:53 +0300 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2022-01-03 05:38:46 +0300 |
commit | d1a931ce2e3b7761d293ba8e0bde2b0180f456e9 (patch) | |
tree | 1de9314a0edcfd133b19d83dc9cddc6772a77c2d /fs/cifs/connect.c | |
parent | 0b66fa776c361824a700793e34f866bf479dac92 (diff) | |
download | linux-d1a931ce2e3b7761d293ba8e0bde2b0180f456e9.tar.xz |
cifs: track individual channel status using chans_need_reconnect
We needed a way to identify the channels under the smb session
which are in reconnect, so that the traffic to other channels
can continue. So I replaced the bool need_reconnect with
a bitmask identifying all the channels that need reconnection
(named chans_need_reconnect). When a channel needs reconnection,
the bit corresponding to the index of the server in ses->chans
is used to set this bitmask. Checking if no channels or all
the channels need reconnect then becomes very easy.
Also wrote some helper macros for checking and setting the bits.
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1060164b984a..fa80a23f9fcf 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -191,11 +191,23 @@ 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) { - ses->need_reconnect = true; + spin_lock(&ses->chan_lock); + if (cifs_chan_needs_reconnect(ses, server)) + goto next_session; + + cifs_chan_set_need_reconnect(ses, server); + + /* If all channels need reconnect, then tcon needs reconnect */ + if (!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) + goto next_session; + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) tcon->need_reconnect = true; if (ses->tcon_ipc) ses->tcon_ipc->need_reconnect = true; + +next_session: + spin_unlock(&ses->chan_lock); } spin_unlock(&cifs_tcp_ses_lock); @@ -1988,7 +2000,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ses->status); mutex_lock(&ses->session_mutex); - if (ses->need_reconnect) { + spin_lock(&ses->chan_lock); + if (cifs_chan_needs_reconnect(ses, server)) { + spin_unlock(&ses->chan_lock); cifs_dbg(FYI, "Session needs reconnect\n"); rc = cifs_negotiate_protocol(xid, ses); @@ -2009,7 +2023,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) free_xid(xid); return ERR_PTR(rc); } + spin_lock(&ses->chan_lock); } + spin_unlock(&ses->chan_lock); mutex_unlock(&ses->session_mutex); /* existing SMB ses has a server reference already */ @@ -2067,6 +2083,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ses->chans[0].server = server; ses->chan_count = 1; ses->chan_max = ctx->multichannel ? ctx->max_channels:1; + ses->chans_need_reconnect = 1; spin_unlock(&ses->chan_lock); rc = cifs_negotiate_protocol(xid, ses); @@ -2081,7 +2098,11 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) if (rc) goto get_ses_fail; - /* success, put it on the list and add it as first channel */ + /* + * success, put it on the list and add it as first channel + * note: the session becomes active soon after this. So you'll + * need to lock before changing something in the session. + */ spin_lock(&cifs_tcp_ses_lock); list_add(&ses->smb_ses_list, &server->smb_ses_list); spin_unlock(&cifs_tcp_ses_lock); @@ -2161,6 +2182,9 @@ cifs_put_tcon(struct cifs_tcon *tcon) /* tc_count can never go negative */ WARN_ON(tcon->tc_count < 0); + list_del_init(&tcon->tcon_list); + spin_unlock(&cifs_tcp_ses_lock); + if (tcon->use_witness) { int rc; @@ -2171,9 +2195,6 @@ cifs_put_tcon(struct cifs_tcon *tcon) } } - list_del_init(&tcon->tcon_list); - spin_unlock(&cifs_tcp_ses_lock); - xid = get_xid(); if (ses->server->ops->tree_disconnect) ses->server->ops->tree_disconnect(xid, tcon); |