> 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 = ©->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, > + ©->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, ©->c_fh, > - ©->stateid); > + filp = nfs42_ssc_open(copy->ss_nsui->nsui_vfsmount, > + ©->c_fh, ©->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, > - ©->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