Lockd: per-net up and down routines introduced
[cascardo/linux.git] / net / sunrpc / svc.c
index e4aabc0..4153846 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/nsproxy.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
@@ -30,7 +31,7 @@
 
 #define RPCDBG_FACILITY        RPCDBG_SVCDSP
 
-static void svc_unregister(const struct svc_serv *serv);
+static void svc_unregister(const struct svc_serv *serv, struct net *net);
 
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
@@ -368,23 +369,24 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
        return &serv->sv_pools[pidx % serv->sv_nrpools];
 }
 
-static int svc_rpcb_setup(struct svc_serv *serv)
+int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 {
        int err;
 
-       err = rpcb_create_local();
+       err = rpcb_create_local(net);
        if (err)
                return err;
 
        /* Remove any stale portmap registrations */
-       svc_unregister(serv);
+       svc_unregister(serv, net);
        return 0;
 }
+EXPORT_SYMBOL_GPL(svc_rpcb_setup);
 
-void svc_rpcb_cleanup(struct svc_serv *serv)
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
 {
-       svc_unregister(serv);
-       rpcb_put_local();
+       svc_unregister(serv, net);
+       rpcb_put_local(net);
 }
 EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
 
@@ -410,7 +412,7 @@ static int svc_uses_rpcbind(struct svc_serv *serv)
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-            void (*shutdown)(struct svc_serv *serv))
+            void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
        struct svc_serv *serv;
        unsigned int vers;
@@ -470,7 +472,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
        }
 
        if (svc_uses_rpcbind(serv)) {
-               if (svc_rpcb_setup(serv) < 0) {
+               if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
                        kfree(serv->sv_pools);
                        kfree(serv);
                        return NULL;
@@ -484,7 +486,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-          void (*shutdown)(struct svc_serv *serv))
+          void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
        return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
@@ -492,7 +494,7 @@ EXPORT_SYMBOL_GPL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-                 void (*shutdown)(struct svc_serv *serv),
+                 void (*shutdown)(struct svc_serv *serv, struct net *net),
                  svc_thread_fn func, struct module *mod)
 {
        struct svc_serv *serv;
@@ -509,6 +511,24 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
 }
 EXPORT_SYMBOL_GPL(svc_create_pooled);
 
+void svc_shutdown_net(struct svc_serv *serv, struct net *net)
+{
+       /*
+        * The set of xprts (contained in the sv_tempsocks and
+        * sv_permsocks lists) is now constant, since it is modified
+        * only by accepting new sockets (done by service threads in
+        * svc_recv) or aging old ones (done by sv_temptimer), or
+        * configuration changes (excluded by whatever locking the
+        * caller is using--nfsd_mutex in the case of nfsd).  So it's
+        * safe to traverse those lists and shut everything down:
+        */
+       svc_close_net(serv, net);
+
+       if (serv->sv_shutdown)
+               serv->sv_shutdown(serv, net);
+}
+EXPORT_SYMBOL_GPL(svc_shutdown_net);
+
 /*
  * Destroy an RPC service. Should be called with appropriate locking to
  * protect the sv_nrthreads, sv_permsocks and sv_tempsocks.
@@ -516,6 +536,8 @@ EXPORT_SYMBOL_GPL(svc_create_pooled);
 void
 svc_destroy(struct svc_serv *serv)
 {
+       struct net *net = current->nsproxy->net_ns;
+
        dprintk("svc: svc_destroy(%s, %d)\n",
                                serv->sv_program->pg_name,
                                serv->sv_nrthreads);
@@ -529,19 +551,15 @@ svc_destroy(struct svc_serv *serv)
                printk("svc_destroy: no threads for serv=%p!\n", serv);
 
        del_timer_sync(&serv->sv_temptimer);
+
+       svc_shutdown_net(serv, net);
+
        /*
-        * The set of xprts (contained in the sv_tempsocks and
-        * sv_permsocks lists) is now constant, since it is modified
-        * only by accepting new sockets (done by service threads in
-        * svc_recv) or aging old ones (done by sv_temptimer), or
-        * configuration changes (excluded by whatever locking the
-        * caller is using--nfsd_mutex in the case of nfsd).  So it's
-        * safe to traverse those lists and shut everything down:
+        * The last user is gone and thus all sockets have to be destroyed to
+        * the point. Check this.
         */
-       svc_close_all(serv);
-
-       if (serv->sv_shutdown)
-               serv->sv_shutdown(serv);
+       BUG_ON(!list_empty(&serv->sv_permsocks));
+       BUG_ON(!list_empty(&serv->sv_tempsocks));
 
        cache_clean_deferred(serv);
 
