SUNRPC: Ensure we always close the socket after a connection shuts down
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 5 Feb 2018 15:20:06 +0000 (10:20 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 6 Feb 2018 00:23:28 +0000 (19:23 -0500)
Ensure that we release the TCP socket once it is in the TCP_CLOSE or
TCP_TIME_WAIT state (and only then) so that we don't confuse rkhunter
and its ilk.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
net/sunrpc/xprtsock.c

index 1880302..5d01081 100644 (file)
@@ -807,13 +807,6 @@ static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt)
        smp_mb__after_atomic();
 }
 
-static void xs_sock_mark_closed(struct rpc_xprt *xprt)
-{
-       xs_sock_reset_connection_flags(xprt);
-       /* Mark transport as closed and wake up all pending tasks */
-       xprt_disconnect_done(xprt);
-}
-
 /**
  * xs_error_report - callback to handle TCP socket state errors
  * @sk: socket
@@ -833,9 +826,6 @@ static void xs_error_report(struct sock *sk)
        err = -sk->sk_err;
        if (err == 0)
                goto out;
-       /* Is this a reset event? */
-       if (sk->sk_state == TCP_CLOSE)
-               xs_sock_mark_closed(xprt);
        dprintk("RPC:       xs_error_report client %p, error=%d...\n",
                        xprt, -err);
        trace_rpc_socket_error(xprt, sk->sk_socket, err);
@@ -1655,9 +1645,11 @@ static void xs_tcp_state_change(struct sock *sk)
                if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
                                        &transport->sock_state))
                        xprt_clear_connecting(xprt);
+               clear_bit(XPRT_CLOSING, &xprt->state);
                if (sk->sk_err)
                        xprt_wake_pending_tasks(xprt, -sk->sk_err);
-               xs_sock_mark_closed(xprt);
+               /* Trigger the socket release */
+               xs_tcp_force_close(xprt);
        }
  out:
        read_unlock_bh(&sk->sk_callback_lock);
@@ -2265,14 +2257,19 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct socket *sock = transport->sock;
+       int skst = transport->inet ? transport->inet->sk_state : TCP_CLOSE;
 
        if (sock == NULL)
                return;
-       if (xprt_connected(xprt)) {
+       switch (skst) {
+       default:
                kernel_sock_shutdown(sock, SHUT_RDWR);
                trace_rpc_socket_shutdown(xprt, sock);
-       } else
+               break;
+       case TCP_CLOSE:
+       case TCP_TIME_WAIT:
                xs_reset_transport(transport);
+       }
 }
 
 static void xs_tcp_set_socket_timeouts(struct rpc_xprt *xprt,