* xs_close - close a socket
  * @xprt: transport
  *
+ * This is used when all requests are complete; ie, no DRC state remains
+ * on the server we want to save.
  */
 static void xs_close(struct rpc_xprt *xprt)
 {
        xprt_clear_connecting(xprt);
 }
 
+/*
+ * We need to preserve the port number so the reply cache on the server can
+ * find our cached RPC replies when we get around to reconnecting.
+ */
+static void xs_tcp_reuse_connection(struct rpc_xprt *xprt)
+{
+       int result;
+       struct socket *sock = xprt->sock;
+       struct sockaddr any;
+
+       dprintk("RPC:      disconnecting xprt %p to reuse port\n", xprt);
+
+       /*
+        * Disconnect the transport socket by doing a connect operation
+        * with AF_UNSPEC.  This should return immediately...
+        */
+       memset(&any, 0, sizeof(any));
+       any.sa_family = AF_UNSPEC;
+       result = sock->ops->connect(sock, &any, sizeof(any), 0);
+       if (result)
+               dprintk("RPC:      AF_UNSPEC connect return code %d\n",
+                               result);
+}
+
 /**
  * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
  * @args: RPC transport to connect
 
        dprintk("RPC:      xs_tcp_connect_worker for xprt %p\n", xprt);
 
-       /* Start by resetting any existing socket state */
-       xs_close(xprt);
-
-       if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-               dprintk("RPC:      can't create TCP transport socket (%d).\n", -err);
-               goto out;
-       }
+       if (!xprt->sock) {
+               /* start from scratch */
+               if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
+                       dprintk("RPC:      can't create TCP transport socket (%d).\n", -err);
+                       goto out;
+               }
 
-       if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) {
-               sock_release(sock);
-               goto out;
-       }
+               if (xprt->resvport && xs_bindresvport(xprt, sock) < 0) {
+                       sock_release(sock);
+                       goto out;
+               }
+       } else
+               /* "close" the socket, preserving the local port */
+               xs_tcp_reuse_connection(xprt);
 
        if (!xprt->inet) {
                struct sock *sk = sock->sk;
                sk->sk_data_ready = xs_tcp_data_ready;
                sk->sk_state_change = xs_tcp_state_change;
                sk->sk_write_space = xs_tcp_write_space;
-               tcp_sk(sk)->nonagle = 1;
+
+               /* socket options */
+               sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
+               sock_reset_flag(sk, SOCK_LINGER);
+               tcp_sk(sk)->linger2 = 0;
+               tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
 
                xprt_clear_connected(xprt);
 
                        case -EINPROGRESS:
                        case -EALREADY:
                                goto out_clear;
+                       case -ECONNREFUSED:
+                       case -ECONNRESET:
+                               /* retry with existing socket, after a delay */
+                               break;
+                       default:
+                               /* get rid of existing socket, and retry */
+                               xs_close(xprt);
+                               break;
                }
        }
 out: