Page MenuHomeFreeBSD

D11735.id31233.diff
No OneTemporary

D11735.id31233.diff

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

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)

Event Timeline