diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-07-10 13:06:27 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-07-10 13:06:27 +0000 |
commit | dcad543730471729425b8fede9a5d282f259cb3c (patch) | |
tree | 6a1c57cbcf2180fb11c431d948f41811d4aa9317 /sys/arch | |
parent | 1504306b698b9c2a07b9632566c87f7e8c4e9e10 (diff) |
Committed from the wrong tree. So now for real:
Don't call pool_put(9) while holding a mutex. Instead collect pv entries in
a list and put them back into the pool after releasing the mutex. This
prevents a lock ordering problem between the per-pmap mutexes and the kernel
lock that arises because pool_put(9) may grab the kernel lock when it decides
to free a pool page.
This seems to make the i386 pmap mpsafe enough to run the reaper without
holding the kernel lock.
ok sthen@ (who helped me a lot debugging this)
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/i386/i386/pmapae.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/sys/arch/i386/i386/pmapae.c b/sys/arch/i386/i386/pmapae.c index cb98bd18d57..384143ab11c 100644 --- a/sys/arch/i386/i386/pmapae.c +++ b/sys/arch/i386/i386/pmapae.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmapae.c,v 1.39 2015/07/10 11:52:59 kettenis Exp $ */ +/* $OpenBSD: pmapae.c,v 1.40 2015/07/10 13:06:26 kettenis Exp $ */ /* * Copyright (c) 2006-2008 Michael Shalayeff @@ -462,7 +462,7 @@ pt_entry_t *pmap_map_ptes_pae(struct pmap *); void pmap_unmap_ptes_pae(struct pmap *); void pmap_do_remove_pae(struct pmap *, vaddr_t, vaddr_t, int); void pmap_remove_ptes_pae(struct pmap *, struct vm_page *, - vaddr_t, vaddr_t, vaddr_t, int); + vaddr_t, vaddr_t, vaddr_t, int, struct pv_entry **); void pmap_sync_flags_pte_pae(struct vm_page *, pt_entry_t); static __inline u_int @@ -962,7 +962,7 @@ pmap_copy_page_pae(struct vm_page *srcpg, struct vm_page *dstpg) void pmap_remove_ptes_pae(struct pmap *pmap, struct vm_page *ptp, vaddr_t ptpva, -vaddr_t startva, vaddr_t endva, int flags) + vaddr_t startva, vaddr_t endva, int flags, struct pv_entry **free_pvs) { struct pv_entry *pve; pt_entry_t *pte = (pt_entry_t *) ptpva; @@ -1023,8 +1023,10 @@ vaddr_t startva, vaddr_t endva, int flags) /* sync R/M bits */ pmap_sync_flags_pte_pae(pg, opte); pve = pmap_remove_pv(pg, pmap, startva); - if (pve) - pool_put(&pmap_pv_pool, pve); + if (pve) { + pve->pv_next = *free_pvs; + *free_pvs = pve; + } /* end of "for" loop: time for next pte */ } @@ -1043,6 +1045,8 @@ pmap_do_remove_pae(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags) paddr_t ptppa; vaddr_t blkendva; struct vm_page *ptp; + struct pv_entry *pve; + struct pv_entry *free_pvs = NULL; TAILQ_HEAD(, vm_page) empty_ptps; int shootall; vaddr_t va; @@ -1111,7 +1115,7 @@ pmap_do_remove_pae(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags) } pmap_remove_ptes_pae(pmap, ptp, (vaddr_t)&ptes[atop(va)], - va, blkendva, flags); + va, blkendva, flags, &free_pvs); /* If PTP is no longer being used, free it. */ if (ptp && ptp->wire_count <= 1) { @@ -1129,6 +1133,11 @@ pmap_do_remove_pae(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags) pmap_unmap_ptes_pae(pmap); pmap_tlb_shootwait(); + while ((pve = free_pvs) != NULL) { + free_pvs = pve->pv_next; + pmap_free_pv(pmap, pve); + } + while ((ptp = TAILQ_FIRST(&empty_ptps)) != NULL) { TAILQ_REMOVE(&empty_ptps, ptp, pageq); uvm_pagefree(ptp); @@ -1197,7 +1206,7 @@ pmap_page_remove_pae(struct vm_page *pg) pmap_unmap_ptes_pae(pve->pv_pmap); /* unlocks pmap */ pmap_destroy(pve->pv_pmap); - pool_put(&pmap_pv_pool, pve); + pmap_free_pv(NULL, pve); mtx_enter(&pg->mdpage.pv_mtx); } mtx_leave(&pg->mdpage.pv_mtx); @@ -1496,7 +1505,7 @@ pmap_enter_pae(struct pmap *pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, #endif if (pmap_initialized) - pve = pool_get(&pmap_pv_pool, PR_NOWAIT); + pve = pmap_alloc_pv(pmap, ALLOCPV_NEED); else pve = NULL; wired_count = resident_count = ptp_count = 0; @@ -1674,9 +1683,9 @@ enter_now: out: if (pve) - pool_put(&pmap_pv_pool, pve); + pmap_free_pv(pmap, pve); if (opve) - pool_put(&pmap_pv_pool, opve); + pmap_free_pv(pmap, opve); return error; } |