aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/rpcb_clnt.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-01 17:00:56 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-02 15:36:38 -0500
commit2446ab6070861aba2dd9229463ffbc40016a9f33 (patch)
tree2e366c3236788936b9f4f58c0787ae01c265f4a4 /net/sunrpc/rpcb_clnt.c
parenta3ca5651cb5eebe2e56e510bbf5cd60abc301c9f (diff)
SUNRPC: Use RCU to dereference the rpc_clnt.cl_xprt field
A migration event will replace the rpc_xprt used by an rpc_clnt. To ensure this can be done safely, all references to cl_xprt must now use a form of rcu_dereference(). Special care is taken with rpc_peeraddr2str(), which returns a pointer to memory whose lifetime is the same as the rpc_xprt. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> [ cel: fix lockdep splats and layering violations ] [ cel: forward ported to 3.4 ] [ cel: remove rpc_max_reqs(), add rpc_net_ns() ] Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r--net/sunrpc/rpcb_clnt.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index b1f08bd67883..4f8af63798a2 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -620,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
620static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) 620static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
621{ 621{
622 struct rpc_clnt *parent = clnt->cl_parent; 622 struct rpc_clnt *parent = clnt->cl_parent;
623 struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
623 624
624 while (parent != clnt) { 625 while (parent != clnt) {
625 if (parent->cl_xprt != clnt->cl_xprt) 626 if (rcu_dereference(parent->cl_xprt) != xprt)
626 break; 627 break;
627 if (clnt->cl_autobind) 628 if (clnt->cl_autobind)
628 break; 629 break;
@@ -653,8 +654,12 @@ void rpcb_getport_async(struct rpc_task *task)
653 size_t salen; 654 size_t salen;
654 int status; 655 int status;
655 656
656 clnt = rpcb_find_transport_owner(task->tk_client); 657 rcu_read_lock();
657 xprt = clnt->cl_xprt; 658 do {
659 clnt = rpcb_find_transport_owner(task->tk_client);
660 xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
661 } while (xprt == NULL);
662 rcu_read_unlock();
658 663
659 dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", 664 dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
660 task->tk_pid, __func__, 665 task->tk_pid, __func__,
@@ -667,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task)
667 if (xprt_test_and_set_binding(xprt)) { 672 if (xprt_test_and_set_binding(xprt)) {
668 dprintk("RPC: %5u %s: waiting for another binder\n", 673 dprintk("RPC: %5u %s: waiting for another binder\n",
669 task->tk_pid, __func__); 674 task->tk_pid, __func__);
675 xprt_put(xprt);
670 return; 676 return;
671 } 677 }
672 678
@@ -734,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task)
734 switch (bind_version) { 740 switch (bind_version) {
735 case RPCBVERS_4: 741 case RPCBVERS_4:
736 case RPCBVERS_3: 742 case RPCBVERS_3:
737 map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); 743 map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
738 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); 744 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);
739 map->r_owner = ""; 745 map->r_owner = "";
740 break; 746 break;
@@ -763,6 +769,7 @@ bailout_release_client:
763bailout_nofree: 769bailout_nofree:
764 rpcb_wake_rpcbind_waiters(xprt, status); 770 rpcb_wake_rpcbind_waiters(xprt, status);
765 task->tk_status = status; 771 task->tk_status = status;
772 xprt_put(xprt);
766} 773}
767EXPORT_SYMBOL_GPL(rpcb_getport_async); 774EXPORT_SYMBOL_GPL(rpcb_getport_async);
768 775