Module Name:    src
Committed By:   hannken
Date:           Mon Nov 12 11:00:07 UTC 2012

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

Log Message:
Bring back Manuel Bouyers patch to resolve races between vget() and vrelel()
resulting in vget() returning dead vnodes.
It is impossible to resolve these races in vn_lock().

Needs pullup to NetBSD-6.


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/kern/vfs_vnode.c
cvs rdiff -u -r1.185 -r1.186 src/sys/kern/vfs_vnops.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.16 src/sys/kern/vfs_vnode.c:1.17
--- src/sys/kern/vfs_vnode.c:1.16	Fri Oct 12 21:10:55 2012
+++ src/sys/kern/vfs_vnode.c	Mon Nov 12 11:00:07 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnode.c,v 1.16 2012/10/12 21:10:55 rmind Exp $	*/
+/*	$NetBSD: vfs_vnode.c,v 1.17 2012/11/12 11:00:07 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -124,7 +124,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.16 2012/10/12 21:10:55 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.17 2012/11/12 11:00:07 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -564,6 +564,22 @@ vget(vnode_t *vp, int flags)
 		return ENOENT;
 	}
 
+	if ((vp->v_iflag & VI_INACTNOW) != 0) {
+		/*
+		 * if it's being desactived, wait for it to complete.
+		 * Make sure to not return a clean vnode.
+		 */
+		 if ((flags & LK_NOWAIT) != 0) {
+			vrelel(vp, 0);
+			return EBUSY;
+		}
+		vwait(vp, VI_INACTNOW);
+		if ((vp->v_iflag & VI_CLEAN) != 0) {
+			vrelel(vp, 0);
+			return ENOENT;
+		}
+	}
+
 	/*
 	 * Ok, we got it in good shape.  Just locking left.
 	 */
@@ -674,8 +690,12 @@ retry:
 			/* The pagedaemon can't wait around; defer. */
 			defer = true;
 		} else if (curlwp == vrele_lwp) {
-			/* We have to try harder. */
-			vp->v_iflag &= ~VI_INACTREDO;
+			/*
+			 * We have to try harder. But we can't sleep
+			 * with VI_INACTNOW as vget() may be waiting on it.
+			 */
+			vp->v_iflag &= ~(VI_INACTREDO|VI_INACTNOW);
+			cv_broadcast(&vp->v_cv);
 			mutex_exit(vp->v_interlock);
 			error = vn_lock(vp, LK_EXCLUSIVE);
 			if (error != 0) {
@@ -683,6 +703,18 @@ retry:
 				vnpanic(vp, "%s: unable to lock %p",
 				    __func__, vp);
 			}
+			mutex_enter(vp->v_interlock);
+			/*
+			 * if we did get another reference while
+			 * sleeping, don't try to inactivate it yet.
+			 */
+			if (__predict_false(vtryrele(vp))) {
+				VOP_UNLOCK(vp);
+				mutex_exit(vp->v_interlock);
+				return;
+			}
+			vp->v_iflag |= VI_INACTNOW;
+			mutex_exit(vp->v_interlock);
 			defer = false;
 		} else if ((vp->v_iflag & VI_LAYER) != 0) {
 			/* 
@@ -718,6 +750,7 @@ retry:
 			if (++vrele_pending > (desiredvnodes >> 8))
 				cv_signal(&vrele_cv); 
 			mutex_exit(&vrele_lock);
+			cv_broadcast(&vp->v_cv);
 			mutex_exit(vp->v_interlock);
 			return;
 		}
@@ -735,6 +768,7 @@ retry:
 		VOP_INACTIVE(vp, &recycle);
 		mutex_enter(vp->v_interlock);
 		vp->v_iflag &= ~VI_INACTNOW;
+		cv_broadcast(&vp->v_cv);
 		if (!recycle) {
 			if (vtryrele(vp)) {
 				mutex_exit(vp->v_interlock);

Index: src/sys/kern/vfs_vnops.c
diff -u src/sys/kern/vfs_vnops.c:1.185 src/sys/kern/vfs_vnops.c:1.186
--- src/sys/kern/vfs_vnops.c:1.185	Fri Aug 24 05:52:17 2012
+++ src/sys/kern/vfs_vnops.c	Mon Nov 12 11:00:07 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnops.c,v 1.185 2012/08/24 05:52:17 dholland Exp $	*/
+/*	$NetBSD: vfs_vnops.c,v 1.186 2012/11/12 11:00:07 hannken Exp $	*/
 
 /*-
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.185 2012/08/24 05:52:17 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.186 2012/11/12 11:00:07 hannken Exp $");
 
 #include "veriexec.h"
 
@@ -807,15 +807,6 @@ vn_lock(struct vnode *vp, int flags)
 		} else {
 			mutex_exit(vp->v_interlock);
 			error = VOP_LOCK(vp, (flags & ~LK_RETRY));
-			if (error == 0 && (flags & LK_RETRY) == 0) {
-				mutex_enter(vp->v_interlock);
-				if ((vp->v_iflag & VI_CLEAN)) {
-					mutex_exit(vp->v_interlock);
-					VOP_UNLOCK(vp);
-					return ENOENT;
-				}
-				mutex_exit(vp->v_interlock);
-			}
 			if (error == 0 || error == EDEADLK || error == EBUSY)
 				return (error);
 		}

Reply via email to