kernel - Implement QUICKHALT shortcut for unmounting during shutdown
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 19 Mar 2018 05:39:10 +0000 (22:39 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 19 Mar 2018 05:39:10 +0000 (22:39 -0700)
* Add the MNTK_QUICKHALT flag which allows the system to just unlink but
  otherwise ignore certain mount types during a halt or reboot.  For now
  we flag tmpfs, devfs, and procfs.

* The main impetus for this is to reduce the messing around we
  do with devfs during a shutdown.  Devfs has its fingers, and its
  vnodes, prettymuch sunk throughout the system (e.g. /dev/null, system
  console, vty's, root mount, and so on and so forth).  There's no
  real need to attempt to unwind all of that mess nicely.

sys/kern/kern_shutdown.c
sys/kern/vfs_subr.c
sys/kern/vfs_syscalls.c
sys/sys/mount.h
sys/vfs/devfs/devfs_vfsops.c
sys/vfs/mfs/mfs_vfsops.c
sys/vfs/nfs/nfs_kerb.c
sys/vfs/procfs/procfs_vfsops.c
sys/vfs/puffs/puffs_msgif.c
sys/vfs/tmpfs/tmpfs_vfsops.c

index 24e1a15..8b1c4a8 100644 (file)
@@ -376,7 +376,7 @@ boot(int howto)
                         * Unmount filesystems
                         */
                        if (panicstr == NULL)
-                               vfs_unmountall();
+                               vfs_unmountall(1);
                }
                tsleep(boot, 0, "shutdn", hz / 10 + 1);
        }
index 82dab5c..718092d 100644 (file)
@@ -1869,13 +1869,13 @@ vfs_mountedon(struct vnode *vp)
 static int vfs_umountall_callback(struct mount *mp, void *data);
 
 void
-vfs_unmountall(void)
+vfs_unmountall(int halting)
 {
        int count;
 
        do {
-               count = mountlist_scan(vfs_umountall_callback, 
-                                       NULL, MNTSCAN_REVERSE|MNTSCAN_NOBUSY);
+               count = mountlist_scan(vfs_umountall_callback, &halting,
+                                      MNTSCAN_REVERSE|MNTSCAN_NOBUSY);
        } while (count);
 }
 
