Author: trasz
Date: Thu Jul  7 09:03:57 2016
New Revision: 302388
URL: https://svnweb.freebsd.org/changeset/base/302388

Log:
  Add new unmount(2) flag, MNT_NONBUSY, to check whether there are
  any open vnodes before proceeding. Make autounmound(8) use this flag.
  Without it, even an unsuccessfull unmount causes filesystem flush,
  which interferes with normal operation.
  
  Reviewed by:  kib@
  Approved by:  re (gjb@)
  MFC after:    1 month
  Differential Revision:        https://reviews.freebsd.org/D7047

Modified:
  head/sbin/umount/umount.8
  head/sbin/umount/umount.c
  head/sys/kern/vfs_mount.c
  head/sys/sys/mount.h
  head/usr.sbin/autofs/autounmountd.c

Modified: head/sbin/umount/umount.8
==============================================================================
--- head/sbin/umount/umount.8   Thu Jul  7 05:47:42 2016        (r302387)
+++ head/sbin/umount/umount.8   Thu Jul  7 09:03:57 2016        (r302388)
@@ -28,7 +28,7 @@
 .\"     @(#)umount.8   8.2 (Berkeley) 5/8/95
 .\" $FreeBSD$
 .\"
-.Dd June 17, 2015
+.Dd July 7, 2016
 .Dt UMOUNT 8
 .Os
 .Sh NAME
@@ -36,12 +36,12 @@
 .Nd unmount file systems
 .Sh SYNOPSIS
 .Nm
-.Op Fl fv
+.Op Fl fnv
 .Ar special ... | node ... | fsid ...
 .Nm
 .Fl a | A
 .Op Fl F Ar fstab
-.Op Fl fv
+.Op Fl fnv
 .Op Fl h Ar host
 .Op Fl t Ar type
 .Sh DESCRIPTION
@@ -94,6 +94,15 @@ option and, unless otherwise specified w
 option, will only unmount
 .Tn NFS
 file systems.
+.It Fl n
+Unless the
+.Fl f
+is used, the
+.Nm
+will not unmount an active file system.
+It will, however, perform a flush.
+This flag disables this behaviour, preventing the flush
+if there are any files open.
 .It Fl t Ar type
 Is used to indicate the actions should only be taken on
 file systems of the specified type.

Modified: head/sbin/umount/umount.c
==============================================================================
--- head/sbin/umount/umount.c   Thu Jul  7 05:47:42 2016        (r302387)
+++ head/sbin/umount/umount.c   Thu Jul  7 09:03:57 2016        (r302388)
@@ -91,7 +91,7 @@ main(int argc, char *argv[])
        struct addrinfo hints;
 
        all = errs = 0;
-       while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1)
+       while ((ch = getopt(argc, argv, "AaF:fh:nt:v")) != -1)
                switch (ch) {
                case 'A':
                        all = 2;
@@ -103,12 +103,15 @@ main(int argc, char *argv[])
                        setfstab(optarg);
                        break;
                case 'f':
-                       fflag = MNT_FORCE;
+                       fflag |= MNT_FORCE;
                        break;
                case 'h':       /* -h implies -A. */
                        all = 2;
                        nfshost = optarg;
                        break;
+               case 'n':
+                       fflag |= MNT_NONBUSY;
+                       break;
                case 't':
                        if (typelist != NULL)
                                err(1, "only one -t option may be specified");
@@ -124,8 +127,11 @@ main(int argc, char *argv[])
        argc -= optind;
        argv += optind;
 
+       if ((fflag & MNT_FORCE) != 0 && (fflag & MNT_NONBUSY) != 0)
+               err(1, "-f and -n are mutually exclusive");
+
        /* Start disks transferring immediately. */
-       if ((fflag & MNT_FORCE) == 0)
+       if ((fflag & (MNT_FORCE | MNT_NONBUSY)) == 0)
                sync();
 
        if ((argc == 0 && !all) || (argc != 0 && all))
@@ -609,7 +615,7 @@ usage(void)
 {
 
        (void)fprintf(stderr, "%s\n%s\n",
-           "usage: umount [-fv] special ... | node ... | fsid ...",
-           "       umount -a | -A [-F fstab] [-fv] [-h host] [-t type]");
+           "usage: umount [-fnv] special ... | node ... | fsid ...",
+           "       umount -a | -A [-F fstab] [-fnv] [-h host] [-t type]");
        exit(1);
 }

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c   Thu Jul  7 05:47:42 2016        (r302387)
+++ head/sys/kern/vfs_mount.c   Thu Jul  7 09:03:57 2016        (r302388)
@@ -1205,6 +1205,28 @@ sys_unmount(struct thread *td, struct un
 }
 
 /*
+ * Return error if any of the vnodes, ignoring the root vnode
+ * and the syncer vnode, have non-zero usecount.
+ */
+static int
+vfs_check_usecounts(struct mount *mp)
+{
+       struct vnode *vp, *mvp;
+
+       MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
+               if ((vp->v_vflag & VV_ROOT) == 0 && vp->v_type != VNON &&
+                   vp->v_usecount != 0) {
+                       VI_UNLOCK(vp);
+                       MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
+                       return (EBUSY);
+               }
+               VI_UNLOCK(vp);
+       }
+
+       return (0);
+}
+
+/*
  * Do the actual filesystem unmount.
  */
 int
