Commit 7ffbe655 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

cifs: Fix infinite loop when using hard mount option

For every request we send, whether it is SMB1 or SMB2+, we attempt to
reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying
out the request.

So, while server->tcpStatus != CifsNeedReconnect, we wait for the
reconnection to succeed on wait_event_interruptible_timeout(). If it
returns, that means that either the condition was evaluated to true, or
timeout elapsed, or it was interrupted by a signal.

Since we're not handling the case where the process woke up due to a
received signal (-ERESTARTSYS), the next call to
wait_event_interruptible_timeout() will _always_ fail and we end up
looping forever inside either cifs_reconnect_tcon() or smb2_reconnect().

Here's an example of how to trigger that:

$ mount.cifs //foo/share /mnt/test -o
username=foo,password=foo,vers=1.0,hard

(break connection to server before executing bellow cmd)
$ stat -f /mnt/test & sleep 140
[1] 2511

$ ps -aux -q 2511
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      2511  0.0  0.0  12892  1008 pts/0    S    12:24   0:00 stat -f
/mnt/test

$ kill -9 2511

(wait for a while; process is stuck in the kernel)
$ ps -aux -q 2511
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      2511 83.2  0.0  12892  1008 pts/0    R    12:24  30:01 stat -f
/mnt/test

By using 'hard' mount point means that cifs.ko will keep retrying
indefinitely, however we must allow the process to be killed otherwise
it would hang the system.
Signed-off-by: default avatarPaulo Alcantara <palcantara@suse.de>
Cc: stable@vger.kernel.org
Reviewed-by: default avatarAurelien Aptel <aaptel@suse.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent f46ecbd9
...@@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
* greater than cifs socket timeout which is 7 seconds * greater than cifs socket timeout which is 7 seconds
*/ */
while (server->tcpStatus == CifsNeedReconnect) { while (server->tcpStatus == CifsNeedReconnect) {
wait_event_interruptible_timeout(server->response_q, rc = wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ); (server->tcpStatus != CifsNeedReconnect),
10 * HZ);
if (rc < 0) {
cifs_dbg(FYI, "%s: aborting reconnect due to a received"
" signal by the process\n", __func__);
return -ERESTARTSYS;
}
/* are we still trying to reconnect? */ /* are we still trying to reconnect? */
if (server->tcpStatus != CifsNeedReconnect) if (server->tcpStatus != CifsNeedReconnect)
......
...@@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, ...@@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
static int static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
{ {
int rc = 0; int rc;
struct nls_table *nls_codepage; struct nls_table *nls_codepage;
struct cifs_ses *ses; struct cifs_ses *ses;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
...@@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
* for those three - in the calling routine. * for those three - in the calling routine.
*/ */
if (tcon == NULL) if (tcon == NULL)
return rc; return 0;
if (smb2_command == SMB2_TREE_CONNECT) if (smb2_command == SMB2_TREE_CONNECT)
return rc; return 0;
if (tcon->tidStatus == CifsExiting) { if (tcon->tidStatus == CifsExiting) {
/* /*
...@@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
return -EAGAIN; return -EAGAIN;
} }
wait_event_interruptible_timeout(server->response_q, rc = wait_event_interruptible_timeout(server->response_q,
(server->tcpStatus != CifsNeedReconnect), 10 * HZ); (server->tcpStatus != CifsNeedReconnect),
10 * HZ);
if (rc < 0) {
cifs_dbg(FYI, "%s: aborting reconnect due to a received"
" signal by the process\n", __func__);
return -ERESTARTSYS;
}
/* are we still trying to reconnect? */ /* are we still trying to reconnect? */
if (server->tcpStatus != CifsNeedReconnect) if (server->tcpStatus != CifsNeedReconnect)
...@@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
} }
if (!tcon->ses->need_reconnect && !tcon->need_reconnect) if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
return rc; return 0;
nls_codepage = load_nls_default(); nls_codepage = load_nls_default();
......
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