aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nfsclient/nfs_clport.c
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2017-07-29 19:52:47 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2017-07-29 19:52:47 +0000
commit47cbff34fa9a88fc8c12c4de15882a0563a33055 (patch)
treeaa3367f7e70e9c66d04fd0ade1463d1b6ee266a1 /sys/fs/nfsclient/nfs_clport.c
parentd35f6548e63e5deb4e9a7ac40f517fc10b1dc7b9 (diff)
downloadsrc-47cbff34fa9a88fc8c12c4de15882a0563a33055.tar.gz
src-47cbff34fa9a88fc8c12c4de15882a0563a33055.zip
Notes
Diffstat (limited to 'sys/fs/nfsclient/nfs_clport.c')
-rw-r--r--sys/fs/nfsclient/nfs_clport.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index e49382ea6783..c22d87227b2f 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -1311,6 +1311,8 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
cap_rights_t rights;
char *buf;
int error;
+ struct mount *mp;
+ struct nfsmount *nmp;
if (uap->flag & NFSSVC_CBADDSOCK) {
error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg));
@@ -1365,6 +1367,56 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
dumpmntopts.ndmnt_blen);
free(buf, M_TEMP);
}
+ } else if (uap->flag & NFSSVC_FORCEDISM) {
+ buf = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
+ error = copyinstr(uap->argp, buf, MNAMELEN + 1, NULL);
+ if (error == 0) {
+ nmp = NULL;
+ mtx_lock(&mountlist_mtx);
+ TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+ if (strcmp(mp->mnt_stat.f_mntonname, buf) ==
+ 0 && strcmp(mp->mnt_stat.f_fstypename,
+ "nfs") == 0 && mp->mnt_data != NULL) {
+ nmp = VFSTONFS(mp);
+ mtx_lock(&nmp->nm_mtx);
+ if ((nmp->nm_privflag &
+ NFSMNTP_FORCEDISM) == 0) {
+ nmp->nm_privflag |=
+ (NFSMNTP_FORCEDISM |
+ NFSMNTP_CANCELRPCS);
+ mtx_unlock(&nmp->nm_mtx);
+ } else {
+ nmp = NULL;
+ mtx_unlock(&nmp->nm_mtx);
+ }
+ break;
+ }
+ }
+ mtx_unlock(&mountlist_mtx);
+
+ if (nmp != NULL) {
+ /*
+ * Call newnfs_nmcancelreqs() to cause
+ * any RPCs in progress on the mount point to
+ * fail.
+ * This will cause any process waiting for an
+ * RPC to complete while holding a vnode lock
+ * on the mounted-on vnode (such as "df" or
+ * a non-forced "umount") to fail.
+ * This will unlock the mounted-on vnode so
+ * a forced dismount can succeed.
+ * Then clear NFSMNTP_CANCELRPCS and wakeup(),
+ * so that nfs_unmount() can complete.
+ */
+ newnfs_nmcancelreqs(nmp);
+ mtx_lock(&nmp->nm_mtx);
+ nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
+ wakeup(nmp);
+ mtx_unlock(&nmp->nm_mtx);
+ } else
+ error = EINVAL;
+ }
+ free(buf, M_TEMP);
} else {
error = EINVAL;
}