SUNRPC: Ensure client closes the socket when server initiates a close
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 3 Jan 2006 08:55:55 +0000 (09:55 +0100)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 6 Jan 2006 19:58:57 +0000 (14:58 -0500)
 If the server decides to close the RPC socket, we currently don't actually
 respond until either another RPC call is scheduled, or until xprt_autoclose()
 gets called by the socket expiry timer (which may be up to 5 minutes
 later).

 This patch ensures that xprt_autoclose() is called much sooner if the
 server closes the socket.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/xprt.h
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index dd86012..6ef99b1 100644 (file)
@@ -254,6 +254,7 @@ int                 xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
 #define XPRT_LOCKED            (0)
 #define XPRT_CONNECTED         (1)
 #define XPRT_CONNECTING                (2)
+#define XPRT_CLOSE_WAIT                (3)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index 069a6cb..8bc0d5a 100644 (file)
@@ -119,6 +119,17 @@ out_sleep:
        return 0;
 }
 
+static void xprt_clear_locked(struct rpc_xprt *xprt)
+{
+       xprt->snd_task = NULL;
+       if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
+               smp_mb__before_clear_bit();
+               clear_bit(XPRT_LOCKED, &xprt->state);
+               smp_mb__after_clear_bit();
+       } else
+               schedule_work(&xprt->task_cleanup);
+}
+
 /*
  * xprt_reserve_xprt_cong - serialize write access to transports
  * @task: task that is requesting access to the transport
@@ -145,9 +156,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task)
                }
                return 1;
        }
-       smp_mb__before_clear_bit();
-       clear_bit(XPRT_LOCKED, &xprt->state);
-       smp_mb__after_clear_bit();
+       xprt_clear_locked(xprt);
 out_sleep:
        dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt);
        task->tk_timeout = 0;
@@ -193,9 +202,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
        return;
 
 out_unlock:
-       smp_mb__before_clear_bit();
-       clear_bit(XPRT_LOCKED, &xprt->state);
-       smp_mb__after_clear_bit();
+       xprt_clear_locked(xprt);
 }
 
 static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
@@ -222,9 +229,7 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
                return;
        }
 out_unlock:
-       smp_mb__before_clear_bit();
-       clear_bit(XPRT_LOCKED, &xprt->state);
-       smp_mb__after_clear_bit();
+       xprt_clear_locked(xprt);
 }
 
 /**
@@ -237,10 +242,7 @@ out_unlock:
 void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
 {
        if (xprt->snd_task == task) {
-               xprt->snd_task = NULL;
-               smp_mb__before_clear_bit();
-               clear_bit(XPRT_LOCKED, &xprt->state);
-               smp_mb__after_clear_bit();
+               xprt_clear_locked(xprt);
                __xprt_lock_write_next(xprt);
        }
 }
@@ -256,10 +258,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
 void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
 {
        if (xprt->snd_task == task) {
-               xprt->snd_task = NULL;
-               smp_mb__before_clear_bit();
-               clear_bit(XPRT_LOCKED, &xprt->state);
-               smp_mb__after_clear_bit();
+               xprt_clear_locked(xprt);
                __xprt_lock_write_next_cong(xprt);
        }
 }
index 3e88930..c458f8d 100644 (file)
@@ -425,7 +425,7 @@ static void xs_close(struct rpc_xprt *xprt)
        struct sock *sk = xprt->inet;
 
        if (!sk)
-               return;
+               goto clear_close_wait;
 
        dprintk("RPC:      xs_close xprt %p\n", xprt);
 
@@ -442,6 +442,10 @@ static void xs_close(struct rpc_xprt *xprt)
        sk->sk_no_check = 0;
 
        sock_release(sock);
+clear_close_wait:
+       smp_mb__before_clear_bit();
+       clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
+       smp_mb__after_clear_bit();
 }
 
 /**
@@ -801,9 +805,13 @@ static void xs_tcp_state_change(struct sock *sk)
        case TCP_SYN_SENT:
        case TCP_SYN_RECV:
                break;
+       case TCP_CLOSE_WAIT:
+               /* Try to schedule an autoclose RPC calls */
+               set_bit(XPRT_CLOSE_WAIT, &xprt->state);
+               if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
+                       schedule_work(&xprt->task_cleanup);
        default:
                xprt_disconnect(xprt);
-               break;
        }
  out:
        read_unlock(&sk->sk_callback_lock);