summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2016-01-12 10:09:03 +0000
committertrasz <trasz@FreeBSD.org>2016-01-12 10:09:03 +0000
commita35cfac66cd13b8a8193084a71a760710f87703e (patch)
tree9323e17144f0c21cec420ec7a5815cc2ff607ff9 /sys/kern
parent51adb09baa42149bdf1b01ca23587b8743c2292e (diff)
downloadFreeBSD-src-a35cfac66cd13b8a8193084a71a760710f87703e.zip
FreeBSD-src-a35cfac66cd13b8a8193084a71a760710f87703e.tar.gz
MFC r287107:
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. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D3467
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_mount.c2
-rw-r--r--sys/kern/vfs_mountroot.c6
-rw-r--r--sys/kern/vfs_subr.c57
3 files changed, 37 insertions, 28 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 36d03f9..3ca995f 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -1359,6 +1359,8 @@ dounmount(struct mount *mp, int flags, struct thread *td)
vput(coveredvp);
}
vfs_event_signal(NULL, VQ_UNMOUNT, 0);
+ if (mp == rootdevmp)
+ rootdevmp = NULL;
vfs_mount_destroy(mp);
return (0);
}
diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c
index 473cd79..5c49ff7 100644
--- a/sys/kern/vfs_mountroot.c
+++ b/sys/kern/vfs_mountroot.c
@@ -95,6 +95,11 @@ static struct mntarg *parse_mountroot_options(struct mntarg *, const char *);
*/
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, struct mount **mpp)
mtx_unlock(&mountlist_mtx);
*mpp = mp;
+ rootdevmp = mp;
set_rootvnode();
error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index bad816b..cd5d6f0 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3728,6 +3728,21 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE | CTLFLAG_RD |
"");
#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.
@@ -3735,42 +3750,28 @@ SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE | CTLFLAG_RD |
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);
}
/*
OpenPOWER on IntegriCloud