From 4a79c510d744b0b27cb574a1684ac2805fc5ed8c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 21 Aug 2003 04:27:54 -0700 Subject: If an RPC request has to be resent due to a timeout, it turns out that call_encode() may cause rq_rcv_buf to be reset despite the fact that a reply might be delivered at any moment by a softirq. This typically results in 'NFS: server cheating in read reply' error messages. Solve by adding rq_private_buf, which is updated atomically from rq_rcv_buf. --- include/linux/sunrpc/xprt.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b360e54f894a..2687ba7b9f13 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -98,6 +98,10 @@ struct rpc_rqst { struct list_head rq_list; + struct xdr_buf rq_private_buf; /* The receive buffer + * used in the softirq. + */ + /* * For authentication (e.g. auth_des) */ -- cgit v1.2.3 From df9e22888f4ad5dc4f06f7e339de0b12e59626d7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 21 Aug 2003 04:29:14 -0700 Subject: Back out some congestion control changes that were causing trouble, among other things, for the "soft" mount option. --- include/linux/sunrpc/timer.h | 16 ---------------- net/sunrpc/clnt.c | 4 ++-- net/sunrpc/timer.c | 2 -- net/sunrpc/xprt.c | 29 +++-------------------------- 4 files changed, 5 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h index ff6bc599eeec..f2f2ffc4f2cd 100644 --- a/include/linux/sunrpc/timer.h +++ b/include/linux/sunrpc/timer.h @@ -15,7 +15,6 @@ struct rpc_rtt { unsigned long timeo; /* default timeout value */ unsigned long srtt[5]; /* smoothed round trip time << 3 */ unsigned long sdrtt[5]; /* smoothed medium deviation of RTT */ - atomic_t ntimeouts; /* Global count of the number of timeouts */ }; @@ -23,19 +22,4 @@ extern void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo); extern void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m); extern unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer); -static inline void rpc_inc_timeo(struct rpc_rtt *rt) -{ - atomic_inc(&rt->ntimeouts); -} - -static inline void rpc_clear_timeo(struct rpc_rtt *rt) -{ - atomic_set(&rt->ntimeouts, 0); -} - -static inline int rpc_ntimeo(struct rpc_rtt *rt) -{ - return atomic_read(&rt->ntimeouts); -} - #endif /* _LINUX_SUNRPC_TIMER_H */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 83d8d6e2c775..36c1f394b007 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -744,14 +744,14 @@ call_timeout(struct rpc_task *task) dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid); if (clnt->cl_softrtry) { - if (clnt->cl_chatty && !task->tk_exit) + if (clnt->cl_chatty) printk(KERN_NOTICE "%s: server %s not responding, timed out\n", clnt->cl_protname, clnt->cl_server); rpc_exit(task, -EIO); return; } - if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) { + if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) { task->tk_flags |= RPC_CALL_MAJORSEEN; printk(KERN_NOTICE "%s: server %s not responding, still trying\n", clnt->cl_protname, clnt->cl_server); diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c index 6cd6f8a9a8db..bf32f588ecd8 100644 --- a/net/sunrpc/timer.c +++ b/net/sunrpc/timer.c @@ -41,8 +41,6 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo) rt->srtt[i] = init; rt->sdrtt[i] = RPC_RTO_INIT; } - - atomic_set(&rt->ntimeouts, 0); } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e572a821d793..7c8678157d09 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -585,7 +585,6 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) rpc_update_rtt(&clnt->cl_rtt, timer, (long)jiffies - req->rq_xtime); } - rpc_clear_timeo(&clnt->cl_rtt); } #ifdef RPC_PROFILE @@ -1051,21 +1050,6 @@ out: read_unlock(&sk->sk_callback_lock); } -/* - * Exponential backoff for UDP retries - */ -static inline int -xprt_expbackoff(struct rpc_task *task, struct rpc_rqst *req) -{ - int backoff; - - req->rq_ntimeo++; - backoff = min(rpc_ntimeo(&task->tk_client->cl_rtt), XPRT_MAX_BACKOFF); - if (req->rq_ntimeo < (1 << backoff)) - return 1; - return 0; -} - /* * RPC receive timeout handler. */ @@ -1079,14 +1063,7 @@ xprt_timer(struct rpc_task *task) if (req->rq_received) goto out; - if (!xprt->nocong) { - if (xprt_expbackoff(task, req)) { - rpc_add_timer(task, xprt_timer); - goto out_unlock; - } - rpc_inc_timeo(&task->tk_client->cl_rtt); - xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT); - } + xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT); req->rq_nresend++; dprintk("RPC: %4d xprt_timer (%s request)\n", @@ -1096,7 +1073,6 @@ xprt_timer(struct rpc_task *task) out: task->tk_timeout = 0; rpc_wake_up_task(task); -out_unlock: spin_unlock(&xprt->sock_lock); } @@ -1246,7 +1222,8 @@ xprt_transmit(struct rpc_task *task) if (!xprt->nocong) { task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt, task->tk_msg.rpc_proc->p_timer); - req->rq_ntimeo = 0; + task->tk_timeout <<= clnt->cl_timeout.to_retries + - req->rq_timeout.to_retries; if (task->tk_timeout > req->rq_timeout.to_maxval) task->tk_timeout = req->rq_timeout.to_maxval; } else -- cgit v1.2.3 From 5579cbd6894d83f81517c6b790c4f511f94e7976 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 21 Aug 2003 04:42:05 -0700 Subject: A request cannot be used as part of the RTO estimation if it gets resent since you don't know whether the server is replying to the first or the second transmission. However we're currently setting the cutoff point to be the timeout of the first transmission. This patch moves the cutoff point to the actual start of the retransmission. --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/xprt.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 2687ba7b9f13..e29381edeaea 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -115,7 +115,7 @@ struct rpc_rqst { unsigned long rq_xtime; /* when transmitted */ int rq_ntimeo; - int rq_nresend; + int rq_ntrans; }; #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 7c8678157d09..858337425e84 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -143,15 +143,17 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) if (!xprt->snd_task) { if (xprt->nocong || __xprt_get_cong(xprt, task)) { xprt->snd_task = task; - if (req) + if (req) { req->rq_bytes_sent = 0; + req->rq_ntrans++; + } } } if (xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full\n", task->tk_pid); task->tk_timeout = 0; task->tk_status = -EAGAIN; - if (req && req->rq_nresend) + if (req && req->rq_ntrans) rpc_sleep_on(&xprt->resend, task, NULL, NULL); else rpc_sleep_on(&xprt->sending, task, NULL, NULL); @@ -189,8 +191,10 @@ __xprt_lock_write_next(struct rpc_xprt *xprt) if (xprt->nocong || __xprt_get_cong(xprt, task)) { struct rpc_rqst *req = task->tk_rqstp; xprt->snd_task = task; - if (req) + if (req) { req->rq_bytes_sent = 0; + req->rq_ntrans++; + } } } @@ -578,7 +582,7 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) if (!xprt->nocong) { xprt_adjust_cwnd(xprt, copied); __xprt_put_cong(xprt, req); - if (!req->rq_nresend) { + if (req->rq_ntrans == 1) { unsigned timer = task->tk_msg.rpc_proc->p_timer; if (timer) @@ -1064,7 +1068,7 @@ xprt_timer(struct rpc_task *task) goto out; xprt_adjust_cwnd(req->rq_xprt, -ETIMEDOUT); - req->rq_nresend++; + __xprt_put_cong(xprt, req); dprintk("RPC: %4d xprt_timer (%s request)\n", task->tk_pid, req ? "pending" : "backlogged"); -- cgit v1.2.3