aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorShyam Prasad N <sprasad@microsoft.com>2022-04-08 13:31:37 +0000
committerSteve French <stfrench@microsoft.com>2022-05-24 14:16:32 -0500
commit5752bf645f9dd7db600651f726eb04a97c9f597f (patch)
treef486c71eb05d7e37800e182d49325838ac0c2af3 /fs/cifs/connect.c
parentcifs: use new enum for ses_status (diff)
downloadlinux-dev-5752bf645f9dd7db600651f726eb04a97c9f597f.tar.xz
linux-dev-5752bf645f9dd7db600651f726eb04a97c9f597f.zip
cifs: avoid parallel session setups on same channel
After allowing channels to reconnect in parallel, it now becomes important to take care that multiple processes do not call negotiate/session setup in parallel on the same channel. This change avoids that by marking a channel as "in_reconnect". During session setup if the channel in question has this flag set, we return immediately. 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.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index df4bcc581559..199b076f7a64 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3995,17 +3995,27 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
int rc = -ENOSYS;
bool is_binding = false;
- /* only send once per connect */
- spin_lock(&ses->chan_lock);
- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
- spin_unlock(&ses->chan_lock);
spin_lock(&cifs_tcp_ses_lock);
- if (ses->ses_status == SES_EXITING) {
+ if (ses->ses_status != SES_GOOD &&
+ ses->ses_status != SES_NEW &&
+ ses->ses_status != SES_NEED_RECON) {
spin_unlock(&cifs_tcp_ses_lock);
return 0;
}
+ /* only send once per connect */
+ spin_lock(&ses->chan_lock);
+ if (CIFS_ALL_CHANS_GOOD(ses) ||
+ cifs_chan_in_reconnect(ses, server)) {
+ spin_unlock(&ses->chan_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ return 0;
+ }
+ is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+ cifs_chan_set_in_reconnect(ses, server);
+ spin_unlock(&ses->chan_lock);
+
if (!is_binding)
ses->ses_status = SES_IN_SETUP;
spin_unlock(&cifs_tcp_ses_lock);
@@ -4035,16 +4045,19 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
spin_lock(&cifs_tcp_ses_lock);
if (ses->ses_status == SES_IN_SETUP)
ses->ses_status = SES_NEED_RECON;
+ spin_lock(&ses->chan_lock);
+ cifs_chan_clear_in_reconnect(ses, server);
+ spin_unlock(&ses->chan_lock);
spin_unlock(&cifs_tcp_ses_lock);
} else {
spin_lock(&cifs_tcp_ses_lock);
if (ses->ses_status == SES_IN_SETUP)
ses->ses_status = SES_GOOD;
- spin_unlock(&cifs_tcp_ses_lock);
-
spin_lock(&ses->chan_lock);
+ cifs_chan_clear_in_reconnect(ses, server);
cifs_chan_clear_need_reconnect(ses, server);
spin_unlock(&ses->chan_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
}
return rc;