Module Name:    src
Committed By:   hannken
Date:           Sun Nov  3 08:33:00 UTC 2013

Modified Files:
        src/sys/kern: vfs_vnode.c

Log Message:
cleanvnode():
- VC_XLOCK/VC_MASK are not used anymore, remove.
- If we get a reference while cleaning, there is no need to retry as
  these reference and this vnode will disappear soon.
- Make sure we run inside a fstrans transaction to prevent deadlocks
  against vget().

vrecycle():
- don't even try to recycle a vnode currently cleaning.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 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.23 src/sys/kern/vfs_vnode.c:1.24
--- src/sys/kern/vfs_vnode.c:1.23	Tue Oct 29 09:53:51 2013
+++ src/sys/kern/vfs_vnode.c	Sun Nov  3 08:33:00 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnode.c,v 1.23 2013/10/29 09:53:51 hannken Exp $	*/
+/*	$NetBSD: vfs_vnode.c,v 1.24 2013/11/03 08:33:00 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -106,18 +106,8 @@
  *	from zero, the interlock must be held.  To change from a non-zero
  *	value to zero, again the interlock must be held.
  *
- *	There is a flag bit, VC_XLOCK, embedded in v_usecount.  To raise
- *	v_usecount, if the VC_XLOCK bit is set in it, the interlock must
- *	be held.  To modify the VC_XLOCK bit, the interlock must be held.
- *	We always keep the usecount (v_usecount & VC_MASK) non-zero while
- *	the VC_XLOCK bit is set.
- *
- *	Unless the VC_XLOCK bit is set, changing the usecount from a non-zero
- *	value to a non-zero value can safely be done using atomic operations,
- *	without the interlock held.
- *
- *	Even if the VC_XLOCK bit is set, decreasing the usecount to a non-zero
- *	value can be done using atomic operations, without the interlock held.
+ *	Changing the usecount from a non-zero value to a non-zero value can
+ *	safely be done using atomic operations, without the interlock held.
  *
  *	Note: if VI_CLEAN is set, vnode_t::v_interlock will be released while
  *	mntvnode_lock is still held.
@@ -126,7 +116,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.23 2013/10/29 09:53:51 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.24 2013/11/03 08:33:00 hannken Exp $");
 
 #define _VFS_VNODE_PRIVATE
 
@@ -148,14 +138,11 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,
 #include <sys/systm.h>
 #include <sys/vnode.h>
 #include <sys/wapbl.h>
+#include <sys/fstrans.h>
 
 #include <uvm/uvm.h>
 #include <uvm/uvm_readahead.h>
 
-/* v_usecount; see the comment near the top of vfs_vnode.c */
-#define	VC_XLOCK	0x80000000
-#define	VC_MASK		0x7fffffff
-
 #define	DOCLOSE		0x0008		/* vclean: close active files */
 
 /* Flags to vrelel. */
@@ -284,9 +271,10 @@ cleanvnode(void)
 {
 	vnode_t *vp;
 	vnodelst_t *listhd;
+	struct mount *mp;
 
 	KASSERT(mutex_owned(&vnode_free_list_lock));
-retry:
+
 	listhd = &vnode_free_list;
 try_nextlist:
 	TAILQ_FOREACH(vp, listhd, v_freelist) {
@@ -302,9 +290,16 @@ try_nextlist:
 
 		if (!mutex_tryenter(vp->v_interlock))
 			continue;
-		if ((vp->v_iflag & VI_XLOCK) == 0)
-			break;
-		mutex_exit(vp->v_interlock);
+		if ((vp->v_iflag & VI_XLOCK) != 0) {
+			mutex_exit(vp->v_interlock);
+			continue;
+		}
+		mp = vp->v_mount;
+		if (fstrans_start_nowait(mp, FSTRANS_SHARED) != 0) {
+			mutex_exit(vp->v_interlock);
+			continue;
+		}
+		break;
 	}
 
 	if (vp == NULL) {
@@ -326,37 +321,12 @@ try_nextlist:
 	/*
 	 * The vnode is still associated with a file system, so we must
 	 * clean it out before freeing it.  We need to add a reference
-	 * before doing this.  If the vnode gains another reference while
-	 * being cleaned out then we lose - retry.
+	 * before doing this.
 	 */
-	atomic_add_int(&vp->v_usecount, 1 + VC_XLOCK);
+	vp->v_usecount = 1;
 	vclean(vp, DOCLOSE);
-	KASSERT(vp->v_usecount >= 1 + VC_XLOCK);
-	atomic_add_int(&vp->v_usecount, -VC_XLOCK);
-	if (vp->v_usecount > 1) {
-		/*
-		 * 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;
-	}
-
-	KASSERT((vp->v_iflag & VI_CLEAN) == VI_CLEAN);
-	mutex_exit(vp->v_interlock);
-	if (vp->v_type == VBLK || vp->v_type == VCHR) {
-		spec_node_destroy(vp);
-	}
-	vp->v_type = VNON;
-
-	KASSERT(vp->v_data == NULL);
-	KASSERT(vp->v_uobj.uo_npages == 0);
-	KASSERT(TAILQ_EMPTY(&vp->v_uobj.memq));
-	KASSERT(vp->v_numoutput == 0);
-	KASSERT((vp->v_iflag & VI_ONWORKLST) == 0);
-
-	vrele(vp);
+	vrelel(vp, 0);
+	fstrans_done(mp);
 
 	return 0;
 }
@@ -604,7 +574,7 @@ vtryrele(vnode_t *vp)
 		if (use == 1) {
 			return false;
 		}
-		KASSERT((use & VC_MASK) > 1);
+		KASSERT(use > 1);
 		next = atomic_cas_uint(&vp->v_usecount, use, use - 1);
 		if (__predict_true(next == use)) {
 			return true;
@@ -990,7 +960,7 @@ vclean(vnode_t *vp, int flags)
 		atomic_add_int(&uvmexp.filepages, vp->v_uobj.uo_npages);
 	}
 	vp->v_iflag &= ~(VI_TEXT|VI_EXECMAP);
-	active = (vp->v_usecount & VC_MASK) > 1;
+	active = (vp->v_usecount > 1);
 
 	/* XXXAD should not lock vnode under layer */
 	mutex_exit(vp->v_interlock);
@@ -1085,7 +1055,7 @@ vrecycle(vnode_t *vp, kmutex_t *inter_lk
 	KASSERT((vp->v_iflag & VI_MARKER) == 0);
 
 	mutex_enter(vp->v_interlock);
-	if (vp->v_usecount != 0) {
+	if (vp->v_usecount != 0 || (vp->v_iflag & (VI_CLEAN|VI_XLOCK)) != 0) {
 		mutex_exit(vp->v_interlock);
 		return 0;
 	}

Reply via email to