More careful handling of the mount failure.

- VFS_UNMOUNT() requires vn_start_write() around it [*].
- call VFS_PURGE() before unmount.
- do not destroy mp if cleanup unmount did not succeed.
- set MNTK_UNMOUNT, and indicate forced unmount with MNTK_UNMOUNTF
  for VFS_UNMOUNT() in cleanup.

PR:	251320 [*]
Reported by:	Tong Zhang <ztong0001@gmail.com>
Reviewed by:	markj, mjg
Discussed with:	rmacklem
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D27327
This commit is contained in:
kib 2020-11-26 18:08:42 +00:00
parent 80df47be4a
commit a342635df5

View File

@ -903,6 +903,7 @@ vfs_domount_first(
struct mount *mp;
struct vnode *newdp, *rootvp;
int error, error1;
bool unmounted;
ASSERT_VOP_ELOCKED(vp, __func__);
KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
@ -964,23 +965,39 @@ vfs_domount_first(
* get. No freeing of cn_pnbuf.
*/
error1 = 0;
unmounted = true;
if ((error = VFS_MOUNT(mp)) != 0 ||
(error1 = VFS_STATFS(mp, &mp->mnt_stat)) != 0 ||
(error1 = VFS_ROOT(mp, LK_EXCLUSIVE, &newdp)) != 0) {
rootvp = NULL;
if (error1 != 0) {
error = error1;
MPASS(error == 0);
rootvp = vfs_cache_root_clear(mp);
if (rootvp != NULL) {
vhold(rootvp);
vrele(rootvp);
}
if ((error1 = VFS_UNMOUNT(mp, 0)) != 0)
printf("VFS_UNMOUNT returned %d\n", error1);
(void)vn_start_write(NULL, &mp, V_WAIT);
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_UNMOUNTF;
MNT_IUNLOCK(mp);
VFS_PURGE(mp);
error = VFS_UNMOUNT(mp, 0);
vn_finished_write(mp);
if (error != 0) {
printf(
"failed post-mount (%d): rollback unmount returned %d\n",
error1, error);
unmounted = false;
}
error = error1;
}
vfs_unbusy(mp);
mp->mnt_vnodecovered = NULL;
vfs_mount_destroy(mp);
if (unmounted) {
/* XXXKIB wait for mnt_lockref drain? */
vfs_mount_destroy(mp);
}
VI_LOCK(vp);
vp->v_iflag &= ~VI_MOUNT;
VI_UNLOCK(vp);