|
@@ -53,6 +53,7 @@ static void call_allocate(struct rpc_task *task);
|
|
|
static void call_encode(struct rpc_task *task);
|
|
|
static void call_decode(struct rpc_task *task);
|
|
|
static void call_bind(struct rpc_task *task);
|
|
|
+static void call_bind_status(struct rpc_task *task);
|
|
|
static void call_transmit(struct rpc_task *task);
|
|
|
static void call_status(struct rpc_task *task);
|
|
|
static void call_refresh(struct rpc_task *task);
|
|
@@ -734,43 +735,94 @@ static void
|
|
|
call_bind(struct rpc_task *task)
|
|
|
{
|
|
|
struct rpc_clnt *clnt = task->tk_client;
|
|
|
- struct rpc_xprt *xprt = clnt->cl_xprt;
|
|
|
-
|
|
|
- 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;
|
|
|
+ dprintk("RPC: %4d call_bind (status %d)\n",
|
|
|
+ task->tk_pid, task->tk_status);
|
|
|
|
|
|
+ task->tk_action = call_connect;
|
|
|
if (!clnt->cl_port) {
|
|
|
- task->tk_action = call_connect;
|
|
|
+ task->tk_action = call_bind_status;
|
|
|
task->tk_timeout = RPC_CONNECT_TIMEOUT;
|
|
|
rpc_getport(task, clnt);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * 4a. Connect to the RPC server (TCP case)
|
|
|
+ * 4a. Sort out bind result
|
|
|
+ */
|
|
|
+static void
|
|
|
+call_bind_status(struct rpc_task *task)
|
|
|
+{
|
|
|
+ int status = -EACCES;
|
|
|
+
|
|
|
+ if (task->tk_status >= 0) {
|
|
|
+ dprintk("RPC: %4d call_bind_status (status %d)\n",
|
|
|
+ task->tk_pid, task->tk_status);
|
|
|
+ task->tk_status = 0;
|
|
|
+ task->tk_action = call_connect;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (task->tk_status) {
|
|
|
+ case -EACCES:
|
|
|
+ dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
|
|
|
+ task->tk_pid);
|
|
|
+ break;
|
|
|
+ case -ETIMEDOUT:
|
|
|
+ dprintk("RPC: %4d rpcbind request timed out\n",
|
|
|
+ task->tk_pid);
|
|
|
+ if (RPC_IS_SOFT(task)) {
|
|
|
+ status = -EIO;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ goto retry_bind;
|
|
|
+ case -EPFNOSUPPORT:
|
|
|
+ dprintk("RPC: %4d remote rpcbind service unavailable\n",
|
|
|
+ task->tk_pid);
|
|
|
+ break;
|
|
|
+ case -EPROTONOSUPPORT:
|
|
|
+ dprintk("RPC: %4d remote rpcbind version 2 unavailable\n",
|
|
|
+ task->tk_pid);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ dprintk("RPC: %4d unrecognized rpcbind error (%d)\n",
|
|
|
+ task->tk_pid, -task->tk_status);
|
|
|
+ status = -EIO;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ rpc_exit(task, status);
|
|
|
+ return;
|
|
|
+
|
|
|
+retry_bind:
|
|
|
+ task->tk_status = 0;
|
|
|
+ task->tk_action = call_bind;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 4b. Connect to the RPC server
|
|
|
*/
|
|
|
static void
|
|
|
call_connect(struct rpc_task *task)
|
|
|
{
|
|
|
- struct rpc_clnt *clnt = task->tk_client;
|
|
|
+ struct rpc_xprt *xprt = task->tk_xprt;
|
|
|
|
|
|
- dprintk("RPC: %4d call_connect status %d\n",
|
|
|
- task->tk_pid, task->tk_status);
|
|
|
+ dprintk("RPC: %4d call_connect xprt %p %s connected\n",
|
|
|
+ task->tk_pid, xprt,
|
|
|
+ (xprt_connected(xprt) ? "is" : "is not"));
|
|
|
|
|
|
- if (xprt_connected(clnt->cl_xprt)) {
|
|
|
- task->tk_action = call_transmit;
|
|
|
- return;
|
|
|
+ task->tk_action = call_transmit;
|
|
|
+ if (!xprt_connected(xprt)) {
|
|
|
+ task->tk_action = call_connect_status;
|
|
|
+ if (task->tk_status < 0)
|
|
|
+ return;
|
|
|
+ xprt_connect(task);
|
|
|
}
|
|
|
- task->tk_action = call_connect_status;
|
|
|
- if (task->tk_status < 0)
|
|
|
- return;
|
|
|
- xprt_connect(task);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * 4b. Sort out connect result
|
|
|
+ * 4c. Sort out connect result
|
|
|
*/
|
|
|
static void
|
|
|
call_connect_status(struct rpc_task *task)
|
|
@@ -778,6 +830,9 @@ call_connect_status(struct rpc_task *task)
|
|
|
struct rpc_clnt *clnt = task->tk_client;
|
|
|
int status = task->tk_status;
|
|
|
|
|
|
+ dprintk("RPC: %5u call_connect_status (status %d)\n",
|
|
|
+ task->tk_pid, task->tk_status);
|
|
|
+
|
|
|
task->tk_status = 0;
|
|
|
if (status >= 0) {
|
|
|
clnt->cl_stats->netreconn++;
|
|
@@ -785,17 +840,19 @@ call_connect_status(struct rpc_task *task)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Something failed: we may have to rebind */
|
|
|
+ /* Something failed: remote service port may have changed */
|
|
|
if (clnt->cl_autobind)
|
|
|
clnt->cl_port = 0;
|
|
|
+
|
|
|
switch (status) {
|
|
|
case -ENOTCONN:
|
|
|
case -ETIMEDOUT:
|
|
|
case -EAGAIN:
|
|
|
- task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect;
|
|
|
+ task->tk_action = call_bind;
|
|
|
break;
|
|
|
default:
|
|
|
rpc_exit(task, -EIO);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|