summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
authorShyam Prasad N <sprasad@microsoft.com>2021-07-19 17:37:52 +0000
committerSteve French <stfrench@microsoft.com>2022-01-07 20:09:22 -0600
commit73f9bfbe3d818bb52266d5c9f3ba57d97842ffe7 (patch)
treed2cd41b96bddfe592b5a6e9bfd1eb54223947657 /fs/cifs/smb2pdu.c
parent1913e1116a3174648cf2e6faedf29204f31cc438 (diff)
cifs: maintain a state machine for tcp/smb/tcon sessions
If functions like cifs_negotiate_protocol, cifs_setup_session, cifs_tree_connect are called in parallel on different channels, each of these will be execute the requests. This maybe unnecessary in some cases, and only the first caller may need to do the work. This is achieved by having more states for the tcp/smb/tcon session status fields. And tracking the state of reconnection based on the state machine. For example: for tcp connections: CifsNew/CifsNeedReconnect -> CifsNeedNegotiate -> CifsInNegotiate -> CifsNeedSessSetup -> CifsInSessSetup -> CifsGood for smb sessions: CifsNew/CifsNeedReconnect -> CifsGood for tcon: CifsNew/CifsNeedReconnect -> CifsInFilesInvalidate -> CifsNeedTcon -> CifsInTcon -> CifsGood If any channel reconnect sees that it's in the middle of transition to CifsGood, then they can skip the function. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c16
1 files changed, 5 insertions, 11 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 0c18b6f4f9eb..2725e62470e4 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -252,12 +252,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
nls_codepage = load_nls_default();
/*
- * need to prevent multiple threads trying to simultaneously reconnect
- * the same SMB session
- */
- mutex_lock(&ses->session_mutex);
-
- /*
* Recheck after acquire mutex. If another thread is negotiating
* and the server never sends an answer the socket will be closed
* and tcpStatus set to reconnect.
@@ -266,7 +260,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&cifs_tcp_ses_lock);
rc = -EHOSTDOWN;
- mutex_unlock(&ses->session_mutex);
goto out;
}
spin_unlock(&cifs_tcp_ses_lock);
@@ -284,23 +277,23 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
goto skip_sess_setup;
rc = -EHOSTDOWN;
- mutex_unlock(&ses->session_mutex);
goto out;
}
spin_unlock(&ses->chan_lock);
+ mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(0, ses, server);
if (!rc) {
rc = cifs_setup_session(0, ses, server, nls_codepage);
if ((rc == -EACCES) && !tcon->retry) {
- rc = -EHOSTDOWN;
mutex_unlock(&ses->session_mutex);
+ rc = -EHOSTDOWN;
goto failed;
}
}
if (rc || !tcon->need_reconnect) {
- mutex_unlock(&tcon->ses->session_mutex);
+ mutex_unlock(&ses->session_mutex);
goto out;
}
@@ -310,7 +303,7 @@ skip_sess_setup:
tcon->need_reopen_files = true;
rc = cifs_tree_connect(0, tcon, nls_codepage);
- mutex_unlock(&tcon->ses->session_mutex);
+ mutex_unlock(&ses->session_mutex);
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) {
@@ -1397,6 +1390,7 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
/* Even if one channel is active, session is in good state */
spin_lock(&cifs_tcp_ses_lock);
+ server->tcpStatus = CifsGood;
ses->status = CifsGood;
spin_unlock(&cifs_tcp_ses_lock);