diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/pmap.c | 31 |
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); |