aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-03-21 16:19:41 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-19 16:53:20 -0400
commit1e799b673c6b82b336ab13c48b5651d511ca3000 (patch)
tree9954155b2a9bdd72e49a078418ceea6c47bcc609 /net
parentc1d519312dcdf11532fed9f99a8ecc3547ffd9d6 (diff)
SUNRPC: Fix read ordering problems with req->rq_private_buf.len
We want to ensure that req->rq_private_buf.len is updated before req->rq_received, so that call_decode() doesn't use an old value for req->rq_rcv_buf.len. In 'call_decode()' itself, instead of using task->tk_status (which is set using req->rq_received) must use the actual value of req->rq_private_buf.len when deciding whether or not the received RPC reply is too short. Finally ensure that we set req->rq_rcv_buf.len to zero when retrying a request. A typo meant that we were resetting req->rq_private_buf.len in call_decode(), and then clobbering that value with the old rq_rcv_buf.len again in xprt_transmit(). Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/clnt.c26
-rw-r--r--net/sunrpc/xprt.c3
2 files changed, 15 insertions, 14 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 522b06849f86..3ae560464513 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1199,18 +1199,6 @@ call_decode(struct rpc_task *task)
1199 task->tk_flags &= ~RPC_CALL_MAJORSEEN; 1199 task->tk_flags &= ~RPC_CALL_MAJORSEEN;
1200 } 1200 }
1201 1201
1202 if (task->tk_status < 12) {
1203 if (!RPC_IS_SOFT(task)) {
1204 task->tk_action = call_bind;
1205 clnt->cl_stats->rpcretrans++;
1206 goto out_retry;
1207 }
1208 dprintk("RPC: %s: too small RPC reply size (%d bytes)\n",
1209 clnt->cl_protname, task->tk_status);
1210 task->tk_action = call_timeout;
1211 goto out_retry;
1212 }
1213
1214 /* 1202 /*
1215 * Ensure that we see all writes made by xprt_complete_rqst() 1203 * Ensure that we see all writes made by xprt_complete_rqst()
1216 * before it changed req->rq_received. 1204 * before it changed req->rq_received.
@@ -1222,6 +1210,18 @@ call_decode(struct rpc_task *task)
1222 WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, 1210 WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
1223 sizeof(req->rq_rcv_buf)) != 0); 1211 sizeof(req->rq_rcv_buf)) != 0);
1224 1212
1213 if (req->rq_rcv_buf.len < 12) {
1214 if (!RPC_IS_SOFT(task)) {
1215 task->tk_action = call_bind;
1216 clnt->cl_stats->rpcretrans++;
1217 goto out_retry;
1218 }
1219 dprintk("RPC: %s: too small RPC reply size (%d bytes)\n",
1220 clnt->cl_protname, task->tk_status);
1221 task->tk_action = call_timeout;
1222 goto out_retry;
1223 }
1224
1225 /* Verify the RPC header */ 1225 /* Verify the RPC header */
1226 p = call_verify(task); 1226 p = call_verify(task);
1227 if (IS_ERR(p)) { 1227 if (IS_ERR(p)) {
@@ -1243,7 +1243,7 @@ out_retry:
1243 task->tk_status = 0; 1243 task->tk_status = 0;
1244 /* Note: call_verify() may have freed the RPC slot */ 1244 /* Note: call_verify() may have freed the RPC slot */
1245 if (task->tk_rqstp == req) { 1245 if (task->tk_rqstp == req) {
1246 req->rq_received = req->rq_private_buf.len = 0; 1246 req->rq_received = req->rq_rcv_buf.len = 0;
1247 if (task->tk_client->cl_discrtry) 1247 if (task->tk_client->cl_discrtry)
1248 xprt_force_disconnect(task->tk_xprt); 1248 xprt_force_disconnect(task->tk_xprt);
1249 } 1249 }
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 3ba64f9f84ba..5110a4ea7fdf 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -757,9 +757,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
757 task->tk_rtt = (long)jiffies - req->rq_xtime; 757 task->tk_rtt = (long)jiffies - req->rq_xtime;
758 758
759 list_del_init(&req->rq_list); 759 list_del_init(&req->rq_list);
760 req->rq_private_buf.len = copied;
760 /* Ensure all writes are done before we update req->rq_received */ 761 /* Ensure all writes are done before we update req->rq_received */
761 smp_wmb(); 762 smp_wmb();
762 req->rq_received = req->rq_private_buf.len = copied; 763 req->rq_received = copied;
763 rpc_wake_up_queued_task(&xprt->pending, task); 764 rpc_wake_up_queued_task(&xprt->pending, task);
764} 765}
765EXPORT_SYMBOL_GPL(xprt_complete_rqst); 766EXPORT_SYMBOL_GPL(xprt_complete_rqst);