From owner-svn-src-all@freebsd.org Thu Jul 7 09:03:58 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 96B5CB74158; Thu, 7 Jul 2016 09:03:58 +0000 (UTC) (envelope-from trasz@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 730F51CF1; Thu, 7 Jul 2016 09:03:58 +0000 (UTC) (envelope-from trasz@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u6793vdk060721; Thu, 7 Jul 2016 09:03:57 GMT (envelope-from trasz@FreeBSD.org) Received: (from trasz@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u6793vI4060716; Thu, 7 Jul 2016 09:03:57 GMT (envelope-from trasz@FreeBSD.org) Message-Id: <201607070903.u6793vI4060716@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: trasz set sender to trasz@FreeBSD.org using -f From: Edward Tomasz Napierala Date: Thu, 7 Jul 2016 09:03:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r302388 - in head: sbin/umount sys/kern sys/sys usr.sbin/autofs X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Jul 2016 09:03:58 -0000 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",