Fix a deadlock cause by a lock ordering interaction between pmap_enter()
and pmap_growkernel().
This commit is contained in:
parent
d493d86cac
commit
18c5f91b0b
|
@ -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 @@ struct pmap_asn_info pmap_asn_info[ALPHA_MAXPROCS];
|
|||
* * 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 @@ pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
|
|||
* 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 @@ pmap_growkernel(vaddr_t maxkvaddr)
|
|||
*
|
||||
* 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 @@ pmap_lev1map_create(pmap_t pmap, long cpu_id)
|
|||
#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_lev1map_create(pmap_t pmap, long cpu_id)
|
|||
PMAP_ACTIVATE(pmap, curproc, cpu_id);
|
||||
}
|
||||
PMAP_LEV1MAP_SHOOTDOWN(pmap, cpu_id);
|
||||
return 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue