diff -u --recursive --new-file linux-2.6.0-test3-01-fix_rcv1/include/linux/sunrpc/xprt.h linux-2.6.0-test3-02-fix_rcv2/include/linux/sunrpc/xprt.h --- linux-2.6.0-test3-01-fix_rcv1/include/linux/sunrpc/xprt.h 2003-05-07 04:03:10.000000000 -0700 +++ linux-2.6.0-test3-02-fix_rcv2/include/linux/sunrpc/xprt.h 2003-08-19 13:06:52.000000000 -0700 @@ -98,6 +98,10 @@ struct list_head rq_list; + struct xdr_buf rq_private_buf; /* The receive buffer + * used in the softirq. + */ + /* * For authentication (e.g. auth_des) */ diff -u --recursive --new-file linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/clnt.c linux-2.6.0-test3-02-fix_rcv2/net/sunrpc/clnt.c --- linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/clnt.c 2003-08-20 12:50:14.000000000 -0700 +++ linux-2.6.0-test3-02-fix_rcv2/net/sunrpc/clnt.c 2003-08-20 12:50:43.000000000 -0700 @@ -798,6 +798,10 @@ 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 */ if (!(p = call_verify(task))) { if (task->tk_action == NULL) diff -u --recursive --new-file linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/xprt.c linux-2.6.0-test3-02-fix_rcv2/net/sunrpc/xprt.c --- linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/xprt.c 2003-08-19 13:06:41.000000000 -0700 +++ linux-2.6.0-test3-02-fix_rcv2/net/sunrpc/xprt.c 2003-08-19 13:06:52.000000000 -0700 @@ -726,11 +726,11 @@ 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; /* 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; /* Something worked... */ @@ -853,7 +853,7 @@ return; } - rcvbuf = &req->rq_rcv_buf; + rcvbuf = &req->rq_private_buf; len = desc->count; if (len > xprt->tcp_reclen - xprt->tcp_offset) { skb_reader_t my_desc; @@ -871,7 +871,7 @@ xprt->tcp_copied += 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; else if (xprt->tcp_offset == xprt->tcp_reclen) { if (xprt->tcp_flags & XPRT_LAST_FRAG) @@ -1130,11 +1130,6 @@ err = -ENOTCONN; goto out_unlock; } - - if (list_empty(&req->rq_list)) { - list_add_tail(&req->rq_list, &xprt->recv); - req->rq_received = 0; - } out_unlock: spin_unlock_bh(&xprt->sock_lock); return err; @@ -1159,6 +1154,20 @@ *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 * to cope with writespace callbacks arriving _after_ we have * called xprt_sendmsg().