diff options
author | alc <alc@FreeBSD.org> | 2012-10-08 16:57:05 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2012-10-08 16:57:05 +0000 |
commit | 41b1f8207c32e613f4f60a6b4e70ff2fb877a32e (patch) | |
tree | c9d5fbd978bf6d11a9da39e1dcf430dca7c9ea8e /sys/i386 | |
parent | ea2e90dbb4d21d52967a0d5a48c7c68205b80759 (diff) | |
download | FreeBSD-src-41b1f8207c32e613f4f60a6b4e70ff2fb877a32e.zip FreeBSD-src-41b1f8207c32e613f4f60a6b4e70ff2fb877a32e.tar.gz |
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
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/pmap.c | 14 | ||||
-rw-r--r-- | sys/i386/xen/pmap.c | 14 |
2 files changed, 16 insertions, 12 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index bea4102..bbd583a 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -475,7 +475,8 @@ pmap_bootstrap(vm_paddr_t firstaddr) KPTmap -= i386_btop(KPTDI << PDRSHIFT); /* - * 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) @@ -2228,7 +2229,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); @@ -2262,10 +2262,13 @@ pmap_pv_reclaim(pmap_t locked_pmap) pde = pmap_pde(pmap, va); if ((*pde & PG_PS) != 0) continue; - 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); @@ -2323,7 +2326,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); 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); |