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