Skip to content

Commit

Permalink
cifs: avoid races in parallel reconnects in smb1
Browse files Browse the repository at this point in the history
Prevent multiple threads of doing negotiate, session setup and tree
connect by holding @ses->session_mutex in cifs_reconnect_tcon() while
reconnecting session and tcon.

Signed-off-by: Paulo Alcantara (SUSE) <[email protected]>
Reviewed-by: Ronnie Sahlberg <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
pcacjr authored and Steve French committed Mar 30, 2023
1 parent 179a88a commit 6cc041e
Showing 1 changed file with 15 additions and 6 deletions.
21 changes: 15 additions & 6 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
int rc;
struct cifs_ses *ses;
struct TCP_Server_Info *server;
struct nls_table *nls_codepage;
struct nls_table *nls_codepage = NULL;

/*
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
Expand Down Expand Up @@ -99,6 +99,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
}
spin_unlock(&tcon->tc_lock);

again:
rc = cifs_wait_for_server_reconnect(server, tcon->retry);
if (rc)
return rc;
Expand All @@ -110,8 +111,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
}
spin_unlock(&ses->chan_lock);

nls_codepage = load_nls_default();

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
Expand All @@ -120,29 +120,38 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&server->srv_lock);
mutex_lock(&ses->session_mutex);

if (tcon->retry)
goto again;
rc = -EHOSTDOWN;
goto out;
}
spin_unlock(&server->srv_lock);

nls_codepage = load_nls_default();

/*
* need to prevent multiple threads trying to simultaneously
* reconnect the same SMB session
*/
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
if (!cifs_chan_needs_reconnect(ses, server)) {
if (!cifs_chan_needs_reconnect(ses, server) &&
ses->ses_status == SES_GOOD) {
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);

/* this means that we only need to tree connect */
if (tcon->need_reconnect)
goto skip_sess_setup;

rc = -EHOSTDOWN;
mutex_unlock(&ses->session_mutex);
goto out;
}
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);

mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(0, ses, server);
if (!rc)
rc = cifs_setup_session(0, ses, server, nls_codepage);
Expand Down

0 comments on commit 6cc041e

Please sign in to comment.