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;

Reply via email to