diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 34abc91058d8..41013dd66ac3 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -460,6 +460,28 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
460 | return rpc_run_task(&task_setup_data); | 460 | return rpc_run_task(&task_setup_data); |
461 | } | 461 | } |
462 | 462 | ||
463 | /* | ||
464 | * In the case where rpc clients have been cloned, we want to make | ||
465 | * sure that we use the program number/version etc of the actual | ||
466 | * owner of the xprt. To do so, we walk back up the tree of parents | ||
467 | * to find whoever created the transport and/or whoever has the | ||
468 | * autobind flag set. | ||
469 | */ | ||
470 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | ||
471 | { | ||
472 | struct rpc_clnt *parent = clnt->cl_parent; | ||
473 | |||
474 | while (parent != clnt) { | ||
475 | if (parent->cl_xprt != clnt->cl_xprt) | ||
476 | break; | ||
477 | if (clnt->cl_autobind) | ||
478 | break; | ||
479 | clnt = parent; | ||
480 | parent = parent->cl_parent; | ||
481 | } | ||
482 | return clnt; | ||
483 | } | ||
484 | |||
463 | /** | 485 | /** |
464 | * rpcb_getport_async - obtain the port for a given RPC service on a given host | 486 | * rpcb_getport_async - obtain the port for a given RPC service on a given host |
465 | * @task: task that is waiting for portmapper request | 487 | * @task: task that is waiting for portmapper request |
@@ -469,10 +491,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
469 | */ | 491 | */ |
470 | void rpcb_getport_async(struct rpc_task *task) | 492 | void rpcb_getport_async(struct rpc_task *task) |
471 | { | 493 | { |
472 | struct rpc_clnt *clnt = task->tk_client; | 494 | struct rpc_clnt *clnt; |
473 | struct rpc_procinfo *proc; | 495 | struct rpc_procinfo *proc; |
474 | u32 bind_version; | 496 | u32 bind_version; |
475 | struct rpc_xprt *xprt = task->tk_xprt; | 497 | struct rpc_xprt *xprt; |
476 | struct rpc_clnt *rpcb_clnt; | 498 | struct rpc_clnt *rpcb_clnt; |
477 | static struct rpcbind_args *map; | 499 | static struct rpcbind_args *map; |
478 | struct rpc_task *child; | 500 | struct rpc_task *child; |
@@ -481,13 +503,13 @@ void rpcb_getport_async(struct rpc_task *task) | |||
481 | size_t salen; | 503 | size_t salen; |
482 | int status; | 504 | int status; |
483 | 505 | ||
506 | clnt = rpcb_find_transport_owner(task->tk_client); | ||
507 | xprt = clnt->cl_xprt; | ||
508 | |||
484 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 509 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
485 | task->tk_pid, __func__, | 510 | task->tk_pid, __func__, |
486 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); | 511 | clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); |
487 | 512 | ||
488 | /* Autobind on cloned rpc clients is discouraged */ | ||
489 | BUG_ON(clnt->cl_parent != clnt); | ||
490 | |||
491 | /* Put self on the wait queue to ensure we get notified if | 513 | /* Put self on the wait queue to ensure we get notified if |
492 | * some other task is already attempting to bind the port */ | 514 | * some other task is already attempting to bind the port */ |
493 | rpc_sleep_on(&xprt->binding, task, NULL); | 515 | rpc_sleep_on(&xprt->binding, task, NULL); |
@@ -549,7 +571,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
549 | status = -ENOMEM; | 571 | status = -ENOMEM; |
550 | dprintk("RPC: %5u %s: no memory available\n", | 572 | dprintk("RPC: %5u %s: no memory available\n", |
551 | task->tk_pid, __func__); | 573 | task->tk_pid, __func__); |
552 | goto bailout_nofree; | 574 | goto bailout_release_client; |
553 | } | 575 | } |
554 | map->r_prog = clnt->cl_prog; | 576 | map->r_prog = clnt->cl_prog; |
555 | map->r_vers = clnt->cl_vers; | 577 | map->r_vers = clnt->cl_vers; |
@@ -569,11 +591,13 @@ void rpcb_getport_async(struct rpc_task *task) | |||
569 | task->tk_pid, __func__); | 591 | task->tk_pid, __func__); |
570 | return; | 592 | return; |
571 | } | 593 | } |
572 | rpc_put_task(child); | ||
573 | 594 | ||
574 | task->tk_xprt->stat.bind_count++; | 595 | xprt->stat.bind_count++; |
596 | rpc_put_task(child); | ||
575 | return; | 597 | return; |
576 | 598 | ||
599 | bailout_release_client: | ||
600 | rpc_release_client(rpcb_clnt); | ||
577 | bailout_nofree: | 601 | bailout_nofree: |
578 | rpcb_wake_rpcbind_waiters(xprt, status); | 602 | rpcb_wake_rpcbind_waiters(xprt, status); |
579 | task->tk_status = status; | 603 | task->tk_status = status; |