SUNRPC: introduce helpers for reference counted rpcbind clients
authorStanislav Kinsbursky <skinsbursky@parallels.com>
Tue, 25 Oct 2011 11:16:36 +0000 (14:16 +0300)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 25 Oct 2011 11:15:48 +0000 (13:15 +0200)
v6:
1) added write memory barrier to rpcb_set_local to make sure, that rpcbind
clients become valid before rpcb_users assignment
2) explicitly set rpcb_users to 1 instead of incrementing it (looks clearer from
my pow).

v5: fixed races with rpcb_users in rpcb_get_local()

This helpers will be used for dynamical creation and destruction of rpcbind
clients.
Variable rpcb_users is actually a counter of lauched RPC services. If rpcbind
clients has been created already, then we just increase rpcb_users.

Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
net/sunrpc/rpcb_clnt.c

index f588b85..78af565 100644 (file)
@@ -114,6 +114,9 @@ static struct rpc_program   rpcb_program;
 static struct rpc_clnt *       rpcb_local_clnt;
 static struct rpc_clnt *       rpcb_local_clnt4;
 
+DEFINE_SPINLOCK(rpcb_clnt_lock);
+unsigned int                   rpcb_users;
+
 struct rpcbind_args {
        struct rpc_xprt *       r_xprt;
 
@@ -161,6 +164,56 @@ static void rpcb_map_release(void *data)
        kfree(map);
 }
 
+static int rpcb_get_local(void)
+{
+       int cnt;
+
+       spin_lock(&rpcb_clnt_lock);
+       if (rpcb_users)
+               rpcb_users++;
+       cnt = rpcb_users;
+       spin_unlock(&rpcb_clnt_lock);
+
+       return cnt;
+}
+
+void rpcb_put_local(void)
+{
+       struct rpc_clnt *clnt = rpcb_local_clnt;
+       struct rpc_clnt *clnt4 = rpcb_local_clnt4;
+       int shutdown;
+
+       spin_lock(&rpcb_clnt_lock);
+       if (--rpcb_users == 0) {
+               rpcb_local_clnt = NULL;
+               rpcb_local_clnt4 = NULL;
+       }
+       shutdown = !rpcb_users;
+       spin_unlock(&rpcb_clnt_lock);
+
+       if (shutdown) {
+               /*
+                * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
+                */
+               if (clnt4)
+                       rpc_shutdown_client(clnt4);
+               if (clnt)
+                       rpc_shutdown_client(clnt);
+       }
+}
+
+static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4)
+{
+       /* Protected by rpcb_create_local_mutex */
+       rpcb_local_clnt = clnt;
+       rpcb_local_clnt4 = clnt4;
+       smp_wmb(); 
+       rpcb_users = 1;
+       dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: "
+                       "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt,
+                       rpcb_local_clnt4);
+}
+
 /*
  * Returns zero on success, otherwise a negative errno value
  * is returned.