Skip to content

Commit bda487a

Browse files
sprasad-microsoftsmfrench
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 73f9bfb commit bda487a

File tree

3 files changed

+6
-24
lines changed

3 files changed

+6
-24
lines changed

fs/cifs/connect.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,11 @@ static void
172172
cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
173173
bool mark_smb_session)
174174
{
175-
unsigned int num_sessions = 0;
175+
struct TCP_Server_Info *pserver;
176176
struct cifs_ses *ses;
177177
struct cifs_tcon *tcon;
178178
struct mid_q_entry *mid, *nmid;
179179
struct list_head retry_list;
180-
struct TCP_Server_Info *pserver;
181180

182181
server->maxBuf = 0;
183182
server->max_read = 0;
@@ -199,17 +198,13 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
199198
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
200199
goto next_session;
201200

202-
if (mark_smb_session)
203-
CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
204-
else
205-
cifs_chan_set_need_reconnect(ses, server);
201+
cifs_chan_set_need_reconnect(ses, server);
206202

207203
/* If all channels need reconnect, then tcon needs reconnect */
208204
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
209205
goto next_session;
210206

211207
ses->status = CifsNeedReconnect;
212-
num_sessions++;
213208

214209
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
215210
tcon->need_reconnect = true;
@@ -223,16 +218,13 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
223218
}
224219
spin_unlock(&cifs_tcp_ses_lock);
225220

226-
if (num_sessions == 0)
227-
return;
228221
/*
229222
* before reconnecting the tcp session, mark the smb session (uid)
230223
* and the tid bad so they are not used until reconnected
231224
*/
232-
cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
225+
cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect and tearing down socket\n",
233226
__func__);
234227
/* do not want to be sending data on a socket we are freeing */
235-
cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
236228
mutex_lock(&server->srv_mutex);
237229
if (server->ssocket) {
238230
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", server->ssocket->state,

fs/cifs/smb2pdu.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
276276
if (tcon->need_reconnect)
277277
goto skip_sess_setup;
278278

279-
rc = -EHOSTDOWN;
280279
goto out;
281280
}
282281
spin_unlock(&ses->chan_lock);
@@ -3858,7 +3857,7 @@ SMB2_echo(struct TCP_Server_Info *server)
38583857
.rq_nvec = 1 };
38593858
unsigned int total_len;
38603859

3861-
cifs_dbg(FYI, "In echo request\n");
3860+
cifs_dbg(FYI, "In echo request for conn_id %lld\n", server->conn_id);
38623861

38633862
spin_lock(&cifs_tcp_ses_lock);
38643863
if (server->tcpStatus == CifsNeedNegotiate) {

fs/cifs/transport.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,18 +1057,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
10571057
if (!ses)
10581058
return NULL;
10591059

1060-
spin_lock(&ses->chan_lock);
10611060
/* round robin */
1062-
pick_another:
1063-
if (ses->chan_count > 1 &&
1064-
!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
1065-
index = (uint)atomic_inc_return(&ses->chan_seq);
1066-
index %= ses->chan_count;
1067-
1068-
if (CIFS_CHAN_NEEDS_RECONNECT(ses, index))
1069-
goto pick_another;
1070-
}
1071-
spin_unlock(&ses->chan_lock);
1061+
index = (uint)atomic_inc_return(&ses->chan_seq);
1062+
index %= ses->chan_count;
10721063

10731064
return ses->chans[index].server;
10741065
}

0 commit comments

Comments
 (0)