1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-18 10:35:55 +00:00

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
This commit is contained in:
Edward Tomasz Napierala 2015-08-24 13:18:13 +00:00
parent e3c074a017
commit c9ba65040f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=287107
4 changed files with 38 additions and 28 deletions

View File

@ -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);
}

View File

@ -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_symlinkat(td, "/", AT_FDCWD, "dev", UIO_SYSSPACE);

View File

@ -3543,6 +3543,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.
@ -3550,42 +3565,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);
}
/*

View File

@ -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;