Commit df24ac7a authored by Dai Ngo's avatar Dai Ngo Committed by Chuck Lever

NFSD: enhance inter-server copy cleanup

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: default avatarDai Ngo <dai.ngo@oracle.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
[ cel: adjusted whitespace and variable/function names ]
Reviewed-by: default avatarOlga Kornievskaia <kolga@netapp.com>
parent f4afc8fe
...@@ -1293,15 +1293,15 @@ extern void nfs_sb_deactive(struct super_block *sb); ...@@ -1293,15 +1293,15 @@ extern void nfs_sb_deactive(struct super_block *sb);
* setup a work entry in the ssc delayed unmount list. * setup a work entry in the ssc delayed unmount list.
*/ */
static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, 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 *ni = NULL;
struct nfsd4_ssc_umount_item *work = NULL; struct nfsd4_ssc_umount_item *work = NULL;
struct nfsd4_ssc_umount_item *tmp; struct nfsd4_ssc_umount_item *tmp;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
__be32 status = 0;
*ss_mnt = NULL; *nsui = NULL;
*retwork = NULL;
work = kzalloc(sizeof(*work), GFP_KERNEL); work = kzalloc(sizeof(*work), GFP_KERNEL);
try_again: try_again:
spin_lock(&nn->nfsd_ssc_lock); spin_lock(&nn->nfsd_ssc_lock);
...@@ -1325,12 +1325,12 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, ...@@ -1325,12 +1325,12 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
finish_wait(&nn->nfsd_ssc_waitq, &wait); finish_wait(&nn->nfsd_ssc_waitq, &wait);
goto try_again; goto try_again;
} }
*ss_mnt = ni->nsui_vfsmount; *nsui = ni;
refcount_inc(&ni->nsui_refcnt); refcount_inc(&ni->nsui_refcnt);
spin_unlock(&nn->nfsd_ssc_lock); spin_unlock(&nn->nfsd_ssc_lock);
kfree(work); kfree(work);
/* return vfsmount in ss_mnt */ /* return vfsmount in (*nsui)->nsui_vfsmount */
return 0; return 0;
} }
if (work) { if (work) {
...@@ -1338,31 +1338,32 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, ...@@ -1338,31 +1338,32 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr,
refcount_set(&work->nsui_refcnt, 2); refcount_set(&work->nsui_refcnt, 2);
work->nsui_busy = true; work->nsui_busy = true;
list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); 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); spin_unlock(&nn->nfsd_ssc_lock);
return 0; return status;
} }
static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn, static void nfsd4_ssc_update_dul(struct nfsd_net *nn,
struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt) struct nfsd4_ssc_umount_item *nsui,
struct vfsmount *ss_mnt)
{ {
/* set nsui_vfsmount, clear busy flag and wakeup waiters */
spin_lock(&nn->nfsd_ssc_lock); spin_lock(&nn->nfsd_ssc_lock);
work->nsui_vfsmount = ss_mnt; nsui->nsui_vfsmount = ss_mnt;
work->nsui_busy = false; nsui->nsui_busy = false;
wake_up_all(&nn->nfsd_ssc_waitq); wake_up_all(&nn->nfsd_ssc_waitq);
spin_unlock(&nn->nfsd_ssc_lock); spin_unlock(&nn->nfsd_ssc_lock);
} }
static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, static void nfsd4_ssc_cancel_dul(struct nfsd_net *nn,
struct nfsd4_ssc_umount_item *work) struct nfsd4_ssc_umount_item *nsui)
{ {
spin_lock(&nn->nfsd_ssc_lock); spin_lock(&nn->nfsd_ssc_lock);
list_del(&work->nsui_list); list_del(&nsui->nsui_list);
wake_up_all(&nn->nfsd_ssc_waitq); wake_up_all(&nn->nfsd_ssc_waitq);
spin_unlock(&nn->nfsd_ssc_lock); spin_unlock(&nn->nfsd_ssc_lock);
kfree(work); kfree(nsui);
} }
/* /*
...@@ -1370,7 +1371,7 @@ static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, ...@@ -1370,7 +1371,7 @@ static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn,
*/ */
static __be32 static __be32
nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, 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 file_system_type *type;
struct vfsmount *ss_mnt; struct vfsmount *ss_mnt;
...@@ -1381,7 +1382,6 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ...@@ -1381,7 +1382,6 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
char *ipaddr, *dev_name, *raw_data; char *ipaddr, *dev_name, *raw_data;
int len, raw_len; int len, raw_len;
__be32 status = nfserr_inval; __be32 status = nfserr_inval;
struct nfsd4_ssc_umount_item *work = NULL;
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
naddr = &nss->u.nl4_addr; naddr = &nss->u.nl4_addr;
...@@ -1389,6 +1389,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ...@@ -1389,6 +1389,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
naddr->addr_len, naddr->addr_len,
(struct sockaddr *)&tmp_addr, (struct sockaddr *)&tmp_addr,
sizeof(tmp_addr)); sizeof(tmp_addr));
*nsui = NULL;
if (tmp_addrlen == 0) if (tmp_addrlen == 0)
goto out_err; goto out_err;
...@@ -1431,10 +1432,10 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ...@@ -1431,10 +1432,10 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
goto out_free_rawdata; goto out_free_rawdata;
snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); 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) if (status)
goto out_free_devname; goto out_free_devname;
if (ss_mnt) if ((*nsui)->nsui_vfsmount)
goto out_done; goto out_done;
/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */ /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
...@@ -1442,15 +1443,12 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ...@@ -1442,15 +1443,12 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
module_put(type->owner); module_put(type->owner);
if (IS_ERR(ss_mnt)) { if (IS_ERR(ss_mnt)) {
status = nfserr_nodev; status = nfserr_nodev;
if (work) nfsd4_ssc_cancel_dul(nn, *nsui);
nfsd4_ssc_cancel_dul_work(nn, work);
goto out_free_devname; goto out_free_devname;
} }
if (work) nfsd4_ssc_update_dul(nn, *nsui, ss_mnt);
nfsd4_ssc_update_dul_work(nn, work, ss_mnt);
out_done: out_done:
status = 0; status = 0;
*mount = ss_mnt;
out_free_devname: out_free_devname:
kfree(dev_name); kfree(dev_name);
...@@ -1474,7 +1472,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ...@@ -1474,7 +1472,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
static __be32 static __be32
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate, struct nfsd4_compound_state *cstate,
struct nfsd4_copy *copy, struct vfsmount **mount) struct nfsd4_copy *copy)
{ {
struct svc_fh *s_fh = NULL; struct svc_fh *s_fh = NULL;
stateid_t *s_stid = &copy->cp_src_stateid; stateid_t *s_stid = &copy->cp_src_stateid;
...@@ -1487,7 +1485,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, ...@@ -1487,7 +1485,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
if (status) if (status)
goto out; goto out;
status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount); status = nfsd4_interssc_connect(copy->cp_src, rqstp, &copy->ss_nsui);
if (status) if (status)
goto out; goto out;
...@@ -1505,45 +1503,27 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, ...@@ -1505,45 +1503,27 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
} }
static void static void
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *nsui, struct file *filp,
struct nfsd_file *dst) 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); struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id);
long timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout);
nfs42_ssc_close(filp); nfs42_ssc_close(filp);
nfsd_file_put(dst); nfsd_file_put(dst);
fput(filp); fput(filp);
if (!nn) {
mntput(ss_mnt);
return;
}
spin_lock(&nn->nfsd_ssc_lock); spin_lock(&nn->nfsd_ssc_lock);
timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); list_del(&nsui->nsui_list);
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, * vfsmount can be shared by multiple exports,
* decrement refcnt. If the count drops to 1 it * decrement refcnt. If the count drops to 1 it
* will be unmounted when nsui_expire expires. * will be unmounted when nsui_expire expires.
*/ */
refcount_dec(&ni->nsui_refcnt); refcount_dec(&nsui->nsui_refcnt);
ni->nsui_expire = jiffies + timeout; nsui->nsui_expire = jiffies + timeout;
list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list); list_add_tail(&nsui->nsui_list, &nn->nfsd_ssc_mount_list);
found = true;
break;
}
}
spin_unlock(&nn->nfsd_ssc_lock); spin_unlock(&nn->nfsd_ssc_lock);
if (!found) {
mntput(ss_mnt);
return;
}
} }
#else /* CONFIG_NFSD_V4_2_INTER_SSC */ #else /* CONFIG_NFSD_V4_2_INTER_SSC */
...@@ -1551,15 +1531,13 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, ...@@ -1551,15 +1531,13 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp,
static __be32 static __be32
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate, struct nfsd4_compound_state *cstate,
struct nfsd4_copy *copy, struct nfsd4_copy *copy)
struct vfsmount **mount)
{ {
*mount = NULL;
return nfserr_inval; return nfserr_inval;
} }
static void static void
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *nsui, struct file *filp,
struct nfsd_file *dst) struct nfsd_file *dst)
{ {
} }
...@@ -1700,7 +1678,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) ...@@ -1700,7 +1678,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->cp_src, src->cp_src, sizeof(struct nl4_server));
memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid)); memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh)); 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) static void cleanup_async_copy(struct nfsd4_copy *copy)
...@@ -1749,8 +1727,8 @@ static int nfsd4_do_async_copy(void *data) ...@@ -1749,8 +1727,8 @@ static int nfsd4_do_async_copy(void *data)
if (nfsd4_ssc_is_inter(copy)) { if (nfsd4_ssc_is_inter(copy)) {
struct file *filp; struct file *filp;
filp = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh, filp = nfs42_ssc_open(copy->ss_nsui->nsui_vfsmount,
&copy->stateid); &copy->c_fh, &copy->stateid);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
switch (PTR_ERR(filp)) { switch (PTR_ERR(filp)) {
case -EBADF: case -EBADF:
...@@ -1764,7 +1742,7 @@ static int nfsd4_do_async_copy(void *data) ...@@ -1764,7 +1742,7 @@ static int nfsd4_do_async_copy(void *data)
} }
nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file, nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
false); false);
nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst); nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst);
} else { } else {
nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
copy->nf_dst->nf_file, false); copy->nf_dst->nf_file, false);
...@@ -1790,8 +1768,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1790,8 +1768,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_notsupp; status = nfserr_notsupp;
goto out; goto out;
} }
status = nfsd4_setup_inter_ssc(rqstp, cstate, copy, status = nfsd4_setup_inter_ssc(rqstp, cstate, copy);
&copy->ss_mnt);
if (status) if (status)
return nfserr_offload_denied; return nfserr_offload_denied;
} else { } else {
......
...@@ -571,7 +571,7 @@ struct nfsd4_copy { ...@@ -571,7 +571,7 @@ struct nfsd4_copy {
struct task_struct *copy_task; struct task_struct *copy_task;
refcount_t refcount; refcount_t refcount;
struct vfsmount *ss_mnt; struct nfsd4_ssc_umount_item *ss_nsui;
struct nfs_fh c_fh; struct nfs_fh c_fh;
nfs4_stateid stateid; nfs4_stateid stateid;
}; };
......
...@@ -53,6 +53,7 @@ static inline void nfs42_ssc_close(struct file *filep) ...@@ -53,6 +53,7 @@ static inline void nfs42_ssc_close(struct file *filep)
if (nfs_ssc_client_tbl.ssc_nfs4_ops) if (nfs_ssc_client_tbl.ssc_nfs4_ops)
(*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep); (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
} }
#endif
struct nfsd4_ssc_umount_item { struct nfsd4_ssc_umount_item {
struct list_head nsui_list; struct list_head nsui_list;
...@@ -66,7 +67,6 @@ struct nfsd4_ssc_umount_item { ...@@ -66,7 +67,6 @@ struct nfsd4_ssc_umount_item {
struct vfsmount *nsui_vfsmount; struct vfsmount *nsui_vfsmount;
char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1]; char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1];
}; };
#endif
/* /*
* NFS_FS * NFS_FS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment