From 4261923e76c8c106ffb972b6524b0485d0fe8120 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Sat, 29 Jul 2017 20:08:25 +0000 Subject: [PATCH] Add a new "-N" option to umount(8), that does a forced dismount of an NFS mount point. The new "-N" option does a forced dismount of an NFS mount point, but avoids doing any checking of the mounted-on path, so that it will not get hung when a vnode lock is held by another hung process on the mounted-on vnode. The most common case of this is a "umount" with the "-f" option. Other than avoiding checking the mounted-on path, it performs the same forced dismount as a successful "umount -f" would do. This commit includes a content change to the man page. Tested by: pho Reviewed by: kib MFC after: 2 weeks Relnotes: yes Differential Revision: https://reviews.freebsd.org/D11735 --- sbin/umount/umount.8 | 31 +++++++++++++++++++++++++++++-- sbin/umount/umount.c | 31 +++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/sbin/umount/umount.8 b/sbin/umount/umount.8 index 8288c1a7da7a..5543820ce185 100644 --- a/sbin/umount/umount.8 +++ b/sbin/umount/umount.8 @@ -28,7 +28,7 @@ .\" @(#)umount.8 8.2 (Berkeley) 5/8/95 .\" $FreeBSD$ .\" -.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,15 @@ The root file system cannot be forcibly unmounted. 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 +.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 +103,24 @@ option and, unless otherwise specified with the 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. +Using this option can result in a loss of file updates that have not been +flushed to the +.Tn NFS +server. .It Fl n Unless the .Fl f diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c index bc7dbcd02d61..f2829a4f9429 100644 --- a/sbin/umount/umount.c +++ b/sbin/umount/umount.c @@ -86,13 +86,13 @@ int xdr_dir (XDR *, char *); 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 @@ main(int argc, char *argv[]) all = 2; nfshost = optarg; break; + case 'N': + nfsforce = 1; + break; case 'n': fflag |= MNT_NONBUSY; break; @@ -132,12 +135,15 @@ main(int argc, char *argv[]) err(1, "-f and -n are mutually exclusive"); /* Start disks transferring immediately. */ - if ((fflag & (MNT_FORCE | MNT_NONBUSY)) == 0) + if ((fflag & (MNT_FORCE | MNT_NONBUSY)) == 0 && nfsforce == 0) sync(); if ((argc == 0 && !all) || (argc != 0 && all)) usage(); + if (nfsforce != 0 && (argc == 0 || nfshost != NULL || typelist != NULL)) + usage(); + /* -h implies "-t nfs" if no -t flag. */ if ((nfshost != NULL) && (typelist == NULL)) typelist = makevfslist("nfs"); @@ -175,7 +181,20 @@ main(int argc, char *argv[]) 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 @@ usage(void) { (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); }