Commit e67b37c3 authored by Hugh Dickins's avatar Hugh Dickins Committed by Andrew Morton

m68k: allow pte_offset_map[_lock]() to fail

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.comSigned-off-by: default avatarHugh 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 0db639f7
...@@ -99,7 +99,7 @@ static inline void load_ksp_mmu(struct task_struct *task) ...@@ -99,7 +99,7 @@ static inline void load_ksp_mmu(struct task_struct *task)
p4d_t *p4d; p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte = NULL;
unsigned long mmuar; unsigned long mmuar;
local_irq_save(flags); local_irq_save(flags);
...@@ -139,7 +139,7 @@ static inline void load_ksp_mmu(struct task_struct *task) ...@@ -139,7 +139,7 @@ static inline void load_ksp_mmu(struct task_struct *task)
pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar) pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar)
: pte_offset_map(pmd, mmuar); : pte_offset_map(pmd, mmuar);
if (pte_none(*pte) || !pte_present(*pte)) if (!pte || pte_none(*pte) || !pte_present(*pte))
goto bug; goto bug;
set_pte(pte, pte_mkyoung(*pte)); set_pte(pte, pte_mkyoung(*pte));
...@@ -161,6 +161,8 @@ static inline void load_ksp_mmu(struct task_struct *task) ...@@ -161,6 +161,8 @@ static inline void load_ksp_mmu(struct task_struct *task)
bug: bug:
pr_info("ksp load failed: mm=0x%p ksp=0x08%lx\n", mm, mmuar); pr_info("ksp load failed: mm=0x%p ksp=0x08%lx\n", mm, mmuar);
end: end:
if (pte && mmuar < PAGE_OFFSET)
pte_unmap(pte);
local_irq_restore(flags); local_irq_restore(flags);
} }
......
...@@ -488,6 +488,8 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, ...@@ -488,6 +488,8 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
if (!pmd_present(*pmd)) if (!pmd_present(*pmd))
goto bad_access; goto bad_access;
pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl); pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
if (!pte)
goto bad_access;
if (!pte_present(*pte) || !pte_dirty(*pte) if (!pte_present(*pte) || !pte_dirty(*pte)
|| !pte_write(*pte)) { || !pte_write(*pte)) {
pte_unmap_unlock(pte, ptl); pte_unmap_unlock(pte, ptl);
......
...@@ -91,7 +91,8 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) ...@@ -91,7 +91,8 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word)
p4d_t *p4d; p4d_t *p4d;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; pte_t *pte = NULL;
int ret = -1;
int asid; int asid;
local_irq_save(flags); local_irq_save(flags);
...@@ -100,47 +101,33 @@ int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) ...@@ -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)); regs->pc + (extension_word * sizeof(long));
mm = (!user_mode(regs) && KMAPAREA(mmuar)) ? &init_mm : current->mm; mm = (!user_mode(regs) && KMAPAREA(mmuar)) ? &init_mm : current->mm;
if (!mm) { if (!mm)
local_irq_restore(flags); goto out;
return -1;
}
pgd = pgd_offset(mm, mmuar); pgd = pgd_offset(mm, mmuar);
if (pgd_none(*pgd)) { if (pgd_none(*pgd))
local_irq_restore(flags); goto out;
return -1;
}
p4d = p4d_offset(pgd, mmuar); p4d = p4d_offset(pgd, mmuar);
if (p4d_none(*p4d)) { if (p4d_none(*p4d))
local_irq_restore(flags); goto out;
return -1;
}
pud = pud_offset(p4d, mmuar); pud = pud_offset(p4d, mmuar);
if (pud_none(*pud)) { if (pud_none(*pud))
local_irq_restore(flags); goto out;
return -1;
}
pmd = pmd_offset(pud, mmuar); pmd = pmd_offset(pud, mmuar);
if (pmd_none(*pmd)) { if (pmd_none(*pmd))
local_irq_restore(flags); goto out;
return -1;
}
pte = (KMAPAREA(mmuar)) ? pte_offset_kernel(pmd, mmuar) pte = (KMAPAREA(mmuar)) ? pte_offset_kernel(pmd, mmuar)
: pte_offset_map(pmd, mmuar); : pte_offset_map(pmd, mmuar);
if (pte_none(*pte) || !pte_present(*pte)) { if (!pte || pte_none(*pte) || !pte_present(*pte))
local_irq_restore(flags); goto out;
return -1;
}
if (write) { if (write) {
if (!pte_write(*pte)) { if (!pte_write(*pte))
local_irq_restore(flags); goto out;
return -1;
}
set_pte(pte, pte_mkdirty(*pte)); 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) ...@@ -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); mmu_write(MMUOR, MMUOR_ACC | MMUOR_UAA);
else else
mmu_write(MMUOR, MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA); mmu_write(MMUOR, MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA);
ret = 0;
out:
if (pte && !KMAPAREA(mmuar))
pte_unmap(pte);
local_irq_restore(flags); local_irq_restore(flags);
return 0; return ret;
} }
void __init cf_bootmem_alloc(void) void __init cf_bootmem_alloc(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment