diff -u --recursive --new-file linux-2.6.0-test3/net/sunrpc/clnt.c linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/clnt.c --- linux-2.6.0-test3/net/sunrpc/clnt.c 2003-07-15 17:02:31.000000000 -0700 +++ linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/clnt.c 2003-08-20 12:50:14.000000000 -0700 @@ -659,7 +659,7 @@ if (task->tk_status < 0) return; task->tk_status = xprt_prepare_transmit(task); - if (task->tk_status < 0) + if (task->tk_status != 0) return; /* Encode here so that rpcsec_gss can use correct sequence number. */ if (!task->tk_rqstp->rq_bytes_sent) @@ -685,7 +685,8 @@ struct rpc_rqst *req = task->tk_rqstp; int status; - if (req->rq_received != 0) + smp_rmb(); + if (req->rq_received > 0 && !req->rq_bytes_sent) task->tk_status = req->rq_received; dprintk("RPC: %4d call_status (status %d)\n", @@ -787,19 +788,22 @@ if (task->tk_status < 12) { if (!clnt->cl_softrtry) { - task->tk_action = call_transmit; + task->tk_action = call_bind; clnt->cl_stats->rpcretrans++; - } else { - printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", - clnt->cl_protname, task->tk_status); - rpc_exit(task, -EIO); + goto out_retry; } + printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", + clnt->cl_protname, task->tk_status); + rpc_exit(task, -EIO); return; } /* Verify the RPC header */ - if (!(p = call_verify(task))) - return; + if (!(p = call_verify(task))) { + if (task->tk_action == NULL) + return; + goto out_retry; + } /* * The following is an NFS-specific hack to cater for setuid @@ -812,7 +816,7 @@ task->tk_flags ^= RPC_CALL_REALUID; task->tk_action = call_bind; task->tk_suid_retry--; - return; + goto out_retry; } } @@ -822,6 +826,10 @@ task->tk_status = decode(req, p, task->tk_msg.rpc_resp); dprintk("RPC: %4d call_decode result %d\n", task->tk_pid, task->tk_status); + return; +out_retry: + req->rq_received = 0; + task->tk_status = 0; } /* diff -u --recursive --new-file linux-2.6.0-test3/net/sunrpc/xprt.c linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/xprt.c --- linux-2.6.0-test3/net/sunrpc/xprt.c 2003-08-02 18:29:29.000000000 -0700 +++ linux-2.6.0-test3-01-fix_rcv1/net/sunrpc/xprt.c 2003-08-19 13:06:41.000000000 -0700 @@ -138,15 +138,20 @@ static int __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) { + struct rpc_rqst *req = task->tk_rqstp; + if (!xprt->snd_task) { - if (xprt->nocong || __xprt_get_cong(xprt, task)) + if (xprt->nocong || __xprt_get_cong(xprt, task)) { xprt->snd_task = task; + if (req) + req->rq_bytes_sent = 0; + } } 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 (task->tk_rqstp && task->tk_rqstp->rq_nresend) + if (req && req->rq_nresend) rpc_sleep_on(&xprt->resend, task, NULL, NULL); else rpc_sleep_on(&xprt->sending, task, NULL, NULL); @@ -181,8 +186,12 @@ if (!task) return; } - if (xprt->nocong || __xprt_get_cong(xprt, task)) + if (xprt->nocong || __xprt_get_cong(xprt, task)) { + struct rpc_rqst *req = task->tk_rqstp; xprt->snd_task = task; + if (req) + req->rq_bytes_sent = 0; + } } /* @@ -422,6 +431,9 @@ if (xprt_connected(xprt)) goto out_write; + if (task->tk_rqstp) + task->tk_rqstp->rq_bytes_sent = 0; + /* * We're here because the xprt was marked disconnected. * Start by resetting any existing state. @@ -1104,10 +1116,11 @@ if (xprt->shutdown) return -EIO; - if (task->tk_rpcwait) - rpc_remove_wait_queue(task); - spin_lock_bh(&xprt->sock_lock); + if (req->rq_received && !req->rq_bytes_sent) { + err = req->rq_received; + goto out_unlock; + } if (!__xprt_lock_write(xprt, task)) { err = -EAGAIN; goto out_unlock; @@ -1160,8 +1173,12 @@ if (xprt->stream) { req->rq_bytes_sent += status; - if (req->rq_bytes_sent >= req->rq_slen) + /* If we've sent the entire packet, immediately + * reset the count of bytes sent. */ + if (req->rq_bytes_sent >= req->rq_slen) { + req->rq_bytes_sent = 0; goto out_receive; + } } else { if (status >= req->rq_slen) goto out_receive; @@ -1182,9 +1199,6 @@ * hence there is no danger of the waking up task being put on * schedq, and being picked up by a parallel run of rpciod(). */ - if (req->rq_received) - goto out_release; - task->tk_status = status; switch (status) { @@ -1214,13 +1228,12 @@ if (xprt->stream) xprt_disconnect(xprt); } - out_release: xprt_release_write(xprt, task); - req->rq_bytes_sent = 0; return; out_receive: dprintk("RPC: %4d xmit complete\n", task->tk_pid); /* Set the task's receive timeout value */ + spin_lock_bh(&xprt->sock_lock); if (!xprt->nocong) { task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt, task->tk_msg.rpc_proc->p_timer); @@ -1229,7 +1242,6 @@ task->tk_timeout = req->rq_timeout.to_maxval; } else task->tk_timeout = req->rq_timeout.to_current; - spin_lock_bh(&xprt->sock_lock); /* Don't race with disconnect */ if (!xprt_connected(xprt)) task->tk_status = -ENOTCONN; @@ -1237,7 +1249,6 @@ rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); __xprt_release_write(xprt, task); spin_unlock_bh(&xprt->sock_lock); - req->rq_bytes_sent = 0; } /*