aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Cabrero <scabrero@suse.de>2017-07-11 06:44:39 -0400
committerSteve French <smfrench@gmail.com>2017-09-04 21:55:29 -0400
commit76e752701a8af4404bbd9c45723f7cbd6e4a251e (patch)
tree1f95432d6854efd181de388fd7a38c6235cf1dc0
parent5517554e43131f542e5f95c94c5cd9a1bb989fab (diff)
cifs: Check for timeout on Negotiate stage
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>
-rw-r--r--fs/cifs/cifssmb.c12
-rw-r--r--fs/cifs/connect.c3
-rw-r--r--fs/cifs/smb2pdu.c12
3 files changed, 26 insertions, 1 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 48455afefec8..7cbe28315971 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -178,6 +178,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
178 * reconnect the same SMB session 178 * reconnect the same SMB session
179 */ 179 */
180 mutex_lock(&ses->session_mutex); 180 mutex_lock(&ses->session_mutex);
181
182 /*
183 * Recheck after acquire mutex. If another thread is negotiating
184 * and the server never sends an answer the socket will be closed
185 * and tcpStatus set to reconnect.
186 */
187 if (server->tcpStatus == CifsNeedReconnect) {
188 rc = -EHOSTDOWN;
189 mutex_unlock(&ses->session_mutex);
190 goto out;
191 }
192
181 rc = cifs_negotiate_protocol(0, ses); 193 rc = cifs_negotiate_protocol(0, ses);
182 if (rc == 0 && ses->need_reconnect) 194 if (rc == 0 && ses->need_reconnect)
183 rc = cifs_setup_session(0, ses, nls_codepage); 195 rc = cifs_setup_session(0, ses, nls_codepage);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 83a8f52cd879..5aa2d278ca84 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -509,7 +509,8 @@ server_unresponsive(struct TCP_Server_Info *server)
509 * 65s kernel_recvmsg times out, and we see that we haven't gotten 509 * 65s kernel_recvmsg times out, and we see that we haven't gotten
510 * a response in >60s. 510 * a response in >60s.
511 */ 511 */
512 if (server->tcpStatus == CifsGood && 512 if ((server->tcpStatus == CifsGood ||
513 server->tcpStatus == CifsNeedNegotiate) &&
513 time_after(jiffies, server->lstrp + 2 * server->echo_interval)) { 514 time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
514 cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n", 515 cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
515 server->hostname, (2 * server->echo_interval) / HZ); 516 server->hostname, (2 * server->echo_interval) / HZ);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index d7595e735304..5531e7ee1210 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -238,6 +238,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
238 * the same SMB session 238 * the same SMB session
239 */ 239 */
240 mutex_lock(&tcon->ses->session_mutex); 240 mutex_lock(&tcon->ses->session_mutex);
241
242 /*
243 * Recheck after acquire mutex. If another thread is negotiating
244 * and the server never sends an answer the socket will be closed
245 * and tcpStatus set to reconnect.
246 */
247 if (server->tcpStatus == CifsNeedReconnect) {
248 rc = -EHOSTDOWN;
249 mutex_unlock(&tcon->ses->session_mutex);
250 goto out;
251 }
252
241 rc = cifs_negotiate_protocol(0, tcon->ses); 253 rc = cifs_negotiate_protocol(0, tcon->ses);
242 if (!rc && tcon->ses->need_reconnect) 254 if (!rc && tcon->ses->need_reconnect)
243 rc = cifs_setup_session(0, tcon->ses, nls_codepage); 255 rc = cifs_setup_session(0, tcon->ses, nls_codepage);