Re: [PATCH] nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Mar 13, 2021 at 04:08:47PM -0500, trondmy@xxxxxxxxxx wrote:
> From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
> 
> In order to ensure that knfsd threads don't linger once the nfsd
> pseudofs is unmounted (e.g. when the container is killed) we let
> nfsd_umount() shut down those threads and wait for them to exit.
> 
> This also should ensure that we don't need to do a kernel mount of
> the pseudofs, since the thread lifetime is now limited by the
> lifetime of the filesystem.

The nfsd filesystem is per-container, and threads are global, so I don't
understand how this works.

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
> ---
>  fs/nfsd/netns.h     |  6 +++---
>  fs/nfsd/nfs4state.c |  8 +-------
>  fs/nfsd/nfsctl.c    | 14 ++------------
>  fs/nfsd/nfsd.h      |  3 +--
>  fs/nfsd/nfssvc.c    | 35 ++++++++++++++++++++++++++++++++++-
>  5 files changed, 41 insertions(+), 25 deletions(-)
> 
> diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
> index c330f5bd0cf3..a75abeb1e698 100644
> --- a/fs/nfsd/netns.h
> +++ b/fs/nfsd/netns.h
> @@ -51,9 +51,6 @@ struct nfsd_net {
>  	bool grace_ended;
>  	time64_t boot_time;
>  
> -	/* internal mount of the "nfsd" pseudofilesystem: */
> -	struct vfsmount *nfsd_mnt;
> -
>  	struct dentry *nfsd_client_dir;
>  
>  	/*
> @@ -130,6 +127,9 @@ struct nfsd_net {
>  	wait_queue_head_t ntf_wq;
>  	atomic_t ntf_refcnt;
>  
> +	/* Allow umount to wait for nfsd state cleanup */
> +	struct completion nfsd_shutdown_complete;
> +
>  	/*
>  	 * clientid and stateid data for construction of net unique COPY
>  	 * stateids.
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 423fd6683f3a..8bf840661d67 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -7346,14 +7346,9 @@ nfs4_state_start_net(struct net *net)
>  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
>  	int ret;
>  
> -	ret = get_nfsdfs(net);
> -	if (ret)
> -		return ret;
>  	ret = nfs4_state_create_net(net);
> -	if (ret) {
> -		mntput(nn->nfsd_mnt);
> +	if (ret)
>  		return ret;
> -	}
>  	locks_start_grace(net, &nn->nfsd4_manager);
>  	nfsd4_client_tracking_init(net);
>  	if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
> @@ -7423,7 +7418,6 @@ nfs4_state_shutdown_net(struct net *net)
>  
>  	nfsd4_client_tracking_exit(net);
>  	nfs4_state_destroy_net(net);
> -	mntput(nn->nfsd_mnt);
>  }
>  
>  void
> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> index ef86ed23af82..02ff7f762e2d 100644
> --- a/fs/nfsd/nfsctl.c
> +++ b/fs/nfsd/nfsctl.c
> @@ -1416,6 +1416,8 @@ static void nfsd_umount(struct super_block *sb)
>  {
>  	struct net *net = sb->s_fs_info;
>  
> +	nfsd_shutdown_threads(net);
> +
>  	kill_litter_super(sb);
>  	put_net(net);
>  }
> @@ -1428,18 +1430,6 @@ static struct file_system_type nfsd_fs_type = {
>  };
>  MODULE_ALIAS_FS("nfsd");
>  
> -int get_nfsdfs(struct net *net)
> -{
> -	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> -	struct vfsmount *mnt;
> -
> -	mnt =  vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
> -	if (IS_ERR(mnt))
> -		return PTR_ERR(mnt);
> -	nn->nfsd_mnt = mnt;
> -	return 0;
> -}
> -
>  #ifdef CONFIG_PROC_FS
>  static int create_proc_exports_entry(void)
>  {
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 8bdc37aa2c2e..27c1308ffc2b 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -93,13 +93,12 @@ int		nfsd_get_nrthreads(int n, int *, struct net *);
>  int		nfsd_set_nrthreads(int n, int *, struct net *);
>  int		nfsd_pool_stats_open(struct inode *, struct file *);
>  int		nfsd_pool_stats_release(struct inode *, struct file *);
> +void		nfsd_shutdown_threads(struct net *net);
>  
>  void		nfsd_destroy(struct net *net);
>  
>  bool		i_am_nfsd(void);
>  
> -int get_nfsdfs(struct net *);
> -
>  struct nfsdfs_client {
>  	struct kref cl_ref;
>  	void (*cl_release)(struct kref *kref);
> diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
> index 6de406322106..f014b7aa0726 100644
> --- a/fs/nfsd/nfssvc.c
> +++ b/fs/nfsd/nfssvc.c
> @@ -596,6 +596,37 @@ static const struct svc_serv_ops nfsd_thread_sv_ops = {
>  	.svo_module		= THIS_MODULE,
>  };
>  
> +static void nfsd_complete_shutdown(struct net *net)
> +{
> +	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> +
> +	WARN_ON(!mutex_is_locked(&nfsd_mutex));
> +
> +	nn->nfsd_serv = NULL;
> +	complete(&nn->nfsd_shutdown_complete);
> +}
> +
> +void nfsd_shutdown_threads(struct net *net)
> +{
> +	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
> +	struct svc_serv *serv;
> +
> +	mutex_lock(&nfsd_mutex);
> +	serv = nn->nfsd_serv;
> +	if (serv == NULL) {
> +		mutex_unlock(&nfsd_mutex);
> +		return;
> +	}
> +
> +	svc_get(serv);
> +	/* Kill outstanding nfsd threads */
> +	serv->sv_ops->svo_setup(serv, NULL, 0);
> +	nfsd_destroy(net);
> +	mutex_unlock(&nfsd_mutex);
> +	/* Wait for shutdown of nfsd_serv to complete */
> +	wait_for_completion(&nn->nfsd_shutdown_complete);
> +}
> +
>  bool i_am_nfsd(void)
>  {
>  	return kthread_func(current) == nfsd;
> @@ -618,11 +649,13 @@ int nfsd_create_serv(struct net *net)
>  						&nfsd_thread_sv_ops);
>  	if (nn->nfsd_serv == NULL)
>  		return -ENOMEM;
> +	init_completion(&nn->nfsd_shutdown_complete);
>  
>  	nn->nfsd_serv->sv_maxconn = nn->max_connections;
>  	error = svc_bind(nn->nfsd_serv, net);
>  	if (error < 0) {
>  		svc_destroy(nn->nfsd_serv);
> +		nfsd_complete_shutdown(net);
>  		return error;
>  	}
>  
> @@ -671,7 +704,7 @@ void nfsd_destroy(struct net *net)
>  		svc_shutdown_net(nn->nfsd_serv, net);
>  	svc_destroy(nn->nfsd_serv);
>  	if (destroy)
> -		nn->nfsd_serv = NULL;
> +		nfsd_complete_shutdown(net);
>  }
>  
>  int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
> -- 
> 2.30.2
> 





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux