Commit 522bbe65 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French

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: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 4266d911
...@@ -400,7 +400,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -400,7 +400,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -422,10 +424,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -522,8 +520,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -534,8 +531,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment