Author: trasz
Date: Mon Aug 24 13:18:13 2015
New Revision: 287107
URL: https://svnweb.freebsd.org/changeset/base/287107

Log:
  Make vfs_unmountall() unmount /dev after /, not before.  The only
  reason this didn't result in an unclean shutdown is that devfs ignores
  MNT_FORCE flag.
  
  Reviewed by:  kib@
  MFC after:    1 month
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D3467

Modified:
  head/sys/kern/vfs_mount.c
  head/sys/kern/vfs_mountroot.c
  head/sys/kern/vfs_subr.c
  head/sys/sys/vnode.h

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c   Mon Aug 24 12:17:15 2015        (r287106)
+++ head/sys/kern/vfs_mount.c   Mon Aug 24 13:18:13 2015        (r287107)
@@ -1359,6 +1359,8 @@ dounmount(struct mount *mp, int flags, s
                vput(coveredvp);
        }
        vfs_event_signal(NULL, VQ_UNMOUNT, 0);
+       if (mp == rootdevmp)
+               rootdevmp = NULL;
        vfs_mount_destroy(mp);
        return (0);
 }

Modified: head/sys/kern/vfs_mountroot.c
==============================================================================
--- head/sys/kern/vfs_mountroot.c       Mon Aug 24 12:17:15 2015        
(r287106)
+++ head/sys/kern/vfs_mountroot.c       Mon Aug 24 13:18:13 2015        
(r287107)
@@ -95,6 +95,11 @@ static struct mntarg *parse_mountroot_op
  */
 struct vnode *rootvnode;
 
+/*
+ * Mount of the system's /dev.
+ */
+struct mount *rootdevmp;
+
 char *rootdevnames[2] = {NULL, NULL};
 
 struct mtx root_holds_mtx;
@@ -236,6 +241,7 @@ vfs_mountroot_devfs(struct thread *td, s
        mtx_unlock(&mountlist_mtx);
 
        *mpp = mp;
+       rootdevmp = mp;
        set_rootvnode();
 
        error = kern_symlinkat(td, "/", AT_FDCWD, "dev", UIO_SYSSPACE);

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c    Mon Aug 24 12:17:15 2015        (r287106)
+++ head/sys/kern/vfs_subr.c    Mon Aug 24 13:18:13 2015        (r287107)
@@ -3543,6 +3543,21 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CT
     "");
 #endif
 
+static void
+unmount_or_warn(struct mount *mp)
+{
+       int error;
+
+       error = dounmount(mp, MNT_FORCE, curthread);
+       if (error != 0) {
+               printf("unmount of %s failed (", mp->mnt_stat.f_mntonname);
+               if (error == EBUSY)
+                       printf("BUSY)\n");
+               else
+                       printf("%d)\n", error);
+       }
+}
+
 /*
  * Unmount all filesystems. The list is traversed in reverse order
  * of mounting to avoid dependencies.
@@ -3550,42 +3565,28 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CT
 void
 vfs_unmountall(void)
 {
-       struct mount *mp;
-       struct thread *td;
-       int error;
+       struct mount *mp, *tmp;
 
        CTR1(KTR_VFS, "%s: unmounting all filesystems", __func__);
-       td = curthread;
 
        /*
         * Since this only runs when rebooting, it is not interlocked.
         */
-       while(!TAILQ_EMPTY(&mountlist)) {
-               mp = TAILQ_LAST(&mountlist, mntlist);
+       TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, tmp) {
                vfs_ref(mp);
-               error = dounmount(mp, MNT_FORCE, td);
-               if (error != 0) {
-                       TAILQ_REMOVE(&mountlist, mp, mnt_list);
-                       /*
-                        * XXX: Due to the way in which we mount the root
-                        * file system off of devfs, devfs will generate a
-                        * "busy" warning when we try to unmount it before
-                        * the root.  Don't print a warning as a result in
-                        * order to avoid false positive errors that may
-                        * cause needless upset.
-                        */
-                       if (strcmp(mp->mnt_vfc->vfc_name, "devfs") != 0) {
-                               printf("unmount of %s failed (",
-                                   mp->mnt_stat.f_mntonname);
-                               if (error == EBUSY)
-                                       printf("BUSY)\n");
-                               else
-                                       printf("%d)\n", error);
-                       }
-               } else {
-                       /* The unmount has removed mp from the mountlist */
-               }
+
+               /*
+                * Forcibly unmounting "/dev" before "/" would prevent clean
+                * unmount of the latter.
+                */
+               if (mp == rootdevmp)
+                       continue;
+
+               unmount_or_warn(mp);
        }
+
+       if (rootdevmp != NULL)
+               unmount_or_warn(rootdevmp);
 }
 
 /*

Modified: head/sys/sys/vnode.h
==============================================================================
--- head/sys/sys/vnode.h        Mon Aug 24 12:17:15 2015        (r287106)
+++ head/sys/sys/vnode.h        Mon Aug 24 13:18:13 2015        (r287107)
@@ -420,6 +420,7 @@ extern int          vttoif_tab[];
  * Global vnode data.
  */
 extern struct vnode *rootvnode;        /* root (i.e. "/") vnode */
+extern struct mount *rootdevmp;        /* "/dev" mount */
 extern int async_io_version;           /* 0 or POSIX version of AIO i'face */
 extern int desiredvnodes;              /* number of vnodes desired */
 extern struct uma_zone *namei_zone;
_______________________________________________
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