Previous did cause a deadlock with layered FS: the vrele thread
can sleep on the vnode lock, while vget is sleeping on the VI_INACTNOW flag (or the vget caller is looping on vget returning failure because of the VI_INACTNOW flag). With layered FSes, the upper and lower vnodes share the same lock, so the vget() caller above can be already holding the vnode lock. Fix by dropping VI_INACTNOW before sleeping on the vnode lock in vrelel(), and check the ref count again once we have the lock. If the vnode has more than one reference, donc VOP_INACTIVE it. Fix PR kern/42318 and PR kern/42377 patch tested by Hisashi T Fujinaka, Joachim König, Stephen Borrill and Matthias Scheler.
This commit is contained in:
parent
c6e1f64d7a
commit
8c392da154
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_subr.c,v 1.391 2009/11/27 16:43:51 pooka Exp $ */
|
||||
/* $NetBSD: vfs_subr.c,v 1.392 2009/11/28 10:10:17 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -91,7 +91,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.391 2009/11/27 16:43:51 pooka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.392 2009/11/28 10:10:17 bouyer Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_compat_netbsd.h"
|
||||
|
@ -1429,14 +1429,30 @@ vrelel(vnode_t *vp, int flags)
|
|||
/* The pagedaemon can't wait around; defer. */
|
||||
defer = true;
|
||||
} else if (curlwp == vrele_lwp) {
|
||||
/* We have to try harder. */
|
||||
vp->v_iflag &= ~VI_INACTREDO;
|
||||
/*
|
||||
* We have to try harder. But we can't sleep
|
||||
* with VI_INACTNOW as vget() may be waiting on it.
|
||||
*/
|
||||
vp->v_iflag &= ~(VI_INACTREDO|VI_INACTNOW);
|
||||
cv_broadcast(&vp->v_cv);
|
||||
error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK |
|
||||
LK_RETRY);
|
||||
if (error != 0) {
|
||||
/* XXX */
|
||||
vpanic(vp, "vrele: unable to lock %p");
|
||||
}
|
||||
mutex_enter(&vp->v_interlock);
|
||||
/*
|
||||
* if we did get another reference while
|
||||
* sleeping, don't try to inactivate it yet.
|
||||
*/
|
||||
if (__predict_false(vtryrele(vp))) {
|
||||
VOP_UNLOCK(vp, 0);
|
||||
mutex_exit(&vp->v_interlock);
|
||||
return;
|
||||
}
|
||||
vp->v_iflag |= VI_INACTNOW;
|
||||
mutex_exit(&vp->v_interlock);
|
||||
defer = false;
|
||||
} else if ((vp->v_iflag & VI_LAYER) != 0) {
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue