cf9b1106c8
In NMI context, printk() messages are stored into per-CPU buffers to avoid a possible deadlock. They are normally flushed to the main ring buffer via an IRQ work. But the work is never called when the system calls panic() in the very same NMI handler. This patch tries to flush NMI buffers before the crash dump is generated. In this case it does not risk a double release and bails out when the logbuf_lock is already taken. The aim is to get the messages into the main ring buffer when possible. It makes them better accessible in the vmcore. Then the patch tries to flush the buffers second time when other CPUs are down. It might be more aggressive and reset logbuf_lock. The aim is to get the messages available for the consequent kmsg_dump() and console_flush_on_panic() calls. The patch causes vprintk_emit() to be called even in NMI context again. But it is done via printk_deferred() so that the console handling is skipped. Consoles use internal locks and we could not prevent a deadlock easily. They are explicitly called later when the crash dump is not generated, see console_flush_on_panic(). Signed-off-by: Petr Mladek <pmladek@suse.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Daniel Thompson <daniel.thompson@linaro.org> Cc: David Miller <davem@davemloft.net> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jan Kara <jack@suse.cz> Cc: Jiri Kosina <jkosina@suse.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Russell King <rmk+kernel@arm.linux.org.uk> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
58 lines
1.6 KiB
C
58 lines
1.6 KiB
C
/*
|
|
* internal.h - printk internal definitions
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <linux/percpu.h>
|
|
|
|
typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);
|
|
|
|
int __printf(1, 0) vprintk_default(const char *fmt, va_list args);
|
|
|
|
#ifdef CONFIG_PRINTK_NMI
|
|
|
|
extern raw_spinlock_t logbuf_lock;
|
|
|
|
/*
|
|
* printk() could not take logbuf_lock in NMI context. Instead,
|
|
* it temporary stores the strings into a per-CPU buffer.
|
|
* The alternative implementation is chosen transparently
|
|
* via per-CPU variable.
|
|
*/
|
|
DECLARE_PER_CPU(printk_func_t, printk_func);
|
|
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
|
|
{
|
|
return this_cpu_read(printk_func)(fmt, args);
|
|
}
|
|
|
|
extern atomic_t nmi_message_lost;
|
|
static inline int get_nmi_message_lost(void)
|
|
{
|
|
return atomic_xchg(&nmi_message_lost, 0);
|
|
}
|
|
|
|
#else /* CONFIG_PRINTK_NMI */
|
|
|
|
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
|
|
{
|
|
return vprintk_default(fmt, args);
|
|
}
|
|
|
|
static inline int get_nmi_message_lost(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_PRINTK_NMI */
|