Re: [PATCH v2 1/1] NFSD: enhance inter-server copy cleanup

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

 




> On Dec 18, 2022, at 7:55 PM, Dai Ngo <dai.ngo@xxxxxxxxxx> wrote:
> 
> Currently nfsd4_setup_inter_ssc returns the vfsmount of the source
> server's export when the mount completes. After the copy is done
> nfsd4_cleanup_inter_ssc is called with the vfsmount of the source
> server and it searches nfsd_ssc_mount_list for a matching entry
> to do the clean up.
> 
> The problems with this approach are (1) the need to search the
> nfsd_ssc_mount_list and (2) the code has to handle the case where
> the matching entry is not found which looks ugly.
> 
> The enhancement is instead of nfsd4_setup_inter_ssc returning the
> vfsmount, it returns the nfsd4_ssc_umount_item which has the
> vfsmount embedded in it. When nfsd4_cleanup_inter_ssc is called
> it's passed with the nfsd4_ssc_umount_item directly to do the
> clean up so no searching is needed and there is no need to handle
> the 'not found' case.
> 
> Signed-off-by: Dai Ngo <dai.ngo@xxxxxxxxxx>
> ---
> V2: fix compile error when CONFIG_NFSD_V4_2_INTER_SSC not defined.
>    Reported by kernel test robot.

Hello Dai - I've looked at this, nothing to comment on so far. I
plan to go over it again sometime this week.

I'd like to hear from others before applying it.


