powerpc/mm: Check for matching hpte without taking hpte lock
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 3 Nov 2014 14:51:34 +0000 (20:21 +0530)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 2 Dec 2014 00:03:45 +0000 (11:03 +1100)
With smaller hash page table config, we would end up in situation
where we would be replacing hash page table slot frequently. In
such config, we will find the hpte to be not matching, and we
can do that check without holding the hpte lock. We need to
recheck the hpte again after holding lock.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/mm/hash_native_64.c

index d53288a08c371a186fa4e90ba1726315e8fd0bc2..558e50bac6f716158646b55d8aaa9b4db726dd0f 100644 (file)
@@ -294,8 +294,6 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
        DBG_LOW("    update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)",
                vpn, want_v & HPTE_V_AVPN, slot, newpp);
 
-       native_lock_hpte(hptep);
-
        hpte_v = be64_to_cpu(hptep->v);
        /*
         * We need to invalidate the TLB always because hpte_remove doesn't do
@@ -308,16 +306,24 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
                DBG_LOW(" -> miss\n");
                ret = -1;
        } else {
-               DBG_LOW(" -> hit\n");
-               /* Update the HPTE */
-               hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) & ~(HPTE_R_PP | HPTE_R_N)) |
-                       (newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C)));
+               native_lock_hpte(hptep);
+               /* recheck with locks held */
+               hpte_v = be64_to_cpu(hptep->v);
+               if (unlikely(!HPTE_V_COMPARE(hpte_v, want_v) ||
+                            !(hpte_v & HPTE_V_VALID))) {
+                       ret = -1;
+               } else {
+                       DBG_LOW(" -> hit\n");
+                       /* Update the HPTE */
+                       hptep->r = cpu_to_be64((be64_to_cpu(hptep->r) &
+                                               ~(HPTE_R_PP | HPTE_R_N)) |
+                                              (newpp & (HPTE_R_PP | HPTE_R_N |
+                                                        HPTE_R_C)));
+               }
+               native_unlock_hpte(hptep);
        }
-       native_unlock_hpte(hptep);
-
        /* Ensure it is out of the tlb too. */
        tlbie(vpn, bpsize, apsize, ssize, local);
-
        return ret;
 }