Commit f2caf901 authored by Ronnie Sahlberg's avatar Ronnie Sahlberg Committed by Steve French

cifs: Fix a race condition with cifs_echo_request

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-remountSigned-off-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 3e272579
...@@ -706,10 +706,10 @@ static bool ...@@ -706,10 +706,10 @@ static bool
server_unresponsive(struct TCP_Server_Info *server) 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: * situations right:
* 1s client sends a normal SMB request * 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 * 30s echo workqueue job pops, and decides we got a response recently
* and don't need to send another * and don't need to send another
* ... * ...
...@@ -718,9 +718,9 @@ server_unresponsive(struct TCP_Server_Info *server) ...@@ -718,9 +718,9 @@ server_unresponsive(struct TCP_Server_Info *server)
*/ */
if ((server->tcpStatus == CifsGood || if ((server->tcpStatus == CifsGood ||
server->tcpStatus == CifsNeedNegotiate) && server->tcpStatus == CifsNeedNegotiate) &&
time_after(jiffies, server->lstrp + 2 * server->echo_interval)) { time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n", cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
server->hostname, (2 * server->echo_interval) / HZ); server->hostname, (3 * server->echo_interval) / HZ);
cifs_reconnect(server); cifs_reconnect(server);
wake_up(&server->response_q); wake_up(&server->response_q);
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment