diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 24db2b4d12d3..172935b046de 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -469,6 +469,28 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
469 | return rpc_run_task(&task_setup_data); | 469 | return rpc_run_task(&task_setup_data); |
470 | } | 470 | } |
471 | 471 | ||
472 | /* | ||
473 | * In the case where rpc clients have been cloned, we want to make | ||
474 | * sure that we use the program number/version etc of the actual | ||
475 | * owner of the xprt. To do so, we walk back up the tree of parents | ||
476 | * to find whoever created the transport and/or whoever has the | ||
477 | * autobind flag set. | ||
478 | */ | ||
479 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | ||
480 | { | ||
481 | struct rpc_clnt *parent = clnt->cl_parent; | ||
482 | |||
483 | while (parent != clnt) { | ||
484 | if (parent->cl_xprt != clnt->cl_xprt) | ||
485 | break; | ||
486 | if (clnt->cl_autobind) | ||
487 | break; | ||
488 | clnt = parent; | ||
489 | parent = parent->cl_parent; | ||
490 | } | ||
491 | return clnt; | ||
492 | } | ||
493 | |||
472 | /** | 494 | /** |
473 | * rpcb_getport_async - obtain the port for a given RPC service on a given host | 495 | * rpcb_getport_async - obtain the port for a given RPC service on a given host |
474 | * @task: task that is waiting for portmapper request | 496 | * @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 | |||
478 | */ | 500 | */ |
479 | void rpcb_getport_async(struct rpc_task *task) | 501 | void rpcb_getport_async(struct rpc_task *task) |
480 | { | 502 | { |
481 | struct rpc_clnt *clnt = task->tk_client; | 503 | struct rpc_clnt *clnt; |
482 | struct rpc_procinfo *proc; | 504 | struct rpc_procinfo *proc; |
483 | u32 bind_version; | 505 | u32 bind_version; |
484 | struct rpc_xprt *xprt = task->tk_xprt; | 506 | struct rpc_xprt *xprt; |
485 | struct rpc_clnt *rpcb_clnt; | 507 | struct rpc_clnt *rpcb_clnt; |
486 | static struct rpcbind_args *map; | 508 | static struct rpcbind_args *map; |
487 | struct rpc_task *child; | 509 | struct rpc_task *child; |
@@ -490,13 +512,13 @@ void rpcb_getport_async(struct rpc_task *task) | |||
490 | size_t salen; | 512 | size_t salen; |
491 | int status; | 513 | int status; |
492 | 514 | ||
515 | clnt = rpcb_find_transport_owner(task->tk_client); | ||
516 | xprt = clnt->cl_xprt; | ||
517 | |||
493 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 518 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
494 | task->tk_pid, __func__, | 519 | task->tk_pid, __func__, |
495 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); | 520 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); |
496 | 521 | ||
497 | /* Autobind on cloned rpc clients is discouraged */ | ||
498 | BUG_ON(clnt->cl_parent != clnt); | ||
499 | |||
500 | /* Put self on the wait queue to ensure we get notified if | 522 | /* Put self on the wait queue to ensure we get notified if |
501 | * some other task is already attempting to bind the port */ | 523 | * some other task is already attempting to bind the port */ |
502 | rpc_sleep_on(&xprt->binding, task, NULL); | 524 | rpc_sleep_on(&xprt->binding, task, NULL); |
@@ -578,9 +600,9 @@ void rpcb_getport_async(struct rpc_task *task) | |||
578 | task->tk_pid, __func__); | 600 | task->tk_pid, __func__); |
579 | return; | 601 | return; |
580 | } | 602 | } |
581 | rpc_put_task(child); | ||
582 | 603 | ||
583 | task->tk_xprt->stat.bind_count++; | 604 | xprt->stat.bind_count++; |
605 | rpc_put_task(child); | ||
584 | return; | 606 | return; |
585 | 607 | ||
586 | bailout_nofree: | 608 | bailout_nofree: |