getcleanvnode(): don't vclean() the vnode if it has gained another
reference while we were getting the v_interlock. vget(): attempt prevent it from returning a clean vnode: if the vnode is being inactivated (by vrelel()), wait for vrelel() to complete (or return EBUSY if we can't wait), and return ENOENT if the vnode has been vclean'ed by vrelel() Fix kern/41147 in a better way, hopefully fix other related race conditions.
This commit is contained in:
parent
5dabc83466
commit
6b8161200e
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vfs_subr.c,v 1.385 2009/10/06 04:28:10 elad Exp $ */
|
||||
/* $NetBSD: vfs_subr.c,v 1.386 2009/11/05 08:18:02 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.385 2009/10/06 04:28:10 elad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.386 2009/11/05 08:18:02 bouyer Exp $");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_compat_netbsd.h"
|
||||
|
@ -371,6 +371,17 @@ try_nextlist:
|
|||
vp->v_freelisthd = NULL;
|
||||
mutex_exit(&vnode_free_list_lock);
|
||||
|
||||
if (vp->v_usecount != 0) {
|
||||
/*
|
||||
* was referenced again before we got the interlock
|
||||
* Don't return to freelist - the holder of the last
|
||||
* reference will destroy it.
|
||||
*/
|
||||
vrelel(vp, 0); /* releases vp->v_interlock */
|
||||
mutex_enter(&vnode_free_list_lock);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* The vnode is still associated with a file system, so we must
|
||||
* clean it out before reusing it. We need to add a reference
|
||||
|
@ -1306,6 +1317,22 @@ vget(vnode_t *vp, int flags)
|
|||
vrelel(vp, 0);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if ((vp->v_iflag & VI_INACTNOW) != 0) {
|
||||
/*
|
||||
* if it's being desactived, wait for it to complete.
|
||||
* Make sure to not return a clean vnode.
|
||||
*/
|
||||
if ((flags & LK_NOWAIT) != 0) {
|
||||
vrelel(vp, 0);
|
||||
return EBUSY;
|
||||
}
|
||||
vwait(vp, VI_INACTNOW);
|
||||
if ((vp->v_iflag & VI_CLEAN) != 0) {
|
||||
vrelel(vp, 0);
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
if (flags & LK_TYPE_MASK) {
|
||||
error = vn_lock(vp, flags | LK_INTERLOCK);
|
||||
if (error != 0) {
|
||||
|
@ -1445,6 +1472,7 @@ vrelel(vnode_t *vp, int flags)
|
|||
if (++vrele_pending > (desiredvnodes >> 8))
|
||||
cv_signal(&vrele_cv);
|
||||
mutex_exit(&vrele_lock);
|
||||
cv_broadcast(&vp->v_cv);
|
||||
mutex_exit(&vp->v_interlock);
|
||||
return;
|
||||
}
|
||||
|
@ -1469,6 +1497,7 @@ vrelel(vnode_t *vp, int flags)
|
|||
VOP_INACTIVE(vp, &recycle);
|
||||
mutex_enter(&vp->v_interlock);
|
||||
vp->v_iflag &= ~VI_INACTNOW;
|
||||
cv_broadcast(&vp->v_cv);
|
||||
if (!recycle) {
|
||||
if (vtryrele(vp)) {
|
||||
mutex_exit(&vp->v_interlock);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ufs_ihash.c,v 1.27 2009/09/20 14:00:24 bouyer Exp $ */
|
||||
/* $NetBSD: ufs_ihash.c,v 1.28 2009/11/05 08:18:02 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1991, 1993
|
||||
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ufs_ihash.c,v 1.27 2009/09/20 14:00:24 bouyer Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ufs_ihash.c,v 1.28 2009/11/05 08:18:02 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -152,15 +152,6 @@ ufs_ihashget(dev_t dev, ino_t inum, int flags)
|
|||
mutex_exit(&ufs_ihash_lock);
|
||||
if (vget(vp, flags | LK_INTERLOCK))
|
||||
goto loop;
|
||||
if (VTOI(vp) != ip ||
|
||||
ip->i_number != inum || ip->i_dev != dev) {
|
||||
/* lost race against vclean() */
|
||||
if (vlockmgr(vp->v_vnlock, LK_RELEASE))
|
||||
printf("can't release lock\n");
|
||||
vrele(vp);
|
||||
vp = NULL;
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
return (vp);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue