summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/amd64/amd64/pmap.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
index bd99dff76c5..73cd3545ad1 100644
--- a/sys/arch/amd64/amd64/pmap.c
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.94 2015/07/10 10:08:49 kettenis Exp $ */
+/* $OpenBSD: pmap.c,v 1.95 2015/09/03 18:47:36 kettenis Exp $ */
/* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */
/*
@@ -1564,6 +1564,7 @@ void
pmap_page_remove(struct vm_page *pg)
{
struct pv_entry *pve;
+ struct pmap *pm;
pt_entry_t *ptes, opte;
pd_entry_t **pdes;
#ifdef DIAGNOSTIC
@@ -1578,14 +1579,36 @@ pmap_page_remove(struct vm_page *pg)
mtx_enter(&pg->mdpage.pv_mtx);
while ((pve = pg->mdpage.pv_list) != NULL) {
- pg->mdpage.pv_list = pve->pv_next;
pmap_reference(pve->pv_pmap);
+ pm = pve->pv_pmap;
mtx_leave(&pg->mdpage.pv_mtx);
/* XXX use direct map? */
- pmap_map_ptes(pve->pv_pmap, &ptes, &pdes, &scr3);
+ pmap_map_ptes(pm, &ptes, &pdes, &scr3); /* locks pmap */
shootself = (scr3 == 0);
+ /*
+ * We dropped the pvlist lock before grabbing the pmap
+ * lock to avoid lock ordering problems. This means
+ * we have to check the pvlist again since somebody
+ * else might have modified it. All we care about is
+ * that the pvlist entry matches the pmap we just
+ * locked. If it doesn't, unlock the pmap and try
+ * again.
+ */
+ mtx_enter(&pg->mdpage.pv_mtx);
+ if ((pve = pg->mdpage.pv_list) == NULL ||
+ pve->pv_pmap != pm) {
+ mtx_leave(&pg->mdpage.pv_mtx);
+ pmap_unmap_ptes(pm, scr3); /* unlocks pmap */
+ pmap_destroy(pm);
+ mtx_enter(&pg->mdpage.pv_mtx);
+ continue;
+ }
+
+ pg->mdpage.pv_list = pve->pv_next;
+ mtx_leave(&pg->mdpage.pv_mtx);
+
#ifdef DIAGNOSTIC
if (pve->pv_ptp && pmap_pdes_valid(pve->pv_va, pdes, &pde) &&
(pde & PG_FRAME) != VM_PAGE_TO_PHYS(pve->pv_ptp)) {
@@ -1619,7 +1642,7 @@ pmap_page_remove(struct vm_page *pg)
pve->pv_va, ptes, pdes, &empty_ptps);
}
}
- pmap_unmap_ptes(pve->pv_pmap, scr3);
+ pmap_unmap_ptes(pve->pv_pmap, scr3); /* unlocks pmap */
pmap_destroy(pve->pv_pmap);
pool_put(&pmap_pv_pool, pve);
mtx_enter(&pg->mdpage.pv_mtx);