aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorShyam Prasad N <sprasad@microsoft.com>2021-10-25 05:44:10 +0000
committerSteve French <stfrench@microsoft.com>2022-01-07 20:09:23 -0600
commitbda487ac4bebf871255cc6f23e16f702cea0ca7c (patch)
treec9002fe22f2e9294726411f82e012835ffef95ac /fs/cifs/connect.c
parentcifs: maintain a state machine for tcp/smb/tcon sessions (diff)
downloadlinux-dev-bda487ac4bebf871255cc6f23e16f702cea0ca7c.tar.xz
linux-dev-bda487ac4bebf871255cc6f23e16f702cea0ca7c.zip
cifs: avoid race during socket reconnect between send and recv
When a TCP connection gets reestablished by the sender in cifs_reconnect, There is a chance for race condition with demultiplex thread waiting in cifs_readv_from_socket on the old socket. It will now return -ECONNRESET. This condition is handled by comparing socket pointer before and after sock_recvmsg. If the socket pointer has changed, we should not call cifs_reconnect again, but instead retry with new socket. Also fixed another bug in my prev mchan commits. We should always reestablish session (even if binding) on a channel that needs reconnection. 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.c14
1 files changed, 3 insertions, 11 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a408187c7002..1dafaf7c4e5e 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -172,12 +172,11 @@ static void
cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
bool mark_smb_session)
{
- unsigned int num_sessions = 0;
+ struct TCP_Server_Info *pserver;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
struct mid_q_entry *mid, *nmid;
struct list_head retry_list;
- struct TCP_Server_Info *pserver;
server->maxBuf = 0;
server->max_read = 0;
@@ -199,17 +198,13 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
goto next_session;
- if (mark_smb_session)
- CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
- else
- cifs_chan_set_need_reconnect(ses, server);
+ cifs_chan_set_need_reconnect(ses, server);
/* If all channels need reconnect, then tcon needs reconnect */
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
goto next_session;
ses->status = CifsNeedReconnect;
- num_sessions++;
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
tcon->need_reconnect = true;
@@ -223,16 +218,13 @@ next_session:
}
spin_unlock(&cifs_tcp_ses_lock);
- if (num_sessions == 0)
- return;
/*
* before reconnecting the tcp session, mark the smb session (uid)
* and the tid bad so they are not used until reconnected
*/
- cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
+ cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect and tearing down socket\n",
__func__);
/* do not want to be sending data on a socket we are freeing */
- cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
mutex_lock(&server->srv_mutex);
if (server->ssocket) {
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", server->ssocket->state,