diff options
| -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: |
