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>
This commit is contained in:
committed by
Steve French
parent
4266d9118f
commit
522bbe65a2
@@ -400,7 +400,9 @@ incomplete_rcv:
|
|||||||
cFYI(1, "call to reconnect done");
|
cFYI(1, "call to reconnect done");
|
||||||
csocket = server->ssocket;
|
csocket = server->ssocket;
|
||||||
continue;
|
continue;
|
||||||
} else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
|
} else if (length == -ERESTARTSYS ||
|
||||||
|
length == -EAGAIN ||
|
||||||
|
length == -EINTR) {
|
||||||
msleep(1); /* minimum sleep to prevent looping
|
msleep(1); /* minimum sleep to prevent looping
|
||||||
allowing socket to clear and app threads to set
|
allowing socket to clear and app threads to set
|
||||||
tcpStatus CifsNeedReconnect if server hung */
|
tcpStatus CifsNeedReconnect if server hung */
|
||||||
@@ -422,10 +424,6 @@ incomplete_rcv:
|
|||||||
and so simply return error to mount */
|
and so simply return error to mount */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!try_to_freeze() && (length == -EINTR)) {
|
|
||||||
cFYI(1, "cifsd thread killed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cFYI(1, "Reconnect after unexpected peek error %d",
|
cFYI(1, "Reconnect after unexpected peek error %d",
|
||||||
length);
|
length);
|
||||||
cifs_reconnect(server);
|
cifs_reconnect(server);
|
||||||
@@ -522,8 +520,7 @@ incomplete_rcv:
|
|||||||
total_read += length) {
|
total_read += length) {
|
||||||
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
|
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
|
||||||
pdu_length - total_read, 0);
|
pdu_length - total_read, 0);
|
||||||
if ((server->tcpStatus == CifsExiting) ||
|
if (server->tcpStatus == CifsExiting) {
|
||||||
(length == -EINTR)) {
|
|
||||||
/* then will exit */
|
/* then will exit */
|
||||||
reconnect = 2;
|
reconnect = 2;
|
||||||
break;
|
break;
|
||||||
@@ -534,8 +531,9 @@ incomplete_rcv:
|
|||||||
/* Now we will reread sock */
|
/* Now we will reread sock */
|
||||||
reconnect = 1;
|
reconnect = 1;
|
||||||
break;
|
break;
|
||||||
} else if ((length == -ERESTARTSYS) ||
|
} else if (length == -ERESTARTSYS ||
|
||||||
(length == -EAGAIN)) {
|
length == -EAGAIN ||
|
||||||
|
length == -EINTR) {
|
||||||
msleep(1); /* minimum sleep to prevent looping,
|
msleep(1); /* minimum sleep to prevent looping,
|
||||||
allowing socket to clear and app
|
allowing socket to clear and app
|
||||||
threads to set tcpStatus
|
threads to set tcpStatus
|
||||||
|
Reference in New Issue
Block a user