Module Name: src
Committed By: hannken
Date: Mon Jan 2 10:35:00 UTC 2017
Modified Files:
src/sys/kern: vfs_vnode.c
Log Message:
Change vcache_*vget() to increment v_usecount on success only.
Increment v_holdcnt to prevent the vnode from disappearing while
vcache_vget() waits for a stable state.
Now v_usecount tracks the number of successfull references.
To generate a diff of this commit:
cvs rdiff -u -r1.66 -r1.67 src/sys/kern/vfs_vnode.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/vfs_vnode.c
diff -u src/sys/kern/vfs_vnode.c:1.66 src/sys/kern/vfs_vnode.c:1.67
--- src/sys/kern/vfs_vnode.c:1.66 Mon Jan 2 10:33:28 2017
+++ src/sys/kern/vfs_vnode.c Mon Jan 2 10:35:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_vnode.c,v 1.66 2017/01/02 10:33:28 hannken Exp $ */
+/* $NetBSD: vfs_vnode.c,v 1.67 2017/01/02 10:35:00 hannken Exp $ */
/*-
* Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -156,7 +156,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.66 2017/01/02 10:33:28 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.67 2017/01/02 10:35:00 hannken Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -755,18 +755,11 @@ vrelel(vnode_t *vp, int flags)
return;
}
- if (VSTATE_GET(vp) == VS_RECLAIMED) {
+ if (VSTATE_GET(vp) == VS_RECLAIMED && vp->v_holdcnt == 0) {
/*
* It's clean so destroy it. It isn't referenced
* anywhere since it has been reclaimed.
*/
- KASSERT(vp->v_holdcnt == 0);
- KASSERT(vp->v_writecount == 0);
- mutex_exit(vp->v_interlock);
- vfs_insmntque(vp, NULL);
- if (vp->v_type == VBLK || vp->v_type == VCHR) {
- spec_node_destroy(vp);
- }
vcache_free(VNODE_TO_VIMPL(vp));
} else {
/*
@@ -1049,6 +1042,7 @@ vcache_alloc(void)
/*
* Free an unused, unreferenced vcache node.
+ * v_interlock locked on entry.
*/
static void
vcache_free(vnode_impl_t *node)
@@ -1056,10 +1050,18 @@ vcache_free(vnode_impl_t *node)
vnode_t *vp;
vp = VIMPL_TO_VNODE(node);
+ KASSERT(mutex_owned(vp->v_interlock));
KASSERT(vp->v_usecount == 0);
-
+ KASSERT(vp->v_holdcnt == 0);
+ KASSERT(vp->v_writecount == 0);
lru_requeue(vp, NULL);
+ mutex_exit(vp->v_interlock);
+
+ vfs_insmntque(vp, NULL);
+ if (vp->v_type == VBLK || vp->v_type == VCHR)
+ spec_node_destroy(vp);
+
rw_destroy(&vp->v_lock);
uvm_obj_destroy(&vp->v_uobj, true);
cv_destroy(&vp->v_cv);
@@ -1076,39 +1078,22 @@ vcache_free(vnode_impl_t *node)
int
vcache_tryvget(vnode_t *vp)
{
+ int error = 0;
KASSERT(mutex_owned(vp->v_interlock));
- /*
- * Before adding a reference, we must remove the vnode
- * from its freelist.
- */
- if (vp->v_usecount == 0) {
+ if (__predict_false(VSTATE_GET(vp) == VS_RECLAIMED))
+ error = ENOENT;
+ else if (__predict_false(VSTATE_GET(vp) != VS_ACTIVE))
+ error = EBUSY;
+ else if (vp->v_usecount == 0)
vp->v_usecount = 1;
- } else {
+ else
atomic_inc_uint(&vp->v_usecount);
- }
- /*
- * If the vnode is in the process of changing state we wait
- * for the change to complete and take care not to return
- * a clean vnode.
- */
- if (VSTATE_GET(vp) == VS_RECLAIMED) {
- vrelel(vp, 0);
- return ENOENT;
- } else if (VSTATE_GET(vp) != VS_ACTIVE) {
- vrelel(vp, 0);
- return EBUSY;
- }
-
- /*
- * Ok, we got it in good shape.
- */
- VSTATE_ASSERT(vp, VS_ACTIVE);
mutex_exit(vp->v_interlock);
- return 0;
+ return error;
}
/*
@@ -1124,34 +1109,25 @@ vcache_vget(vnode_t *vp)
KASSERT(mutex_owned(vp->v_interlock));
- /*
- * Before adding a reference, we must remove the vnode
- * from its freelist.
- */
- if (vp->v_usecount == 0) {
- vp->v_usecount = 1;
- } else {
- atomic_inc_uint(&vp->v_usecount);
- }
-
- /*
- * If the vnode is in the process of changing state we wait
- * for the change to complete and take care not to return
- * a clean vnode.
- */
+ /* Increment hold count to prevent vnode from disappearing. */
+ vp->v_holdcnt++;
VSTATE_WAIT_STABLE(vp);
- if (VSTATE_GET(vp) == VS_RECLAIMED) {
- vrelel(vp, 0);
+ vp->v_holdcnt--;
+
+ /* If this was the last reference to a reclaimed vnode free it now. */
+ if (__predict_false(VSTATE_GET(vp) == VS_RECLAIMED)) {
+ if (vp->v_holdcnt == 0 && vp->v_usecount == 0)
+ vcache_free(VNODE_TO_VIMPL(vp));
+ else
+ mutex_exit(vp->v_interlock);
return ENOENT;
- } else if (VSTATE_GET(vp) != VS_ACTIVE) {
- vrelel(vp, 0);
- return EBUSY;
}
-
- /*
- * Ok, we got it in good shape.
- */
VSTATE_ASSERT(vp, VS_ACTIVE);
+ if (vp->v_usecount == 0)
+ vp->v_usecount = 1;
+ else
+ atomic_inc_uint(&vp->v_usecount);
+
mutex_exit(vp->v_interlock);
return 0;