@@ -1260,6 +1282,21 @@ dounmount(struct mount *mp, int flags, s
                return (EBUSY);
        }
        mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ;
+       if (flags & MNT_NONBUSY) {
+               MNT_IUNLOCK(mp);
+               error = vfs_check_usecounts(mp);
+               MNT_ILOCK(mp);
+               if (error != 0) {
+                       mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_NOINSMNTQ);
+                       MNT_IUNLOCK(mp);
+                       if (coveredvp != NULL) {
+                               VOP_UNLOCK(coveredvp, 0);
+                               vdrop(coveredvp);
+                       }
+                       vn_finished_write(mp);
+                       return (error);
+               }
+       }
        /* Allow filesystems to detect that a forced unmount is in progress. */
        if (flags & MNT_FORCE) {
                mp->mnt_kern_flag |= MNTK_UNMOUNTF;

Modified: head/sys/sys/mount.h
==============================================================================
--- head/sys/sys/mount.h        Thu Jul  7 05:47:42 2016        (r302387)
+++ head/sys/sys/mount.h        Thu Jul  7 09:03:57 2016        (r302388)
@@ -312,17 +312,21 @@ void          __mnt_vnode_markerfree_act
  * External filesystem command modifier flags.
  * Unmount can use the MNT_FORCE flag.
  * XXX: These are not STATES and really should be somewhere else.
- * XXX: MNT_BYFSID collides with MNT_ACLS, but because MNT_ACLS is only used 
for
- *      mount(2) and MNT_BYFSID is only used for unmount(2) it's harmless.
+ * XXX: MNT_BYFSID and MNT_NONBUSY collide with MNT_ACLS and MNT_MULTILABEL,
+ *      but because MNT_ACLS and MNT_MULTILABEL are only used for mount(2),
+ *      and MNT_BYFSID and MNT_NONBUSY are only used for unmount(2),
+ *      it's harmless.
  */
 #define        MNT_UPDATE      0x0000000000010000ULL /* not real mount, just 
update */
 #define        MNT_DELEXPORT   0x0000000000020000ULL /* delete export host 
lists */
 #define        MNT_RELOAD      0x0000000000040000ULL /* reload filesystem data 
*/
 #define        MNT_FORCE       0x0000000000080000ULL /* force unmount or 
readonly */
 #define        MNT_SNAPSHOT    0x0000000001000000ULL /* snapshot the 
filesystem */
+#define        MNT_NONBUSY     0x0000000004000000ULL /* check vnode use 
counts. */
 #define        MNT_BYFSID      0x0000000008000000ULL /* specify filesystem by 
ID. */
 #define MNT_CMDFLAGS   (MNT_UPDATE     | MNT_DELEXPORT | MNT_RELOAD    | \
-                       MNT_FORCE       | MNT_SNAPSHOT  | MNT_BYFSID)
+                       MNT_FORCE       | MNT_SNAPSHOT  | MNT_NONBUSY   | \
+                       MNT_BYFSID)
 /*
  * Internal filesystem control flags stored in mnt_kern_flag.
  *

Modified: head/usr.sbin/autofs/autounmountd.c
==============================================================================
--- head/usr.sbin/autofs/autounmountd.c Thu Jul  7 05:47:42 2016        
(r302387)
+++ head/usr.sbin/autofs/autounmountd.c Thu Jul  7 09:03:57 2016        
(r302388)
@@ -161,7 +161,7 @@ unmount_by_fsid(const fsid_t fsid, const
        if (ret < 0)
                log_err(1, "asprintf");
 
-       error = unmount(fsid_str, MNT_BYFSID);
+       error = unmount(fsid_str, MNT_NONBUSY | MNT_BYFSID);
        if (error != 0) {
                if (errno == EBUSY) {
                        log_debugx("cannot unmount %s (%s): %s",
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to