]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Fix RPC over TCP 'connect' code
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Sat, 4 May 2002 04:28:55 +0000 (21:28 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sat, 4 May 2002 04:28:55 +0000 (21:28 -0700)
xprt.c:
  Fix the RPC over TCP socket reconnect code.

Cheers,
  Trond

net/sunrpc/xprt.c

index 7c58a3ed7c4a52d27adbd9a7cb56cbb453a9c736..2ce434437168a637499286494ebfa30e4b21a1b6 100644 (file)
@@ -399,7 +399,7 @@ xprt_reconnect(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
        struct socket   *sock = xprt->sock;
-       struct sock     *inet = xprt->inet;
+       struct sock     *inet;
        int             status;
 
        dprintk("RPC: %4d xprt_reconnect %p connected %d\n",
@@ -420,8 +420,10 @@ xprt_reconnect(struct rpc_task *task)
        if (xprt_connected(xprt))
                goto out_write;
 
+       if (sock && sock->state != SS_UNCONNECTED)
+               xprt_close(xprt);
        status = -ENOTCONN;
-       if (!inet) {
+       if (!(inet = xprt->inet)) {
                /* Create an unconnected socket */
                if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout)))
                        goto defer;
@@ -429,14 +431,6 @@ xprt_reconnect(struct rpc_task *task)
                inet = sock->sk;
        }
 
-       xprt_disconnect(xprt);
-
-       /* Reset TCP record info */
-       xprt->tcp_offset = 0;
-       xprt->tcp_reclen = 0;
-       xprt->tcp_copied = 0;
-       xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
-
        /* Now connect it asynchronously. */
        dprintk("RPC: %4d connecting new socket\n", task->tk_pid);
        status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
@@ -459,17 +453,21 @@ xprt_reconnect(struct rpc_task *task)
                        goto defer;
                }
 
+               /* Protect against TCP socket state changes */
+               lock_sock(inet);
                dprintk("RPC: %4d connect status %d connected %d\n",
                                task->tk_pid, status, xprt_connected(xprt));
 
-               spin_lock_bh(&xprt->sock_lock);
-               if (!xprt_connected(xprt)) {
+               if (inet->state != TCP_ESTABLISHED) {
                        task->tk_timeout = xprt->timeout.to_maxval;
+                       /* if the socket is already closing, delay 5 secs */
+                       if ((1<<inet->state) & ~(TCP_SYN_SENT|TCP_SYN_RECV))
+                               task->tk_timeout = 5*HZ;
                        rpc_sleep_on(&xprt->sending, task, xprt_reconn_status, NULL);
-                       spin_unlock_bh(&xprt->sock_lock);
+                       release_sock(inet);
                        return;
                }
-               spin_unlock_bh(&xprt->sock_lock);
+               release_sock(inet);
        }
 defer:
        if (status < 0) {
@@ -917,6 +915,13 @@ tcp_state_change(struct sock *sk)
        case TCP_ESTABLISHED:
                if (xprt_test_and_set_connected(xprt))
                        break;
+
+               /* Reset TCP record info */
+               xprt->tcp_offset = 0;
+               xprt->tcp_reclen = 0;
+               xprt->tcp_copied = 0;
+               xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
+
                spin_lock(&xprt->sock_lock);
                if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
                        rpc_wake_up_task(xprt->snd_task);