Lockd: pass network namespace to creation and destruction routines
Subsystems (3)
PATCH 1/4 Lockd: pass network namespace to creation and destruction routines
From: Stanislav Kinsbursky <[email protected]>
upstream commit e3f70eadb7dddfb5a2bb9afff7abfc6ee17a29d0.
v2: dereference of most probably already released nlm_host removed in nlmclnt_done() and reclaimer().
These routines are called from locks reclaimer() kernel thread. This thread works in "init_net" network context and currently relays on persence on lockd thread and it's per-net resources. Thus lockd_up() and lockd_down() can't relay on current network context. So let's pass corrent one into them.
--- fs/lockd/clntlock.c | 13 ++++++++----- fs/lockd/svc.c | 7 +++---- fs/nfsd/nfssvc.c | 6 +++--- include/linux/lockd/bind.h | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-)
fs/lockd/clntlock.c +8 -5
@@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)u32 nlm_version = (nlm_init->nfs_version ==2 ) ?1 :4 ;int status; - status =lockd_up (); + status =lockd_up (nlm_init->net);if (status <0 )return ERR_PTR (status);
@@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) nlm_init->hostname, nlm_init->noresvport, nlm_init->net);if (host ==NULL ) { -lockd_down (); +lockd_down (nlm_init->net);return ERR_PTR (-ENOLCK ); }
@@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init);*/ void nlmclnt_done (struct nlm_host *host) { +struct net *net = host->net; +nlmclnt_release_host (host); -lockd_down (); +lockd_down (net); }EXPORT_SYMBOL_GPL (nlmclnt_done);
@@ -220,11 +222,12 @@ reclaimer(void *ptr)struct nlm_wait *block;struct file_lock *fl, *next;u32 nsmstate; +struct net *net = host->net;allow_signal (SIGKILL );down_write (&host->h_rwsem); -lockd_up ();/* note: this cannot fail as lockd is already running */ +lockd_up (net);/* note: this cannot fail as lockd is already running */ dprintk ("lockd: reclaiming locks for host %s\n" , host->h_name);
@@ -275,6 +278,6 @@ restart:/* Release host handle after use */ nlmclnt_release_host (host); -lockd_down (); +lockd_down (net);return 0 ; }
fs/lockd/svc.c +3 -4
@@ -295,11 +295,10 @@ static void lockd_down_net(struct net *net)/* * Bring up the lockd process if it's not already up. */ -int lockd_up (void ) +int lockd_up (struct net *net) {struct svc_serv *serv;int error =0 ; -struct net *net = current->nsproxy->net_ns;mutex_lock (&nlmsvc_mutex);/*
@@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up);* Decrement the user count and bring down lockd if we're the last. */ void -lockd_down (void ) +lockd_down (struct net *net) {mutex_lock (&nlmsvc_mutex);if (nlmsvc_users) {if (--nlmsvc_users) { -lockd_down_net (current->nsproxy->net_ns); +lockd_down_net (net); goto out; } }else {
fs/nfsd/nfssvc.c +3 -3
@@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs) ret =nfsd_init_socks (port);if (ret) goto out_racache; - ret =lockd_up (); + ret =lockd_up (&init_net);if (ret) goto out_racache; ret =nfs4_state_start ();
@@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short port, int nrservs) nfsd_up = true;return 0 ; out_lockd: -lockd_down (); +lockd_down (&init_net); out_racache:nfsd_racache_shutdown ();return ret;
@@ -246,7 +246,7 @@ static void nfsd_shutdown(void)if (!nfsd_up)return ;nfs4_state_shutdown (); -lockd_down (); +lockd_down (&init_net);nfsd_racache_shutdown (); nfsd_up = false; }
include/linux/lockd/bind.h +2 -2
@@ -54,7 +54,7 @@ extern void nlmclnt_done(struct nlm_host *host);extern int nlmclnt_proc (struct nlm_host *host,int cmd,struct file_lock *fl); -extern int lockd_up (void ); -extern void lockd_down (void ); +extern int lockd_up (struct net *net); +extern void lockd_down (struct net *net);#endif /* LINUX_LOCKD_BIND_H */
Signature · 1 line
1.7.9.5
PATCH 2/4 SUNRPC: new svc_bind() routine introduced
From: Stanislav Kinsbursky <[email protected]>
upstream commit 9793f7c88937e7ac07305ab1af1a519225836823.
This new routine is responsible for service registration in a specified network context.
The idea is to separate service creation from per-net operations.
Note also: since registering service with svc_bind() can fail, the service will be destroyed and during destruction it will try to unregister itself from rpcbind. In this case unregistration has to be skipped.
--- fs/lockd/svc.c | 6 ++++++ fs/nfs/callback.c | 8 ++++++++ fs/nfsd/nfssvc.c | 9 +++++++++ include/linux/sunrpc/svc.h | 1 + net/sunrpc/rpcb_clnt.c | 12 +++++++----- net/sunrpc/svc.c | 19 ++++++++++--------- 6 files changed, 41 insertions(+), 14 deletions(-)
fs/lockd/svc.c +6 -0
@@ -324,6 +324,12 @@ int lockd_up(struct net *net) goto out; } + error =svc_bind (serv, net); +if (error <0 ) { +printk (KERN_WARNING "lockd_up: bind service failed\n" ); + goto destroy_and_out; + } + error =make_socks (serv, net);if (error <0 ) goto destroy_and_out;
fs/nfs/callback.c +8 -0
@@ -17,6 +17,7 @@#include <linux/kthread.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/bc_xprt.h> +#include <linux/nsproxy.h> #include <net/inet_sock.h>
@@ -253,6 +254,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)char svc_name[12 ];int ret =0 ;int minorversion_setup; +struct net *net = current->nsproxy->net_ns;mutex_lock (&nfs_callback_mutex);if (cb_info->users++ || cb_info->task !=NULL ) {
@@ -265,6 +267,12 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) goto out_err; } + ret =svc_bind (serv, net); +if (ret <0 ) { +printk (KERN_WARNING "NFS: bind callback service failed\n" ); + goto out_err; + } + minorversion_setup =nfs_minorversion_callback_svc_setup (minorversion, serv, xprt, &rqstp, &callback_svc);if (!minorversion_setup) {
fs/nfsd/nfssvc.c +9 -0
@@ -11,6 +11,7 @@#include <linux/module.h> #include <linux/fs_struct.h> #include <linux/swap.h> +#include <linux/nsproxy.h> #include <linux/sunrpc/stats.h> #include <linux/sunrpc/svcsock.h>
@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(void)int nfsd_create_serv (void ) { +int error; +WARN_ON (!mutex_is_locked (&nfsd_mutex));if (nfsd_serv) {svc_get (nfsd_serv);
@@ -343,6 +346,12 @@ int nfsd_create_serv(void)if (nfsd_serv ==NULL )return -ENOMEM ; + error =svc_bind (nfsd_serv, current->nsproxy->net_ns); +if (error <0 ) { +svc_destroy (nfsd_serv); +return error; + } +set_max_drc ();do_gettimeofday (&nfssvc_boot);/* record boot time */ return 0 ;
include/linux/sunrpc/svc.h +1 -0
@@ -416,6 +416,7 @@ struct svc_procedure {*/ int svc_rpcb_setup (struct svc_serv *serv,struct net *net);void svc_rpcb_cleanup (struct svc_serv *serv,struct net *net); +int svc_bind (struct svc_serv *serv,struct net *net);struct svc_serv *svc_create (struct svc_program *,unsigned int ,void (*shutdown)(struct svc_serv *,struct net *net)); struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
net/sunrpc/rpcb_clnt.c +7 -5
@@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net)struct sunrpc_net *sn =net_generic (net, sunrpc_net_id);struct rpc_clnt *clnt = sn->rpcb_local_clnt;struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; -int shutdown; +int shutdown =0 ;spin_lock (&sn->rpcb_clnt_lock); -if (--sn->rpcb_users ==0 ) { - sn->rpcb_local_clnt =NULL ; - sn->rpcb_local_clnt4 =NULL ; +if (sn->rpcb_users) { +if (--sn->rpcb_users ==0 ) { + sn->rpcb_local_clnt =NULL ; + sn->rpcb_local_clnt4 =NULL ; + } + shutdown = !sn->rpcb_users; } - shutdown = !sn->rpcb_users;spin_unlock (&sn->rpcb_clnt_lock);if (shutdown) {
net/sunrpc/svc.c +10 -9
@@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_serv *serv)return 0 ; } +int svc_bind (struct svc_serv *serv,struct net *net) +{ +if (!svc_uses_rpcbind (serv)) +return 0 ; +return svc_rpcb_setup (serv, net); +} +EXPORT_SYMBOL_GPL (svc_bind); +/* * Create an RPC service */
@@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,spin_lock_init (&pool->sp_lock); } -if (svc_uses_rpcbind (serv)) { -if (svc_rpcb_setup (serv, current->nsproxy->net_ns) <0 ) { -kfree (serv->sv_pools); -kfree (serv); -return NULL ; - } -if (!serv->sv_shutdown) - serv->sv_shutdown = svc_rpcb_cleanup; - } +if (svc_uses_rpcbind (serv) && (!serv->sv_shutdown)) + serv->sv_shutdown = svc_rpcb_cleanup;return serv; }
Signature · 1 line
1.7.9.5
PATCH 3/4 SUNRPC: move per-net operations from svc_destroy()
In reply to J. Bruce FieldsFrom: Stanislav Kinsbursky <[email protected]>
upstream commit 786185b5f8abefa6a8a16695bb4a59c164d5a071.
The idea is to separate service destruction and per-net operations, because these are two different things and the mix looks ugly.
Notes:
1) For NFS server this patch looks ugly (sorry for that). But these place will be rewritten soon during NFSd containerization.
2) LockD per-net counter increase int lockd_up() was moved prior to make_socks() to make lockd_down_net() call safe in case of error.
--- fs/lockd/svc.c | 27 +++++++++++++++------------ fs/nfs/callback.c | 3 +++ fs/nfsd/nfsctl.c | 12 +++++++++--- fs/nfsd/nfssvc.c | 14 ++++++++++++++ net/sunrpc/svc.c | 4 ---- 5 files changed, 41 insertions(+), 19 deletions(-)
fs/lockd/svc.c +15 -12
@@ -257,7 +257,7 @@ static int lockd_up_net(struct net *net)struct svc_serv *serv = nlmsvc_rqst->rq_server;int error; -if (ln->nlmsvc_users) +if (ln->nlmsvc_users++)return 0 ; error =svc_rpcb_setup (serv, net);
@@ -272,6 +272,7 @@ static int lockd_up_net(struct net *net) err_socks:svc_rpcb_cleanup (serv, net); err_rpcb: + ln->nlmsvc_users--;return error; }
@@ -299,6 +300,7 @@ int lockd_up(struct net *net) {struct svc_serv *serv;int error =0 ; +struct lockd_net *ln =net_generic (net, lockd_net_id);mutex_lock (&nlmsvc_mutex);/*
@@ -330,9 +332,11 @@ int lockd_up(struct net *net) goto destroy_and_out; } + ln->nlmsvc_users++; + error =make_socks (serv, net);if (error <0 ) - goto destroy_and_out; + goto err_start;/* * Create the kernel thread and wait for it to start.
@@ -344,7 +348,7 @@ int lockd_up(struct net *net)printk (KERN_WARNING "lockd_up: svc_rqst allocation failed, error=%d\n" , error); - goto destroy_and_out; + goto err_start; }svc_sock_update_bufs (serv);
@@ -358,7 +362,7 @@ int lockd_up(struct net *net) nlmsvc_rqst =NULL ;printk (KERN_WARNING "lockd_up: kthread_run failed, error=%d\n" , error); - goto destroy_and_out; + goto err_start; }/*
@@ -368,14 +372,14 @@ int lockd_up(struct net *net) destroy_and_out:svc_destroy (serv); out: -if (!error) { -struct lockd_net *ln =net_generic (net, lockd_net_id); - - ln->nlmsvc_users++; +if (!error) nlmsvc_users++; - }mutex_unlock (&nlmsvc_mutex);return error; + +err_start: +lockd_down_net (net); + goto destroy_and_out; }EXPORT_SYMBOL_GPL (lockd_up);
@@ -386,11 +390,10 @@ void lockd_down(struct net *net) {mutex_lock (&nlmsvc_mutex); +lockd_down_net (net);if (nlmsvc_users) { -if (--nlmsvc_users) { -lockd_down_net (net); +if (--nlmsvc_users) goto out; - } }else {printk (KERN_ERR "lockd_down: no users! task=%p\n" , nlmsvc_task);
fs/nfs/callback.c +3 -0
@@ -314,6 +314,8 @@ out_err:dprintk ("NFS: Couldn't create callback socket or server thread; " "err = %d\n" , ret); cb_info->users--; +if (serv) +svc_shutdown_net (serv, net); goto out; }
@@ -328,6 +330,7 @@ void nfs_callback_down(int minorversion) cb_info->users--;if (cb_info->users ==0 && cb_info->task !=NULL ) {kthread_stop (cb_info->task); +svc_shutdown_net (cb_info->serv, current->nsproxy->net_ns);svc_exit_thread (cb_info->rqst); cb_info->serv =NULL ; cb_info->rqst =NULL ;
fs/nfsd/nfsctl.c +9 -3
@@ -651,6 +651,7 @@ static ssize_t __write_ports_addfd(char *buf) {char *mesg = buf;int fd, err; +struct net *net = &init_net; err =get_int (&mesg, &fd);if (err !=0 || fd <0 )
@@ -662,6 +663,8 @@ static ssize_t __write_ports_addfd(char *buf) err =svc_addsock (nfsd_serv, fd, buf,SIMPLE_TRANSACTION_LIMIT );if (err <0 ) { +if (nfsd_serv->sv_nrthreads ==1 ) +svc_shutdown_net (nfsd_serv, net);svc_destroy (nfsd_serv);return err; }
@@ -699,6 +702,7 @@ static ssize_t __write_ports_addxprt(char *buf)char transport[16 ];struct svc_xprt *xprt;int port, err; +struct net *net = &init_net;if (sscanf (buf,"%15s %4u" , transport, &port) !=2 )return -EINVAL ;
@@ -710,12 +714,12 @@ static ssize_t __write_ports_addxprt(char *buf)if (err !=0 )return err; - err =svc_create_xprt (nfsd_serv, transport, &init_net, + err =svc_create_xprt (nfsd_serv, transport, net,PF_INET , port,SVC_SOCK_ANONYMOUS );if (err <0 ) goto out_err; - err =svc_create_xprt (nfsd_serv, transport, &init_net, + err =svc_create_xprt (nfsd_serv, transport, net,PF_INET6 , port,SVC_SOCK_ANONYMOUS );if (err <0 && err != -EAFNOSUPPORT ) goto out_close;
@@ -724,12 +728,14 @@ static ssize_t __write_ports_addxprt(char *buf) nfsd_serv->sv_nrthreads--;return 0 ; out_close: - xprt =svc_find_xprt (nfsd_serv, transport, &init_net,PF_INET , port); + xprt =svc_find_xprt (nfsd_serv, transport, net,PF_INET , port);if (xprt !=NULL ) {svc_close_xprt (xprt);svc_xprt_put (xprt); } out_err: +if (nfsd_serv->sv_nrthreads ==1 ) +svc_shutdown_net (nfsd_serv, net);svc_destroy (nfsd_serv);return err; }
fs/nfsd/nfssvc.c +14 -0
@@ -382,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)int i =0 ;int tot =0 ;int err =0 ; +struct net *net = &init_net;WARN_ON (!mutex_is_locked (&nfsd_mutex));
@@ -426,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthreads)if (err)break ; } + +if (nfsd_serv->sv_nrthreads ==1 ) +svc_shutdown_net (nfsd_serv, net);svc_destroy (nfsd_serv);return err;
@@ -441,6 +445,7 @@ nfsd_svc(unsigned short port, int nrservs) {int error;bool nfsd_up_before; +struct net *net = &init_net;mutex_lock (&nfsd_mutex);dprintk ("nfsd: creating service\n" );
@@ -473,6 +478,8 @@ out_shutdown:if (error <0 && !nfsd_up_before)nfsd_shutdown (); out_destroy: +if (nfsd_serv->sv_nrthreads ==1 ) +svc_shutdown_net (nfsd_serv, net);svc_destroy (nfsd_serv);/* Release server */ out:mutex_unlock (&nfsd_mutex);
@@ -556,6 +563,9 @@ nfsd(void *vrqstp) nfsdstats.th_cnt --; out: +if (rqstp->rq_server->sv_nrthreads ==1 ) +svc_shutdown_net (rqstp->rq_server, &init_net); +/* Release the thread */ svc_exit_thread (rqstp);
@@ -668,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file)int nfsd_pool_stats_release (struct inode *inode,struct file *file) {int ret =seq_release (inode, file); +struct net *net = &init_net; +mutex_lock (&nfsd_mutex);/* this function really, really should have been called svc_put() */ +if (nfsd_serv->sv_nrthreads ==1 ) +svc_shutdown_net (nfsd_serv, net);svc_destroy (nfsd_serv);mutex_unlock (&nfsd_mutex);return ret;
net/sunrpc/svc.c +0 -4
@@ -537,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net);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);
@@ -553,8 +551,6 @@ svc_destroy(struct svc_serv *serv)del_timer_sync (&serv->sv_temptimer); -svc_shutdown_net (serv, net); -/* * The last user is gone and thus all sockets have to be destroyed to * the point. Check this.
Signature · 1 line
1.7.9.5
PATCH 4/4 NFS: hard-code init_net for NFS callback transports
In reply to J. Bruce FieldsFrom: Stanislav Kinsbursky <[email protected]>
upstream commit 12918b10d59e975fd5241eef03ef9e6d5ea3dcfe.
In case of destroying mount namespace on child reaper exit, nsproxy is zeroed to the point already. So, dereferencing of it is invalid.
This patch hard-code "init_net" for all network namespace references for NFS callback services. This will be fixed with proper NFS callback containerization.
--- fs/nfs/callback.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/nfs/callback.c +5 -6
@@ -17,7 +17,6 @@#include <linux/kthread.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/bc_xprt.h> -#include <linux/nsproxy.h> #include <net/inet_sock.h>
@@ -107,7 +106,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) {int ret; - ret =svc_create_xprt (serv,"tcp" , xprt->xprt_net,PF_INET , + ret =svc_create_xprt (serv,"tcp" , &init_net,PF_INET , nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS );if (ret <=0 ) goto out_err;
@@ -115,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)dprintk ("NFS: Callback listener port = %u (af %u)\n" , nfs_callback_tcpport,PF_INET ); - ret =svc_create_xprt (serv,"tcp" , xprt->xprt_net,PF_INET6 , + ret =svc_create_xprt (serv,"tcp" , &init_net,PF_INET6 , nfs_callback_set_tcpport,SVC_SOCK_ANONYMOUS );if (ret >0 ) { nfs_callback_tcpport6 = ret;
@@ -184,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)* fore channel connection. * Returns the input port (0) and sets the svc_serv bc_xprt on success */ - ret =svc_create_xprt (serv,"tcp-bc" , xprt->xprt_net,PF_INET ,0 , + ret =svc_create_xprt (serv,"tcp-bc" , &init_net,PF_INET ,0 ,SVC_SOCK_ANONYMOUS );if (ret <0 ) { rqstp =ERR_PTR (ret);
@@ -254,7 +253,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)char svc_name[12 ];int ret =0 ;int minorversion_setup; -struct net *net = current->nsproxy->net_ns; +struct net *net = &init_net;mutex_lock (&nfs_callback_mutex);if (cb_info->users++ || cb_info->task !=NULL ) {
@@ -330,7 +329,7 @@ void nfs_callback_down(int minorversion) cb_info->users--;if (cb_info->users ==0 && cb_info->task !=NULL ) {kthread_stop (cb_info->task); -svc_shutdown_net (cb_info->serv, current->nsproxy->net_ns); +svc_shutdown_net (cb_info->serv, &init_net);svc_exit_thread (cb_info->rqst); cb_info->serv =NULL ; cb_info->rqst =NULL ;
Signature · 1 line
1.7.9.5