Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Previous did cause a deadlock with layered FS: the ...



details:   https://anonhg.NetBSD.org/src/rev/a33241014692
branches:  trunk
changeset: 749378:a33241014692
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Sat Nov 28 10:10:17 2009 +0000

description:
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.

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.

diffstat:

 sys/kern/vfs_subr.c |  24 ++++++++++++++++++++----
 1 files changed, 20 insertions(+), 4 deletions(-)

diffs (51 lines):

diff -r d2aa9d25b463 -r a33241014692 sys/kern/vfs_subr.c
--- a/sys/kern/vfs_subr.c       Sat Nov 28 10:00:24 2009 +0000
+++ b/sys/kern/vfs_subr.c       Sat Nov 28 10:10:17 2009 +0000
@@ -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 <sys/cdefs.h>
-__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 @@
                        /* 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) {
                        /* 



Home | Main Index | Thread Index | Old Index