diff options
-rw-r--r-- | sys/kern/vfs_subr.c | 53 | ||||
-rw-r--r-- | sys/sys/vnode.h | 5 |
2 files changed, 41 insertions, 17 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 311ea54..8e954eb 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -925,7 +925,8 @@ getnewvnode(tag, mp, vops, vpp) for (count = 0; count < freevnodes; count++) { vp = TAILQ_FIRST(&vnode_free_list); - KASSERT(vp->v_usecount == 0, + KASSERT(vp->v_usecount == 0 && + (vp->v_iflag & VI_DOINGINACT) == 0, ("getnewvnode: free vnode isn't")); TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); @@ -2172,8 +2173,8 @@ vrele(vp) KASSERT(vp->v_writecount < vp->v_usecount || vp->v_usecount < 1, ("vrele: missed vn_close")); - if (vp->v_usecount > 1) { - + if (vp->v_usecount > 1 || ((vp->v_iflag & VI_DOINGINACT) && + vp->v_usecount == 1)) { v_incr_usecount(vp, -1); VI_UNLOCK(vp); @@ -2183,13 +2184,20 @@ vrele(vp) if (vp->v_usecount == 1) { v_incr_usecount(vp, -1); /* - * We must call VOP_INACTIVE with the node locked. - * If we are doing a vput, the node is already locked, - * but, in the case of vrele, we must explicitly lock - * the vnode before calling VOP_INACTIVE. + * We must call VOP_INACTIVE with the node locked. Mark + * as VI_DOINGINACT to avoid recursion. */ - if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) == 0) + if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) == 0) { + VI_LOCK(vp); + vp->v_iflag |= VI_DOINGINACT; + VI_UNLOCK(vp); VOP_INACTIVE(vp, td); + VI_LOCK(vp); + KASSERT(vp->v_iflag & VI_DOINGINACT, + ("vrele: lost VI_DOINGINACT")); + vp->v_iflag &= ~VI_DOINGINACT; + VI_UNLOCK(vp); + } VI_LOCK(vp); if (VSHOULDFREE(vp)) vfree(vp); @@ -2225,7 +2233,8 @@ vput(vp) KASSERT(vp->v_writecount < vp->v_usecount || vp->v_usecount < 1, ("vput: missed vn_close")); - if (vp->v_usecount > 1) { + if (vp->v_usecount > 1 || ((vp->v_iflag & VI_DOINGINACT) && + vp->v_usecount == 1)) { v_incr_usecount(vp, -1); VOP_UNLOCK(vp, LK_INTERLOCK, td); return; @@ -2234,13 +2243,17 @@ vput(vp) if (vp->v_usecount == 1) { v_incr_usecount(vp, -1); /* - * We must call VOP_INACTIVE with the node locked. - * If we are doing a vput, the node is already locked, - * so we just need to release the vnode mutex. + * We must call VOP_INACTIVE with the node locked, so + * we just need to release the vnode mutex. Mark as + * as VI_DOINGINACT to avoid recursion. */ + vp->v_iflag |= VI_DOINGINACT; VI_UNLOCK(vp); VOP_INACTIVE(vp, td); VI_LOCK(vp); + KASSERT(vp->v_iflag & VI_DOINGINACT, + ("vput: lost VI_DOINGINACT")); + vp->v_iflag &= ~VI_DOINGINACT; if (VSHOULDFREE(vp)) vfree(vp); else @@ -2545,9 +2558,19 @@ vclean(vp, flags, td) if (active) { if (flags & DOCLOSE) VOP_CLOSE(vp, FNONBLOCK, NOCRED, td); - if (vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT, td) != 0) - panic("vclean: cannot relock."); - VOP_INACTIVE(vp, td); + VI_LOCK(vp); + if ((vp->v_iflag & VI_DOINGINACT) == 0) { + vp->v_iflag |= VI_DOINGINACT; + VI_UNLOCK(vp); + if (vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT, td) != 0) + panic("vclean: cannot relock."); + VOP_INACTIVE(vp, td); + VI_LOCK(vp); + KASSERT(vp->v_iflag & VI_DOINGINACT, + ("vclean: lost VI_DOINGINACT")); + vp->v_iflag &= ~VI_DOINGINACT; + } + VI_UNLOCK(vp); } /* diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index fd7e6c4..1f8cd78 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -214,6 +214,7 @@ struct xvnode { #define VI_DOOMED 0x0080 /* This vnode is being recycled */ #define VI_FREE 0x0100 /* This vnode is on the freelist */ #define VI_OBJDIRTY 0x0400 /* object might be dirty */ +#define VI_DOINGINACT 0x0800 /* VOP_INACTIVE is in progress */ /* * XXX VI_ONWORKLST could be replaced with a check for NULL list elements * in v_synclist. @@ -376,14 +377,14 @@ extern void (*lease_updatetime)(int deltat); /* Requires interlock */ #define VSHOULDFREE(vp) \ - (!((vp)->v_iflag & (VI_FREE|VI_DOOMED)) && \ + (!((vp)->v_iflag & (VI_FREE|VI_DOOMED|VI_DOINGINACT)) && \ !(vp)->v_holdcnt && !(vp)->v_usecount && \ (!(vp)->v_object || \ !((vp)->v_object->ref_count || (vp)->v_object->resident_page_count))) /* Requires interlock */ #define VMIGHTFREE(vp) \ - (!((vp)->v_iflag & (VI_FREE|VI_DOOMED|VI_XLOCK)) && \ + (!((vp)->v_iflag & (VI_FREE|VI_DOOMED|VI_XLOCK|VI_DOINGINACT)) && \ LIST_EMPTY(&(vp)->v_cache_src) && !(vp)->v_usecount) /* Requires interlock */ |