From 8c392da154e356fc8e8ef197e2644deee19a0711 Mon Sep 17 00:00:00 2001 From: bouyer Date: Sat, 28 Nov 2009 10:10:17 +0000 Subject: [PATCH] Previous did cause a deadlock with layered FS: the vrele thread can sleep on the vnode lock, while vget is sleeping on the VI_INACTNOW flag (or the vget caller is looping on vget returning failure because of the VI_INACTNOW flag). With layered FSes, the upper and lower vnodes share the same lock, so the vget() caller above can be already holding the vnode lock. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix by dropping VI_INACTNOW before sleeping on the vnode lock in vrelel(), and check the ref count again once we have the lock. If the vnode has more than one reference, donc VOP_INACTIVE it. Fix PR kern/42318 and PR kern/42377 patch tested by Hisashi T Fujinaka, Joachim König, Stephen Borrill and Matthias Scheler. --- sys/kern/vfs_subr.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index af173b479ca6..a8013e054407 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_subr.c,v 1.391 2009/11/27 16:43:51 pooka Exp $ */ +/* $NetBSD: vfs_subr.c,v 1.392 2009/11/28 10:10:17 bouyer Exp $ */ /*- * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc. @@ -91,7 +91,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.391 2009/11/27 16:43:51 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.392 2009/11/28 10:10:17 bouyer Exp $"); #include "opt_ddb.h" #include "opt_compat_netbsd.h" @@ -1429,14 +1429,30 @@ vrelel(vnode_t *vp, int flags) /* 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); error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY); if (error != 0) { /* XXX */ vpanic(vp, "vrele: unable to lock %p"); } + 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, 0); + 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) { /*