aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sunrpc/xprtsock.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 62c2e7caa345..88ac71fcd335 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -362,6 +362,8 @@ static int xs_tcp_send_request(struct rpc_task *task)
362 * xs_close - close a socket 362 * xs_close - close a socket
363 * @xprt: transport 363 * @xprt: transport
364 * 364 *
365 * This is used when all requests are complete; ie, no DRC state remains
366 * on the server we want to save.
365 */ 367 */
366static void xs_close(struct rpc_xprt *xprt) 368static void xs_close(struct rpc_xprt *xprt)
367{ 369{
@@ -949,6 +951,30 @@ out:
949 xprt_clear_connecting(xprt); 951 xprt_clear_connecting(xprt);
950} 952}
951 953
954/*
955 * We need to preserve the port number so the reply cache on the server can
956 * find our cached RPC replies when we get around to reconnecting.
957 */
958static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
959{
960 int result;
961 struct socket *sock = xprt->sock;
962 struct sockaddr any;
963
964 dprintk("RPC: disconnecting xprt %p to reuse port\n", xprt);
965
966 /*
967 * Disconnect the transport socket by doing a connect operation
968 * with AF_UNSPEC. This should return immediately...
969 */
970 memset(&any, 0, sizeof(any));
971 any.sa_family = AF_UNSPEC;
972 result = sock->ops->connect(sock, &any, sizeof(any), 0);
973 if (result)
974 dprintk("RPC: AF_UNSPEC connect return code %d\n",
975 result);
976}
977
952/** 978/**
953 * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint 979 * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
954 * @args: RPC transport to connect 980 * @args: RPC transport to connect
@@ -966,18 +992,20 @@ static void xs_tcp_connect_worker(void *args)
966 992
967 dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt); 993 dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt);
968 994
969 /* Start by resetting any existing socket state */ 995 if (!xprt->sock) {
970 xs_close(xprt); 996 /* start from scratch */
971 997 if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
972 if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { 998 dprintk("RPC: can't create TCP transport socket (%d).\n", -err);
973 dprintk("RPC: can't create TCP transport socket (%d).\n", -err); 999 goto out;
974 goto out; 1000 }
975 }
976 1001
977 if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) { 1002 if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) {
978 sock_release(sock); 1003 sock_release(sock);
979 goto out; 1004 goto out;
980 } 1005 }
1006 } else
1007 /* "close" the socket, preserving the local port */
1008 xs_tcp_reuse_connection(xprt);
981 1009
982 if (!xprt->inet) { 1010 if (!xprt->inet) {
983 struct sock *sk = sock->sk; 1011 struct sock *sk = sock->sk;
@@ -991,7 +1019,12 @@ static void xs_tcp_connect_worker(void *args)
991 sk->sk_data_ready = xs_tcp_data_ready; 1019 sk->sk_data_ready = xs_tcp_data_ready;
992 sk->sk_state_change = xs_tcp_state_change; 1020 sk->sk_state_change = xs_tcp_state_change;
993 sk->sk_write_space = xs_tcp_write_space; 1021 sk->sk_write_space = xs_tcp_write_space;
994 tcp_sk(sk)->nonagle = 1; 1022
1023 /* socket options */
1024 sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
1025 sock_reset_flag(sk, SOCK_LINGER);
1026 tcp_sk(sk)->linger2 = 0;
1027 tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
995 1028
996 xprt_clear_connected(xprt); 1029 xprt_clear_connected(xprt);
997 1030
@@ -1012,6 +1045,14 @@ static void xs_tcp_connect_worker(void *args)
1012 case -EINPROGRESS: 1045 case -EINPROGRESS:
1013 case -EALREADY: 1046 case -EALREADY:
1014 goto out_clear; 1047 goto out_clear;
1048 case -ECONNREFUSED:
1049 case -ECONNRESET:
1050 /* retry with existing socket, after a delay */
1051 break;
1052 default:
1053 /* get rid of existing socket, and retry */
1054 xs_close(xprt);
1055 break;
1015 } 1056 }
1016 } 1057 }
1017out: 1058out: