diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 1998-12-10 23:48:14 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 1998-12-10 23:48:14 +0000 |
commit | 8cd28d6913d14cfea823502780f14346913b7660 (patch) | |
tree | 8cb6c1062cfa02914c46e922a4bf10300cc3efcc | |
parent | 3355c8c983a8923b015cbdcef2b87de65aefada5 (diff) |
Several fixes to dounmount.
- Check for MNT_UNMOUNT before doing the actual unmount. It shouldn't
matter for normal unmounts that go through sys_unmount, because they
won't be able to do a lookup on the mountpoint when it's being unmounted,
but mfs calls dounmount directly (and there was still a race).
- clear the MNT_UNMOUNT flag after reenabling the lock (almost impossible
race).
- clear the MNT_MWAIT flag after doing a wakeup on the mountpoint.
-rw-r--r-- | sys/kern/vfs_syscalls.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 8abc6e739a1..a9c02ad2f9f 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.47 1998/11/12 04:30:01 csapuntz Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.48 1998/12/10 23:48:13 art Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -427,6 +427,12 @@ dounmount(mp, flags, p) int error; simple_lock(&mountlist_slock); + if (mp->mnt_flag & MNT_UNMOUNT) { + simple_unlock(&mountlist_slock); + mp->mnt_flag |= MNT_WAIT; + sleep(mp, PVFS); + return ENOENT; + } mp->mnt_flag |= MNT_UNMOUNT; lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); mp->mnt_flag &=~ MNT_ASYNC; @@ -442,11 +448,12 @@ dounmount(mp, flags, p) if (error) { if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) (void) vfs_allocate_syncvnode(mp); - mp->mnt_flag &= ~MNT_UNMOUNT; lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, &mountlist_slock, p); + mp->mnt_flag &= ~MNT_UNMOUNT; if (mp->mnt_flag & MNT_MWAIT) wakeup((caddr_t)mp); + mp->mnt_flag &= ~MNT_MWAIT; return (error); } CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); |