Commit 6da1abab authored by Trond Myklebust's avatar Trond Myklebust

Following a suggestion by Jamie Lokier

RPC: Make "major" timeouts be of fixed length "timeo<<retrans"
     rather than counting the number of retransmissions. The
     clock starts at the first attempt to send each request.
                                                                                
RPC: Ensure that we "slow start" the RTT estimation after a
     major timeout has occurred.
parent 015d2aec
...@@ -69,8 +69,7 @@ extern unsigned int xprt_tcp_slot_table_entries; ...@@ -69,8 +69,7 @@ extern unsigned int xprt_tcp_slot_table_entries;
* This describes a timeout strategy * This describes a timeout strategy
*/ */
struct rpc_timeout { struct rpc_timeout {
unsigned long to_current, /* current timeout */ unsigned long to_initval, /* initial timeout */
to_initval, /* initial timeout */
to_maxval, /* max timeout */ to_maxval, /* max timeout */
to_increment; /* if !exponential */ to_increment; /* if !exponential */
unsigned int to_retries; /* max # of retries */ unsigned int to_retries; /* max # of retries */
...@@ -85,7 +84,6 @@ struct rpc_rqst { ...@@ -85,7 +84,6 @@ struct rpc_rqst {
* This is the user-visible part * This is the user-visible part
*/ */
struct rpc_xprt * rq_xprt; /* RPC client */ struct rpc_xprt * rq_xprt; /* RPC client */
struct rpc_timeout rq_timeout; /* timeout parms */
struct xdr_buf rq_snd_buf; /* send buffer */ struct xdr_buf rq_snd_buf; /* send buffer */
struct xdr_buf rq_rcv_buf; /* recv buffer */ struct xdr_buf rq_rcv_buf; /* recv buffer */
...@@ -103,6 +101,9 @@ struct rpc_rqst { ...@@ -103,6 +101,9 @@ struct rpc_rqst {
struct xdr_buf rq_private_buf; /* The receive buffer struct xdr_buf rq_private_buf; /* The receive buffer
* used in the softirq. * used in the softirq.
*/ */
unsigned long rq_majortimeo; /* major timeout alarm */
unsigned long rq_timeout; /* Current timeout value */
unsigned int rq_retries; /* # of retries */
/* /*
* For authentication (e.g. auth_des) * For authentication (e.g. auth_des)
*/ */
...@@ -115,7 +116,6 @@ struct rpc_rqst { ...@@ -115,7 +116,6 @@ struct rpc_rqst {
u32 rq_bytes_sent; /* Bytes we have sent */ u32 rq_bytes_sent; /* Bytes we have sent */
unsigned long rq_xtime; /* when transmitted */ unsigned long rq_xtime; /* when transmitted */
int rq_ntimeo;
int rq_ntrans; int rq_ntrans;
}; };
#define rq_svec rq_snd_buf.head #define rq_svec rq_snd_buf.head
...@@ -210,7 +210,7 @@ void xprt_reserve(struct rpc_task *); ...@@ -210,7 +210,7 @@ void xprt_reserve(struct rpc_task *);
int xprt_prepare_transmit(struct rpc_task *); int xprt_prepare_transmit(struct rpc_task *);
void xprt_transmit(struct rpc_task *); void xprt_transmit(struct rpc_task *);
void xprt_receive(struct rpc_task *); void xprt_receive(struct rpc_task *);
int xprt_adjust_timeout(struct rpc_timeout *); int xprt_adjust_timeout(struct rpc_rqst *req);
void xprt_release(struct rpc_task *); void xprt_release(struct rpc_task *);
void xprt_connect(struct rpc_task *); void xprt_connect(struct rpc_task *);
int xprt_clear_backlog(struct rpc_xprt *); int xprt_clear_backlog(struct rpc_xprt *);
......
...@@ -736,10 +736,8 @@ static int ...@@ -736,10 +736,8 @@ static int
gss_refresh(struct rpc_task *task) gss_refresh(struct rpc_task *task)
{ {
struct rpc_clnt *clnt = task->tk_client; struct rpc_clnt *clnt = task->tk_client;
struct rpc_xprt *xprt = task->tk_xprt;
struct rpc_cred *cred = task->tk_msg.rpc_cred; struct rpc_cred *cred = task->tk_msg.rpc_cred;
task->tk_timeout = xprt->timeout.to_current;
if (!gss_cred_is_uptodate_ctx(cred)) if (!gss_cred_is_uptodate_ctx(cred))
return gss_upcall(clnt, task, cred); return gss_upcall(clnt, task, cred);
return 0; return 0;
......
...@@ -788,13 +788,11 @@ static void ...@@ -788,13 +788,11 @@ static void
call_timeout(struct rpc_task *task) call_timeout(struct rpc_task *task)
{ {
struct rpc_clnt *clnt = task->tk_client; struct rpc_clnt *clnt = task->tk_client;
struct rpc_timeout *to = &task->tk_rqstp->rq_timeout;
if (xprt_adjust_timeout(to)) { if (xprt_adjust_timeout(task->tk_rqstp) == 0) {
dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid); dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid);
goto retry; goto retry;
} }
to->to_retries = clnt->cl_timeout.to_retries;
dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);
if (RPC_IS_SOFT(task)) { if (RPC_IS_SOFT(task)) {
......
...@@ -39,6 +39,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) ...@@ -39,6 +39,7 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
rt->srtt[i] = init; rt->srtt[i] = init;
rt->sdrtt[i] = RPC_RTO_INIT; rt->sdrtt[i] = RPC_RTO_INIT;
rt->ntimeouts[i] = 0;
} }
} }
......
...@@ -351,36 +351,58 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) ...@@ -351,36 +351,58 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result)
xprt->cwnd = cwnd; xprt->cwnd = cwnd;
} }
/*
* Reset the major timeout value
*/
static void xprt_reset_majortimeo(struct rpc_rqst *req)
{
struct rpc_timeout *to = &req->rq_xprt->timeout;
req->rq_majortimeo = req->rq_timeout;
if (to->to_exponential)
req->rq_majortimeo <<= to->to_retries;
else
req->rq_majortimeo += to->to_increment * to->to_retries;
if (req->rq_majortimeo > to->to_maxval || req->rq_majortimeo == 0)
req->rq_majortimeo = to->to_maxval;
req->rq_majortimeo += jiffies;
}
/* /*
* Adjust timeout values etc for next retransmit * Adjust timeout values etc for next retransmit
*/ */
int int xprt_adjust_timeout(struct rpc_rqst *req)
xprt_adjust_timeout(struct rpc_timeout *to)
{ {
if (to->to_retries > 0) { struct rpc_xprt *xprt = req->rq_xprt;
struct rpc_timeout *to = &xprt->timeout;
int status = 0;
if (time_before(jiffies, req->rq_majortimeo)) {
if (to->to_exponential) if (to->to_exponential)
to->to_current <<= 1; req->rq_timeout <<= 1;
else else
to->to_current += to->to_increment; req->rq_timeout += to->to_increment;
if (to->to_maxval && to->to_current >= to->to_maxval) if (to->to_maxval && req->rq_timeout >= to->to_maxval)
to->to_current = to->to_maxval; req->rq_timeout = to->to_maxval;
req->rq_retries++;
pprintk("RPC: %lu retrans\n", jiffies);
} else { } else {
if (to->to_exponential) req->rq_timeout = to->to_initval;
to->to_initval <<= 1; req->rq_retries = 0;
else xprt_reset_majortimeo(req);
to->to_initval += to->to_increment; /* Reset the RTT counters == "slow start" */
if (to->to_maxval && to->to_initval >= to->to_maxval) spin_lock_bh(&xprt->sock_lock);
to->to_initval = to->to_maxval; rpc_init_rtt(req->rq_task->tk_client->cl_rtt, to->to_initval);
to->to_current = to->to_initval; spin_unlock_bh(&xprt->sock_lock);
pprintk("RPC: %lu timeout\n", jiffies);
status = -ETIMEDOUT;
} }
if (!to->to_current) { if (req->rq_timeout == 0) {
printk(KERN_WARNING "xprt_adjust_timeout: to_current = 0!\n"); printk(KERN_WARNING "xprt_adjust_timeout: rq_timeout = 0!\n");
to->to_current = 5 * HZ; req->rq_timeout = 5 * HZ;
} }
pprintk("RPC: %lu %s\n", jiffies, return status;
to->to_retries? "retrans" : "timeout");
return to->to_retries-- > 0;
} }
/* /*
...@@ -1174,6 +1196,7 @@ xprt_transmit(struct rpc_task *task) ...@@ -1174,6 +1196,7 @@ xprt_transmit(struct rpc_task *task)
/* Add request to the receive list */ /* Add request to the receive list */
list_add_tail(&req->rq_list, &xprt->recv); list_add_tail(&req->rq_list, &xprt->recv);
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
xprt_reset_majortimeo(req);
} }
} else if (!req->rq_bytes_sent) } else if (!req->rq_bytes_sent)
return; return;
...@@ -1229,7 +1252,7 @@ xprt_transmit(struct rpc_task *task) ...@@ -1229,7 +1252,7 @@ xprt_transmit(struct rpc_task *task)
if (!xprt_connected(xprt)) if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
task->tk_timeout = req->rq_timeout.to_current; task->tk_timeout = req->rq_timeout;
rpc_sleep_on(&xprt->pending, task, NULL, NULL); rpc_sleep_on(&xprt->pending, task, NULL, NULL);
} }
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
...@@ -1256,13 +1279,11 @@ xprt_transmit(struct rpc_task *task) ...@@ -1256,13 +1279,11 @@ xprt_transmit(struct rpc_task *task)
if (!xprt->nocong) { if (!xprt->nocong) {
int timer = task->tk_msg.rpc_proc->p_timer; int timer = task->tk_msg.rpc_proc->p_timer;
task->tk_timeout = rpc_calc_rto(clnt->cl_rtt, timer); task->tk_timeout = rpc_calc_rto(clnt->cl_rtt, timer);
task->tk_timeout <<= rpc_ntimeo(clnt->cl_rtt, timer); task->tk_timeout <<= rpc_ntimeo(clnt->cl_rtt, timer) + req->rq_retries;
task->tk_timeout <<= clnt->cl_timeout.to_retries if (task->tk_timeout > xprt->timeout.to_maxval || task->tk_timeout == 0)
- req->rq_timeout.to_retries; task->tk_timeout = xprt->timeout.to_maxval;
if (task->tk_timeout > req->rq_timeout.to_maxval)
task->tk_timeout = req->rq_timeout.to_maxval;
} else } else
task->tk_timeout = req->rq_timeout.to_current; task->tk_timeout = req->rq_timeout;
/* Don't race with disconnect */ /* Don't race with disconnect */
if (!xprt_connected(xprt)) if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
...@@ -1332,7 +1353,7 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) ...@@ -1332,7 +1353,7 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
{ {
struct rpc_rqst *req = task->tk_rqstp; struct rpc_rqst *req = task->tk_rqstp;
req->rq_timeout = xprt->timeout; req->rq_timeout = xprt->timeout.to_initval;
req->rq_task = task; req->rq_task = task;
req->rq_xprt = xprt; req->rq_xprt = xprt;
req->rq_xid = xprt_alloc_xid(xprt); req->rq_xid = xprt_alloc_xid(xprt);
...@@ -1389,7 +1410,6 @@ xprt_default_timeout(struct rpc_timeout *to, int proto) ...@@ -1389,7 +1410,6 @@ xprt_default_timeout(struct rpc_timeout *to, int proto)
void void
xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr) xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr)
{ {
to->to_current =
to->to_initval = to->to_initval =
to->to_increment = incr; to->to_increment = incr;
to->to_maxval = incr * retr; to->to_maxval = incr * retr;
...@@ -1454,7 +1474,6 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) ...@@ -1454,7 +1474,6 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
/* Set timeout parameters */ /* Set timeout parameters */
if (to) { if (to) {
xprt->timeout = *to; xprt->timeout = *to;
xprt->timeout.to_current = to->to_initval;
} else } else
xprt_default_timeout(&xprt->timeout, xprt->prot); xprt_default_timeout(&xprt->timeout, xprt->prot);
......
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