Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111879981
D11735.id31233.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D11735.id31233.diff
View Options
Index: sbin/umount/umount.8
===================================================================
--- sbin/umount/umount.8
+++ sbin/umount/umount.8
@@ -28,7 +28,7 @@
.\" @(#)umount.8 8.2 (Berkeley) 5/8/95
.\" $FreeBSD: head/sbin/umount/umount.8 314436 2017-02-28 23:42:47Z imp $
.\"
-.Dd September 10, 2016
+.Dd July 25, 2017
.Dt UMOUNT 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Nd unmount file systems
.Sh SYNOPSIS
.Nm
-.Op Fl fnv
+.Op Fl fNnv
.Ar special ... | node ... | fsid ...
.Nm
.Fl a | A
@@ -81,6 +81,17 @@
For NFS, a forced dismount can take up to 1 minute or more to
complete against an unresponsive server and may throw away
data not yet written to the server for this case.
+If a process, such as
+.Xr df 1
+or
+.Nm
+without the
+.Fl f
+flag is hung on an
+.Tn NFS
+mount point, use the
+.Fl N
+flag instead.
Also, doing a forced dismount of an NFSv3 mount when
.Xr rpc.lockd 8
is running is unsafe and can result in a crash.
@@ -94,6 +105,20 @@
option, will only unmount
.Tn NFS
file systems.
+.It Fl N
+Do a forced dismount of an
+.Tn NFS
+mount point without checking the mount path.
+This option can only be used with the path to the mount point
+.Ar node
+and the path must be specified exactly as it was at mount time.
+This option is useful when a process is hung waiting for an unresponsive
+.Tn NFS
+server while holding a vnode lock on the mounted-on vnode, such that
+.Nm
+with the
+.Fl f
+flag can't complete.
.It Fl n
Unless the
.Fl f
Index: sbin/umount/umount.c
===================================================================
--- sbin/umount/umount.c
+++ sbin/umount/umount.c
@@ -86,13 +86,13 @@
int
main(int argc, char *argv[])
{
- int all, errs, ch, mntsize, error;
+ int all, errs, ch, mntsize, error, nfsforce, ret;
char **typelist = NULL;
struct statfs *mntbuf, *sfs;
struct addrinfo hints;
- all = errs = 0;
- while ((ch = getopt(argc, argv, "AaF:fh:nt:v")) != -1)
+ nfsforce = all = errs = 0;
+ while ((ch = getopt(argc, argv, "AaF:fh:Nnt:v")) != -1)
switch (ch) {
case 'A':
all = 2;
@@ -110,6 +110,9 @@
all = 2;
nfshost = optarg;
break;
+ case 'N':
+ nfsforce = 1;
+ break;
case 'n':
fflag |= MNT_NONBUSY;
break;
@@ -138,6 +141,9 @@
if ((argc == 0 && !all) || (argc != 0 && all))
usage();
+ if (argc == 0 && nfsforce != 0)
+ usage();
+
/* -h implies "-t nfs" if no -t flag. */
if ((nfshost != NULL) && (typelist == NULL))
typelist = makevfslist("nfs");
@@ -175,7 +181,20 @@
break;
case 0:
for (errs = 0; *argv != NULL; ++argv)
- if (checkname(*argv, typelist) != 0)
+ if (nfsforce != 0) {
+ /*
+ * First do the nfssvc() syscall to shut down
+ * the mount point and then do the forced
+ * dismount.
+ */
+ ret = nfssvc(NFSSVC_FORCEDISM, *argv);
+ if (ret >= 0)
+ ret = unmount(*argv, MNT_FORCE);
+ if (ret < 0) {
+ warn("%s", *argv);
+ errs = 1;
+ }
+ } else if (checkname(*argv, typelist) != 0)
errs = 1;
break;
}
@@ -635,7 +654,7 @@
{
(void)fprintf(stderr, "%s\n%s\n",
- "usage: umount [-fnv] special ... | node ... | fsid ...",
+ "usage: umount [-fNnv] special ... | node ... | fsid ...",
" umount -a | -A [-F fstab] [-fnv] [-h host] [-t type]");
exit(1);
}
Index: sys/fs/nfs/nfs_commonkrpc.c
===================================================================
--- sys/fs/nfs/nfs_commonkrpc.c
+++ sys/fs/nfs/nfs_commonkrpc.c
@@ -511,7 +511,8 @@
if (xidp != NULL)
*xidp = 0;
/* Reject requests while attempting a forced unmount. */
- if (nmp != NULL && (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)) {
+ if (nmp != NULL && ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0
+ || (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0)) {
m_freem(nd->nd_mreq);
return (ESTALE);
}
@@ -1231,7 +1232,8 @@
sigset_t tmpset;
/* Terminate all requests while attempting a forced unmount. */
- if (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
+ if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0)
return (EIO);
if (!(nmp->nm_flag & NFSMNT_INT))
return (0);
Index: sys/fs/nfs/nfs_commonsubs.c
===================================================================
--- sys/fs/nfs/nfs_commonsubs.c
+++ sys/fs/nfs/nfs_commonsubs.c
@@ -1834,7 +1834,8 @@
lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
}
while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
- if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if (mp != NULL && ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mp)->nm_privflag & NFSMNTP_FORCEDISM) != 0)) {
lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
return (0);
}
@@ -1888,8 +1889,8 @@
* not wait for threads that want the exclusive lock. If priority needs
* to be given to threads that need the exclusive lock, a call to nfsv4_lock()
* with the 2nd argument == 0 should be done before calling nfsv4_getref().
- * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
- * return without getting a refcnt for that case.
+ * If the mp argument is not NULL, check for MNTK_UNMOUNTF/NFSMNTP_FORCEDISM
+ * being set and return without getting a refcnt for that case.
*/
APPLESTATIC void
nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
@@ -1903,7 +1904,8 @@
* Wait for a lock held.
*/
while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
- if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
+ if (mp != NULL && ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mp)->nm_privflag & NFSMNTP_FORCEDISM) != 0))
return;
lp->nfslock_lock |= NFSV4LOCK_WANTED;
if (isleptp)
@@ -1911,7 +1913,8 @@
(void) nfsmsleep(&lp->nfslock_lock, mutex,
PZERO - 1, "nfsv4gr", NULL);
}
- if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
+ if (mp != NULL && ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mp)->nm_privflag & NFSMNTP_FORCEDISM) != 0))
return;
lp->nfslock_usecnt++;
@@ -4192,9 +4195,9 @@
* This RPC attempt will fail when it calls
* newnfs_request().
*/
- if (nmp != NULL &&
- (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
- != 0) {
+ if (nmp != NULL && ((nmp->nm_mountp->mnt_kern_flag &
+ MNTK_UNMOUNTF) != 0 || (nmp->nm_privflag &
+ NFSMNTP_FORCEDISM) != 0)) {
mtx_unlock(&sep->nfsess_mtx);
return (ESTALE);
}
Index: sys/fs/nfsclient/nfs_clbio.c
===================================================================
--- sys/fs/nfsclient/nfs_clbio.c
+++ sys/fs/nfsclient/nfs_clbio.c
@@ -1341,7 +1341,8 @@
if ((nmp->nm_flag & NFSMNT_INT) == 0)
intrflg = 0;
- if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF))
+ if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0)
intrflg = 1;
if (intrflg) {
slpflag = PCATCH;
Index: sys/fs/nfsclient/nfs_clport.c
===================================================================
--- sys/fs/nfsclient/nfs_clport.c
+++ sys/fs/nfsclient/nfs_clport.c
@@ -313,7 +313,8 @@
*npp = NULL;
/* For forced dismounts, just return error. */
- if ((mntp->mnt_kern_flag & MNTK_UNMOUNTF))
+ if ((mntp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mntp)->nm_privflag & NFSMNTP_FORCEDISM) != 0)
return (EINTR);
MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize,
M_NFSFH, M_WAITOK);
@@ -333,10 +334,12 @@
/*
* It is safe so long as a vflush() with
* FORCECLOSE has not been done. Since the Renew thread is
- * stopped and the MNTK_UNMOUNTF flag is set before doing
- * a vflush() with FORCECLOSE, we should be ok here.
+ * stopped and the MNTK_UNMOUNTF/NFSMNTP_FORCEDISM flag is set
+ * before doing a vflush() with FORCECLOSE, we should be ok
+ * here.
*/
- if ((mntp->mnt_kern_flag & MNTK_UNMOUNTF))
+ if ((mntp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mntp)->nm_privflag & NFSMNTP_FORCEDISM) != 0)
error = EINTR;
else {
vfs_hash_ref(mntp, hash, td, &nvp, newnfs_vncmpf, nfhp);
@@ -1311,6 +1314,8 @@
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 +1370,56 @@
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;
}
Index: sys/fs/nfsclient/nfs_clstate.c
===================================================================
--- sys/fs/nfsclient/nfs_clstate.c
+++ sys/fs/nfsclient/nfs_clstate.c
@@ -803,7 +803,8 @@
* allocate a new clientid and get out now. For the case where
* clp != NULL, this is a harmless optimization.
*/
- if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0) {
NFSUNLOCKCLSTATE();
if (newclp != NULL)
free(newclp, M_NFSCLCLIENT);
@@ -843,7 +844,8 @@
}
NFSLOCKCLSTATE();
while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock &&
- (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0)
+ (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0 &&
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) == 0)
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
NFSCLSTATEMUTEXPTR, mp);
if (igotlock == 0) {
@@ -858,12 +860,13 @@
nfsv4_lock(&clp->nfsc_lock, 0, NULL, NFSCLSTATEMUTEXPTR, mp);
nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
}
- if (igotlock == 0 && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if (igotlock == 0 && ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0)) {
/*
* Both nfsv4_lock() and nfsv4_getref() know to check
- * for MNTK_UNMOUNTF and return without sleeping to
- * wait for the exclusive lock to be released, since it
- * might be held by nfscl_umount() and we need to get out
+ * for MNTK_UNMOUNTF/NFSMNTP_FORCEDISM and return without
+ * sleeping to wait for the exclusive lock to be released, since
+ * it might be held by nfscl_umount() and we need to get out
* now for that case and not wait until nfscl_umount()
* releases it.
*/
@@ -4844,7 +4847,8 @@
lyp->nfsly_timestamp = NFSD_MONOSEC + 120;
}
nfsv4_getref(&lyp->nfsly_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
- if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (nmp->nm_privflag & NFSMNTP_FORCEDISM) != 0) {
NFSUNLOCKCLSTATE();
if (tlyp != NULL)
free(tlyp, M_NFSLAYOUT);
@@ -4904,10 +4908,14 @@
igotlock = nfsv4_lock(&lyp->nfsly_lock,
1, NULL, NFSCLSTATEMUTEXPTR, mp);
} while (igotlock == 0 &&
- (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0);
+ (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0 &&
+ (VFSTONFS(mp)->nm_privflag &
+ NFSMNTP_FORCEDISM) == 0);
*retflpp = NULL;
}
- if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mp)->nm_privflag &
+ NFSMNTP_FORCEDISM) != 0) {
lyp = NULL;
*recalledp = 1;
}
Index: sys/fs/nfsclient/nfs_clvfsops.c
===================================================================
--- sys/fs/nfsclient/nfs_clvfsops.c
+++ sys/fs/nfsclient/nfs_clvfsops.c
@@ -1698,6 +1698,11 @@
*/
if ((mntflags & MNT_FORCE) == 0)
nfscl_umount(nmp, td);
+ else {
+ mtx_lock(&nmp->nm_mtx);
+ nmp->nm_privflag |= NFSMNTP_FORCEDISM;
+ mtx_unlock(&nmp->nm_mtx);
+ }
/* Make sure no nfsiods are assigned to this mount. */
mtx_lock(&ncl_iod_mutex);
for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
@@ -1706,6 +1711,19 @@
ncl_iodmount[i] = NULL;
}
mtx_unlock(&ncl_iod_mutex);
+
+ /*
+ * We can now set mnt_data to NULL and wait for
+ * nfssvc(NFSSVC_FORCEDISM) to complete.
+ */
+ mtx_lock(&mountlist_mtx);
+ mtx_lock(&nmp->nm_mtx);
+ mp->mnt_data = NULL;
+ mtx_unlock(&mountlist_mtx);
+ while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
+ msleep(nmp, &nmp->nm_mtx, PZERO, "nfsfdism", 0);
+ mtx_unlock(&nmp->nm_mtx);
+
newnfs_disconnect(&nmp->nm_sockreq);
crfree(nmp->nm_sockreq.nr_cred);
FREE(nmp->nm_nam, M_SONAME);
@@ -1775,7 +1793,8 @@
* the umount(2) syscall doesn't get stuck in VFS_SYNC() before
* calling VFS_UNMOUNT().
*/
- if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(mp)->nm_privflag & NFSMNTP_FORCEDISM) != 0) {
MNT_IUNLOCK(mp);
return (EBADF);
}
Index: sys/fs/nfsclient/nfs_clvnops.c
===================================================================
--- sys/fs/nfsclient/nfs_clvnops.c
+++ sys/fs/nfsclient/nfs_clvnops.c
@@ -663,7 +663,8 @@
int error = 0, ret, localcred = 0;
int fmode = ap->a_fflag;
- if ((vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF))
+ if ((vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) != 0 ||
+ (VFSTONFS(vp->v_mount)->nm_privflag & NFSMNTP_FORCEDISM) != 0)
return (0);
/*
* During shutdown, a_cred isn't valid, so just use root.
Index: sys/fs/nfsclient/nfsmount.h
===================================================================
--- sys/fs/nfsclient/nfsmount.h
+++ sys/fs/nfsclient/nfsmount.h
@@ -44,6 +44,7 @@
*/
struct nfsmount {
struct nfsmount_common nm_com; /* Common fields for nlm */
+ uint32_t nm_privflag; /* Private flags */
int nm_numgrps; /* Max. size of groupslist */
u_char nm_fh[NFSX_FHMAX]; /* File handle of root dir */
int nm_fhsize; /* Size of root file handle */
@@ -99,6 +100,10 @@
#define nm_getinfo nm_com.nmcom_getinfo
#define nm_vinvalbuf nm_com.nmcom_vinvalbuf
+/* Private flags. */
+#define NFSMNTP_FORCEDISM 0x00000001
+#define NFSMNTP_CANCELRPCS 0x00000002
+
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \
(&((m)->nm_name[(m)->nm_krbnamelen + (m)->nm_dirpathlen + 2]))
Index: sys/nfs/nfs_nfssvc.c
===================================================================
--- sys/nfs/nfs_nfssvc.c
+++ sys/nfs/nfs_nfssvc.c
@@ -92,7 +92,7 @@
nfsd_call_nfsserver != NULL)
error = (*nfsd_call_nfsserver)(td, uap);
else if ((uap->flag & (NFSSVC_CBADDSOCK | NFSSVC_NFSCBD |
- NFSSVC_DUMPMNTOPTS)) && nfsd_call_nfscl != NULL)
+ NFSSVC_DUMPMNTOPTS | NFSSVC_FORCEDISM)) && nfsd_call_nfscl != NULL)
error = (*nfsd_call_nfscl)(td, uap);
else if ((uap->flag & (NFSSVC_IDNAME | NFSSVC_GETSTATS |
NFSSVC_GSSDADDPORT | NFSSVC_GSSDADDFIRST | NFSSVC_GSSDDELETEALL |
Index: sys/nfs/nfssvc.h
===================================================================
--- sys/nfs/nfssvc.h
+++ sys/nfs/nfssvc.h
@@ -70,6 +70,7 @@
#define NFSSVC_RESUMENFSD 0x08000000
#define NFSSVC_DUMPMNTOPTS 0x10000000
#define NFSSVC_NEWSTRUCT 0x20000000
+#define NFSSVC_FORCEDISM 0x40000000
/* Argument structure for NFSSVC_DUMPMNTOPTS. */
struct nfscl_dumpmntopts {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 10, 5:45 PM (16 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17087493
Default Alt Text
D11735.id31233.diff (16 KB)
Attached To
Mode
D11735: Add an NFS forced dismount option to umount(8)
Attached
Detach File
Event Timeline
Log In to Comment