1 From 7ffbe65578b44fafdef577a360eb0583929f7c6e Mon Sep 17 00:00:00 2001
2 From: Paulo Alcantara <paulo@paulo.ac>
3 Date: Thu, 5 Jul 2018 13:46:34 -0300
4 Subject: cifs: Fix infinite loop when using hard mount option
6 From: Paulo Alcantara <paulo@paulo.ac>
8 commit 7ffbe65578b44fafdef577a360eb0583929f7c6e upstream.
10 For every request we send, whether it is SMB1 or SMB2+, we attempt to
11 reconnect tcon (cifs_reconnect_tcon or smb2_reconnect) before carrying
14 So, while server->tcpStatus != CifsNeedReconnect, we wait for the
15 reconnection to succeed on wait_event_interruptible_timeout(). If it
16 returns, that means that either the condition was evaluated to true, or
17 timeout elapsed, or it was interrupted by a signal.
19 Since we're not handling the case where the process woke up due to a
20 received signal (-ERESTARTSYS), the next call to
21 wait_event_interruptible_timeout() will _always_ fail and we end up
22 looping forever inside either cifs_reconnect_tcon() or smb2_reconnect().
24 Here's an example of how to trigger that:
26 $ mount.cifs //foo/share /mnt/test -o
27 username=foo,password=foo,vers=1.0,hard
29 (break connection to server before executing bellow cmd)
30 $ stat -f /mnt/test & sleep 140
34 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
35 root 2511 0.0 0.0 12892 1008 pts/0 S 12:24 0:00 stat -f
40 (wait for a while; process is stuck in the kernel)
42 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
43 root 2511 83.2 0.0 12892 1008 pts/0 R 12:24 30:01 stat -f
46 By using 'hard' mount point means that cifs.ko will keep retrying
47 indefinitely, however we must allow the process to be killed otherwise
48 it would hang the system.
50 Signed-off-by: Paulo Alcantara <palcantara@suse.de>
51 Cc: stable@vger.kernel.org
52 Reviewed-by: Aurelien Aptel <aaptel@suse.com>
53 Signed-off-by: Steve French <stfrench@microsoft.com>
54 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
57 fs/cifs/cifssmb.c | 10 ++++++++--
58 fs/cifs/smb2pdu.c | 18 ++++++++++++------
59 2 files changed, 20 insertions(+), 8 deletions(-)
61 --- a/fs/cifs/cifssmb.c
62 +++ b/fs/cifs/cifssmb.c
63 @@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tc
64 * greater than cifs socket timeout which is 7 seconds
66 while (server->tcpStatus == CifsNeedReconnect) {
67 - wait_event_interruptible_timeout(server->response_q,
68 - (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
69 + rc = wait_event_interruptible_timeout(server->response_q,
70 + (server->tcpStatus != CifsNeedReconnect),
73 + cifs_dbg(FYI, "%s: aborting reconnect due to a received"
74 + " signal by the process\n", __func__);
75 + return -ERESTARTSYS;
78 /* are we still trying to reconnect? */
79 if (server->tcpStatus != CifsNeedReconnect)
80 --- a/fs/cifs/smb2pdu.c
81 +++ b/fs/cifs/smb2pdu.c
82 @@ -158,7 +158,7 @@ out:
84 smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
88 struct nls_table *nls_codepage;
90 struct TCP_Server_Info *server;
91 @@ -169,10 +169,10 @@ smb2_reconnect(__le16 smb2_command, stru
92 * for those three - in the calling routine.
98 if (smb2_command == SMB2_TREE_CONNECT)
102 if (tcon->tidStatus == CifsExiting) {
104 @@ -215,8 +215,14 @@ smb2_reconnect(__le16 smb2_command, stru
108 - wait_event_interruptible_timeout(server->response_q,
109 - (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
110 + rc = wait_event_interruptible_timeout(server->response_q,
111 + (server->tcpStatus != CifsNeedReconnect),
114 + cifs_dbg(FYI, "%s: aborting reconnect due to a received"
115 + " signal by the process\n", __func__);
116 + return -ERESTARTSYS;
119 /* are we still trying to reconnect? */
120 if (server->tcpStatus != CifsNeedReconnect)
121 @@ -234,7 +240,7 @@ smb2_reconnect(__le16 smb2_command, stru
124 if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
128 nls_codepage = load_nls_default();