@@ -795,7 +813,8 @@ EXPORT_SYMBOL_GPL(svc_exit_thread);
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register4(const u32 program, const u32 version,
+static int __svc_rpcb_register4(struct net *net, const u32 program,
+                               const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
@@ -818,7 +837,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                return -ENOPROTOOPT;
        }
 
-       error = rpcb_v4_register(program, version,
+       error = rpcb_v4_register(net, program, version,
                                        (const struct sockaddr *)&sin, netid);
 
        /*
@@ -826,7 +845,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
         * registration request with the legacy rpcbind v2 protocol.
         */
        if (error == -EPROTONOSUPPORT)
-               error = rpcb_register(program, version, protocol, port);
+               error = rpcb_register(net, program, version, protocol, port);
 
        return error;
 }
@@ -842,7 +861,8 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register6(const u32 program, const u32 version,
+static int __svc_rpcb_register6(struct net *net, const u32 program,
+                               const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
@@ -865,7 +885,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                return -ENOPROTOOPT;
        }
 
-       error = rpcb_v4_register(program, version,
+       error = rpcb_v4_register(net, program, version,
                                        (const struct sockaddr *)&sin6, netid);
 
        /*
@@ -885,7 +905,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_register(const char *progname,
+static int __svc_register(struct net *net, const char *progname,
                          const u32 program, const u32 version,
                          const int family,
                          const unsigned short protocol,
@@ -895,12 +915,12 @@ static int __svc_register(const char *progname,
 
        switch (family) {
        case PF_INET:
-               error = __svc_rpcb_register4(program, version,
+               error = __svc_rpcb_register4(net, program, version,
                                                protocol, port);
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case PF_INET6:
-               error = __svc_rpcb_register6(program, version,
+               error = __svc_rpcb_register6(net, program, version,
                                                protocol, port);
 #endif
        }
@@ -914,14 +934,16 @@ static int __svc_register(const char *progname,
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @net: net namespace for the service to register
  * @family: protocol family of service's listener socket
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
  * Service is registered for any address in the passed-in protocol family
  */
-int svc_register(const struct svc_serv *serv, const int family,
-                const unsigned short proto, const unsigned short port)
+int svc_register(const struct svc_serv *serv, struct net *net,
+                const int family, const unsigned short proto,
+                const unsigned short port)
 {
        struct svc_program      *progp;
        unsigned int            i;
@@ -946,7 +968,7 @@ int svc_register(const struct svc_serv *serv, const int family,
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = __svc_register(progp->pg_name, progp->pg_prog,
+                       error = __svc_register(net, progp->pg_name, progp->pg_prog,
                                                i, family, proto, port);
                        if (error < 0)
                                break;
@@ -963,19 +985,19 @@ int svc_register(const struct svc_serv *serv, const int family,
  * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
  * in this case to clear all existing entries for [program, version].
  */
-static void __svc_unregister(const u32 program, const u32 version,
+static void __svc_unregister(struct net *net, const u32 program, const u32 version,
                             const char *progname)
 {
        int error;
 
-       error = rpcb_v4_register(program, version, NULL, "");
+       error = rpcb_v4_register(net, program, version, NULL, "");
 
        /*
         * User space didn't support rpcbind v4, so retry this
         * request with the legacy rpcbind v2 protocol.
         */
        if (error == -EPROTONOSUPPORT)
-               error = rpcb_register(program, version, 0, 0);
+               error = rpcb_register(net, program, version, 0, 0);
 
        dprintk("svc: %s(%sv%u), error %d\n",
                        __func__, progname, version, error);
@@ -989,7 +1011,7 @@ static void __svc_unregister(const u32 program, const u32 version,
  * The result of unregistration is reported via dprintk for those who want
  * verification of the result, but is otherwise not important.
  */
-static void svc_unregister(const struct svc_serv *serv)
+static void svc_unregister(const struct svc_serv *serv, struct net *net)
 {
        struct svc_program *progp;
        unsigned long flags;
@@ -1006,7 +1028,7 @@ static void svc_unregister(const struct svc_serv *serv)
 
                        dprintk("svc: attempting to unregister %sv%u\n",
                                progp->pg_name, i);
-                       __svc_unregister(progp->pg_prog, i, progp->pg_name);
+                       __svc_unregister(net, progp->pg_prog, i, progp->pg_name);
                }
        }