--- /dev/null
+From 57aa47dce67bc9657b9c6f069110336e5baad01e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <scabrero@suse.de>
+
+[ 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 <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>
+---
+ 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
+
--- /dev/null
+From 1ad27ac06c8caf0acccccf25d12b6f3e9bbad601 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 6 Jul 2019 06:52:46 +1000
+Subject: cifs: Fix a race condition with cifs_echo_request
+
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+
+[ 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 <lsahlber@redhat.com>
+Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+