> fs/nfsd/nfs4proc.c      | 94 +++++++++++++++++++------------------------------
> fs/nfsd/xdr4.h          |  2 +-
> include/linux/nfs_ssc.h |  2 +-
> 3 files changed, 38 insertions(+), 60 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index b79ee65ae016..6515b00520bc 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1295,15 +1295,15 @@ extern void nfs_sb_deactive(struct super_block *sb);
>  * setup a work entry in the ssc delayed unmount list.
>  */
> static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
> -		struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt)
> +		struct nfsd4_ssc_umount_item **nsui)
> {
> 	struct nfsd4_ssc_umount_item *ni = NULL;
> 	struct nfsd4_ssc_umount_item *work = NULL;
> 	struct nfsd4_ssc_umount_item *tmp;
> 	DEFINE_WAIT(wait);
> +	__be32 status = 0;
> 
> -	*ss_mnt = NULL;
> -	*retwork = NULL;
> +	*nsui = NULL;
> 	work = kzalloc(sizeof(*work), GFP_KERNEL);
> try_again:
> 	spin_lock(&nn->nfsd_ssc_lock);
> @@ -1326,12 +1326,12 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
> 			finish_wait(&nn->nfsd_ssc_waitq, &wait);
> 			goto try_again;
> 		}
> -		*ss_mnt = ni->nsui_vfsmount;
> +		*nsui = ni;
> 		refcount_inc(&ni->nsui_refcnt);
> 		spin_unlock(&nn->nfsd_ssc_lock);
> 		kfree(work);
> 
> -		/* return vfsmount in ss_mnt */
> +		/* return vfsmount in (*nsui)->nsui_vfsmount */
> 		return 0;
> 	}
> 	if (work) {
> @@ -1339,10 +1339,11 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
> 		refcount_set(&work->nsui_refcnt, 2);
> 		work->nsui_busy = true;
> 		list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list);
> -		*retwork = work;
> -	}
> +		*nsui = work;
> +	} else
> +		status = nfserr_resource;
> 	spin_unlock(&nn->nfsd_ssc_lock);
> -	return 0;
> +	return status;
> }
> 
> static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn,
> @@ -1371,7 +1372,7 @@ static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn,
>  */
> static __be32
> nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
> -		       struct vfsmount **mount)
> +			struct nfsd4_ssc_umount_item **nsui)
> {
> 	struct file_system_type *type;
> 	struct vfsmount *ss_mnt;
> @@ -1382,7 +1383,6 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
> 	char *ipaddr, *dev_name, *raw_data;
> 	int len, raw_len;
> 	__be32 status = nfserr_inval;
> -	struct nfsd4_ssc_umount_item *work = NULL;
> 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> 
> 	naddr = &nss->u.nl4_addr;
> @@ -1390,6 +1390,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
> 					 naddr->addr_len,
> 					 (struct sockaddr *)&tmp_addr,
> 					 sizeof(tmp_addr));
> +	*nsui = NULL;
> 	if (tmp_addrlen == 0)
> 		goto out_err;
> 
> @@ -1432,10 +1433,10 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
> 		goto out_free_rawdata;
> 	snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
> 
> -	status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt);
> +	status = nfsd4_ssc_setup_dul(nn, ipaddr, nsui);
> 	if (status)
> 		goto out_free_devname;
> -	if (ss_mnt)
> +	if ((*nsui)->nsui_vfsmount)
> 		goto out_done;
> 
> 	/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
> @@ -1443,15 +1444,12 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
> 	module_put(type->owner);
> 	if (IS_ERR(ss_mnt)) {
> 		status = nfserr_nodev;
> -		if (work)
> -			nfsd4_ssc_cancel_dul_work(nn, work);
> +		nfsd4_ssc_cancel_dul_work(nn, *nsui);
> 		goto out_free_devname;
> 	}
> -	if (work)
> -		nfsd4_ssc_update_dul_work(nn, work, ss_mnt);
> +	nfsd4_ssc_update_dul_work(nn, *nsui, ss_mnt);
> out_done:
> 	status = 0;
> -	*mount = ss_mnt;
> 
> out_free_devname:
> 	kfree(dev_name);
> @@ -1474,8 +1472,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
>  */
> static __be32
> nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> -		      struct nfsd4_compound_state *cstate,
> -		      struct nfsd4_copy *copy, struct vfsmount **mount)
> +		struct nfsd4_compound_state *cstate, struct nfsd4_copy *copy)
> {
> 	struct svc_fh *s_fh = NULL;
> 	stateid_t *s_stid = &copy->cp_src_stateid;
> @@ -1488,7 +1485,8 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> 	if (status)
> 		goto out;
> 
> -	status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount);
> +	status = nfsd4_interssc_connect(copy->cp_src, rqstp,
> +				&copy->ss_nsui);
> 	if (status)
> 		goto out;
> 
> @@ -1506,61 +1504,42 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> }
> 
> static void
> -nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
> +nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *ni, struct file *filp,
> 			struct nfsd_file *dst)
> {
> -	bool found = false;
> 	long timeout;
> -	struct nfsd4_ssc_umount_item *tmp;
> -	struct nfsd4_ssc_umount_item *ni = NULL;
> 	struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
> 
> 	nfs42_ssc_close(filp);
> 	nfsd_file_put(dst);
> 	fput(filp);
> 
> -	if (!nn) {
> -		mntput(ss_mnt);
> -		return;
> -	}
> 	spin_lock(&nn->nfsd_ssc_lock);
> 	timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout);
> -	list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) {
> -		if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) {
> -			list_del(&ni->nsui_list);
> -			/*
> -			 * vfsmount can be shared by multiple exports,
> -			 * decrement refcnt. If the count drops to 1 it
> -			 * will be unmounted when nsui_expire expires.
> -			 */
> -			refcount_dec(&ni->nsui_refcnt);
> -			ni->nsui_expire = jiffies + timeout;
> -			list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list);
> -			found = true;
> -			break;
> -		}
> -	}
> +	list_del(&ni->nsui_list);
> +	/*
> +	 * vfsmount can be shared by multiple exports,
> +	 * decrement refcnt. If the count drops to 1 it
> +	 * will be unmounted when nsui_expire expires.
> +	 */
> +	refcount_dec(&ni->nsui_refcnt);
> +	ni->nsui_expire = jiffies + timeout;
> +	list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list);
> 	spin_unlock(&nn->nfsd_ssc_lock);
> -	if (!found) {
> -		mntput(ss_mnt);
> -		return;
> -	}
> }
> 
> #else /* CONFIG_NFSD_V4_2_INTER_SSC */
> 
> static __be32
> nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
> -		      struct nfsd4_compound_state *cstate,
> -		      struct nfsd4_copy *copy,
> -		      struct vfsmount **mount)
> +			struct nfsd4_compound_state *cstate,
> +			struct nfsd4_copy *copy)
> {
> -	*mount = NULL;
> 	return nfserr_inval;
> }
> 
> static void
> -nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
> +nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *ni, struct file *filp,
> 			struct nfsd_file *dst)
> {
> }
> @@ -1700,7 +1679,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
> 	memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server));
> 	memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
> 	memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
> -	dst->ss_mnt = src->ss_mnt;
> +	dst->ss_nsui = src->ss_nsui;
> }
> 
> static void cleanup_async_copy(struct nfsd4_copy *copy)
> @@ -1749,8 +1728,8 @@ static int nfsd4_do_async_copy(void *data)
> 	if (nfsd4_ssc_is_inter(copy)) {
> 		struct file *filp;
> 
> -		filp = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
> -				      &copy->stateid);
> +		filp = nfs42_ssc_open(copy->ss_nsui->nsui_vfsmount,
> +				&copy->c_fh, &copy->stateid);
> 		if (IS_ERR(filp)) {
> 			switch (PTR_ERR(filp)) {
> 			case -EBADF:
> @@ -1764,7 +1743,7 @@ static int nfsd4_do_async_copy(void *data)
> 		}
> 		nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
> 				       false);
> -		nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst);
> +		nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst);
> 	} else {
> 		nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
> 				       copy->nf_dst->nf_file, false);
> @@ -1790,8 +1769,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> 			status = nfserr_notsupp;
> 			goto out;
> 		}
> -		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
> -				&copy->ss_mnt);
> +		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy);
> 		if (status)
> 			return nfserr_offload_denied;
> 	} else {
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 0eb00105d845..36c3340c1d54 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -571,7 +571,7 @@ struct nfsd4_copy {
> 	struct task_struct	*copy_task;
> 	refcount_t		refcount;
> 
> -	struct vfsmount		*ss_mnt;
> +	struct nfsd4_ssc_umount_item *ss_nsui;
> 	struct nfs_fh		c_fh;
> 	nfs4_stateid		stateid;
> };
> diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h
> index 75843c00f326..22265b1ff080 100644
> --- a/include/linux/nfs_ssc.h
> +++ b/include/linux/nfs_ssc.h
> @@ -53,6 +53,7 @@ static inline void nfs42_ssc_close(struct file *filep)
> 	if (nfs_ssc_client_tbl.ssc_nfs4_ops)
> 		(*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
> }
> +#endif
> 
> struct nfsd4_ssc_umount_item {
> 	struct list_head nsui_list;
> @@ -66,7 +67,6 @@ struct nfsd4_ssc_umount_item {
> 	struct vfsmount *nsui_vfsmount;
> 	char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
> };
> -#endif
> 
> /*
>  * NFS_FS
> -- 
> 2.9.5
> 

--
Chuck Lever







[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