svn commit: r241353 - in head/sys/i386: i386 xen
Alan Cox
alc at FreeBSD.org
Mon Oct 8 16:57:06 UTC 2012
Author: alc
Date: Mon Oct 8 16:57:05 2012
New Revision: 241353
URL: http://svn.freebsd.org/changeset/base/241353
Log:
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
Modified:
head/sys/i386/i386/pmap.c
head/sys/i386/xen/pmap.c
Modified: head/sys/i386/i386/pmap.c
==============================================================================
--- head/sys/i386/i386/pmap.c Mon Oct 8 16:00:33 2012 (r241352)
+++ head/sys/i386/i386/pmap.c Mon Oct 8 16:57:05 2012 (r241353)
@@ -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);
Modified: head/sys/i386/xen/pmap.c
==============================================================================
--- head/sys/i386/xen/pmap.c Mon Oct 8 16:00:33 2012 (r241352)
+++ head/sys/i386/xen/pmap.c Mon Oct 8 16:57:05 2012 (r241353)
@@ -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);
More information about the svn-src-all
mailing list