diff options
author | Shyam Prasad N <sprasad@microsoft.com> | 2022-04-08 13:31:37 +0000 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2022-05-24 14:16:32 -0500 |
commit | 5752bf645f9dd7db600651f726eb04a97c9f597f (patch) | |
tree | f486c71eb05d7e37800e182d49325838ac0c2af3 /fs/cifs/connect.c | |
parent | dd3cd8709ed5f4ae8998e0cd44c05bd26bc879e8 (diff) | |
download | linux-5752bf645f9dd7db600651f726eb04a97c9f597f.tar.gz |
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.c | 27 |
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; |