Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/alpha/alpha Fix a deadlock cause by a lock ordering...



details:   https://anonhg.NetBSD.org/src/rev/5cf2cd0d3c0d
branches:  trunk
changeset: 509474:5cf2cd0d3c0d
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sat May 05 18:22:04 2001 +0000

description:
Fix a deadlock cause by a lock ordering interaction between pmap_enter()
and pmap_growkernel().

diffstat:

 sys/arch/alpha/alpha/pmap.c |  59 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 46 insertions(+), 13 deletions(-)

diffs (117 lines):

diff -r df1c044a7685 -r 5cf2cd0d3c0d sys/arch/alpha/alpha/pmap.c
--- a/sys/arch/alpha/alpha/pmap.c       Sat May 05 17:56:58 2001 +0000
+++ b/sys/arch/alpha/alpha/pmap.c       Sat May 05 18:22:04 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.178 2001/05/01 05:53:29 ross Exp $ */
+/* $NetBSD: pmap.c,v 1.179 2001/05/05 18:22:04 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -154,7 +154,7 @@
 
 #include <sys/cdefs.h>                 /* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.178 2001/05/01 05:53:29 ross Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.179 2001/05/05 18:22:04 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -372,6 +372,18 @@
  *     * pmap_growkernel_slock - This lock protects pmap_growkernel()
  *       and the virtual_end variable.
  *
+ *       There is a lock ordering constraint for pmap_growkernel_slock.
+ *       pmap_growkernel() acquires the locks in the following order:
+ *
+ *             pmap_growkernel_slock -> pmap_all_pmaps_slock ->
+ *                 pmap->pm_slock
+ *
+ *       But pmap_lev1map_create() is called with pmap->pm_slock held,
+ *       and also needs to acquire the pmap_growkernel_slock.  So,
+ *       we require that the caller of pmap_lev1map_create() (currently,
+ *       the only caller is pmap_enter()) acquire pmap_growkernel_slock
+ *       before acquring pmap->pm_slock.
+ *
  *     Address space number management (global ASN counters and per-pmap
  *     ASN state) are not locked; they use arrays of values indexed
  *     per-processor.
@@ -1679,7 +1691,23 @@
                 * created.
                 */
                if (pmap->pm_lev1map == kernel_lev1map) {
+                       /*
+                        * XXX Yuck.
+                        * We have to unlock the pmap, lock the
+                        * pmap_growkernel_slock, and re-lock the
+                        * pmap here, in order to avoid a deadlock
+                        * with pmap_growkernel().
+                        *
+                        * Because we unlock, we have a window for
+                        * someone else to add a mapping, thus creating
+                        * a level 1 map; pmap_lev1map_create() checks
+                        * for this condition.
+                        */
+                       PMAP_UNLOCK(pmap);
+                       simple_lock(&pmap_growkernel_slock);
+                       PMAP_LOCK(pmap);
                        error = pmap_lev1map_create(pmap, cpu_id);
+                       simple_unlock(&pmap_growkernel_slock);
                        if (error) {
                                if (flags & PMAP_CANFAIL)
                                        goto out;
@@ -3231,7 +3259,7 @@
  *
  *     Create a new level 1 page table for the specified pmap.
  *
- *     Note: the pmap must already be locked.
+ *     Note: growkernel and the pmap must already be locked.
  */
 int
 pmap_lev1map_create(pmap_t pmap, long cpu_id)
@@ -3241,23 +3269,28 @@
 #ifdef DIAGNOSTIC
        if (pmap == pmap_kernel())
                panic("pmap_lev1map_create: got kernel pmap");
-
+#endif
+
+       if (pmap->pm_lev1map != kernel_lev1map) {
+               /*
+                * We have to briefly unlock the pmap in pmap_enter()
+                * do deal with a lock ordering constraint, so it's
+                * entirely possible for this to happen.
+                */
+               return (0);
+       }
+
+#ifdef DIAGNOSTIC
        if (pmap->pm_asni[cpu_id].pma_asn != PMAP_ASN_RESERVED)
                panic("pmap_lev1map_create: pmap uses non-reserved ASN");
 #endif
 
-       simple_lock(&pmap_growkernel_slock);
-
        l1pt = pool_cache_get(&pmap_l1pt_cache, PR_NOWAIT);
-       if (l1pt == NULL) {
-               simple_unlock(&pmap_growkernel_slock);
-               return ENOMEM;
-       }
+       if (l1pt == NULL)
+               return (ENOMEM);
 
        pmap->pm_lev1map = l1pt;
 
-       simple_unlock(&pmap_growkernel_slock);
-
        /*
         * The page table base has changed; if the pmap was active,
         * reactivate it.
@@ -3267,7 +3300,7 @@
                PMAP_ACTIVATE(pmap, curproc, cpu_id);
        }
        PMAP_LEV1MAP_SHOOTDOWN(pmap, cpu_id);
-       return 0;
+       return (0);
 }
 
 /*



Home | Main Index | Thread Index | Old Index