Commit 4a79c510 authored by Trond Myklebust's avatar Trond Myklebust

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.
parent f3f324e7
...@@ -98,6 +98,10 @@ struct rpc_rqst { ...@@ -98,6 +98,10 @@ struct rpc_rqst {
struct list_head rq_list; struct list_head rq_list;
struct xdr_buf rq_private_buf; /* The receive buffer
* used in the softirq.
*/
/* /*
* For authentication (e.g. auth_des) * For authentication (e.g. auth_des)
*/ */
......
...@@ -797,6 +797,10 @@ call_decode(struct rpc_task *task) ...@@ -797,6 +797,10 @@ call_decode(struct rpc_task *task)
return; return;
} }
/* Check that the softirq receive buffer is valid */
WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
sizeof(req->rq_rcv_buf)) != 0);
/* Verify the RPC header */ /* Verify the RPC header */
if (!(p = call_verify(task))) { if (!(p = call_verify(task))) {
if (task->tk_action == NULL) if (task->tk_action == NULL)
......
...@@ -726,11 +726,11 @@ udp_data_ready(struct sock *sk, int len) ...@@ -726,11 +726,11 @@ udp_data_ready(struct sock *sk, int len)
dprintk("RPC: %4d received reply\n", task->tk_pid); dprintk("RPC: %4d received reply\n", task->tk_pid);
if ((copied = rovr->rq_rlen) > repsize) if ((copied = rovr->rq_private_buf.len) > repsize)
copied = repsize; copied = repsize;
/* Suck it into the iovec, verify checksum if not done by hw. */ /* Suck it into the iovec, verify checksum if not done by hw. */
if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb)) if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb))
goto out_unlock; goto out_unlock;
/* Something worked... */ /* Something worked... */
...@@ -853,7 +853,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) ...@@ -853,7 +853,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
return; return;
} }
rcvbuf = &req->rq_rcv_buf; rcvbuf = &req->rq_private_buf;
len = desc->count; len = desc->count;
if (len > xprt->tcp_reclen - xprt->tcp_offset) { if (len > xprt->tcp_reclen - xprt->tcp_offset) {
skb_reader_t my_desc; skb_reader_t my_desc;
...@@ -871,7 +871,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) ...@@ -871,7 +871,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
xprt->tcp_copied += len; xprt->tcp_copied += len;
xprt->tcp_offset += len; xprt->tcp_offset += len;
if (xprt->tcp_copied == req->rq_rlen) if (xprt->tcp_copied == req->rq_private_buf.len)
xprt->tcp_flags &= ~XPRT_COPY_DATA; xprt->tcp_flags &= ~XPRT_COPY_DATA;
else if (xprt->tcp_offset == xprt->tcp_reclen) { else if (xprt->tcp_offset == xprt->tcp_reclen) {
if (xprt->tcp_flags & XPRT_LAST_FRAG) if (xprt->tcp_flags & XPRT_LAST_FRAG)
...@@ -1130,11 +1130,6 @@ xprt_prepare_transmit(struct rpc_task *task) ...@@ -1130,11 +1130,6 @@ xprt_prepare_transmit(struct rpc_task *task)
err = -ENOTCONN; err = -ENOTCONN;
goto out_unlock; goto out_unlock;
} }
if (list_empty(&req->rq_list)) {
list_add_tail(&req->rq_list, &xprt->recv);
req->rq_received = 0;
}
out_unlock: out_unlock:
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
return err; return err;
...@@ -1159,6 +1154,20 @@ xprt_transmit(struct rpc_task *task) ...@@ -1159,6 +1154,20 @@ xprt_transmit(struct rpc_task *task)
*marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker)));
} }
smp_rmb();
if (!req->rq_received) {
if (list_empty(&req->rq_list)) {
spin_lock_bh(&xprt->sock_lock);
/* Update the softirq receive buffer */
memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
sizeof(req->rq_private_buf));
/* Add request to the receive list */
list_add_tail(&req->rq_list, &xprt->recv);
spin_unlock_bh(&xprt->sock_lock);
}
} else if (!req->rq_bytes_sent)
return;
/* Continue transmitting the packet/record. We must be careful /* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have * to cope with writespace callbacks arriving _after_ we have
* called xprt_sendmsg(). * called xprt_sendmsg().
......
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