m68k: allow pte_offset_map[_lock]() to fail
authorHugh Dickins <hughd@google.com>
Thu, 8 Jun 2023 19:15:16 +0000 (12:15 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 19 Jun 2023 23:19:06 +0000 (16:19 -0700)
In rare transient cases, not yet made possible, pte_offset_map() and
pte_offset_map_lock() may not find a page table: handle appropriately.

Restructure cf_tlb_miss() with a pte_unmap() (previously omitted)
at label out, followed by one local_irq_restore() for all.

Link: https://lkml.kernel.org/r/795f6a7-bcca-cdf-ad2a-fbdaa232998c@google.com
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Alexandre Ghiti <alexghiti@rivosinc.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Greg Ungerer <gerg@linux-m68k.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Helge Deller <deller@gmx.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: John David Anglin <dave.anglin@bell.net>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Mike Rapoport (IBM) <rppt@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
arch/m68k/include/asm/mmu_context.h
arch/m68k/kernel/sys_m68k.c
arch/m68k/mm/mcfmmu.c

index 8ed6ac1..141bbdf 100644 (file)
@@ -99,7 +99,7 @@ static inline void load_ksp_mmu(struct task_struct *task)
        p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte;
+       pte_t *pte = NULL;
        unsigned long mmuar;
 
        local_irq_save(flags);
@@ -139,7 +139,7 @@ static inline void load_ksp_mmu(struct task_struct *task)
 
        pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar)
                                     : pte_offset_map(pmd, mmuar);
-       if (pte_none(*pte) || !pte_present(*pte))
+       if (!pte || pte_none(*pte) || !pte_present(*pte))
                goto bug;
 
        set_pte(pte, pte_mkyoung(*pte));
@@ -161,6 +161,8 @@ static inline void load_ksp_mmu(struct task_struct *task)
 bug:
        pr_info("ksp load failed: mm=0x%p ksp=0x08%lx\n", mm, mmuar);
 end:
+       if (pte && mmuar < PAGE_OFFSET)
+               pte_unmap(pte);
        local_irq_restore(flags);
 }
 
index bd0274c..c586034 100644 (file)
@@ -488,6 +488,8 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
                if (!pmd_present(*pmd))
                        goto bad_access;
                pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
+               if (!pte)
+                       goto bad_access;
                if (!pte_present(*pte) || !pte_dirty(*pte)
                    || !pte_write(*pte)) {
                        pte_unmap_unlock(pte, ptl);
index 70aa097..42f45ab 100644 (file)
@@ -91,7 +91,8 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
        p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte;
+       pte_t *pte = NULL;
+       int ret = -1;
        int asid;
 
        local_irq_save(flags);
@@ -100,47 +101,33 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
                regs->pc + (extension_word * sizeof(long));
 
        mm = (!user_mode(regs) && KMAPAREA(mmuar)) ? &init_mm : current->mm;
-       if (!mm) {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (!mm)
+               goto out;
 
        pgd = pgd_offset(mm, mmuar);
-       if (pgd_none(*pgd))  {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (pgd_none(*pgd))
+               goto out;
 
        p4d = p4d_offset(pgd, mmuar);
-       if (p4d_none(*p4d)) {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (p4d_none(*p4d))
+               goto out;
 
        pud = pud_offset(p4d, mmuar);
-       if (pud_none(*pud)) {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (pud_none(*pud))
+               goto out;
 
        pmd = pmd_offset(pud, mmuar);
-       if (pmd_none(*pmd)) {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (pmd_none(*pmd))
+               goto out;
 
        pte = (KMAPAREA(mmuar)) ? pte_offset_kernel(pmd, mmuar)
                                : pte_offset_map(pmd, mmuar);
-       if (pte_none(*pte) || !pte_present(*pte)) {
-               local_irq_restore(flags);
-               return -1;
-       }
+       if (!pte || pte_none(*pte) || !pte_present(*pte))
+               goto out;
 
        if (write) {
-               if (!pte_write(*pte)) {
-                       local_irq_restore(flags);
-                       return -1;
-               }
+               if (!pte_write(*pte))
+                       goto out;
                set_pte(pte, pte_mkdirty(*pte));
        }
 
@@ -161,9 +148,12 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
                mmu_write(MMUOR, MMUOR_ACC | MMUOR_UAA);
        else
                mmu_write(MMUOR, MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA);
-
+       ret = 0;
+out:
+       if (pte && !KMAPAREA(mmuar))
+               pte_unmap(pte);
        local_irq_restore(flags);
-       return 0;
+       return ret;
 }
 
 void __init cf_bootmem_alloc(void)