[PATCH] ppc64: Fix huge pages MMU mapping bug

Benjamin Herrenschmidt benh at kernel.crashing.org
Fri Sep 23 16:25:26 EST 2005


Current kernel has a couple of sneaky bugs in the ppc64 hugetlb code
that cause huge pages to be potentially left stale in the hash table and
TLBs (improperly invalidated), with all the nasty consequences that can
have. One is that we forgot to set the "secondary" bit in the hash PTEs
when hashing a huge page in the secondary bucket (fortunately very
rare). The other one is on non-LPAR machines (like Apple G5s),
flush_hash_range() which is used to flush a batch of PTEs simply did not
work for huge pages. Historically, our huge page code didn't batch, but
this was changed without fixing this routine. This patch fixes both.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>

Index: linux-work/arch/ppc64/mm/hugetlbpage.c
===================================================================
--- linux-work.orig/arch/ppc64/mm/hugetlbpage.c	2005-09-23 14:08:34.000000000 +1000
+++ linux-work/arch/ppc64/mm/hugetlbpage.c	2005-09-23 16:11:44.000000000 +1000
@@ -710,10 +710,13 @@
 			hpte_group = ((~hash & htab_hash_mask) *
 				      HPTES_PER_GROUP) & ~0x7UL; 
 			slot = ppc_md.hpte_insert(hpte_group, va, prpn,
-						  HPTE_V_LARGE, rflags);
+						  HPTE_V_LARGE |
+						  HPTE_V_SECONDARY,
+						  rflags);
 			if (slot == -1) {
 				if (mftb() & 0x1)
-					hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+					hpte_group = ((hash & htab_hash_mask) *
+						      HPTES_PER_GROUP)&~0x7UL;
 
 				ppc_md.hpte_remove(hpte_group);
 				goto repeat;
Index: linux-work/arch/ppc64/mm/hash_native.c
===================================================================
--- linux-work.orig/arch/ppc64/mm/hash_native.c	2005-09-23 12:43:22.000000000 +1000
+++ linux-work/arch/ppc64/mm/hash_native.c	2005-09-23 16:13:31.000000000 +1000
@@ -343,9 +343,7 @@
 	hpte_t *hptep;
 	unsigned long hpte_v;
 	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
-
-	/* XXX fix for large ptes */
-	unsigned long large = 0;
+	unsigned long large;
 
 	local_irq_save(flags);
 
@@ -358,6 +356,7 @@
 
 		va = (vsid << 28) | (batch->addr[i] & 0x0fffffff);
 		batch->vaddr[j] = va;
+		large = pte_huge(batch->pte[i]);
 		if (large)
 			vpn = va >> HPAGE_SHIFT;
 		else






More information about the Linuxppc64-dev mailing list