From 41b1f8207c32e613f4f60a6b4e70ff2fb877a32e Mon Sep 17 00:00:00 2001 From: alc Date: Mon, 8 Oct 2012 16:57:05 +0000 Subject: In a few places, like the implementation of ptrace(), a thread may call upon pmap_enter() to create a mapping within a different address space, i.e., not the thread's own address space. On i386, this entails the creation of a temporary mapping to the affected page table page (PTP). In general, pmap_enter() will read from this PTP, allocate a PV entry, and write to this PTP. The trouble comes when the system is short of memory. In order to allocate a new PV entry, an older PV entry has to be reclaimed. Reclaiming a PV entry involves destroying a mapping, which requires access to the affected PTP. Thus, the PTP mapped at the beginning of pmap_enter() is no longer mapped at the end of pmap_enter(), which leads to pmap_enter() modifying the wrong PTP. To address this problem, pmap_pv_reclaim() is changed to use an alternate method of mapping PTPs. Update a related comment. Reported by: pho Diagnosed by: kib MFC after: 5 days --- sys/i386/xen/pmap.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sys/i386/xen/pmap.c') diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c index 46cb43c..2eea8c6 100644 --- a/sys/i386/xen/pmap.c +++ b/sys/i386/xen/pmap.c @@ -429,7 +429,8 @@ pmap_bootstrap(vm_paddr_t firstaddr) SYSMAP(struct msgbuf *, unused, msgbufp, atop(round_page(msgbufsize))) /* - * ptemap is used for pmap_pte_quick + * PADDR1 and PADDR2 are used by pmap_pte_quick() and pmap_pte(), + * respectively. */ SYSMAP(pt_entry_t *, PMAP1, PADDR1, 1) SYSMAP(pt_entry_t *, PMAP2, PADDR2, 1) @@ -1976,7 +1977,6 @@ pmap_pv_reclaim(pmap_t locked_pmap) pmap = NULL; free = m_pc = NULL; TAILQ_INIT(&newtail); - sched_pin(); while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && (pv_vafree == 0 || free == NULL)) { TAILQ_REMOVE(&pv_chunks, pc, pc_lru); @@ -2007,10 +2007,13 @@ pmap_pv_reclaim(pmap_t locked_pmap) bit = bsfl(inuse); pv = &pc->pc_pventry[field * 32 + bit]; va = pv->pv_va; - pte = pmap_pte_quick(pmap, va); - if ((*pte & PG_W) != 0) + pte = pmap_pte(pmap, va); + tpte = *pte; + if ((tpte & PG_W) == 0) + tpte = pte_load_clear(pte); + pmap_pte_release(pte); + if ((tpte & PG_W) != 0) continue; - tpte = pte_load_clear(pte); if ((tpte & PG_G) != 0) pmap_invalidate_page(pmap, va); m = PHYS_TO_VM_PAGE(tpte & PG_FRAME); @@ -2062,7 +2065,6 @@ pmap_pv_reclaim(pmap_t locked_pmap) } } out: - sched_unpin(); TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru); if (pmap != NULL) { pmap_invalidate_all(pmap); -- cgit v1.1