From 9b61a1796fbc4b0d513ea0feb1ac1d83f7ac2bfe Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 15 May 2020 12:27:06 -0400 Subject: [PATCH] Fixes for 4.4 Signed-off-by: Sasha Levin --- ...check-for-timeout-on-negotiate-stage.patch | 124 ++++++++++++++++++ ...ace-condition-with-cifs_echo_request.patch | 65 +++++++++ queue-4.4/series | 2 + 3 files changed, 191 insertions(+) create mode 100644 queue-4.4/cifs-check-for-timeout-on-negotiate-stage.patch create mode 100644 queue-4.4/cifs-fix-a-race-condition-with-cifs_echo_request.patch diff --git a/queue-4.4/cifs-check-for-timeout-on-negotiate-stage.patch b/queue-4.4/cifs-check-for-timeout-on-negotiate-stage.patch new file mode 100644 index 00000000000..4ffae40c36e --- /dev/null +++ b/queue-4.4/cifs-check-for-timeout-on-negotiate-stage.patch @@ -0,0 +1,124 @@ +From 57aa47dce67bc9657b9c6f069110336e5baad01e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Jul 2017 12:44:39 +0200 +Subject: cifs: Check for timeout on Negotiate stage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Samuel Cabrero + +[ Upstream commit 76e752701a8af4404bbd9c45723f7cbd6e4a251e ] + +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] + #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] + #5 [ffff880fbfdc1c80] cifs_reconnect_tcon at ffffffffa042f911 [cifs] + #6 [ffff880fbfdc1d20] smb_init at ffffffffa042faeb [cifs] + #7 [ffff880fbfdc1d60] CIFSSMBQFSInfo at ffffffffa0434eb0 [cifs] + .... + +Signed-off-by: Samuel Cabrero +Reviewed-by: Aurélien Aptel +Reviewed-by: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/cifssmb.c | 12 ++++++++++++ + fs/cifs/connect.c | 3 ++- + fs/cifs/smb2pdu.c | 12 ++++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + +diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c +index b9b8f19dce0e1..fa07f7cb85a51 100644 +--- a/fs/cifs/cifssmb.c ++++ b/fs/cifs/cifssmb.c +@@ -184,6 +184,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) + * reconnect the same SMB session + */ + mutex_lock(&ses->session_mutex); ++ ++ /* ++ * Recheck after acquire mutex. If another thread is negotiating ++ * and the server never sends an answer the socket will be closed ++ * and tcpStatus set to reconnect. ++ */ ++ if (server->tcpStatus == CifsNeedReconnect) { ++ rc = -EHOSTDOWN; ++ mutex_unlock(&ses->session_mutex); ++ goto out; ++ } ++ + rc = cifs_negotiate_protocol(0, ses); + if (rc == 0 && ses->need_reconnect) + rc = cifs_setup_session(0, ses, nls_codepage); +diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c +index c9793ce0d3368..7022750cae2fd 100644 +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -558,7 +558,8 @@ server_unresponsive(struct TCP_Server_Info *server) + * 65s kernel_recvmsg times out, and we see that we haven't gotten + * a response in >60s. + */ +- if (server->tcpStatus == CifsGood && ++ if ((server->tcpStatus == CifsGood || ++ server->tcpStatus == CifsNeedNegotiate) && + time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) { + cifs_dbg(VFS, "Server %s has not responded in %d seconds. Reconnecting...\n", + server->hostname, (2 * SMB_ECHO_INTERVAL) / HZ); +diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c +index d4472a4947581..4ffd5e177288e 100644 +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -249,6 +249,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) + * the same SMB session + */ + mutex_lock(&tcon->ses->session_mutex); ++ ++ /* ++ * Recheck after acquire mutex. If another thread is negotiating ++ * and the server never sends an answer the socket will be closed ++ * and tcpStatus set to reconnect. ++ */ ++ if (server->tcpStatus == CifsNeedReconnect) { ++ rc = -EHOSTDOWN; ++ mutex_unlock(&tcon->ses->session_mutex); ++ goto out; ++ } ++ + rc = cifs_negotiate_protocol(0, tcon->ses); + if (!rc && tcon->ses->need_reconnect) { + rc = cifs_setup_session(0, tcon->ses, nls_codepage); +-- +2.20.1 + diff --git a/queue-4.4/cifs-fix-a-race-condition-with-cifs_echo_request.patch b/queue-4.4/cifs-fix-a-race-condition-with-cifs_echo_request.patch new file mode 100644 index 00000000000..0b96a659a07 --- /dev/null +++ b/queue-4.4/cifs-fix-a-race-condition-with-cifs_echo_request.patch @@ -0,0 +1,65 @@ +From 1ad27ac06c8caf0acccccf25d12b6f3e9bbad601 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 6 Jul 2019 06:52:46 +1000 +Subject: cifs: Fix a race condition with cifs_echo_request + +From: Ronnie Sahlberg + +[ Upstream commit f2caf901c1b7ce65f9e6aef4217e3241039db768 ] + +There is a race condition with how we send (or supress and don't send) +smb echos that will cause the client to incorrectly think the +server is unresponsive and thus needs to be reconnected. + +Summary of the race condition: + 1) Daisy chaining scheduling creates a gap. + 2) If traffic comes unfortunate shortly after + the last echo, the planned echo is suppressed. + 3) Due to the gap, the next echo transmission is delayed + until after the timeout, which is set hard to twice + the echo interval. + +This is fixed by changing the timeouts from 2 to three times the echo interval. + +Detailed description of the bug: https://lutz.donnerhacke.de/eng/Blog/Groundhog-Day-with-SMB-remount + +Signed-off-by: Ronnie Sahlberg +Reviewed-by: Pavel Shilovsky +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/connect.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c +index 7022750cae2fd..21ddfd77966eb 100644 +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -548,10 +548,10 @@ static bool + server_unresponsive(struct TCP_Server_Info *server) + { + /* +- * We need to wait 2 echo intervals to make sure we handle such ++ * We need to wait 3 echo intervals to make sure we handle such + * situations right: + * 1s client sends a normal SMB request +- * 2s client gets a response ++ * 3s client gets a response + * 30s echo workqueue job pops, and decides we got a response recently + * and don't need to send another + * ... +@@ -560,9 +560,9 @@ server_unresponsive(struct TCP_Server_Info *server) + */ + if ((server->tcpStatus == CifsGood || + server->tcpStatus == CifsNeedNegotiate) && +- time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) { ++ time_after(jiffies, server->lstrp + 3 * SMB_ECHO_INTERVAL)) { + cifs_dbg(VFS, "Server %s has not responded in %d seconds. Reconnecting...\n", +- server->hostname, (2 * SMB_ECHO_INTERVAL) / HZ); ++ server->hostname, (3 * SMB_ECHO_INTERVAL) / HZ); + cifs_reconnect(server); + wake_up(&server->response_q); + return true; +-- +2.20.1 + diff --git a/queue-4.4/series b/queue-4.4/series index c0f037a4310..811d666f50d 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -38,3 +38,5 @@ net-moxa-fix-a-potential-double-free_irq.patch drop_monitor-work-around-gcc-10-stringop-overflow-wa.patch scsi-sg-add-sg_remove_request-in-sg_write.patch spi-spi-dw-add-lock-protect-dw_spi-rx-tx-to-prevent-concurrent-calls.patch +cifs-check-for-timeout-on-negotiate-stage.patch +cifs-fix-a-race-condition-with-cifs_echo_request.patch -- 2.47.3