powerpc/mm: Move the DSISR_PROTFAULT sanity check
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 19 Jul 2017 04:49:39 +0000 (14:49 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 3 Aug 2017 06:06:49 +0000 (16:06 +1000)
This has a page of comment explaining what's going on right in
the middle of do_page_fault() which makes things a bit hard to
follow. Move it to a helper instead. Also do the test earlier
as there's no point waiting until after we found the VMA.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/mm/fault.c

index bd5d668b47ff2f422773bfb80594e31d6b9243a4..6f3a2437008a61b5cab664215905b114af1a3063 100644 (file)
@@ -239,6 +239,45 @@ static inline void cmo_account_page_fault(void)
 static inline void cmo_account_page_fault(void) { }
 #endif /* CONFIG_PPC_SMLPAR */
 
+#ifdef CONFIG_PPC_STD_MMU
+static void sanity_check_fault(bool is_write, unsigned long error_code)
+{
+       /*
+        * For hash translation mode, we should never get a
+        * PROTFAULT. Any update to pte to reduce access will result in us
+        * removing the hash page table entry, thus resulting in a DSISR_NOHPTE
+        * fault instead of DSISR_PROTFAULT.
+        *
+        * A pte update to relax the access will not result in a hash page table
+        * entry invalidate and hence can result in DSISR_PROTFAULT.
+        * ptep_set_access_flags() doesn't do a hpte flush. This is why we have
+        * the special !is_write in the below conditional.
+        *
+        * For platforms that doesn't supports coherent icache and do support
+        * per page noexec bit, we do setup things such that we do the
+        * sync between D/I cache via fault. But that is handled via low level
+        * hash fault code (hash_page_do_lazy_icache()) and we should not reach
+        * here in such case.
+        *
+        * For wrong access that can result in PROTFAULT, the above vma->vm_flags
+        * check should handle those and hence we should fall to the bad_area
+        * handling correctly.
+        *
+        * For embedded with per page exec support that doesn't support coherent
+        * icache we do get PROTFAULT and we handle that D/I cache sync in
+        * set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
+        * is conditional for server MMU.
+        *
+        * For radix, we can get prot fault for autonuma case, because radix
+        * page table will have them marked noaccess for user.
+        */
+       if (!radix_enabled() && !is_write)
+               WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
+}
+#else
+static void sanity_check_fault(bool is_write, unsigned long error_code) { }
+#endif /* CONFIG_PPC_STD_MMU */
+
 /*
  * Define the correct "is_write" bit in error_code based
  * on the processor family
@@ -306,6 +345,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
                return SIGBUS;
        }
 
+       /* Additional sanity check(s) */
+       sanity_check_fault(is_write, error_code);
+
        /*
         * The kernel should never take an execute fault nor should it
         * take a page fault to a kernel address.
@@ -441,39 +483,6 @@ good_area:
                if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
                        return bad_area(regs, address);
        }
-#ifdef CONFIG_PPC_STD_MMU
-       /*
-        * For hash translation mode, we should never get a
-        * PROTFAULT. Any update to pte to reduce access will result in us
-        * removing the hash page table entry, thus resulting in a DSISR_NOHPTE
-        * fault instead of DSISR_PROTFAULT.
-        *
-        * A pte update to relax the access will not result in a hash page table
-        * entry invalidate and hence can result in DSISR_PROTFAULT.
-        * ptep_set_access_flags() doesn't do a hpte flush. This is why we have
-        * the special !is_write in the below conditional.
-        *
-        * For platforms that doesn't supports coherent icache and do support
-        * per page noexec bit, we do setup things such that we do the
-        * sync between D/I cache via fault. But that is handled via low level
-        * hash fault code (hash_page_do_lazy_icache()) and we should not reach
-        * here in such case.
-        *
-        * For wrong access that can result in PROTFAULT, the above vma->vm_flags
-        * check should handle those and hence we should fall to the bad_area
-        * handling correctly.
-        *
-        * For embedded with per page exec support that doesn't support coherent
-        * icache we do get PROTFAULT and we handle that D/I cache sync in
-        * set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
-        * is conditional for server MMU.
-        *
-        * For radix, we can get prot fault for autonuma case, because radix
-        * page table will have them marked noaccess for user.
-        */
-       if (!radix_enabled() && !is_write)
-               WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
-#endif /* CONFIG_PPC_STD_MMU */
 
        /*
         * If for any reason at all we couldn't handle the fault,