@@ -1884,8 +1884,13 @@ int
 vfs_umountall_callback(struct mount *mp, void *data)
 {
        int error;
+       int halting = *(int *)data;
 
-       error = dounmount(mp, MNT_FORCE);
+       /*
+        * NOTE: When halting, dounmount will disconnect but leave
+        *       certain mount points intact.  e.g. devfs.
+        */
+       error = dounmount(mp, MNT_FORCE, halting);
        if (error) {
                kprintf("unmount of filesystem mounted from %s failed (", 
                        mp->mnt_stat.f_mntfromname);
index 6dcf038..1cace89 100644 (file)
@@ -643,7 +643,7 @@ out:
        if (error == 0) {
                mount_hold(mp);
                nlookup_done(&nd);
-               error = dounmount(mp, uap->flags);
+               error = dounmount(mp, uap->flags, 0);
                mount_drop(mp);
        } else {
                nlookup_done(&nd);
@@ -684,9 +684,15 @@ unmount_allproc_cb(struct proc *p, void *arg)
  * The guts of the unmount code.  The mount owns one ref and one hold
  * count.  If we successfully interlock the unmount, those refs are ours.
  * (The ref is from mnt_ncmountpt).
+ *
+ * When halting we shortcut certain mount types such as devfs by not actually
+ * issuing the VFS_SYNC() or VFS_UNMOUNT().  They are still disconnected
+ * from the mountlist so higher-level filesytems can unmount cleanly.
+ *
+ * The mount types that allow QUICKHALT are: devfs, tmpfs, procfs.
  */
 int
-dounmount(struct mount *mp, int flags)
+dounmount(struct mount *mp, int flags, int halting)
 {
        struct namecache *ncp;
        struct nchandle nch;
@@ -696,9 +702,22 @@ dounmount(struct mount *mp, int flags)
        int lflags;
        int freeok = 1;
        int retry;
+       int quickhalt;
 
        lwkt_gettoken(&mp->mnt_token);
 
+       /*
+        * When halting, certain mount points can essentially just
+        * be unhooked and otherwise ignored.
+        */
+       if (halting && (mp->mnt_kern_flag & MNTK_QUICKHALT)) {
+               quickhalt = 1;
+               freeok = 0;
+       } else {
+               quickhalt = 0;
+       }
+
+
        /*
         * Exclusive access for unmounting purposes.
         */
@@ -782,8 +801,11 @@ dounmount(struct mount *mp, int flags)
                atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
                vrele(vp);
        }
-       if ((mp->mnt_flag & MNT_RDONLY) == 0)
-               VFS_SYNC(mp, MNT_WAIT);
+
+       if (quickhalt == 0) {
+               if ((mp->mnt_flag & MNT_RDONLY) == 0)
+                       VFS_SYNC(mp, MNT_WAIT);
+       }
 
        /*
         * nchandle records ref the mount structure.  Expect a count of 1
@@ -817,7 +839,7 @@ dounmount(struct mount *mp, int flags)
         * So far so good, sync the filesystem once more and
         * call the VFS unmount code if the sync succeeds.
         */
-       if (error == 0) {
+       if (error == 0 && quickhalt == 0) {
                if (mp->mnt_flag & MNT_RDONLY) {
                        error = VFS_UNMOUNT(mp, flags);
                } else {
@@ -882,7 +904,12 @@ dounmount(struct mount *mp, int flags)
        }
 
        mp->mnt_vfc->vfc_refcount--;
-       if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
+
+       /*
+        * If not quickhalting the mount, we expect there to be no
+        * vnodes left.
+        */
+       if (quickhalt == 0 && !TAILQ_EMPTY(&mp->mnt_nvnodelist))
                panic("unmount: dangling vnode");
 
        /*
index 7f57ae8..42aa8df 100644 (file)
@@ -339,6 +339,7 @@ struct mount {
  * MNTK_NOSTKMNT prevents mounting another filesystem inside the flagged one.
  */
 #define MNTK_UNMOUNTF  0x00000001      /* forced unmount in progress */
+#define MNTK_QUICKHALT 0x00008000      /* quick unmount on halt */
 #define MNTK_MPSAFE    0x00010000      /* call vops without mnt_token lock */
 #define MNTK_RD_MPSAFE 0x00020000      /* vop_read is MPSAFE */
 #define MNTK_WR_MPSAFE 0x00040000      /* vop_write is MPSAFE */
@@ -714,7 +715,7 @@ struct netexport {
  */
 void   mount_hold(struct mount *);
 void   mount_drop(struct mount *);
-int    dounmount (struct mount *, int);
+int    dounmount (struct mount *, int, int);
 int    vfs_setpublicfs                     /* set publicly exported fs */
          (struct mount *, struct netexport *, const struct export_args *);
 int    vfs_lock (struct mount *);         /* lock a vfs */
@@ -734,7 +735,7 @@ int vfs_modevent (module_t, int, void *);
 int    vfs_mountedon (struct vnode *);    /* is a vfs mounted on vp */
 int    vfs_rootmountalloc (char *, char *, struct mount **);
 void   vfs_unbusy (struct mount *);
-void   vfs_unmountall (void);
+void   vfs_unmountall (int halting);
 int    vfs_register (struct vfsconf *);
 int    vfs_unregister (struct vfsconf *);
 extern struct nfs_public nfs_pub;
index da3486d..42b2e25 100644 (file)
@@ -89,6 +89,7 @@ devfs_vfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
 
        mp->mnt_flag |= MNT_LOCAL;
        mp->mnt_kern_flag |= MNTK_NOSTKMNT | MNTK_ALL_MPSAFE;
+       mp->mnt_kern_flag |= MNTK_QUICKHALT;   /* no teardown needed on halt */
        mp->mnt_data = NULL;
        vfs_getnewfsid(mp);
 
index 6a9048d..c83eee8 100644 (file)
@@ -473,7 +473,7 @@ mfs_start(struct mount *mp, int flags)
                 */
                if (gotsig) {
                        gotsig = 0;
-                       if (dounmount(mp, 0) != 0) {
+                       if (dounmount(mp, 0, 0) != 0) {
                                KKASSERT(td->td_proc);
                                lwkt_gettoken(&td->td_proc->p_token);
                                sig = CURSIG(td->td_lwp);
index 57a9462..66dcd8c 100644 (file)
@@ -126,7 +126,7 @@ nfs_clientd(struct nfsmount *nmp, struct ucred *cred, struct nfsd_cargs *ncd,
                    error = tsleep((caddr_t)&nmp->nm_authstr, PCATCH,
                        "nqnfstimr", hz / 3);
                    if (error == EINTR || error == ERESTART)
-                       (void) dounmount(nmp->nm_mountp, 0);
+                       (void) dounmount(nmp->nm_mountp, 0, 0);
            }
        }
 
index 81453b6..3372680 100644 (file)
@@ -77,6 +77,7 @@ procfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
 
        mp->mnt_flag |= MNT_LOCAL;
        mp->mnt_kern_flag |= MNTK_NOSTKMNT;
+       mp->mnt_kern_flag |= MNTK_QUICKHALT;   /* no teardown needed on halt */
        mp->mnt_data = NULL;
        vfs_getnewfsid(mp);
 
index 2a70061..24a4871 100644 (file)
@@ -1055,7 +1055,7 @@ puffs_sop_thread(void *arg)
         * is eventually completed.
         */
        if (unmountme) {
-               (void)dounmount(mp, MNT_FORCE);
+               dounmount(mp, MNT_FORCE, 0);
        }
 
        kthread_exit();
@@ -1104,7 +1104,7 @@ puffs_msgif_close(void *this)
        lockmgr(&pmp->pmp_lock, LK_RELEASE);
 
        /* Detach from VFS. */
-       (void)dounmount(mp, MNT_FORCE);
+       dounmount(mp, MNT_FORCE, 0);
 
        return 0;
 }
index 45e9b19..c52163a 100644 (file)
@@ -282,6 +282,7 @@ tmpfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
        mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
        mp->mnt_kern_flag |= MNTK_NOMSYNC;
        mp->mnt_kern_flag |= MNTK_THR_SYNC;     /* new vsyncscan semantics */
+       mp->mnt_kern_flag |= MNTK_QUICKHALT;    /* no teardown needed on halt */
        mp->mnt_data = (qaddr_t)tmp;
        vfs_getnewfsid(mp);