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.
Unified · Split
| @@ -157,8 +157,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) · 156 unmodified lines | |||
| 157 | * greater than cifs socket timeout which is 7 seconds | 157 | * greater than cifs socket timeout which is 7 seconds |
| 158 | */ | 158 | */ |
| 159 | while (server->tcpStatus == CifsNeedReconnect) { | 159 | while (server->tcpStatus == CifsNeedReconnect) { |
| 160 | wait_event_interruptible_timeout(server->response_q, | 160 | rc = wait_event_interruptible_timeout(server->response_q, |
| 161 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); | 161 | (server->tcpStatus != CifsNeedReconnect), |
| 162 | 10 * HZ); | ||
| 163 | if (rc < 0) { | ||
| 164 | cifs_dbg(FYI, "%s: aborting reconnect due to a received" | ||
| 165 | " signal by the process\n", __func__); | ||
| 166 | return -ERESTARTSYS; | ||
| 167 | } | ||
| 162 | 168 | ||
| 163 | /* are we still trying to reconnect? */ | 169 | /* are we still trying to reconnect? */ |
| 164 | if (server->tcpStatus != CifsNeedReconnect) | 170 | if (server->tcpStatus != CifsNeedReconnect) |
| @@ -155,7 +155,7 @@ out: · 154 unmodified lines | |||
| 155 | static int | 155 | static int |
| 156 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) | 156 | smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) |
| 157 | { | 157 | { |
| 158 | int rc = 0; | 158 | int rc; |
| 159 | struct nls_table *nls_codepage; | 159 | struct nls_table *nls_codepage; |
| 160 | struct cifs_ses *ses; | 160 | struct cifs_ses *ses; |
| 161 | struct TCP_Server_Info *server; | 161 | struct TCP_Server_Info *server; |
| @@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) · 4 unmodified lines | |||
| 166 | * for those three - in the calling routine. | 166 | * for those three - in the calling routine. |
| 167 | */ | 167 | */ |
| 168 | if (tcon == NULL) | 168 | if (tcon == NULL) |
| 169 | return rc; | 169 | return 0; |
| 170 | 170 | ||
| 171 | if (smb2_command == SMB2_TREE_CONNECT) | 171 | if (smb2_command == SMB2_TREE_CONNECT) |
| 172 | return rc; | 172 | return 0; |
| 173 | 173 | ||
| 174 | if (tcon->tidStatus == CifsExiting) { | 174 | if (tcon->tidStatus == CifsExiting) { |
| 175 | /* | 175 | /* |
| @@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) · 36 unmodified lines | |||
| 212 | return -EAGAIN; | 212 | return -EAGAIN; |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | wait_event_interruptible_timeout(server->response_q, | 215 | rc = wait_event_interruptible_timeout(server->response_q, |
| 216 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); | 216 | (server->tcpStatus != CifsNeedReconnect), |
| 217 | 10 * HZ); | ||
| 218 | if (rc < 0) { | ||
| 219 | cifs_dbg(FYI, "%s: aborting reconnect due to a received" | ||
| 220 | " signal by the process\n", __func__); | ||
| 221 | return -ERESTARTSYS; | ||
| 222 | } | ||
| 217 | 223 | ||
| 218 | /* are we still trying to reconnect? */ | 224 | /* are we still trying to reconnect? */ |
| 219 | if (server->tcpStatus != CifsNeedReconnect) | 225 | if (server->tcpStatus != CifsNeedReconnect) |
| @@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) · 11 unmodified lines | |||
| 231 | } | 237 | } |
| 232 | 238 | ||
| 233 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) | 239 | if (!tcon->ses->need_reconnect && !tcon->need_reconnect) |
| 234 | return rc; | 240 | return 0; |
| 235 | 241 | ||
| 236 | nls_codepage = load_nls_default(); | 242 | nls_codepage = load_nls_default(); |
| 237 | 243 | ||