From: Nicholas Piggin Date: Fri, 8 May 2020 04:34:03 +0000 (+1000) Subject: powerpc/64s: machine check interrupt update NMI accounting X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=116ac378bb3ff844df333e7609e7604651a0db9d;p=linux.git powerpc/64s: machine check interrupt update NMI accounting machine_check_early() is taken as an NMI, so nmi_enter() is used there. machine_check_exception() is no longer taken as an NMI (it's invoked via irq_work in the case a machine check hits in kernel mode), so remove the nmi_enter() from that case. In NMI context, hash faults don't try to refill the hash table, which can lead to crashes accessing non-pinned kernel pages. System reset still has this potential problem. Signed-off-by: Nicholas Piggin [mpe: Drop change in show_regs() which breaks Book3E] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20200508043408.886394-12-npiggin@gmail.com --- diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index 8077b5fb18a79..be7e3f92a7b5e 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -574,6 +574,9 @@ EXPORT_SYMBOL_GPL(machine_check_print_event_info); long machine_check_early(struct pt_regs *regs) { long handled = 0; + bool nested = in_nmi(); + if (!nested) + nmi_enter(); hv_nmi_check_nonrecoverable(regs); @@ -582,6 +585,10 @@ long machine_check_early(struct pt_regs *regs) */ if (ppc_md.machine_check_early) handled = ppc_md.machine_check_early(regs); + + if (!nested) + nmi_exit(); + return handled; } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 3fca22276bb10..9f6852322e595 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -823,7 +823,19 @@ int machine_check_generic(struct pt_regs *regs) void machine_check_exception(struct pt_regs *regs) { int recover = 0; - bool nested = in_nmi(); + bool nested; + + /* + * BOOK3S_64 does not call this handler as a non-maskable interrupt + * (it uses its own early real-mode handler to handle the MCE proper + * and then raises irq_work to call this handler when interrupts are + * enabled). Set nested = true for this case, which just makes it avoid + * the nmi_enter/exit. + */ + if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) || in_nmi()) + nested = true; + else + nested = false; if (!nested) nmi_enter();