{
 }
 
+#ifndef CONFIG_PPC_BOOK3S_64
 static inline void arch_exit_mmap(struct mm_struct *mm)
 {
 }
+#else
+extern void arch_exit_mmap(struct mm_struct *mm);
+#endif
 
 static inline void arch_unmap(struct mm_struct *mm,
                              struct vm_area_struct *vma,
 
 #ifdef CONFIG_SPAPR_TCE_IOMMU
        WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list));
 #endif
+       if (radix_enabled())
+               WARN_ON(process_tb[mm->context.id].prtb0 != 0);
+       else
+               subpage_prot_free(mm);
+       destroy_pagetable_page(mm);
+       __destroy_context(mm->context.id);
+       mm->context.id = MMU_NO_CONTEXT;
+}
+
+void arch_exit_mmap(struct mm_struct *mm)
+{
        if (radix_enabled()) {
                /*
                 * Radix doesn't have a valid bit in the process table
                 * entries. However we know that at least P9 implementation
                 * will avoid caching an entry with an invalid RTS field,
                 * and 0 is invalid. So this will do.
+                *
+                * This runs before the "fullmm" tlb flush in exit_mmap,
+                * which does a RIC=2 tlbie to clear the process table
+                * entry. See the "fullmm" comments in tlb-radix.c.
+                *
+                * No barrier required here after the store because
+                * this process will do the invalidate, which starts with
+                * ptesync.
                 */
                process_tb[mm->context.id].prtb0 = 0;
-       } else
-               subpage_prot_free(mm);
-       destroy_pagetable_page(mm);
-       __destroy_context(mm->context.id);
-       mm->context.id = MMU_NO_CONTEXT;
+       }
 }
 
 #ifdef CONFIG_PPC_RADIX_MMU
 
        psize = radix_get_mmu_psize(page_size);
        /*
         * if page size is not something we understand, do a full mm flush
+        *
+        * A "fullmm" flush must always do a flush_all_mm (RIC=2) flush
+        * that flushes the process table entry cache upon process teardown.
+        * See the comment for radix in arch_exit_mmap().
         */
        if (psize != -1 && !tlb->fullmm && !tlb->need_flush_all)
                radix__flush_tlb_range_psize(mm, tlb->start, tlb->end, psize);
-       else if (tlb->need_flush_all) {
+       else if (tlb->fullmm || tlb->need_flush_all) {
                tlb->need_flush_all = 0;
                radix__flush_all_mm(mm);
        } else