diff options
Diffstat (limited to 'fs/lockd/svc.c')
| -rw-r--r-- | fs/lockd/svc.c | 117 | 
1 files changed, 102 insertions, 15 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c061b9aa7dd..2774e1013b3 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -35,6 +35,8 @@  #include <linux/lockd/lockd.h>  #include <linux/nfs.h> +#include "netns.h" +  #define NLMDBG_FACILITY		NLMDBG_SVC  #define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)  #define ALLOWED_SIGS		(sigmask(SIGKILL)) @@ -50,6 +52,8 @@ static struct task_struct	*nlmsvc_task;  static struct svc_rqst		*nlmsvc_rqst;  unsigned long			nlmsvc_timeout; +int lockd_net_id; +  /*   * These can be set at insmod time (useful for NFS as root filesystem),   * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003 @@ -189,27 +193,29 @@ lockd(void *vrqstp)  }  static int create_lockd_listener(struct svc_serv *serv, const char *name, -				 const int family, const unsigned short port) +				 struct net *net, const int family, +				 const unsigned short port)  {  	struct svc_xprt *xprt; -	xprt = svc_find_xprt(serv, name, family, 0); +	xprt = svc_find_xprt(serv, name, net, family, 0);  	if (xprt == NULL) -		return svc_create_xprt(serv, name, &init_net, family, port, +		return svc_create_xprt(serv, name, net, family, port,  						SVC_SOCK_DEFAULTS);  	svc_xprt_put(xprt);  	return 0;  } -static int create_lockd_family(struct svc_serv *serv, const int family) +static int create_lockd_family(struct svc_serv *serv, struct net *net, +			       const int family)  {  	int err; -	err = create_lockd_listener(serv, "udp", family, nlm_udpport); +	err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);  	if (err < 0)  		return err; -	return create_lockd_listener(serv, "tcp", family, nlm_tcpport); +	return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);  }  /* @@ -222,16 +228,16 @@ static int create_lockd_family(struct svc_serv *serv, const int family)   * Returns zero if all listeners are available; otherwise a   * negative errno value is returned.   */ -static int make_socks(struct svc_serv *serv) +static int make_socks(struct svc_serv *serv, struct net *net)  {  	static int warned;  	int err; -	err = create_lockd_family(serv, PF_INET); +	err = create_lockd_family(serv, net, PF_INET);  	if (err < 0)  		goto out_err; -	err = create_lockd_family(serv, PF_INET6); +	err = create_lockd_family(serv, net, PF_INET6);  	if (err < 0 && err != -EAFNOSUPPORT)  		goto out_err; @@ -245,6 +251,47 @@ out_err:  	return err;  } +static int lockd_up_net(struct net *net) +{ +	struct lockd_net *ln = net_generic(net, lockd_net_id); +	struct svc_serv *serv = nlmsvc_rqst->rq_server; +	int error; + +	if (ln->nlmsvc_users) +		return 0; + +	error = svc_rpcb_setup(serv, net); +	if (error) +		goto err_rpcb; + +	error = make_socks(serv, net); +	if (error < 0) +		goto err_socks; +	return 0; + +err_socks: +	svc_rpcb_cleanup(serv, net); +err_rpcb: +	return error; +} + +static void lockd_down_net(struct net *net) +{ +	struct lockd_net *ln = net_generic(net, lockd_net_id); +	struct svc_serv *serv = nlmsvc_rqst->rq_server; + +	if (ln->nlmsvc_users) { +		if (--ln->nlmsvc_users == 0) { +			nlm_shutdown_hosts_net(net); +			svc_shutdown_net(serv, net); +		} +	} else { +		printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n", +				nlmsvc_task, net); +		BUG(); +	} +} +  /*   * Bring up the lockd process if it's not already up.   */ @@ -252,13 +299,16 @@ int lockd_up(void)  {  	struct svc_serv *serv;  	int		error = 0; +	struct net *net = current->nsproxy->net_ns;  	mutex_lock(&nlmsvc_mutex);  	/*  	 * Check whether we're already up and running.  	 */ -	if (nlmsvc_rqst) +	if (nlmsvc_rqst) { +		error = lockd_up_net(net);  		goto out; +	}  	/*  	 * Sanity check: if there's no pid, @@ -275,7 +325,7 @@ int lockd_up(void)  		goto out;  	} -	error = make_socks(serv); +	error = make_socks(serv, net);  	if (error < 0)  		goto destroy_and_out; @@ -313,8 +363,12 @@ int lockd_up(void)  destroy_and_out:  	svc_destroy(serv);  out: -	if (!error) +	if (!error) { +		struct lockd_net *ln = net_generic(net, lockd_net_id); + +		ln->nlmsvc_users++;  		nlmsvc_users++; +	}  	mutex_unlock(&nlmsvc_mutex);  	return error;  } @@ -328,8 +382,10 @@ lockd_down(void)  {  	mutex_lock(&nlmsvc_mutex);  	if (nlmsvc_users) { -		if (--nlmsvc_users) +		if (--nlmsvc_users) { +			lockd_down_net(current->nsproxy->net_ns);  			goto out; +		}  	} else {  		printk(KERN_ERR "lockd_down: no users! task=%p\n",  			nlmsvc_task); @@ -497,24 +553,55 @@ module_param_call(nlm_tcpport, param_set_port, param_get_int,  module_param(nsm_use_hostnames, bool, 0644);  module_param(nlm_max_connections, uint, 0644); +static int lockd_init_net(struct net *net) +{ +	return 0; +} + +static void lockd_exit_net(struct net *net) +{ +} + +static struct pernet_operations lockd_net_ops = { +	.init = lockd_init_net, +	.exit = lockd_exit_net, +	.id = &lockd_net_id, +	.size = sizeof(struct lockd_net), +}; + +  /*   * Initialising and terminating the module.   */  static int __init init_nlm(void)  { +	int err; +  #ifdef CONFIG_SYSCTL +	err = -ENOMEM;  	nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); -	return nlm_sysctl_table ? 0 : -ENOMEM; -#else +	if (nlm_sysctl_table == NULL) +		goto err_sysctl; +#endif +	err = register_pernet_subsys(&lockd_net_ops); +	if (err) +		goto err_pernet;  	return 0; + +err_pernet: +#ifdef CONFIG_SYSCTL +	unregister_sysctl_table(nlm_sysctl_table);  #endif +err_sysctl: +	return err;  }  static void __exit exit_nlm(void)  {  	/* FIXME: delete all NLM clients */  	nlm_shutdown_hosts(); +	unregister_pernet_subsys(&lockd_net_ops);  #ifdef CONFIG_SYSCTL  	unregister_sysctl_table(nlm_sysctl_table);  #endif  |