Skip to content

Commit 3c0070f

Browse files
Paulo Alcantarasmfrench
authored andcommitted
cifs: prevent data race in smb2_reconnect()
Make sure to get an up-to-date TCP_Server_Info::nr_targets value prior to waiting the server to be reconnected in smb2_reconnect(). It is set in cifs_tcp_ses_needs_reconnect() and protected by TCP_Server_Info::srv_lock. Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 77e3f33 commit 3c0070f

File tree

1 file changed

+64
-55
lines changed

1 file changed

+64
-55
lines changed

fs/cifs/smb2pdu.c

Lines changed: 64 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,73 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
139139
return;
140140
}
141141

142+
static int wait_for_server_reconnect(struct TCP_Server_Info *server,
143+
__le16 smb2_command, bool retry)
144+
{
145+
int timeout = 10;
146+
int rc;
147+
148+
spin_lock(&server->srv_lock);
149+
if (server->tcpStatus != CifsNeedReconnect) {
150+
spin_unlock(&server->srv_lock);
151+
return 0;
152+
}
153+
timeout *= server->nr_targets;
154+
spin_unlock(&server->srv_lock);
155+
156+
/*
157+
* Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
158+
* here since they are implicitly done when session drops.
159+
*/
160+
switch (smb2_command) {
161+
/*
162+
* BB Should we keep oplock break and add flush to exceptions?
163+
*/
164+
case SMB2_TREE_DISCONNECT:
165+
case SMB2_CANCEL:
166+
case SMB2_CLOSE:
167+
case SMB2_OPLOCK_BREAK:
168+
return -EAGAIN;
169+
}
170+
171+
/*
172+
* Give demultiplex thread up to 10 seconds to each target available for
173+
* reconnect -- should be greater than cifs socket timeout which is 7
174+
* seconds.
175+
*
176+
* On "soft" mounts we wait once. Hard mounts keep retrying until
177+
* process is killed or server comes back on-line.
178+
*/
179+
do {
180+
rc = wait_event_interruptible_timeout(server->response_q,
181+
(server->tcpStatus != CifsNeedReconnect),
182+
timeout * HZ);
183+
if (rc < 0) {
184+
cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n",
185+
__func__);
186+
return -ERESTARTSYS;
187+
}
188+
189+
/* are we still trying to reconnect? */
190+
spin_lock(&server->srv_lock);
191+
if (server->tcpStatus != CifsNeedReconnect) {
192+
spin_unlock(&server->srv_lock);
193+
return 0;
194+
}
195+
spin_unlock(&server->srv_lock);
196+
} while (retry);
197+
198+
cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__);
199+
return -EHOSTDOWN;
200+
}
201+
142202
static int
143203
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
144204
struct TCP_Server_Info *server)
145205
{
146206
int rc = 0;
147207
struct nls_table *nls_codepage;
148208
struct cifs_ses *ses;
149-
int retries;
150209

151210
/*
152211
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
@@ -184,61 +243,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
184243
(!tcon->ses->server) || !server)
185244
return -EIO;
186245

187-
ses = tcon->ses;
188-
retries = server->nr_targets;
189-
190-
/*
191-
* Give demultiplex thread up to 10 seconds to each target available for
192-
* reconnect -- should be greater than cifs socket timeout which is 7
193-
* seconds.
194-
*/
195-
while (server->tcpStatus == CifsNeedReconnect) {
196-
/*
197-
* Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
198-
* here since they are implicitly done when session drops.
199-
*/
200-
switch (smb2_command) {
201-
/*
202-
* BB Should we keep oplock break and add flush to exceptions?
203-
*/
204-
case SMB2_TREE_DISCONNECT:
205-
case SMB2_CANCEL:
206-
case SMB2_CLOSE:
207-
case SMB2_OPLOCK_BREAK:
208-
return -EAGAIN;
209-
}
210-
211-
rc = wait_event_interruptible_timeout(server->response_q,
212-
(server->tcpStatus != CifsNeedReconnect),
213-
10 * HZ);
214-
if (rc < 0) {
215-
cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
216-
__func__);
217-
return -ERESTARTSYS;
218-
}
219-
220-
/* are we still trying to reconnect? */
221-
spin_lock(&server->srv_lock);
222-
if (server->tcpStatus != CifsNeedReconnect) {
223-
spin_unlock(&server->srv_lock);
224-
break;
225-
}
226-
spin_unlock(&server->srv_lock);
227-
228-
if (retries && --retries)
229-
continue;
246+
rc = wait_for_server_reconnect(server, smb2_command, tcon->retry);
247+
if (rc)
248+
return rc;
230249

231-
/*
232-
* on "soft" mounts we wait once. Hard mounts keep
233-
* retrying until process is killed or server comes
234-
* back on-line
235-
*/
236-
if (!tcon->retry) {
237-
cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
238-
return -EHOSTDOWN;
239-
}
240-
retries = server->nr_targets;
241-
}
250+
ses = tcon->ses;
242251

243252
spin_lock(&ses->chan_lock);
244253
if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {

0 commit comments

Comments
 (0)