PERFORCE change 95000 for review
Alan Cox
alc at FreeBSD.org
Tue Apr 11 17:23:39 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=95000
Change 95000 by alc at alc_home on 2006/04/11 17:23:10
IF user/alc/superpages
Catch up with the change to pmap_remove_pages()'s parameters.
Clean up code.
Avoid kernel pmap page table page leaks on promotion of kernel pages.
Affected files ...
.. //depot/projects/superpages/src/sys/amd64/amd64/pmap.c#15 integrate
Differences ...
==== //depot/projects/superpages/src/sys/amd64/amd64/pmap.c#15 (text+ko) ====
@@ -208,6 +208,8 @@
static pv_entry_t get_pv_entry(pmap_t locked_pmap);
static void pmap_clear_ptes(vm_page_t m, long bit);
+static boolean_t pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va);
+static void pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, reservation_t reserv);
static boolean_t pmap_protect_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t sva);
static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva);
static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq,
@@ -227,9 +229,6 @@
static int pmap_unuse_pt(pmap_t, vm_offset_t, pd_entry_t);
static vm_offset_t pmap_kmem_choose(vm_offset_t addr);
-static void mach_promote(pmap_t pmap, pd_entry_t *pde, reservation_t reserv);
-static boolean_t pmap_demote(pmap_t pmap, pd_entry_t *pde, vm_offset_t va);
-
CTASSERT(1 << PDESHIFT == sizeof(pd_entry_t));
CTASSERT(1 << PTESHIFT == sizeof(pt_entry_t));
@@ -1291,7 +1290,7 @@
* normal 4K page.
*/
if (pd != 0 && (*pd & (PG_PS | PG_V)) == (PG_PS | PG_V)) {
- if (!pmap_demote(pmap, pd, va)) {
+ if (!pmap_demote_pde(pmap, pd, va)) {
/*
* Invalidation of the 2MB page mapping may have caused
* the deallocation of the underlying PD page.
@@ -1500,7 +1499,7 @@
pmap->pm_stats.resident_count--;
pde = pmap_pde(pmap, va);
if ((*pde & PG_PS) != 0 &&
- !pmap_demote(pmap, pde, va)) {
+ !pmap_demote_pde(pmap, pde, va)) {
/*
* All mappings within the same 2mpage were
* destroyed and pv was freed.
@@ -1796,13 +1795,19 @@
if (sva + NBPDR == va_next && eva >= va_next) {
DPRINTF(("pmap_remove: superpage at %lx to destroy.\n",
sva));
+
+ /*
+ * The TLB entry for a PG_G mapping is
+ * invalidated by pmap_remove_pde().
+ */
+ if ((ptpaddr & PG_G) == 0)
+ anyvalid = 1;
pmap_remove_pde(pmap, pde, sva);
- anyvalid = 1;
continue;
} else {
DPRINTF(("pmap_remove: superpage at %lx to demote !!!\n",
sva));
- if (!pmap_demote(pmap, pde, sva)) {
+ if (!pmap_demote_pde(pmap, pde, sva)) {
anyvalid = 1; /* XXX */
continue;
}
@@ -1878,7 +1883,7 @@
pde = pmap_pde(pmap, pv->pv_va);
if (*pde & PG_PS) {
DPRINTF(("pmap_remove_all: superpage to demote !!!\n"));
- if (!pmap_demote(pmap, pde, pv->pv_va)) {
+ if (!pmap_demote_pde(pmap, pde, pv->pv_va)) {
/*
* All mappings within the same 2mpage were
* destroyed and pv was freed.
@@ -2017,7 +2022,7 @@
anychanged = 1;
continue;
} else {
- if (!pmap_demote(pmap, pde, sva)) {
+ if (!pmap_demote_pde(pmap, pde, sva)) {
anychanged = 1; /* XXX */
continue;
}
@@ -2262,7 +2267,7 @@
m->reserv->refcnt == NBPDR / PAGE_SIZE) {
DPRINTF(("%s: pmap %p va %lx XXX\n", __func__, pmap, va));
KASSERT(m->object->flags & OBJ_SUPERPAGES, ("pmap_enter: xxx"));
- mach_promote(pmap, pmap_pde(pmap, va), m->reserv);
+ pmap_promote_pde(pmap, pmap_pde(pmap, va), m->reserv);
}
vm_page_unlock_queues();
@@ -2392,7 +2397,7 @@
DPRINTF(("%s: pmap %p va %lx XXX\n", __func__, pmap, va));
KASSERT(m->object->flags & OBJ_SUPERPAGES,
("pmap_enter_quick: xxx"));
- mach_promote(pmap, pmap_pde(pmap, va), m->reserv);
+ pmap_promote_pde(pmap, pmap_pde(pmap, va), m->reserv);
}
out:
PMAP_UNLOCK(pmap);
@@ -2799,24 +2804,11 @@
npv = TAILQ_NEXT(pv, pv_plist);
continue;
}
- if (sva <= trunc_2mpage(pv->pv_va) &&
- eva >= round_2mpage(pv->pv_va + 1)) {
- DPRINTF(("pmap_remove_pages: superpage at %lx to destroy.\n",
- trunc_2mpage(pv->pv_va)));
- pmap_remove_pde(pmap, pde, trunc_2mpage(pv->pv_va));
- npv = TAILQ_FIRST(&pmap->pm_pvlist);
- continue;
- }
- DPRINTF(("pmap_remove_pages: superpage at %lx to demote !!!\n",
- pv->pv_va));
- if (!pmap_demote(pmap, pde, pv->pv_va)) {
- /*
- * All mappings within the same 2mpage were
- * destroyed and pv was freed.
- */
- npv = TAILQ_FIRST(&pmap->pm_pvlist);
- continue;
- }
+ DPRINTF(("pmap_remove_pages: superpage at %lx to destroy.\n",
+ trunc_2mpage(pv->pv_va)));
+ pmap_remove_pde(pmap, pde, trunc_2mpage(pv->pv_va));
+ npv = TAILQ_FIRST(&pmap->pm_pvlist);
+ continue;
}
#ifdef PMAP_REMOVE_PAGES_CURPROC_ONLY
@@ -2970,7 +2962,7 @@
if (*pde & PG_PS) {
DPRINTF(("pmap_clear_ptes: superpage to demote !!!\n"));
if ((*pde & bit) == 0 ||
- !pmap_demote(pmap, pde, pv->pv_va)) {
+ !pmap_demote_pde(pmap, pde, pv->pv_va)) {
/*
* All mappings within the same 2mpage were
* destroyed and pv was freed.
@@ -3267,7 +3259,7 @@
#define COMPATIBLE_PTE(a,b) ((a & COMPATIBLE_PTE_MASK) == (b & COMPATIBLE_PTE_MASK))
static void
-mach_promote(pmap_t pmap, pd_entry_t *pde, reservation_t reserv)
+pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, reservation_t reserv)
{
vm_paddr_t pa;
pt_entry_t *pte, *first_pte, flags;
@@ -3287,8 +3279,9 @@
pa += PAGE_SIZE;
page_pa = PHYS_TO_VM_PAGE(*pte & PG_FRAME);
- KASSERT(page_pa->reserv,("mach_promote: page has no reservation"));
- KASSERT(page_pa->reserv == reserv,("mach_promote: reservation mismatch"));
+ KASSERT(page_pa->reserv,("pmap_promote_pde: page has no reservation"));
+ KASSERT(page_pa->reserv == reserv,
+ ("pmap_promote_pde: reservation mismatch"));
if ((*pte & PG_V) == 0 || !COMPATIBLE_PTE(*pte, flags))
return;
@@ -3306,15 +3299,10 @@
/* Invalidate old TLB entries */
pmap_invalidate_all(pmap);
- /*
- * XXX
- *
- * File system corruption occurs if pte pages belonging to the
- * kernel pmap are freed.
- */
- if (pmap != kernel_pmap) {
+ /* This leaks up to nkpt kernel pmap page table pages. XXX */
+ if (pmap != kernel_pmap || tofree->wire_count == NPTEPG) {
KASSERT(tofree->wire_count == NPTEPG,
- ("pmap_promote: pte page wire count error"));
+ ("pmap_promote_pde: pte page wire count error"));
tofree->wire_count = 0;
vm_page_free(tofree);
atomic_subtract_int(&cnt.v_wire_count, 1);
@@ -3324,35 +3312,35 @@
}
static boolean_t
-pmap_demote(pmap_t pmap, pd_entry_t *pde0, vm_offset_t va)
+pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
{
pd_entry_t save_pde_value, new_pte_value ;
pt_entry_t *pte_page_va, *new_pte_va;
vm_paddr_t pte_page_pa;
vm_page_t pte_page;
- KASSERT((*pde0 & PG_PS) != 0,
- ("pmap_demote: not a superpage, impossible to demote"));
+ KASSERT((*pde & PG_PS) != 0,
+ ("pmap_demote_pde: not a superpage, impossible to demote"));
/* STEP 1
* Allocate the PTE page
*/
if ((pte_page = vm_page_alloc(NULL, pmap_pde_pindex(va),
VM_ALLOC_NOOBJ | VM_ALLOC_NORMAL | VM_ALLOC_WIRED)) == NULL) {
- pmap_remove_pde(pmap, pde0, trunc_2mpage(va));
+ pmap_remove_pde(pmap, pde, trunc_2mpage(va));
pmap_invalidate_all(pmap);
return (FALSE);
}
pte_page->wire_count += NPTEPG - 1;
KASSERT(pte_page->wire_count == NPTEPG,
- ("pmap_demote: page table page %p has wire count %d",
+ ("pmap_demote_pde: page table page %p has wire count %d",
pte_page, pte_page->wire_count));
if (pmap != kernel_pmap)
pmap->pm_stats.resident_count++;
pte_page_pa = VM_PAGE_TO_PHYS(pte_page);
pte_page_va = (vm_offset_t *) PHYS_TO_DMAP(pte_page_pa);
- pte_page_pa |= PG_U | PG_RW | PG_V | PG_A | PG_M;
+ pte_page_pa |= PG_M | PG_A | (*pde & PG_U) | PG_RW | PG_V;
repeat:
@@ -3360,7 +3348,7 @@
* Save the value of the pde entry
* Define the value of the first pte entry
*/
- save_pde_value = *pde0;
+ save_pde_value = *pde;
/* STEP 3
* Fill the PTE page with the physical address of the base pages
@@ -3378,7 +3366,7 @@
* If not, assign the new pde value.
* If yes, repeat the pte assignment loop.
*/
- if (!atomic_cmpset_long(pde0, save_pde_value, pte_page_pa))
+ if (!atomic_cmpset_long(pde, save_pde_value, pte_page_pa))
goto repeat;
/*
More information about the p4-projects
mailing list