diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 65 |
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 | */ |
366 | static void xs_close(struct rpc_xprt *xprt) | 368 | static 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 | */ | ||
958 | static 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 | } |
1017 | out: | 1058 | out: |