diff options
| author | Jeff Layton <jlayton@redhat.com> | 2010-09-03 12:00:49 -0400 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2010-09-08 17:22:30 -0400 |
| commit | 522bbe65a2415fabce618186fc7777eb4c502989 (patch) | |
| tree | 6eb66dac2892728d93e3220511c0ec7e35f40ce4 | |
| parent | 4266d9118f85b050a341992f0cfab40d392ef32c (diff) | |
cifs: prevent cifsd from exiting prematurely
When cifs_demultiplex_thread exits, it does a number of cleanup tasks
including freeing the TCP_Server_Info struct. Much of the existing code
in cifs assumes that when there is a cisfSesInfo struct, that it holds a
reference to a valid TCP_Server_Info struct.
We can never allow cifsd to exit when a cifsSesInfo struct is still
holding a reference to the server. The server pointers will then point
to freed memory.
This patch eliminates a couple of questionable conditions where it does
this. The idea here is to make an -EINTR return from kernel_recvmsg
behave the same way as -ERESTARTSYS or -EAGAIN. If the task was
signalled from cifs_put_tcp_session, then tcpStatus will be CifsExiting,
and the kernel_recvmsg call will return quickly.
There's also another condition where this can occur too -- if the
tcpStatus is still in CifsNew, then it will also exit if the server
closes the socket prematurely. I think we'll probably also need to fix
that situation, but that requires a bit more consideration.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
| -rw-r--r-- | fs/cifs/connect.c | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0ea52e9f9065..5f68b968faa7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -400,7 +400,9 @@ incomplete_rcv: | |||
| 400 | cFYI(1, "call to reconnect done"); | 400 | cFYI(1, "call to reconnect done"); |
| 401 | csocket = server->ssocket; | 401 | csocket = server->ssocket; |
| 402 | continue; | 402 | continue; |
| 403 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | 403 | } else if (length == -ERESTARTSYS || |
| 404 | length == -EAGAIN || | ||
| 405 | length == -EINTR) { | ||
| 404 | msleep(1); /* minimum sleep to prevent looping | 406 | msleep(1); /* minimum sleep to prevent looping |
| 405 | allowing socket to clear and app threads to set | 407 | allowing socket to clear and app threads to set |
| 406 | tcpStatus CifsNeedReconnect if server hung */ | 408 | tcpStatus CifsNeedReconnect if server hung */ |
| @@ -422,10 +424,6 @@ incomplete_rcv: | |||
| 422 | and so simply return error to mount */ | 424 | and so simply return error to mount */ |
| 423 | break; | 425 | break; |
| 424 | } | 426 | } |
| 425 | if (!try_to_freeze() && (length == -EINTR)) { | ||
| 426 | cFYI(1, "cifsd thread killed"); | ||
| 427 | break; | ||
| 428 | } | ||
| 429 | cFYI(1, "Reconnect after unexpected peek error %d", | 427 | cFYI(1, "Reconnect after unexpected peek error %d", |
| 430 | length); | 428 | length); |
| 431 | cifs_reconnect(server); | 429 | cifs_reconnect(server); |
| @@ -522,8 +520,7 @@ incomplete_rcv: | |||
| 522 | total_read += length) { | 520 | total_read += length) { |
| 523 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | 521 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, |
| 524 | pdu_length - total_read, 0); | 522 | pdu_length - total_read, 0); |
| 525 | if ((server->tcpStatus == CifsExiting) || | 523 | if (server->tcpStatus == CifsExiting) { |
| 526 | (length == -EINTR)) { | ||
| 527 | /* then will exit */ | 524 | /* then will exit */ |
| 528 | reconnect = 2; | 525 | reconnect = 2; |
| 529 | break; | 526 | break; |
| @@ -534,8 +531,9 @@ incomplete_rcv: | |||
| 534 | /* Now we will reread sock */ | 531 | /* Now we will reread sock */ |
| 535 | reconnect = 1; | 532 | reconnect = 1; |
| 536 | break; | 533 | break; |
| 537 | } else if ((length == -ERESTARTSYS) || | 534 | } else if (length == -ERESTARTSYS || |
| 538 | (length == -EAGAIN)) { | 535 | length == -EAGAIN || |
| 536 | length == -EINTR) { | ||
| 539 | msleep(1); /* minimum sleep to prevent looping, | 537 | msleep(1); /* minimum sleep to prevent looping, |
| 540 | allowing socket to clear and app | 538 | allowing socket to clear and app |
| 541 | threads to set tcpStatus | 539 | threads to set tcpStatus |
