[PATCH] RPC: separate xprt_timer implementations
Allow transports to hook the retransmit timer interrupt. Some transports calculate their congestion window here so that a retransmit timeout has immediate effect on the congestion window. Test-plan: Use WAN simulation to cause sporadic bursty packet loss. Look for significant regression in performance or client stability. Signed-off-by: Chuck Lever <cel@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
49e9a89086
commit
46c0ee8bc4
@ -137,6 +137,7 @@ struct rpc_xprt_ops {
|
|||||||
void (*connect)(struct rpc_task *task);
|
void (*connect)(struct rpc_task *task);
|
||||||
int (*send_request)(struct rpc_task *task);
|
int (*send_request)(struct rpc_task *task);
|
||||||
void (*set_retrans_timeout)(struct rpc_task *task);
|
void (*set_retrans_timeout)(struct rpc_task *task);
|
||||||
|
void (*timer)(struct rpc_task *task);
|
||||||
void (*close)(struct rpc_xprt *xprt);
|
void (*close)(struct rpc_xprt *xprt);
|
||||||
void (*destroy)(struct rpc_xprt *xprt);
|
void (*destroy)(struct rpc_xprt *xprt);
|
||||||
};
|
};
|
||||||
@ -257,6 +258,7 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task);
|
|||||||
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
|
void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status);
|
||||||
void xprt_wait_for_buffer_space(struct rpc_task *task);
|
void xprt_wait_for_buffer_space(struct rpc_task *task);
|
||||||
void xprt_write_space(struct rpc_xprt *xprt);
|
void xprt_write_space(struct rpc_xprt *xprt);
|
||||||
|
void xprt_adjust_cwnd(struct rpc_task *task, int result);
|
||||||
struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid);
|
struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid);
|
||||||
void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied);
|
void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied);
|
||||||
void xprt_disconnect(struct rpc_xprt *xprt);
|
void xprt_disconnect(struct rpc_xprt *xprt);
|
||||||
|
@ -289,16 +289,19 @@ __xprt_put_cong(struct rpc_xprt *xprt, struct rpc_rqst *req)
|
|||||||
__xprt_lock_write_next_cong(xprt);
|
__xprt_lock_write_next_cong(xprt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Adjust RPC congestion window
|
* xprt_adjust_cwnd - adjust transport congestion window
|
||||||
|
* @task: recently completed RPC request used to adjust window
|
||||||
|
* @result: result code of completed RPC request
|
||||||
|
*
|
||||||
* We use a time-smoothed congestion estimator to avoid heavy oscillation.
|
* We use a time-smoothed congestion estimator to avoid heavy oscillation.
|
||||||
*/
|
*/
|
||||||
static void
|
void xprt_adjust_cwnd(struct rpc_task *task, int result)
|
||||||
xprt_adjust_cwnd(struct rpc_xprt *xprt, int result)
|
|
||||||
{
|
{
|
||||||
unsigned long cwnd;
|
struct rpc_rqst *req = task->tk_rqstp;
|
||||||
|
struct rpc_xprt *xprt = task->tk_xprt;
|
||||||
|
unsigned long cwnd = xprt->cwnd;
|
||||||
|
|
||||||
cwnd = xprt->cwnd;
|
|
||||||
if (result >= 0 && cwnd <= xprt->cong) {
|
if (result >= 0 && cwnd <= xprt->cong) {
|
||||||
/* The (cwnd >> 1) term makes sure
|
/* The (cwnd >> 1) term makes sure
|
||||||
* the result gets rounded properly. */
|
* the result gets rounded properly. */
|
||||||
@ -314,6 +317,7 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result)
|
|||||||
dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n",
|
dprintk("RPC: cong %ld, cwnd was %ld, now %ld\n",
|
||||||
xprt->cong, xprt->cwnd, cwnd);
|
xprt->cong, xprt->cwnd, cwnd);
|
||||||
xprt->cwnd = cwnd;
|
xprt->cwnd = cwnd;
|
||||||
|
__xprt_put_cong(xprt, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,8 +606,7 @@ void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
|
|||||||
/* Adjust congestion window */
|
/* Adjust congestion window */
|
||||||
if (!xprt->nocong) {
|
if (!xprt->nocong) {
|
||||||
unsigned timer = task->tk_msg.rpc_proc->p_timer;
|
unsigned timer = task->tk_msg.rpc_proc->p_timer;
|
||||||
xprt_adjust_cwnd(xprt, copied);
|
xprt_adjust_cwnd(task, copied);
|
||||||
__xprt_put_cong(xprt, req);
|
|
||||||
if (timer) {
|
if (timer) {
|
||||||
if (req->rq_ntrans == 1)
|
if (req->rq_ntrans == 1)
|
||||||
rpc_update_rtt(clnt->cl_rtt, timer,
|
rpc_update_rtt(clnt->cl_rtt, timer,
|
||||||
@ -640,27 +643,19 @@ void xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void xprt_timer(struct rpc_task *task)
|
||||||
* RPC receive timeout handler.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
xprt_timer(struct rpc_task *task)
|
|
||||||
{
|
{
|
||||||
struct rpc_rqst *req = task->tk_rqstp;
|
struct rpc_rqst *req = task->tk_rqstp;
|
||||||
struct rpc_xprt *xprt = req->rq_xprt;
|
struct rpc_xprt *xprt = req->rq_xprt;
|
||||||
|
|
||||||
|
dprintk("RPC: %4d xprt_timer\n", task->tk_pid);
|
||||||
|
|
||||||
spin_lock(&xprt->transport_lock);
|
spin_lock(&xprt->transport_lock);
|
||||||
if (req->rq_received)
|
if (!req->rq_received) {
|
||||||
goto out;
|
if (xprt->ops->timer)
|
||||||
|
xprt->ops->timer(task);
|
||||||
xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT);
|
task->tk_status = -ETIMEDOUT;
|
||||||
__xprt_put_cong(xprt, req);
|
}
|
||||||
|
|
||||||
dprintk("RPC: %4d xprt_timer (%s request)\n",
|
|
||||||
task->tk_pid, req ? "pending" : "backlogged");
|
|
||||||
|
|
||||||
task->tk_status = -ETIMEDOUT;
|
|
||||||
out:
|
|
||||||
task->tk_timeout = 0;
|
task->tk_timeout = 0;
|
||||||
rpc_wake_up_task(task);
|
rpc_wake_up_task(task);
|
||||||
spin_unlock(&xprt->transport_lock);
|
spin_unlock(&xprt->transport_lock);
|
||||||
|
@ -860,6 +860,17 @@ static void xs_tcp_set_buffer_size(struct rpc_xprt *xprt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xs_udp_timer - called when a retransmit timeout occurs on a UDP transport
|
||||||
|
* @task: task that timed out
|
||||||
|
*
|
||||||
|
* Adjust the congestion window after a retransmit timeout has occurred.
|
||||||
|
*/
|
||||||
|
static void xs_udp_timer(struct rpc_task *task)
|
||||||
|
{
|
||||||
|
xprt_adjust_cwnd(task, -ETIMEDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
|
static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
|
||||||
{
|
{
|
||||||
struct sockaddr_in myaddr = {
|
struct sockaddr_in myaddr = {
|
||||||
@ -1050,6 +1061,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
|
|||||||
.connect = xs_connect,
|
.connect = xs_connect,
|
||||||
.send_request = xs_udp_send_request,
|
.send_request = xs_udp_send_request,
|
||||||
.set_retrans_timeout = xprt_set_retrans_timeout_rtt,
|
.set_retrans_timeout = xprt_set_retrans_timeout_rtt,
|
||||||
|
.timer = xs_udp_timer,
|
||||||
.close = xs_close,
|
.close = xs_close,
|
||||||
.destroy = xs_destroy,
|
.destroy = xs_destroy,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user