Skip to content

Commit 79d25ee

Browse files
scabrerogregkh
authored andcommitted
cifs: Check for timeout on Negotiate stage
[ Upstream commit 76e7527 ] Some servers seem to accept connections while booting but never send the SMBNegotiate response neither close the connection, causing all processes accessing the share hang on uninterruptible sleep state. This happens when the cifs_demultiplex_thread detects the server is unresponsive so releases the socket and start trying to reconnect. At some point, the faulty server will accept the socket and the TCP status will be set to NeedNegotiate. The first issued command accessing the share will start the negotiation (pid 5828 below), but the response will never arrive so other commands will be blocked waiting on the mutex (pid 55352). This patch checks for unresponsive servers also on the negotiate stage releasing the socket and reconnecting if the response is not received and checking again the tcp state when the mutex is acquired. PID: 55352 TASK: ffff880fd6cc02c0 CPU: 0 COMMAND: "ls" #0 [ffff880fd9add9f0] schedule at ffffffff81467eb9 #1 [ffff880fd9addb38] __mutex_lock_slowpath at ffffffff81468fe0 #2 [ffff880fd9addba8] mutex_lock at ffffffff81468b1a #3 [ffff880fd9addbc0] cifs_reconnect_tcon at ffffffffa042f905 [cifs] #4 [ffff880fd9addc60] smb_init at ffffffffa042faeb [cifs] khadas#5 [ffff880fd9addca0] CIFSSMBQPathInfo at ffffffffa04360b5 [cifs] .... Which is waiting a mutex owned by: PID: 5828 TASK: ffff880fcc55e400 CPU: 0 COMMAND: "xxxx" #0 [ffff880fbfdc19b8] schedule at ffffffff81467eb9 #1 [ffff880fbfdc1b00] wait_for_response at ffffffffa044f96d [cifs] #2 [ffff880fbfdc1b60] SendReceive at ffffffffa04505ce [cifs] #3 [ffff880fbfdc1bb0] CIFSSMBNegotiate at ffffffffa0438d79 [cifs] #4 [ffff880fbfdc1c50] cifs_negotiate_protocol at ffffffffa043b383 [cifs] khadas#5 [ffff880fbfdc1c80] cifs_reconnect_tcon at ffffffffa042f911 [cifs] khadas#6 [ffff880fbfdc1d20] smb_init at ffffffffa042faeb [cifs] khadas#7 [ffff880fbfdc1d60] CIFSSMBQFSInfo at ffffffffa0434eb0 [cifs] .... Signed-off-by: Samuel Cabrero <scabrero@suse.de> Reviewed-by: Aurélien Aptel <aaptel@suse.de> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <smfrench@gmail.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 1502915 commit 79d25ee

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

fs/cifs/cifssmb.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
184184
* reconnect the same SMB session
185185
*/
186186
mutex_lock(&ses->session_mutex);
187+
188+
/*
189+
* Recheck after acquire mutex. If another thread is negotiating
190+
* and the server never sends an answer the socket will be closed
191+
* and tcpStatus set to reconnect.
192+
*/
193+
if (server->tcpStatus == CifsNeedReconnect) {
194+
rc = -EHOSTDOWN;
195+
mutex_unlock(&ses->session_mutex);
196+
goto out;
197+
}
198+
187199
rc = cifs_negotiate_protocol(0, ses);
188200
if (rc == 0 && ses->need_reconnect)
189201
rc = cifs_setup_session(0, ses, nls_codepage);

fs/cifs/connect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ server_unresponsive(struct TCP_Server_Info *server)
561561
* 65s kernel_recvmsg times out, and we see that we haven't gotten
562562
* a response in >60s.
563563
*/
564-
if (server->tcpStatus == CifsGood &&
564+
if ((server->tcpStatus == CifsGood ||
565+
server->tcpStatus == CifsNeedNegotiate) &&
565566
time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
566567
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
567568
server->hostname, (2 * server->echo_interval) / HZ);

fs/cifs/smb2pdu.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
246246
* the same SMB session
247247
*/
248248
mutex_lock(&tcon->ses->session_mutex);
249+
250+
/*
251+
* Recheck after acquire mutex. If another thread is negotiating
252+
* and the server never sends an answer the socket will be closed
253+
* and tcpStatus set to reconnect.
254+
*/
255+
if (server->tcpStatus == CifsNeedReconnect) {
256+
rc = -EHOSTDOWN;
257+
mutex_unlock(&tcon->ses->session_mutex);
258+
goto out;
259+
}
260+
249261
rc = cifs_negotiate_protocol(0, tcon->ses);
250262
if (!rc && tcon->ses->need_reconnect) {
251263
rc = cifs_setup_session(0, tcon->ses, nls_codepage);

0 commit comments

Comments
 (0)