aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-09-03 12:00:49 -0400
committerSteve French <sfrench@us.ibm.com>2010-09-08 17:22:30 -0400
commit522bbe65a2415fabce618186fc7777eb4c502989 (patch)
tree6eb66dac2892728d93e3220511c0ec7e35f40ce4 /fs/cifs
parent4266d9118f85b050a341992f0cfab40d392ef32c (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>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/connect.c16
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