diff options
-rw-r--r-- | sys/kern/vfs_subr.c | 187 | ||||
-rw-r--r-- | sys/sys/vnode.h | 1 |
2 files changed, 85 insertions, 103 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 14f8528..7d72443 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -102,12 +102,10 @@ static int flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, int slptimeo); static void syncer_shutdown(void *arg, int howto); static int vtryrecycle(struct vnode *vp); -static void vbusy(struct vnode *vp); static void v_incr_usecount(struct vnode *); static void v_decr_usecount(struct vnode *); static void v_decr_useonly(struct vnode *); static void v_upgrade_usecount(struct vnode *); -static void vfree(struct vnode *); static void vnlru_free(int); static void vgonel(struct vnode *); static void vfs_knllock(void *arg); @@ -118,8 +116,7 @@ static void destroy_vpollinfo(struct vpollinfo *vi); /* * Number of vnodes in existence. Increased whenever getnewvnode() - * allocates a new vnode, decreased on vdestroy() called on VI_DOOMed - * vnode. + * allocates a new vnode, decreased in vdropl() for VI_DOOMED vnode. */ static unsigned long numvnodes; @@ -878,46 +875,6 @@ SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, * Routines having to do with the management of the vnode table. */ -void -vdestroy(struct vnode *vp) -{ - struct bufobj *bo; - - CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - mtx_lock(&vnode_free_list_mtx); - numvnodes--; - mtx_unlock(&vnode_free_list_mtx); - bo = &vp->v_bufobj; - VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, - ("cleaned vnode still on the free list.")); - VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); - VNASSERT(vp->v_holdcnt == 0, vp, ("Non-zero hold count")); - VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); - VNASSERT(vp->v_writecount == 0, vp, ("Non-zero write count")); - VNASSERT(bo->bo_numoutput == 0, vp, ("Clean vnode has pending I/O's")); - VNASSERT(bo->bo_clean.bv_cnt == 0, vp, ("cleanbufcnt not 0")); - VNASSERT(bo->bo_clean.bv_root == NULL, vp, ("cleanblkroot not NULL")); - VNASSERT(bo->bo_dirty.bv_cnt == 0, vp, ("dirtybufcnt not 0")); - VNASSERT(bo->bo_dirty.bv_root == NULL, vp, ("dirtyblkroot not NULL")); - VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst")); - VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src")); - VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for ..")); - VI_UNLOCK(vp); -#ifdef MAC - mac_vnode_destroy(vp); -#endif - if (vp->v_pollinfo != NULL) - destroy_vpollinfo(vp->v_pollinfo); -#ifdef INVARIANTS - /* XXX Elsewhere we can detect an already freed vnode via NULL v_op. */ - vp->v_op = NULL; -#endif - lockdestroy(vp->v_vnlock); - mtx_destroy(&vp->v_interlock); - mtx_destroy(BO_MTX(bo)); - uma_zfree(vnode_zone, vp); -} - /* * Try to recycle a freed vnode. We abort if anyone picks up a reference * before we actually vgone(). This function must be called with the vnode @@ -2346,19 +2303,33 @@ vhold(struct vnode *vp) VI_UNLOCK(vp); } +/* + * Increase the hold count and activate if this is the first reference. + */ void vholdl(struct vnode *vp) { CTR2(KTR_VFS, "%s: vp %p", __func__, vp); vp->v_holdcnt++; - if (VSHOULDBUSY(vp)) - vbusy(vp); + if (!VSHOULDBUSY(vp)) + return; + ASSERT_VI_LOCKED(vp, "vholdl"); + VNASSERT((vp->v_iflag & VI_FREE) != 0, vp, ("vnode not free")); + VNASSERT(vp->v_op != NULL, vp, ("vholdl: vnode already reclaimed.")); + /* + * Remove a vnode from the free list and mark it as in use. + */ + mtx_lock(&vnode_free_list_mtx); + TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); + freevnodes--; + vp->v_iflag &= ~(VI_FREE|VI_AGE); + mtx_unlock(&vnode_free_list_mtx); } /* - * Note that there is one less who cares about this vnode. vdrop() is the - * opposite of vhold(). + * Note that there is one less who cares about this vnode. + * vdrop() is the opposite of vhold(). */ void vdrop(struct vnode *vp) @@ -2370,28 +2341,84 @@ vdrop(struct vnode *vp) /* * Drop the hold count of the vnode. If this is the last reference to - * the vnode we will free it if it has been vgone'd otherwise it is - * placed on the free list. + * the vnode we place it on the free list unless it has been vgone'd + * (marked VI_DOOMED) in which case we will free it. */ void vdropl(struct vnode *vp) { + struct bufobj *bo; ASSERT_VI_LOCKED(vp, "vdropl"); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); if (vp->v_holdcnt <= 0) panic("vdrop: holdcnt %d", vp->v_holdcnt); vp->v_holdcnt--; - if (vp->v_holdcnt == 0) { - if (vp->v_iflag & VI_DOOMED) { - CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, - vp); - vdestroy(vp); - return; - } else - vfree(vp); + if (vp->v_holdcnt > 0) { + VI_UNLOCK(vp); + return; + } + if ((vp->v_iflag & VI_DOOMED) == 0) { + /* + * Mark a vnode as free, putting it up for recycling. + */ + mtx_lock(&vnode_free_list_mtx); + VNASSERT(vp->v_op != NULL, vp, + ("vdropl: vnode already reclaimed.")); + VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, + ("vnode already free")); + VNASSERT(VSHOULDFREE(vp), vp, + ("vdropl: freeing when we shouldn't")); + VNASSERT((vp->v_iflag & VI_DOOMED) == 0, vp, + ("vdropl: Freeing doomed vnode")); + if (vp->v_iflag & VI_AGE) { + TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); + } else { + TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); + } + freevnodes++; + vp->v_iflag &= ~VI_AGE; + vp->v_iflag |= VI_FREE; + mtx_unlock(&vnode_free_list_mtx); + VI_UNLOCK(vp); + return; } + /* + * The vnode has been marked for destruction, so free it. + */ + CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); + mtx_lock(&vnode_free_list_mtx); + numvnodes--; + mtx_unlock(&vnode_free_list_mtx); + bo = &vp->v_bufobj; + VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, + ("cleaned vnode still on the free list.")); + VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); + VNASSERT(vp->v_holdcnt == 0, vp, ("Non-zero hold count")); + VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); + VNASSERT(vp->v_writecount == 0, vp, ("Non-zero write count")); + VNASSERT(bo->bo_numoutput == 0, vp, ("Clean vnode has pending I/O's")); + VNASSERT(bo->bo_clean.bv_cnt == 0, vp, ("cleanbufcnt not 0")); + VNASSERT(bo->bo_clean.bv_root == NULL, vp, ("cleanblkroot not NULL")); + VNASSERT(bo->bo_dirty.bv_cnt == 0, vp, ("dirtybufcnt not 0")); + VNASSERT(bo->bo_dirty.bv_root == NULL, vp, ("dirtyblkroot not NULL")); + VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst")); + VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src")); + VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for ..")); VI_UNLOCK(vp); +#ifdef MAC + mac_vnode_destroy(vp); +#endif + if (vp->v_pollinfo != NULL) + destroy_vpollinfo(vp->v_pollinfo); +#ifdef INVARIANTS + /* XXX Elsewhere we detect an already freed vnode via NULL v_op. */ + vp->v_op = NULL; +#endif + lockdestroy(vp->v_vnlock); + mtx_destroy(&vp->v_interlock); + mtx_destroy(BO_MTX(bo)); + uma_zfree(vnode_zone, vp); } /* @@ -3298,50 +3325,6 @@ vfs_msync(struct mount *mp, int flags) } } -/* - * Mark a vnode as free, putting it up for recycling. - */ -static void -vfree(struct vnode *vp) -{ - - ASSERT_VI_LOCKED(vp, "vfree"); - mtx_lock(&vnode_free_list_mtx); - VNASSERT(vp->v_op != NULL, vp, ("vfree: vnode already reclaimed.")); - VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, ("vnode already free")); - VNASSERT(VSHOULDFREE(vp), vp, ("vfree: freeing when we shouldn't")); - VNASSERT((vp->v_iflag & VI_DOOMED) == 0, vp, - ("vfree: Freeing doomed vnode")); - CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - if (vp->v_iflag & VI_AGE) { - TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); - } else { - TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); - } - freevnodes++; - vp->v_iflag &= ~VI_AGE; - vp->v_iflag |= VI_FREE; - mtx_unlock(&vnode_free_list_mtx); -} - -/* - * Opposite of vfree() - mark a vnode as in use. - */ -static void -vbusy(struct vnode *vp) -{ - ASSERT_VI_LOCKED(vp, "vbusy"); - VNASSERT((vp->v_iflag & VI_FREE) != 0, vp, ("vnode not free")); - VNASSERT(vp->v_op != NULL, vp, ("vbusy: vnode already reclaimed.")); - CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - - mtx_lock(&vnode_free_list_mtx); - TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); - freevnodes--; - vp->v_iflag &= ~(VI_FREE|VI_AGE); - mtx_unlock(&vnode_free_list_mtx); -} - static void destroy_vpollinfo(struct vpollinfo *vi) { diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 453f015..3946405 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -626,7 +626,6 @@ void vattr_null(struct vattr *vap); int vcount(struct vnode *vp); void vdrop(struct vnode *); void vdropl(struct vnode *); -void vdestroy(struct vnode *); int vflush(struct mount *mp, int rootrefs, int flags, struct thread *td); int vget(struct vnode *vp, int lockflag, struct thread *td); void vgone(struct vnode *vp); |