Skip to content

Commit 7643dbd

Browse files
Paulo AlcantaraSteve French
authored andcommitted
smb: client: don't retry IO on failed negprotos with soft mounts
If @server->tcpStatus is set to CifsNeedReconnect after acquiring @ses->session_mutex in smb2_reconnect() or cifs_reconnect_tcon(), it means that a concurrent thread failed to negotiate, in which case the server is no longer responding to any SMB requests, so there is no point making the caller retry the IO by returning -EAGAIN. Fix this by returning -EHOSTDOWN to the callers on soft mounts. Cc: David Howells <dhowells@redhat.com> Reported-by: Jay Shin <jaeshin@redhat.com> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 4701f33 commit 7643dbd

File tree

2 files changed

+69
-73
lines changed

2 files changed

+69
-73
lines changed

fs/smb/client/cifssmb.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,23 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
114114

115115
mutex_lock(&ses->session_mutex);
116116
/*
117-
* Recheck after acquire mutex. If another thread is negotiating
118-
* and the server never sends an answer the socket will be closed
119-
* and tcpStatus set to reconnect.
117+
* Handle the case where a concurrent thread failed to negotiate or
118+
* killed a channel.
120119
*/
121120
spin_lock(&server->srv_lock);
122-
if (server->tcpStatus == CifsNeedReconnect) {
121+
switch (server->tcpStatus) {
122+
case CifsExiting:
123123
spin_unlock(&server->srv_lock);
124124
mutex_unlock(&ses->session_mutex);
125-
126-
if (tcon->retry)
127-
goto again;
128-
rc = -EHOSTDOWN;
129-
goto out;
125+
return -EHOSTDOWN;
126+
case CifsNeedReconnect:
127+
spin_unlock(&server->srv_lock);
128+
mutex_unlock(&ses->session_mutex);
129+
if (!tcon->retry)
130+
return -EHOSTDOWN;
131+
goto again;
132+
default:
133+
break;
130134
}
131135
spin_unlock(&server->srv_lock);
132136

@@ -152,16 +156,20 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
152156
spin_unlock(&ses->ses_lock);
153157

154158
rc = cifs_negotiate_protocol(0, ses, server);
155-
if (!rc) {
156-
rc = cifs_setup_session(0, ses, server, ses->local_nls);
157-
if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) {
158-
/*
159-
* Try alternate password for next reconnect if an alternate
160-
* password is available.
161-
*/
162-
if (ses->password2)
163-
swap(ses->password2, ses->password);
164-
}
159+
if (rc) {
160+
mutex_unlock(&ses->session_mutex);
161+
if (!tcon->retry)
162+
return -EHOSTDOWN;
163+
goto again;
164+
}
165+
rc = cifs_setup_session(0, ses, server, ses->local_nls);
166+
if ((rc == -EACCES) || (rc == -EHOSTDOWN) || (rc == -EKEYREVOKED)) {
167+
/*
168+
* Try alternate password for next reconnect if an alternate
169+
* password is available.
170+
*/
171+
if (ses->password2)
172+
swap(ses->password2, ses->password);
165173
}
166174

167175
/* do we need to reconnect tcon? */

fs/smb/client/smb2pdu.c

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -300,32 +300,23 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
300300

301301
mutex_lock(&ses->session_mutex);
302302
/*
303-
* if this is called by delayed work, and the channel has been disabled
304-
* in parallel, the delayed work can continue to execute in parallel
305-
* there's a chance that this channel may not exist anymore
303+
* Handle the case where a concurrent thread failed to negotiate or
304+
* killed a channel.
306305
*/
307306
spin_lock(&server->srv_lock);
308-
if (server->tcpStatus == CifsExiting) {
307+
switch (server->tcpStatus) {
308+
case CifsExiting:
309309
spin_unlock(&server->srv_lock);
310310
mutex_unlock(&ses->session_mutex);
311-
rc = -EHOSTDOWN;
312-
goto out;
313-
}
314-
315-
/*
316-
* Recheck after acquire mutex. If another thread is negotiating
317-
* and the server never sends an answer the socket will be closed
318-
* and tcpStatus set to reconnect.
319-
*/
320-
if (server->tcpStatus == CifsNeedReconnect) {
311+
return -EHOSTDOWN;
312+
case CifsNeedReconnect:
321313
spin_unlock(&server->srv_lock);
322314
mutex_unlock(&ses->session_mutex);
323-
324-
if (tcon->retry)
325-
goto again;
326-
327-
rc = -EHOSTDOWN;
328-
goto out;
315+
if (!tcon->retry)
316+
return -EHOSTDOWN;
317+
goto again;
318+
default:
319+
break;
329320
}
330321
spin_unlock(&server->srv_lock);
331322

@@ -350,43 +341,41 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
350341
spin_unlock(&ses->ses_lock);
351342

352343
rc = cifs_negotiate_protocol(0, ses, server);
353-
if (!rc) {
354-
/*
355-
* if server stopped supporting multichannel
356-
* and the first channel reconnected, disable all the others.
357-
*/
358-
if (ses->chan_count > 1 &&
359-
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
360-
rc = cifs_chan_skip_or_disable(ses, server,
361-
from_reconnect);
362-
if (rc) {
363-
mutex_unlock(&ses->session_mutex);
364-
goto out;
365-
}
366-
}
367-
368-
rc = cifs_setup_session(0, ses, server, ses->local_nls);
369-
if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
370-
/*
371-
* Try alternate password for next reconnect (key rotation
372-
* could be enabled on the server e.g.) if an alternate
373-
* password is available and the current password is expired,
374-
* but do not swap on non pwd related errors like host down
375-
*/
376-
if (ses->password2)
377-
swap(ses->password2, ses->password);
378-
}
379-
380-
if ((rc == -EACCES) && !tcon->retry) {
381-
mutex_unlock(&ses->session_mutex);
382-
rc = -EHOSTDOWN;
383-
goto failed;
384-
} else if (rc) {
344+
if (rc) {
345+
mutex_unlock(&ses->session_mutex);
346+
if (!tcon->retry)
347+
return -EHOSTDOWN;
348+
goto again;
349+
}
350+
/*
351+
* if server stopped supporting multichannel
352+
* and the first channel reconnected, disable all the others.
353+
*/
354+
if (ses->chan_count > 1 &&
355+
!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
356+
rc = cifs_chan_skip_or_disable(ses, server,
357+
from_reconnect);
358+
if (rc) {
385359
mutex_unlock(&ses->session_mutex);
386360
goto out;
387361
}
388-
} else {
362+
}
363+
364+
rc = cifs_setup_session(0, ses, server, ses->local_nls);
365+
if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
366+
/*
367+
* Try alternate password for next reconnect (key rotation
368+
* could be enabled on the server e.g.) if an alternate
369+
* password is available and the current password is expired,
370+
* but do not swap on non pwd related errors like host down
371+
*/
372+
if (ses->password2)
373+
swap(ses->password2, ses->password);
374+
}
375+
if (rc) {
389376
mutex_unlock(&ses->session_mutex);
377+
if (rc == -EACCES && !tcon->retry)
378+
return -EHOSTDOWN;
390379
goto out;
391380
}
392381

@@ -490,7 +479,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
490479
case SMB2_IOCTL:
491480
rc = -EAGAIN;
492481
}
493-
failed:
494482
return rc;
495483
}
496484

0 commit comments

Comments
 (0)