summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-09-12 16:31:32 +0000
committerkib <kib@FreeBSD.org>2007-09-12 16:31:32 +0000
commite651705b7e9100bab6eada7793ec8c47c24d65aa (patch)
tree9af9fa02ecb42b6b92fe2fefa1fb1be0c3c57232
parentea3192c3f4d2f82afb6215fb244df50276cd3558 (diff)
downloadFreeBSD-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.c13
-rw-r--r--sys/kern/vfs_subr.c2
-rw-r--r--sys/sys/mount.h5
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 */
OpenPOWER on IntegriCloud