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); }