The problem was due to an interaction between the doomed unmounts done by
amd and getnewvnode.
I convinced myself that it's ok for getnewvnode() to do a sleeping vfs_busy().
Tested with multiple builds running while another process attempted to unmount
/usr once a second.
getnewvnode now checks this bit, and it if's set makes sure a vnode's not
locked before removing it from the free list.
Closes PR 7954 by Alan Barrett <apb@iafrica.com>.
mp->mnt_flags & MNT_MWAIT is replaced by mp->mnt_wcnt, and a new mount
flag MNT_GONE is created (reusing the same bit).
In insmntque(), add DIAGNOSTIC check to fail if the filesystem vnode
is being moved to is in the process of being unmounted.
getnewvnode() now protects the list of vnodes active on mp with
vfs_busy()/vfs_unbusy().
To avoid generating spurious errors during a doomed unmount, change
the "wait for unmount to finish" protocol between dounmount() and
vfs_busy(). In vfs_busy(), instead of only sleeping once, sleep until
either MNT_UNMOUNT is clear or MNT_GONE is set; also, maintain a count
of waiters in mp->mnt_wcnt so that dounmount() knows when it's safe to
free mp.
tested by running a "while :; do mount /d1; umount -f /d1; done" loop
against multiple find(1) processes.
deadlock in VOP_FSYNC() if the unreferenced vnode picked for
reclamation happened to be stacked on top of a vnode the process
already had locked. This could happen if the same filesystem was
accessed both through a union mount and directly; it seemed to happen
most frequently when the direct access was through NFS.
Avoid this deadlock by changing vinvalbuf to pass a new FSYNC_RECLAIM
flag bit to VOP_FSYNC() to indicate that a reclaim is in progress and
only a `shallow' fsync is necessary.
Do nothing in *_fsync() in umapfs, nullfs, and unionfs when
FSYNC_RECLAIM is set; the underlying vnodes will shortly be released
in *_reclaim and may be reclaimed (and fsync'ed) later.
only benefit this provides is that we don't use kmem_map to map the memory
used for vnodes (though, this is a 30 virtual page savings on my PPro)
since vnodes are never freed (they have their own freelist).
* we already have the vnode interlock, so vref() should not ask for it again.
* we call VOP_RECLAIM/VOP_INACTIVE(), which shouldn't be duplicated in vrele().
UVM was written by chuck cranor <chuck@maria.wustl.edu>, with some
minor portions derived from the old Mach code. i provided some help
getting swap and paging working, and other bug fixes/ideas. chuck
silvers <chuq@chuq.com> also provided some other fixes.
this is the rest of the MI portion changes.
this will be KNF'd shortly. :-)
unmounting all of the file systems. If we encounter a condition where
all of the dirty buffers could not flush, then don't unmount file systems,
since it might be likely to wedge.
anon cred are the same. Should probably be handled better in the mountd,
but this will do for now. Fixes PR 469, submitted Sept 1994 by
a certain "Jason R. Thorpe".. ;-)
so that if the drop to spl0() causes another panic (e.g. because there's
still some fatal hardware interrupt that's pending) we'll know that we
dropped IPL to sync the disks.
* When a delayed write buffer falls off the LRU queue, arrange for it to go on
the AGE queue after being flushed out to disk.
* When a delayed write buffer is synced, leave it in its relative position in
the LRU queue.
work. Not quite as good as with the Lite2 merges, but it'll do until then.
* dounmount() expects to be called with the mountpoint marked busy
* all callers of dounmount() thus make the call themselves
* if a filesystem was being unmounted, and we're woken up in vfs_busy(),
don't reference the mountpoint struct pointer, as it has very probably
been freed.