diff mbox

powerpc/mm: Always invalidate tlb on hpte invalidate and update

Message ID 1369998204-31490-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com (mailing list archive)
State Accepted, archived
Commit 0608d692463598c1d6e826d9dd7283381b4f246c
Headers show

Commit Message

Aneesh Kumar K.V May 31, 2013, 11:03 a.m. UTC
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>

If a hash bucket gets full, we "evict" a more/less random entry from it.
When we do that we don't invalidate the TLB (hpte_remove) because we assume
the old translation is still technically "valid". This implies that when
we are invalidating or updating pte, even if HPTE entry is not valid
we should do a tlb invalidate.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 arch/powerpc/mm/hash_native_64.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

Comments

Michael Ellerman June 1, 2013, 11:19 a.m. UTC | #1
On Fri, May 31, 2013 at 04:33:24PM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> If a hash bucket gets full, we "evict" a more/less random entry from it.
> When we do that we don't invalidate the TLB (hpte_remove) because we assume
> the old translation is still technically "valid". This implies that when
> we are invalidating or updating pte, even if HPTE entry is not valid
> we should do a tlb invalidate.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

Has this always been a bug? I assume not.

I'm asking because I have a kernel that's crashing and I'm wondering if
I might need this commit.

cheers
Benjamin Herrenschmidt June 1, 2013, 11:44 a.m. UTC | #2
On Sat, 2013-06-01 at 21:19 +1000, Michael Ellerman wrote:
> On Fri, May 31, 2013 at 04:33:24PM +0530, Aneesh Kumar K.V wrote:
> > From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> > 
> > If a hash bucket gets full, we "evict" a more/less random entry from it.
> > When we do that we don't invalidate the TLB (hpte_remove) because we assume
> > the old translation is still technically "valid". This implies that when
> > we are invalidating or updating pte, even if HPTE entry is not valid
> > we should do a tlb invalidate.
> > 
> > Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> 
> Has this always been a bug? I assume not.
> 
> I'm asking because I have a kernel that's crashing and I'm wondering if
> I might need this commit.

Bug got introduced in either 
b1022fbd293564de91596b8775340cf41ad5214c or
7e74c3921ad9610c0b49f28b8fc69f7480505841, the jury is still out on
that one :-)

It's unlikely to crash the kernel however (it *can*, it's just unlikely).

Patch is good to have regardless...

Cheers,
Ben.
Aneesh Kumar K.V June 2, 2013, 7:26 a.m. UTC | #3
Michael Ellerman <michael@ellerman.id.au> writes:

> On Fri, May 31, 2013 at 04:33:24PM +0530, Aneesh Kumar K.V wrote:
>> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>> 
>> If a hash bucket gets full, we "evict" a more/less random entry from it.
>> When we do that we don't invalidate the TLB (hpte_remove) because we assume
>> the old translation is still technically "valid". This implies that when
>> we are invalidating or updating pte, even if HPTE entry is not valid
>> we should do a tlb invalidate.
>> 
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>
> Has this always been a bug? I assume not.
>
> I'm asking because I have a kernel that's crashing and I'm wondering if
> I might need this commit.

Which config are you seeing the issue ? The changes should not impact
lpar. Can you share more info on crashes. There is a high chance that any crashes
that we are seeing in ppc64 can be the result of THP related changes,
because that did touch some subtle areas like tlb flushing,page table format etc.

-aneesh
diff mbox

Patch

diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 6a2aead..4c122c3 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -336,11 +336,18 @@  static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
 
 	hpte_v = hptep->v;
 	actual_psize = hpte_actual_psize(hptep, psize);
+	/*
+	 * We need to invalidate the TLB always because hpte_remove doesn't do
+	 * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
+	 * random entry from it. When we do that we don't invalidate the TLB
+	 * (hpte_remove) because we assume the old translation is still
+	 * technically "valid".
+	 */
 	if (actual_psize < 0) {
-		native_unlock_hpte(hptep);
-		return -1;
+		actual_psize = psize;
+		ret = -1;
+		goto err_out;
 	}
-	/* Even if we miss, we need to invalidate the TLB */
 	if (!HPTE_V_COMPARE(hpte_v, want_v)) {
 		DBG_LOW(" -> miss\n");
 		ret = -1;
@@ -350,6 +357,7 @@  static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
 		hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
 			(newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
 	}
+err_out:
 	native_unlock_hpte(hptep);
 
 	/* Ensure it is out of the tlb too. */
@@ -409,7 +417,7 @@  static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
 	hptep = htab_address + slot;
 	actual_psize = hpte_actual_psize(hptep, psize);
 	if (actual_psize < 0)
-		return;
+		actual_psize = psize;
 
 	/* Update the HPTE */
 	hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
@@ -437,21 +445,27 @@  static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
 	hpte_v = hptep->v;
 
 	actual_psize = hpte_actual_psize(hptep, psize);
+	/*
+	 * We need to invalidate the TLB always because hpte_remove doesn't do
+	 * a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
+	 * random entry from it. When we do that we don't invalidate the TLB
+	 * (hpte_remove) because we assume the old translation is still
+	 * technically "valid".
+	 */
 	if (actual_psize < 0) {
+		actual_psize = psize;
 		native_unlock_hpte(hptep);
-		local_irq_restore(flags);
-		return;
+		goto err_out;
 	}
-	/* Even if we miss, we need to invalidate the TLB */
 	if (!HPTE_V_COMPARE(hpte_v, want_v))
 		native_unlock_hpte(hptep);
 	else
 		/* Invalidate the hpte. NOTE: this also unlocks it */
 		hptep->v = 0;
 
+err_out:
 	/* Invalidate the TLB */
 	tlbie(vpn, psize, actual_psize, ssize, local);
-
 	local_irq_restore(flags);
 }