mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
cifs: avoid races in parallel reconnects in smb1
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) <pc@manguebit.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
179a88a855
commit
6cc041e90c
@ -71,7 +71,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||||||
int rc;
|
int rc;
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct TCP_Server_Info *server;
|
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
|
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
|
||||||
@ -99,6 +99,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||||||
}
|
}
|
||||||
spin_unlock(&tcon->tc_lock);
|
spin_unlock(&tcon->tc_lock);
|
||||||
|
|
||||||
|
again:
|
||||||
rc = cifs_wait_for_server_reconnect(server, tcon->retry);
|
rc = cifs_wait_for_server_reconnect(server, tcon->retry);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
@ -110,8 +111,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||||||
}
|
}
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
|
|
||||||
nls_codepage = load_nls_default();
|
mutex_lock(&ses->session_mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recheck after acquire mutex. If another thread is negotiating
|
* Recheck after acquire mutex. If another thread is negotiating
|
||||||
* and the server never sends an answer the socket will be closed
|
* and the server never sends an answer the socket will be closed
|
||||||
@ -120,29 +120,38 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
|||||||
spin_lock(&server->srv_lock);
|
spin_lock(&server->srv_lock);
|
||||||
if (server->tcpStatus == CifsNeedReconnect) {
|
if (server->tcpStatus == CifsNeedReconnect) {
|
||||||
spin_unlock(&server->srv_lock);
|
spin_unlock(&server->srv_lock);
|
||||||
|
mutex_lock(&ses->session_mutex);
|
||||||
|
|
||||||
|
if (tcon->retry)
|
||||||
|
goto again;
|
||||||
rc = -EHOSTDOWN;
|
rc = -EHOSTDOWN;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
spin_unlock(&server->srv_lock);
|
spin_unlock(&server->srv_lock);
|
||||||
|
|
||||||
|
nls_codepage = load_nls_default();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* need to prevent multiple threads trying to simultaneously
|
* need to prevent multiple threads trying to simultaneously
|
||||||
* reconnect the same SMB session
|
* reconnect the same SMB session
|
||||||
*/
|
*/
|
||||||
|
spin_lock(&ses->ses_lock);
|
||||||
spin_lock(&ses->chan_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->chan_lock);
|
||||||
|
spin_unlock(&ses->ses_lock);
|
||||||
|
|
||||||
/* this means that we only need to tree connect */
|
/* this means that we only need to tree connect */
|
||||||
if (tcon->need_reconnect)
|
if (tcon->need_reconnect)
|
||||||
goto skip_sess_setup;
|
goto skip_sess_setup;
|
||||||
|
|
||||||
rc = -EHOSTDOWN;
|
mutex_unlock(&ses->session_mutex);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
|
spin_unlock(&ses->ses_lock);
|
||||||
|
|
||||||
mutex_lock(&ses->session_mutex);
|
|
||||||
rc = cifs_negotiate_protocol(0, ses, server);
|
rc = cifs_negotiate_protocol(0, ses, server);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = cifs_setup_session(0, ses, server, nls_codepage);
|
rc = cifs_setup_session(0, ses, server, nls_codepage);
|
||||||
|
Loading…
Reference in New Issue
Block a user