patch-2.4.22 linux-2.4.22/net/sunrpc/clnt.c
Next file: linux-2.4.22/net/sunrpc/svcsock.c
Previous file: linux-2.4.22/net/socket.c
Back to the patch index
Back to the overall index
- Lines: 341
- Date:
2003-08-25 04:44:44.000000000 -0700
- Orig file:
linux-2.4.21/net/sunrpc/clnt.c
- Orig date:
2003-06-13 07:51:39.000000000 -0700
diff -urN linux-2.4.21/net/sunrpc/clnt.c linux-2.4.22/net/sunrpc/clnt.c
@@ -55,9 +55,8 @@
static void call_refresh(struct rpc_task *task);
static void call_refreshresult(struct rpc_task *task);
static void call_timeout(struct rpc_task *task);
-static void call_reconnect(struct rpc_task *task);
-static void child_reconnect(struct rpc_task *);
-static void child_reconnect_status(struct rpc_task *);
+static void call_connect(struct rpc_task *task);
+static void call_connect_status(struct rpc_task *);
static u32 * call_header(struct rpc_task *task);
static u32 * call_verify(struct rpc_task *task);
@@ -394,8 +393,6 @@
static void
call_reserve(struct rpc_task *task)
{
- struct rpc_clnt *clnt = task->tk_client;
-
dprintk("RPC: %4d call_reserve\n", task->tk_pid);
if (!rpcauth_uptodatecred(task)) {
@@ -405,7 +402,6 @@
task->tk_status = 0;
task->tk_action = call_reserveresult;
- task->tk_timeout = clnt->cl_timeout.to_resrvval;
xprt_reserve(task);
}
@@ -419,38 +415,46 @@
dprintk("RPC: %4d call_reserveresult (status %d)\n",
task->tk_pid, task->tk_status);
+
/*
* After a call to xprt_reserve(), we must have either
* a request slot or else an error status.
*/
- if ((task->tk_status >= 0 && !task->tk_rqstp) ||
- (task->tk_status < 0 && task->tk_rqstp))
- printk(KERN_ERR "call_reserveresult: status=%d, request=%p??\n",
- task->tk_status, task->tk_rqstp);
+ task->tk_status = 0;
+ if (status >= 0) {
+ if (task->tk_rqstp) {
+ task->tk_action = call_allocate;
+ return;
+ }
- if (task->tk_status >= 0) {
- task->tk_action = call_allocate;
+ printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
+ __FUNCTION__, status);
+ rpc_exit(task, -EIO);
return;
}
- task->tk_status = 0;
+ /*
+ * Even though there was an error, we may have acquired
+ * a request slot somehow. Make sure not to leak it.
+ */
+ if (task->tk_rqstp) {
+ printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
+ __FUNCTION__, status);
+ xprt_release(task);
+ }
+
switch (status) {
- case -EAGAIN:
- case -ENOBUFS:
- task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
+ case -EAGAIN: /* woken up; retry */
task->tk_action = call_reserve;
- break;
- case -ETIMEDOUT:
- dprintk("RPC: task timed out\n");
- task->tk_action = call_timeout;
+ return;
+ case -EIO: /* probably a shutdown */
break;
default:
- if (!task->tk_rqstp) {
- printk(KERN_INFO "RPC: task has no request, exit EIO\n");
- rpc_exit(task, -EIO);
- } else
- rpc_exit(task, status);
+ printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
+ __FUNCTION__, status);
+ break;
}
+ rpc_exit(task, status);
}
/*
@@ -545,53 +549,69 @@
struct rpc_clnt *clnt = task->tk_client;
struct rpc_xprt *xprt = clnt->cl_xprt;
- task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_reconnect;
+ dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid,
+ xprt, (xprt_connected(xprt) ? "is" : "is not"));
+
+ task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect;
if (!clnt->cl_port) {
- task->tk_action = call_reconnect;
+ task->tk_action = call_connect;
task->tk_timeout = clnt->cl_timeout.to_maxval;
rpc_getport(task, clnt);
}
}
/*
- * 4a. Reconnect to the RPC server (TCP case)
+ * 4a. Establish socket
+ * Connect to the RPC server (TCP case)
*/
static void
-call_reconnect(struct rpc_task *task)
+call_connect(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
- struct rpc_task *child;
- dprintk("RPC: %4d call_reconnect status %d\n",
+ dprintk("RPC: %4d call_connect status %d\n",
task->tk_pid, task->tk_status);
- task->tk_action = call_transmit;
- if (task->tk_status < 0 || !clnt->cl_xprt->stream)
+ if (xprt_connected(clnt->cl_xprt)) {
+ task->tk_action = call_transmit;
return;
-
- /* Run as a child to ensure it runs as an rpciod task */
- child = rpc_new_child(clnt, task);
- if (child) {
- child->tk_action = child_reconnect;
- rpc_run_child(task, child, NULL);
}
+ task->tk_action = call_connect_status;
+ if (task->tk_status < 0)
+ return;
+ xprt_connect(task);
}
-static void child_reconnect(struct rpc_task *task)
+/*
+ * 4b. Sort out reconnection result
+ */
+static void call_connect_status(struct rpc_task *task)
{
- task->tk_client->cl_stats->netreconn++;
+ struct rpc_clnt *clnt = task->tk_client;
+ int status = task->tk_status;
+
task->tk_status = 0;
- task->tk_action = child_reconnect_status;
- xprt_reconnect(task);
-}
+ if (status >= 0) {
+ clnt->cl_stats->netreconn++;
+ task->tk_action = call_transmit;
+ return;
+ }
-static void child_reconnect_status(struct rpc_task *task)
-{
- if (task->tk_status == -EAGAIN)
- task->tk_action = child_reconnect;
- else
- task->tk_action = NULL;
+ /* Something failed: we may have to rebind */
+ if (clnt->cl_autobind)
+ clnt->cl_port = 0;
+ switch (status) {
+ case -ECONNREFUSED:
+ case -ECONNRESET:
+ case -ENOTCONN:
+ case -ETIMEDOUT:
+ case -EAGAIN:
+ task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect;
+ break;
+ default:
+ rpc_exit(task, status);
+ }
}
/*
@@ -626,7 +646,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",
@@ -651,10 +672,8 @@
task->tk_action = call_bind;
break;
}
- if (xprt->stream) {
- task->tk_action = call_reconnect;
- break;
- }
+ task->tk_action = call_connect;
+ break;
/*
* Sleep and dream of an open connection
*/
@@ -681,54 +700,34 @@
call_timeout(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
- struct rpc_rqst *req = task->tk_rqstp;
+ struct rpc_timeout *to = &task->tk_rqstp->rq_timeout;
- if (req) {
- struct rpc_timeout *to = &req->rq_timeout;
-
- if (xprt_adjust_timeout(to)) {
- dprintk("RPC: %4d call_timeout (minor timeo)\n",
- task->tk_pid);
- goto minor_timeout;
- }
- to->to_retries = clnt->cl_timeout.to_retries;
+ if (xprt_adjust_timeout(to)) {
+ dprintk("RPC: %4d call_timeout (minor)\n", task->tk_pid);
+ goto retry;
}
+ to->to_retries = clnt->cl_timeout.to_retries;
- dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid);
+ dprintk("RPC: %4d call_timeout (major)\n", task->tk_pid);
if (clnt->cl_softrtry) {
- if (clnt->cl_chatty && !task->tk_exit)
+ if (clnt->cl_chatty)
printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
clnt->cl_protname, clnt->cl_server);
rpc_exit(task, -EIO);
return;
}
- if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN) && rpc_ntimeo(&clnt->cl_rtt) > 7) {
+
+ if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
task->tk_flags |= RPC_CALL_MAJORSEEN;
- if (req)
- printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
- clnt->cl_protname, clnt->cl_server);
-#ifdef RPC_DEBUG
- else
- printk(KERN_NOTICE "%s: task %d can't get a request slot\n",
- clnt->cl_protname, task->tk_pid);
-#endif
+ printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
+ clnt->cl_protname, clnt->cl_server);
}
if (clnt->cl_autobind)
clnt->cl_port = 0;
-minor_timeout:
- if (!req)
- task->tk_action = call_reserve;
- else if (!clnt->cl_port) {
- task->tk_action = call_bind;
- clnt->cl_stats->rpcretrans++;
- } else if (!xprt_connected(clnt->cl_xprt)) {
- task->tk_action = call_reconnect;
- clnt->cl_stats->rpcretrans++;
- } else {
- task->tk_action = call_transmit;
- clnt->cl_stats->rpcretrans++;
- }
+retry:
+ clnt->cl_stats->rpcretrans++;
+ task->tk_action = call_bind;
task->tk_status = 0;
}
@@ -756,18 +755,31 @@
if (!clnt->cl_softrtry) {
task->tk_action = call_transmit;
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;
+ /* Check that the softirq receive buffer is valid */
+ if (unlikely(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
+ sizeof(req->rq_rcv_buf)) != 0))
+ printk(KERN_WARNING "%s: receive buffer is inconsistent. Please contact maintainer.\n",
+ __FUNCTION__);
+ /* Verify the RPC header */
+ if (!(p = call_verify(task))) {
+ /*
+ * When call_verfiy sets tk_action to NULL (via task_exit)
+ * a non-retry-able error has occurred (like the server
+ * not supporting a particular procedure call).
+ */
+ if (task->tk_action == NULL)
+ return;
+ goto out_retry;
+ }
/*
* The following is an NFS-specific hack to cater for setuid
* processes whose uid is mapped to nobody on the server.
@@ -779,7 +791,7 @@
task->tk_flags ^= RPC_CALL_REALUID;
task->tk_action = call_encode;
task->tk_suid_retry--;
- return;
+ goto out_retry;
}
}
@@ -789,6 +801,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;
}
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)