diff options
author | kib <kib@FreeBSD.org> | 2007-09-12 16:31:32 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2007-09-12 16:31:32 +0000 |
commit | e651705b7e9100bab6eada7793ec8c47c24d65aa (patch) | |
tree | 9af9fa02ecb42b6b92fe2fefa1fb1be0c3c57232 | |
parent | ea3192c3f4d2f82afb6215fb244df50276cd3558 (diff) | |
download | FreeBSD-src-e651705b7e9100bab6eada7793ec8c47c24d65aa.zip FreeBSD-src-e651705b7e9100bab6eada7793ec8c47c24d65aa.tar.gz |
When restoring the mount after umount failed, the MNTK_UNMOUNT flag
prevents insmntque() from placing reallocated syncer vnode on mount
list, that causes panic in vfs_allocate_syncvnode().
Introduce MNTK_NOINSMNTQ flag, that marks the period when instmntque is
not allowed to success, instead of MNTK_UNMOUNT. The MNTK_NOINSMNTQ is
set and cleared simultaneously with MNTK_UNMOUNT, except on umount error
path, where it is cleaned just before the syncer vnode is going to be
allocated.
Reported by: Peter Jeremy <peterjeremy optushome com au>
Suggested by: tegge
Approved by: re (rwatson)
-rw-r--r-- | sys/kern/vfs_mount.c | 13 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 2 | ||||
-rw-r--r-- | sys/sys/mount.h | 5 |
3 files changed, 15 insertions, 5 deletions
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 5e6a84a..a109a3b 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1222,7 +1222,7 @@ dounmount(mp, flags, td) VOP_UNLOCK(coveredvp, 0, td); return (EBUSY); } - mp->mnt_kern_flag |= MNTK_UNMOUNT; + mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ; /* Allow filesystems to detect that a forced unmount is in progress. */ if (flags & MNT_FORCE) mp->mnt_kern_flag |= MNTK_UNMOUNTF; @@ -1230,7 +1230,8 @@ dounmount(mp, flags, td) ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), MNT_MTX(mp), td); if (error) { MNT_ILOCK(mp); - mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); + mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_NOINSMNTQ | + MNTK_UNMOUNTF); if (mp->mnt_kern_flag & MNTK_MWAIT) wakeup(mp); MNT_IUNLOCK(mp); @@ -1285,9 +1286,13 @@ dounmount(mp, flags, td) } vput(fsrootvp); } - if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) - (void) vfs_allocate_syncvnode(mp); MNT_ILOCK(mp); + mp->mnt_kern_flag &= ~MNTK_NOINSMNTQ; + if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) { + MNT_IUNLOCK(mp); + (void) vfs_allocate_syncvnode(mp); + MNT_ILOCK(mp); + } mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); mp->mnt_flag |= async_flag; if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index c825eb6..9c168d7 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1021,7 +1021,7 @@ insmntque1(struct vnode *vp, struct mount *mp, ("insmntque: vnode already on per mount vnode list")); VNASSERT(mp != NULL, vp, ("Don't call insmntque(foo, NULL)")); MNT_ILOCK(mp); - if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 && + if ((mp->mnt_kern_flag & MNTK_NOINSMNTQ) != 0 && mp->mnt_nvnodelistsize == 0) { MNT_IUNLOCK(mp); if (dtr != NULL) diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 37dd9af..4061720 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -303,10 +303,15 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); * dounmount() is still waiting to lock the mountpoint. This allows * the filesystem to cancel operations that might otherwise deadlock * with the unmount attempt (used by NFS). + * + * MNTK_NOINSMNTQ is strict subset of MNTK_UNMOUNT. They are separated + * to allow for failed unmount attempt to restore the syncer vnode for + * the mount. */ #define MNTK_UNMOUNTF 0x00000001 /* forced unmount in progress */ #define MNTK_ASYNC 0x00000002 /* filtered async flag */ #define MNTK_SOFTDEP 0x00000004 /* async disabled by softdep */ +#define MNTK_NOINSMNTQ 0x00000008 /* insmntque is not allowed */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_SUSPEND 0x08000000 /* request write suspension */ |