diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-09-12 16:49:15 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-09-19 18:16:10 -0400 |
commit | a519fc7a70d1a918574bb826cc6905b87b482eb9 (patch) | |
tree | c83f9217abc40b69e10f6288e78285238bf6a9e1 /net/sunrpc/xprtsock.c | |
parent | c46de2263f42fb4bbde411b9126f471e9343cb22 (diff) |
SUNRPC: Ensure that the TCP socket is closed when in CLOSE_WAIT
Instead of doing a shutdown() call, we need to do an actual close().
Ditto if/when the server is sending us junk RPC headers.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Tested-by: Simon Kirby <sim@hostway.ca>
Cc: stable@vger.kernel.org
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a35b8e52e551..d1988cf8bf33 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -1025,6 +1025,16 @@ static void xs_udp_data_ready(struct sock *sk, int len) | |||
1025 | read_unlock_bh(&sk->sk_callback_lock); | 1025 | read_unlock_bh(&sk->sk_callback_lock); |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | /* | ||
1029 | * Helper function to force a TCP close if the server is sending | ||
1030 | * junk and/or it has put us in CLOSE_WAIT | ||
1031 | */ | ||
1032 | static void xs_tcp_force_close(struct rpc_xprt *xprt) | ||
1033 | { | ||
1034 | set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); | ||
1035 | xprt_force_disconnect(xprt); | ||
1036 | } | ||
1037 | |||
1028 | static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) | 1038 | static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) |
1029 | { | 1039 | { |
1030 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 1040 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -1051,7 +1061,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
1051 | /* Sanity check of the record length */ | 1061 | /* Sanity check of the record length */ |
1052 | if (unlikely(transport->tcp_reclen < 8)) { | 1062 | if (unlikely(transport->tcp_reclen < 8)) { |
1053 | dprintk("RPC: invalid TCP record fragment length\n"); | 1063 | dprintk("RPC: invalid TCP record fragment length\n"); |
1054 | xprt_force_disconnect(xprt); | 1064 | xs_tcp_force_close(xprt); |
1055 | return; | 1065 | return; |
1056 | } | 1066 | } |
1057 | dprintk("RPC: reading TCP record fragment of length %d\n", | 1067 | dprintk("RPC: reading TCP record fragment of length %d\n", |
@@ -1132,7 +1142,7 @@ static inline void xs_tcp_read_calldir(struct sock_xprt *transport, | |||
1132 | break; | 1142 | break; |
1133 | default: | 1143 | default: |
1134 | dprintk("RPC: invalid request message type\n"); | 1144 | dprintk("RPC: invalid request message type\n"); |
1135 | xprt_force_disconnect(&transport->xprt); | 1145 | xs_tcp_force_close(&transport->xprt); |
1136 | } | 1146 | } |
1137 | xs_tcp_check_fraghdr(transport); | 1147 | xs_tcp_check_fraghdr(transport); |
1138 | } | 1148 | } |
@@ -1455,6 +1465,8 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt) | |||
1455 | static void xs_sock_mark_closed(struct rpc_xprt *xprt) | 1465 | static void xs_sock_mark_closed(struct rpc_xprt *xprt) |
1456 | { | 1466 | { |
1457 | smp_mb__before_clear_bit(); | 1467 | smp_mb__before_clear_bit(); |
1468 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); | ||
1469 | clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state); | ||
1458 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | 1470 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); |
1459 | clear_bit(XPRT_CLOSING, &xprt->state); | 1471 | clear_bit(XPRT_CLOSING, &xprt->state); |
1460 | smp_mb__after_clear_bit(); | 1472 | smp_mb__after_clear_bit(); |
@@ -1512,8 +1524,8 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1512 | break; | 1524 | break; |
1513 | case TCP_CLOSE_WAIT: | 1525 | case TCP_CLOSE_WAIT: |
1514 | /* The server initiated a shutdown of the socket */ | 1526 | /* The server initiated a shutdown of the socket */ |
1515 | xprt_force_disconnect(xprt); | ||
1516 | xprt->connect_cookie++; | 1527 | xprt->connect_cookie++; |
1528 | xs_tcp_force_close(xprt); | ||
1517 | case TCP_CLOSING: | 1529 | case TCP_CLOSING: |
1518 | /* | 1530 | /* |
1519 | * If the server closed down the connection, make sure that | 1531 | * If the server closed down the connection, make sure that |
@@ -2199,8 +2211,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2199 | /* We're probably in TIME_WAIT. Get rid of existing socket, | 2211 | /* We're probably in TIME_WAIT. Get rid of existing socket, |
2200 | * and retry | 2212 | * and retry |
2201 | */ | 2213 | */ |
2202 | set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); | 2214 | xs_tcp_force_close(xprt); |
2203 | xprt_force_disconnect(xprt); | ||
2204 | break; | 2215 | break; |
2205 | case -ECONNREFUSED: | 2216 | case -ECONNREFUSED: |
2206 | case -ECONNRESET: | 2217 | case -ECONNRESET: |