|
@@ -469,6 +469,28 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
|
|
|
return rpc_run_task(&task_setup_data);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * In the case where rpc clients have been cloned, we want to make
|
|
|
+ * sure that we use the program number/version etc of the actual
|
|
|
+ * owner of the xprt. To do so, we walk back up the tree of parents
|
|
|
+ * to find whoever created the transport and/or whoever has the
|
|
|
+ * autobind flag set.
|
|
|
+ */
|
|
|
+static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
|
|
|
+{
|
|
|
+ struct rpc_clnt *parent = clnt->cl_parent;
|
|
|
+
|
|
|
+ while (parent != clnt) {
|
|
|
+ if (parent->cl_xprt != clnt->cl_xprt)
|
|
|
+ break;
|
|
|
+ if (clnt->cl_autobind)
|
|
|
+ break;
|
|
|
+ clnt = parent;
|
|
|
+ parent = parent->cl_parent;
|
|
|
+ }
|
|
|
+ return clnt;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* rpcb_getport_async - obtain the port for a given RPC service on a given host
|
|
|
* @task: task that is waiting for portmapper request
|
|
@@ -478,10 +500,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
|
|
|
*/
|
|
|
void rpcb_getport_async(struct rpc_task *task)
|
|
|
{
|
|
|
- struct rpc_clnt *clnt = task->tk_client;
|
|
|
+ struct rpc_clnt *clnt;
|
|
|
struct rpc_procinfo *proc;
|
|
|
u32 bind_version;
|
|
|
- struct rpc_xprt *xprt = task->tk_xprt;
|
|
|
+ struct rpc_xprt *xprt;
|
|
|
struct rpc_clnt *rpcb_clnt;
|
|
|
static struct rpcbind_args *map;
|
|
|
struct rpc_task *child;
|
|
@@ -490,13 +512,13 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
|
size_t salen;
|
|
|
int status;
|
|
|
|
|
|
+ clnt = rpcb_find_transport_owner(task->tk_client);
|
|
|
+ xprt = clnt->cl_xprt;
|
|
|
+
|
|
|
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
|
|
|
task->tk_pid, __func__,
|
|
|
clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
|
|
|
|
|
|
- /* Autobind on cloned rpc clients is discouraged */
|
|
|
- BUG_ON(clnt->cl_parent != clnt);
|
|
|
-
|
|
|
/* Put self on the wait queue to ensure we get notified if
|
|
|
* some other task is already attempting to bind the port */
|
|
|
rpc_sleep_on(&xprt->binding, task, NULL);
|
|
@@ -578,9 +600,9 @@ void rpcb_getport_async(struct rpc_task *task)
|
|
|
task->tk_pid, __func__);
|
|
|
return;
|
|
|
}
|
|
|
- rpc_put_task(child);
|
|
|
|
|
|
- task->tk_xprt->stat.bind_count++;
|
|
|
+ xprt->stat.bind_count++;
|
|
|
+ rpc_put_task(child);
|
|
|
return;
|
|
|
|
|
|
bailout_nofree:
|