lockd: per-net NSM client creation and destruction helpers introduced
[pandora-kernel.git] / fs / lockd / mon.c
index 65ba36b..38f240e 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <asm/unaligned.h>
 
+#include "netns.h"
+
 #define NLMDBG_FACILITY                NLMDBG_MONITOR
 #define NSM_PROGRAM            100024
 #define NSM_VERSION            1
@@ -47,7 +49,7 @@ struct nsm_res {
        u32                     state;
 };
 
-static struct rpc_program      nsm_program;
+static const struct rpc_program        nsm_program;
 static                         LIST_HEAD(nsm_handles);
 static                         DEFINE_SPINLOCK(nsm_lock);
 
@@ -62,15 +64,15 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
        return (struct sockaddr *)&nsm->sm_addr;
 }
 
-static struct rpc_clnt *nsm_create(void)
+static struct rpc_clnt *nsm_create(struct net *net)
 {
        struct sockaddr_in sin = {
                .sin_family             = AF_INET,
                .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
        };
        struct rpc_create_args args = {
-               .net                    = &init_net,
-               .protocol               = XPRT_TRANSPORT_UDP,
+               .net                    = net,
+               .protocol               = XPRT_TRANSPORT_TCP,
                .address                = (struct sockaddr *)&sin,
                .addrsize               = sizeof(sin),
                .servername             = "rpc.statd",
@@ -83,7 +85,53 @@ static struct rpc_clnt *nsm_create(void)
        return rpc_create(&args);
 }
 
-static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
+__maybe_unused static struct rpc_clnt *nsm_client_get(struct net *net)
+{
+       static DEFINE_MUTEX(nsm_create_mutex);
+       struct rpc_clnt *clnt;
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+       spin_lock(&ln->nsm_clnt_lock);
+       if (ln->nsm_users) {
+               ln->nsm_users++;
+               clnt = ln->nsm_clnt;
+               spin_unlock(&ln->nsm_clnt_lock);
+               goto out;
+       }
+       spin_unlock(&ln->nsm_clnt_lock);
+
+       mutex_lock(&nsm_create_mutex);
+       clnt = nsm_create(net);
+       if (!IS_ERR(clnt)) {
+               ln->nsm_clnt = clnt;
+               smp_wmb();
+               ln->nsm_users = 1;
+       }
+       mutex_unlock(&nsm_create_mutex);
+out:
+       return clnt;
+}
+
+__maybe_unused static void nsm_client_put(struct net *net)
+{
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+       struct rpc_clnt *clnt = ln->nsm_clnt;
+       int shutdown = 0;
+
+       spin_lock(&ln->nsm_clnt_lock);
+       if (ln->nsm_users) {
+               if (--ln->nsm_users)
+                       ln->nsm_clnt = NULL;
+               shutdown = !ln->nsm_users;
+       }
+       spin_unlock(&ln->nsm_clnt_lock);
+
+       if (shutdown)
+               rpc_shutdown_client(clnt);
+}
+
+static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
+                        struct net *net)
 {
        struct rpc_clnt *clnt;
        int             status;
@@ -99,7 +147,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
                .rpc_resp       = res,
        };
 
-       clnt = nsm_create();
+       clnt = nsm_create(net);
        if (IS_ERR(clnt)) {
                status = PTR_ERR(clnt);
                dprintk("lockd: failed to create NSM upcall transport, "
@@ -110,7 +158,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
        memset(res, 0, sizeof(*res));
 
        msg.rpc_proc = &clnt->cl_procinfo[proc];
-       status = rpc_call_sync(clnt, &msg, 0);
+       status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
        if (status < 0)
                dprintk("lockd: NSM upcall RPC failed, status=%d\n",
                                status);
@@ -149,7 +197,7 @@ int nsm_monitor(const struct nlm_host *host)
         */
        nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 
-       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
+       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
        if (unlikely(res.status != 0))
                status = -EIO;
        if (unlikely(status < 0)) {
@@ -183,7 +231,7 @@ void nsm_unmonitor(const struct nlm_host *host)
         && nsm->sm_monitored && !nsm->sm_sticky) {
                dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 
-               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
+               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
                if (res.status != 0)
                        status = -EIO;
                if (status < 0)
@@ -534,19 +582,19 @@ static struct rpc_procinfo        nsm_procedures[] = {
        },
 };
 
-static struct rpc_version      nsm_version1 = {
+static const struct rpc_version nsm_version1 = {
                .number         = 1,
                .nrprocs        = ARRAY_SIZE(nsm_procedures),
                .procs          = nsm_procedures
 };
 
-static struct rpc_version *    nsm_version[] = {
+static const struct rpc_version *nsm_version[] = {
        [1] = &nsm_version1,
 };
 
 static struct rpc_stat         nsm_stats;
 
-static struct rpc_program      nsm_program = {
+static const struct rpc_program nsm_program = {
                .name           = "statd",
                .number         = NSM_PROGRAM,
                .nrvers         = ARRAY_SIZE(nsm_version),