Commit f3f324e7 authored by Trond Myklebust's avatar Trond Myklebust

Various RPC client fixes:

   - Ensure that we reset req->rq_received before resending if the
     server has sent us a garbage reply.

   - Whenever we grab the xprt_lock_write "semaphore" ensure that we
     reset req->rq_bytes_sent.

   - When resending a TCP request, do not interrupt in the
     middle of transmission even if we do get a reply from the server.

   - Protect the call to rpc_calc_rto() against modification while
     we are calculating
parent 9f4a648b
...@@ -659,7 +659,7 @@ call_transmit(struct rpc_task *task) ...@@ -659,7 +659,7 @@ call_transmit(struct rpc_task *task)
if (task->tk_status < 0) if (task->tk_status < 0)
return; return;
task->tk_status = xprt_prepare_transmit(task); task->tk_status = xprt_prepare_transmit(task);
if (task->tk_status < 0) if (task->tk_status != 0)
return; return;
/* Encode here so that rpcsec_gss can use correct sequence number. */ /* Encode here so that rpcsec_gss can use correct sequence number. */
if (!task->tk_rqstp->rq_bytes_sent) if (!task->tk_rqstp->rq_bytes_sent)
...@@ -685,7 +685,7 @@ call_status(struct rpc_task *task) ...@@ -685,7 +685,7 @@ call_status(struct rpc_task *task)
struct rpc_rqst *req = task->tk_rqstp; struct rpc_rqst *req = task->tk_rqstp;
int status; int status;
if (req->rq_received != 0) if (req->rq_received > 0 && !req->rq_bytes_sent)
task->tk_status = req->rq_received; task->tk_status = req->rq_received;
dprintk("RPC: %4d call_status (status %d)\n", dprintk("RPC: %4d call_status (status %d)\n",
...@@ -787,19 +787,22 @@ call_decode(struct rpc_task *task) ...@@ -787,19 +787,22 @@ call_decode(struct rpc_task *task)
if (task->tk_status < 12) { if (task->tk_status < 12) {
if (!clnt->cl_softrtry) { if (!clnt->cl_softrtry) {
task->tk_action = call_transmit; task->tk_action = call_bind;
clnt->cl_stats->rpcretrans++; clnt->cl_stats->rpcretrans++;
} else { 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);
} }
printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
clnt->cl_protname, task->tk_status);
rpc_exit(task, -EIO);
return; return;
} }
/* Verify the RPC header */ /* Verify the RPC header */
if (!(p = call_verify(task))) if (!(p = call_verify(task))) {
return; if (task->tk_action == NULL)
return;
goto out_retry;
}
/* /*
* The following is an NFS-specific hack to cater for setuid * The following is an NFS-specific hack to cater for setuid
...@@ -812,7 +815,7 @@ call_decode(struct rpc_task *task) ...@@ -812,7 +815,7 @@ call_decode(struct rpc_task *task)
task->tk_flags ^= RPC_CALL_REALUID; task->tk_flags ^= RPC_CALL_REALUID;
task->tk_action = call_bind; task->tk_action = call_bind;
task->tk_suid_retry--; task->tk_suid_retry--;
return; goto out_retry;
} }
} }
...@@ -822,6 +825,10 @@ call_decode(struct rpc_task *task) ...@@ -822,6 +825,10 @@ call_decode(struct rpc_task *task)
task->tk_status = decode(req, p, task->tk_msg.rpc_resp); task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
dprintk("RPC: %4d call_decode result %d\n", task->tk_pid, dprintk("RPC: %4d call_decode result %d\n", task->tk_pid,
task->tk_status); task->tk_status);
return;
out_retry:
req->rq_received = 0;
task->tk_status = 0;
} }
/* /*
......
...@@ -138,15 +138,20 @@ xprt_from_sock(struct sock *sk) ...@@ -138,15 +138,20 @@ xprt_from_sock(struct sock *sk)
static int static int
__xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
{ {
struct rpc_rqst *req = task->tk_rqstp;
if (!xprt->snd_task) { if (!xprt->snd_task) {
if (xprt->nocong || __xprt_get_cong(xprt, task)) if (xprt->nocong || __xprt_get_cong(xprt, task)) {
xprt->snd_task = task; xprt->snd_task = task;
if (req)
req->rq_bytes_sent = 0;
}
} }
if (xprt->snd_task != task) { if (xprt->snd_task != task) {
dprintk("RPC: %4d TCP write queue full\n", task->tk_pid); dprintk("RPC: %4d TCP write queue full\n", task->tk_pid);
task->tk_timeout = 0; task->tk_timeout = 0;
task->tk_status = -EAGAIN; 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); rpc_sleep_on(&xprt->resend, task, NULL, NULL);
else else
rpc_sleep_on(&xprt->sending, task, NULL, NULL); rpc_sleep_on(&xprt->sending, task, NULL, NULL);
...@@ -181,8 +186,12 @@ __xprt_lock_write_next(struct rpc_xprt *xprt) ...@@ -181,8 +186,12 @@ __xprt_lock_write_next(struct rpc_xprt *xprt)
if (!task) if (!task)
return; 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; xprt->snd_task = task;
if (req)
req->rq_bytes_sent = 0;
}
} }
/* /*
...@@ -422,6 +431,9 @@ xprt_connect(struct rpc_task *task) ...@@ -422,6 +431,9 @@ xprt_connect(struct rpc_task *task)
if (xprt_connected(xprt)) if (xprt_connected(xprt))
goto out_write; goto out_write;
if (task->tk_rqstp)
task->tk_rqstp->rq_bytes_sent = 0;
/* /*
* We're here because the xprt was marked disconnected. * We're here because the xprt was marked disconnected.
* Start by resetting any existing state. * Start by resetting any existing state.
...@@ -1104,10 +1116,11 @@ xprt_prepare_transmit(struct rpc_task *task) ...@@ -1104,10 +1116,11 @@ xprt_prepare_transmit(struct rpc_task *task)
if (xprt->shutdown) if (xprt->shutdown)
return -EIO; return -EIO;
if (task->tk_rpcwait)
rpc_remove_wait_queue(task);
spin_lock_bh(&xprt->sock_lock); 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)) { if (!__xprt_lock_write(xprt, task)) {
err = -EAGAIN; err = -EAGAIN;
goto out_unlock; goto out_unlock;
...@@ -1160,8 +1173,12 @@ xprt_transmit(struct rpc_task *task) ...@@ -1160,8 +1173,12 @@ xprt_transmit(struct rpc_task *task)
if (xprt->stream) { if (xprt->stream) {
req->rq_bytes_sent += status; 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; goto out_receive;
}
} else { } else {
if (status >= req->rq_slen) if (status >= req->rq_slen)
goto out_receive; goto out_receive;
...@@ -1182,9 +1199,6 @@ xprt_transmit(struct rpc_task *task) ...@@ -1182,9 +1199,6 @@ xprt_transmit(struct rpc_task *task)
* hence there is no danger of the waking up task being put on * hence there is no danger of the waking up task being put on
* schedq, and being picked up by a parallel run of rpciod(). * schedq, and being picked up by a parallel run of rpciod().
*/ */
if (req->rq_received)
goto out_release;
task->tk_status = status; task->tk_status = status;
switch (status) { switch (status) {
...@@ -1214,13 +1228,12 @@ xprt_transmit(struct rpc_task *task) ...@@ -1214,13 +1228,12 @@ xprt_transmit(struct rpc_task *task)
if (xprt->stream) if (xprt->stream)
xprt_disconnect(xprt); xprt_disconnect(xprt);
} }
out_release:
xprt_release_write(xprt, task); xprt_release_write(xprt, task);
req->rq_bytes_sent = 0;
return; return;
out_receive: out_receive:
dprintk("RPC: %4d xmit complete\n", task->tk_pid); dprintk("RPC: %4d xmit complete\n", task->tk_pid);
/* Set the task's receive timeout value */ /* Set the task's receive timeout value */
spin_lock_bh(&xprt->sock_lock);
if (!xprt->nocong) { if (!xprt->nocong) {
task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt, task->tk_timeout = rpc_calc_rto(&clnt->cl_rtt,
task->tk_msg.rpc_proc->p_timer); task->tk_msg.rpc_proc->p_timer);
...@@ -1229,7 +1242,6 @@ xprt_transmit(struct rpc_task *task) ...@@ -1229,7 +1242,6 @@ xprt_transmit(struct rpc_task *task)
task->tk_timeout = req->rq_timeout.to_maxval; task->tk_timeout = req->rq_timeout.to_maxval;
} else } else
task->tk_timeout = req->rq_timeout.to_current; task->tk_timeout = req->rq_timeout.to_current;
spin_lock_bh(&xprt->sock_lock);
/* Don't race with disconnect */ /* Don't race with disconnect */
if (!xprt_connected(xprt)) if (!xprt_connected(xprt))
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
...@@ -1237,7 +1249,6 @@ xprt_transmit(struct rpc_task *task) ...@@ -1237,7 +1249,6 @@ xprt_transmit(struct rpc_task *task)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
__xprt_release_write(xprt, task); __xprt_release_write(xprt, task);
spin_unlock_bh(&xprt->sock_lock); spin_unlock_bh(&xprt->sock_lock);
req->rq_bytes_sent = 0;
} }
/* /*
......
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