powerpc/mm: Handle removing maybe-present bolted HPTEs
authorDavid Gibson <david@gibson.dropbear.id.au>
Tue, 9 Feb 2016 03:32:41 +0000 (13:32 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 1 Mar 2016 11:04:18 +0000 (22:04 +1100)
At the moment the hpte_removebolted callback in ppc_md returns void and
will BUG_ON() if the hpte it's asked to remove doesn't exist in the first
place.  This is awkward for the case of cleaning up a mapping which was
partially made before failing.

So, we add a return value to hpte_removebolted, and have it return ENOENT
in the case that the HPTE to remove didn't exist in the first place.

In the (sole) caller, we propagate errors in hpte_removebolted to its
caller to handle.  However, we handle ENOENT specially, continuing to
complete the unmapping over the specified range before returning the error
to the caller.

This means that htab_remove_mapping() will work sanely on a partially
present mapping, removing any HPTEs which are present, while also returning
ENOENT to its caller in case it's important there.

There are two callers of htab_remove_mapping():
   - In remove_section_mapping() we already WARN_ON() any error return,
     which is reasonable - in this case the mapping should be fully
     present
   - In vmemmap_remove_mapping() we BUG_ON() any error.  We change that to
     just a WARN_ON() in the case of ENOENT, since failing to remove a
     mapping that wasn't there in the first place probably shouldn't be
     fatal.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/machdep.h
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/init_64.c
arch/powerpc/platforms/pseries/lpar.c

index 5c38e49ddd42bcea8cf68b7784019125331296c5..fd22442d30a9732eae0489c4e062cfe41628884c 100644 (file)
@@ -54,7 +54,7 @@ struct machdep_calls {
                                       int psize, int apsize,
                                       int ssize);
        long            (*hpte_remove)(unsigned long hpte_group);
-       void            (*hpte_removebolted)(unsigned long ea,
+       int             (*hpte_removebolted)(unsigned long ea,
                                             int psize, int ssize);
        void            (*flush_hash_range)(unsigned long number, int local);
        void            (*hugepage_invalidate)(unsigned long vsid,
index 70490c41e14e28f7441a3426c17f3b9237769dcd..44f145a66578fdeec8cf80505695a2e74f7362b2 100644 (file)
@@ -269,6 +269,8 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend,
 {
        unsigned long vaddr;
        unsigned int step, shift;
+       int rc;
+       int ret = 0;
 
        shift = mmu_psize_defs[psize].shift;
        step = 1 << shift;
@@ -276,10 +278,17 @@ int htab_remove_mapping(unsigned long vstart, unsigned long vend,
        if (!ppc_md.hpte_removebolted)
                return -ENODEV;
 
-       for (vaddr = vstart; vaddr < vend; vaddr += step)
-               ppc_md.hpte_removebolted(vaddr, psize, ssize);
+       for (vaddr = vstart; vaddr < vend; vaddr += step) {
+               rc = ppc_md.hpte_removebolted(vaddr, psize, ssize);
+               if (rc == -ENOENT) {
+                       ret = -ENOENT;
+                       continue;
+               }
+               if (rc < 0)
+                       return rc;
+       }
 
-       return 0;
+       return ret;
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
index 379a6a90644be155483e76ddd45a2bcdfdb28c2a..baa1a23488d3c5e6066618e37c97635a1f3248f9 100644 (file)
@@ -232,10 +232,11 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
 static void vmemmap_remove_mapping(unsigned long start,
                                   unsigned long page_size)
 {
-       int mapped = htab_remove_mapping(start, start + page_size,
-                                        mmu_vmemmap_psize,
-                                        mmu_kernel_ssize);
-       BUG_ON(mapped < 0);
+       int rc = htab_remove_mapping(start, start + page_size,
+                                    mmu_vmemmap_psize,
+                                    mmu_kernel_ssize);
+       BUG_ON((rc < 0) && (rc != -ENOENT));
+       WARN_ON(rc == -ENOENT);
 }
 #endif
 
index 477290ad855e50a5f0c5da5065ba4b174b77fcfa..2415a0d31f8fd82117af5e7ab80582229a40c555 100644 (file)
@@ -505,8 +505,8 @@ static void pSeries_lpar_hugepage_invalidate(unsigned long vsid,
 }
 #endif
 
-static void pSeries_lpar_hpte_removebolted(unsigned long ea,
-                                          int psize, int ssize)
+static int pSeries_lpar_hpte_removebolted(unsigned long ea,
+                                         int psize, int ssize)
 {
        unsigned long vpn;
        unsigned long slot, vsid;
@@ -515,11 +515,14 @@ static void pSeries_lpar_hpte_removebolted(unsigned long ea,
        vpn = hpt_vpn(ea, vsid, ssize);
 
        slot = pSeries_lpar_hpte_find(vpn, psize, ssize);
-       BUG_ON(slot == -1);
+       if (slot == -1)
+               return -ENOENT;
+
        /*
         * lpar doesn't use the passed actual page size
         */
        pSeries_lpar_hpte_invalidate(slot, vpn, psize, 0, ssize, 0);
+       return 0;
 }
 
 /*