Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932798AbbLSKO1 (ORCPT ); Sat, 19 Dec 2015 05:14:27 -0500 Received: from terminus.zytor.com ([198.137.202.10]:36553 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932158AbbLSKOX (ORCPT ); Sat, 19 Dec 2015 05:14:23 -0500 Date: Sat, 19 Dec 2015 02:12:37 -0800 From: tip-bot for Hidehiro Kawai Message-ID: Cc: masami.hiramatsu.pt@hitachi.com, hpa@zytor.com, rusty@rustcorp.com.au, mingo@kernel.org, mhocko@suse.com, prarit@redhat.com, dzickus@redhat.com, d.hatayama@jp.fujitsu.com, peterz@infradead.org, sjenning@redhat.com, fweisbec@gmail.com, nicolas.iooss_linux@m4x.org, mina86@mina86.com, bp@suse.de, vkuznets@redhat.com, atomlin@redhat.com, cmetcalf@ezchip.com, linux-kernel@vger.kernel.org, bhe@redhat.com, linux@rasmusvillemoes.dk, corbet@lwn.net, javi.merino@arm.com, dahi@linux.vnet.ibm.com, rostedt@goodmis.org, luto@kernel.org, uobergfe@redhat.com, hidehiro.kawai.ez@hitachi.com, gobinda.cemk07@gmail.com, akpm@linux-foundation.org, tglx@linutronix.de, ebiederm@xmission.com, vgoyal@redhat.com Reply-To: akpm@linux-foundation.org, gobinda.cemk07@gmail.com, hidehiro.kawai.ez@hitachi.com, vgoyal@redhat.com, tglx@linutronix.de, ebiederm@xmission.com, rostedt@goodmis.org, luto@kernel.org, javi.merino@arm.com, dahi@linux.vnet.ibm.com, corbet@lwn.net, linux@rasmusvillemoes.dk, uobergfe@redhat.com, mina86@mina86.com, fweisbec@gmail.com, nicolas.iooss_linux@m4x.org, peterz@infradead.org, sjenning@redhat.com, bhe@redhat.com, linux-kernel@vger.kernel.org, cmetcalf@ezchip.com, vkuznets@redhat.com, atomlin@redhat.com, bp@suse.de, mingo@kernel.org, hpa@zytor.com, rusty@rustcorp.com.au, masami.hiramatsu.pt@hitachi.com, d.hatayama@jp.fujitsu.com, mhocko@suse.com, prarit@redhat.com, dzickus@redhat.com In-Reply-To: <20151210014626.25437.13302.stgit@softrs> References: <20151210014626.25437.13302.stgit@softrs> To: linux-tip-commits@vger.kernel.org Subject: [tip:x86/apic] panic, x86: Fix re-entrance problem due to panic on NMI Git-Commit-ID: 1717f2096b543cede7a380c858c765c41936bc35 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7215 Lines: 205 Commit-ID: 1717f2096b543cede7a380c858c765c41936bc35 Gitweb: http://git.kernel.org/tip/1717f2096b543cede7a380c858c765c41936bc35 Author: Hidehiro Kawai AuthorDate: Mon, 14 Dec 2015 11:19:09 +0100 Committer: Thomas Gleixner CommitDate: Sat, 19 Dec 2015 11:07:00 +0100 panic, x86: Fix re-entrance problem due to panic on NMI If panic on NMI happens just after panic() on the same CPU, panic() is recursively called. Kernel stalls, as a result, after failing to acquire panic_lock. To avoid this problem, don't call panic() in NMI context if we've already entered panic(). For that, introduce nmi_panic() macro to reduce code duplication. In the case of panic on NMI, don't return from NMI handlers if another CPU already panicked. Signed-off-by: Hidehiro Kawai Acked-by: Michal Hocko Cc: Aaron Tomlin Cc: Andrew Morton Cc: Andy Lutomirski Cc: Baoquan He Cc: Chris Metcalf Cc: David Hildenbrand Cc: Don Zickus Cc: "Eric W. Biederman" Cc: Frederic Weisbecker Cc: Gobinda Charan Maji Cc: HATAYAMA Daisuke Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Javi Merino Cc: Jonathan Corbet Cc: kexec@lists.infradead.org Cc: linux-doc@vger.kernel.org Cc: lkml Cc: Masami Hiramatsu Cc: Michal Nazarewicz Cc: Nicolas Iooss Cc: Peter Zijlstra Cc: Prarit Bhargava Cc: Rasmus Villemoes Cc: Rusty Russell Cc: Seth Jennings Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Ulrich Obergfell Cc: Vitaly Kuznetsov Cc: Vivek Goyal Link: http://lkml.kernel.org/r/20151210014626.25437.13302.stgit@softrs [ Cleanup comments, fixup formatting. ] Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner --- arch/x86/kernel/nmi.c | 16 ++++++++++++---- include/linux/kernel.h | 20 ++++++++++++++++++++ kernel/panic.c | 16 +++++++++++++--- kernel/watchdog.c | 2 +- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 697f90d..fca8793 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -231,7 +231,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs) #endif if (panic_on_unrecovered_nmi) - panic("NMI: Not continuing"); + nmi_panic("NMI: Not continuing"); pr_emerg("Dazed and confused, but trying to continue\n"); @@ -255,8 +255,16 @@ io_check_error(unsigned char reason, struct pt_regs *regs) reason, smp_processor_id()); show_regs(regs); - if (panic_on_io_nmi) - panic("NMI IOCK error: Not continuing"); + if (panic_on_io_nmi) { + nmi_panic("NMI IOCK error: Not continuing"); + + /* + * If we end up here, it means we have received an NMI while + * processing panic(). Simply return without delaying and + * re-enabling NMIs. + */ + return; + } /* Re-enable the IOCK line, wait for a few seconds */ reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK; @@ -297,7 +305,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) pr_emerg("Do you have a strange power saving mode enabled?\n"); if (unknown_nmi_panic || panic_on_unrecovered_nmi) - panic("NMI: Not continuing"); + nmi_panic("NMI: Not continuing"); pr_emerg("Dazed and confused, but trying to continue\n"); } diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 350dfb0..750cc5c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -446,6 +446,26 @@ extern int sysctl_panic_on_stackoverflow; extern bool crash_kexec_post_notifiers; /* + * panic_cpu is used for synchronizing panic() and crash_kexec() execution. It + * holds a CPU number which is executing panic() currently. A value of + * PANIC_CPU_INVALID means no CPU has entered panic() or crash_kexec(). + */ +extern atomic_t panic_cpu; +#define PANIC_CPU_INVALID -1 + +/* + * A variant of panic() called from NMI context. We return if we've already + * panicked on this CPU. + */ +#define nmi_panic(fmt, ...) \ +do { \ + int cpu = raw_smp_processor_id(); \ + \ + if (atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, cpu) != cpu) \ + panic(fmt, ##__VA_ARGS__); \ +} while (0) + +/* * Only to be used by arch init code. If the user over-wrote the default * CONFIG_PANIC_TIMEOUT, honor it. */ diff --git a/kernel/panic.c b/kernel/panic.c index 4b150bc..3344524 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -61,6 +61,8 @@ void __weak panic_smp_self_stop(void) cpu_relax(); } +atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); + /** * panic - halt the system * @fmt: The text string to print @@ -71,17 +73,17 @@ void __weak panic_smp_self_stop(void) */ void panic(const char *fmt, ...) { - static DEFINE_SPINLOCK(panic_lock); static char buf[1024]; va_list args; long i, i_next = 0; int state = 0; + int old_cpu, this_cpu; /* * Disable local interrupts. This will prevent panic_smp_self_stop * from deadlocking the first cpu that invokes the panic, since * there is nothing to prevent an interrupt handler (that runs - * after the panic_lock is acquired) from invoking panic again. + * after setting panic_cpu) from invoking panic() again. */ local_irq_disable(); @@ -94,8 +96,16 @@ void panic(const char *fmt, ...) * multiple parallel invocations of panic, all other CPUs either * stop themself or will wait until they are stopped by the 1st CPU * with smp_send_stop(). + * + * `old_cpu == PANIC_CPU_INVALID' means this is the 1st CPU which + * comes here, so go ahead. + * `old_cpu == this_cpu' means we came from nmi_panic() which sets + * panic_cpu to this CPU. In this case, this is also the 1st CPU. */ - if (!spin_trylock(&panic_lock)) + this_cpu = raw_smp_processor_id(); + old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu); + + if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu) panic_smp_self_stop(); console_verbose(); diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 18f34cf..b9be18f 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -351,7 +351,7 @@ static void watchdog_overflow_callback(struct perf_event *event, trigger_allbutself_cpu_backtrace(); if (hardlockup_panic) - panic("Hard LOCKUP"); + nmi_panic("Hard LOCKUP"); __this_cpu_write(hard_watchdog_warn, true); return; -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/