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: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
@@ -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:
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user