Commit 632e3bdc authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Ensure client closes the socket when server initiates a close

 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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent eadb8c14
...@@ -254,6 +254,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to); ...@@ -254,6 +254,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
#define XPRT_LOCKED (0) #define XPRT_LOCKED (0)
#define XPRT_CONNECTED (1) #define XPRT_CONNECTED (1)
#define XPRT_CONNECTING (2) #define XPRT_CONNECTING (2)
#define XPRT_CLOSE_WAIT (3)
static inline void xprt_set_connected(struct rpc_xprt *xprt) static inline void xprt_set_connected(struct rpc_xprt *xprt)
{ {
......
...@@ -119,6 +119,17 @@ out_sleep: ...@@ -119,6 +119,17 @@ out_sleep:
return 0; 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 * xprt_reserve_xprt_cong - serialize write access to transports
* @task: task that is requesting access to the transport * @task: task that is requesting access to the transport
...@@ -145,9 +156,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task) ...@@ -145,9 +156,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task)
} }
return 1; return 1;
} }
smp_mb__before_clear_bit(); xprt_clear_locked(xprt);
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
out_sleep: out_sleep:
dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt); dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt);
task->tk_timeout = 0; task->tk_timeout = 0;
...@@ -193,9 +202,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) ...@@ -193,9 +202,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
return; return;
out_unlock: out_unlock:
smp_mb__before_clear_bit(); xprt_clear_locked(xprt);
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
} }
static void __xprt_lock_write_next_cong(struct rpc_xprt *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) ...@@ -222,9 +229,7 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
return; return;
} }
out_unlock: out_unlock:
smp_mb__before_clear_bit(); xprt_clear_locked(xprt);
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
} }
/** /**
...@@ -237,10 +242,7 @@ out_unlock: ...@@ -237,10 +242,7 @@ out_unlock:
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
{ {
if (xprt->snd_task == task) { if (xprt->snd_task == task) {
xprt->snd_task = NULL; xprt_clear_locked(xprt);
smp_mb__before_clear_bit();
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
__xprt_lock_write_next(xprt); __xprt_lock_write_next(xprt);
} }
} }
...@@ -256,10 +258,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) ...@@ -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) void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
{ {
if (xprt->snd_task == task) { if (xprt->snd_task == task) {
xprt->snd_task = NULL; xprt_clear_locked(xprt);
smp_mb__before_clear_bit();
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
__xprt_lock_write_next_cong(xprt); __xprt_lock_write_next_cong(xprt);
} }
} }
......
...@@ -425,7 +425,7 @@ static void xs_close(struct rpc_xprt *xprt) ...@@ -425,7 +425,7 @@ static void xs_close(struct rpc_xprt *xprt)
struct sock *sk = xprt->inet; struct sock *sk = xprt->inet;
if (!sk) if (!sk)
return; goto clear_close_wait;
dprintk("RPC: xs_close xprt %p\n", xprt); dprintk("RPC: xs_close xprt %p\n", xprt);
...@@ -442,6 +442,10 @@ static void xs_close(struct rpc_xprt *xprt) ...@@ -442,6 +442,10 @@ static void xs_close(struct rpc_xprt *xprt)
sk->sk_no_check = 0; sk->sk_no_check = 0;
sock_release(sock); 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) ...@@ -801,9 +805,13 @@ static void xs_tcp_state_change(struct sock *sk)
case TCP_SYN_SENT: case TCP_SYN_SENT:
case TCP_SYN_RECV: case TCP_SYN_RECV:
break; 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: default:
xprt_disconnect(xprt); xprt_disconnect(xprt);
break;
} }
out: out:
read_unlock(&sk->sk_callback_lock); read_unlock(&sk->sk_callback_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment