SUNRPC: return negative value in case rpcbind client creation error
[pandora-kernel.git] / net / sunrpc / rpcb_clnt.c
index f588b85..337c68b 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.
@@ -193,7 +246,7 @@ static int rpcb_create_local_unix(void)
        if (IS_ERR(clnt)) {
                dprintk("RPC:       failed to create AF_LOCAL rpcbind "
                                "client (errno %ld).\n", PTR_ERR(clnt));
-               result = -PTR_ERR(clnt);
+               result = PTR_ERR(clnt);
                goto out;
        }
 
@@ -205,9 +258,7 @@ static int rpcb_create_local_unix(void)
                clnt4 = NULL;
        }
 
-       /* Protected by rpcb_create_local_mutex */
-       rpcb_local_clnt = clnt;
-       rpcb_local_clnt4 = clnt4;
+       rpcb_set_local(clnt, clnt4);
 
 out:
        return result;
@@ -242,7 +293,7 @@ static int rpcb_create_local_net(void)
        if (IS_ERR(clnt)) {
                dprintk("RPC:       failed to create local rpcbind "
                                "client (errno %ld).\n", PTR_ERR(clnt));
-               result = -PTR_ERR(clnt);
+               result = PTR_ERR(clnt);
                goto out;
        }
 
@@ -259,9 +310,7 @@ static int rpcb_create_local_net(void)
                clnt4 = NULL;
        }
 
-       /* Protected by rpcb_create_local_mutex */
-       rpcb_local_clnt = clnt;
-       rpcb_local_clnt4 = clnt4;
+       rpcb_set_local(clnt, clnt4);
 
 out:
        return result;
@@ -271,16 +320,16 @@ out:
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local(void)
+int rpcb_create_local(void)
 {
        static DEFINE_MUTEX(rpcb_create_local_mutex);
        int result = 0;
 
-       if (rpcb_local_clnt)
+       if (rpcb_get_local())
                return result;
 
        mutex_lock(&rpcb_create_local_mutex);
-       if (rpcb_local_clnt)
+       if (rpcb_get_local())
                goto out;
 
        if (rpcb_create_local_unix() != 0)
@@ -382,11 +431,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
-       int error;
-
-       error = rpcb_create_local();
-       if (error)
-               return error;
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
                        "rpcbind\n", (port ? "" : "un"),
@@ -522,11 +566,7 @@ int rpcb_v4_register(const u32 program, const u32 version,
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
-       int error;
 
-       error = rpcb_create_local();
-       if (error)
-               return error;
        if (rpcb_local_clnt4 == NULL)
                return -EPROTONOSUPPORT;
 
@@ -1060,15 +1100,3 @@ static struct rpc_program rpcb_program = {
        .version        = rpcb_version,
        .stats          = &rpcb_stats,
 };
-
-/**
- * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
- *
- */
-void cleanup_rpcb_clnt(void)
-{
-       if (rpcb_local_clnt4)
-               rpc_shutdown_client(rpcb_local_clnt4);
-       if (rpcb_local_clnt)
-               rpc_shutdown_client(rpcb_local_clnt);
-}