Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1367318 > unrolled thread
| Started by | Petr Mladek <pmladek@suse.com> |
|---|---|
| First post | 2016-03-30 18:00 +0200 |
| Last post | 2016-03-30 18:00 +0200 |
| Articles | 7 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH v4 0/5] Cleaning printk stuff in NMI context Petr Mladek <pmladek@suse.com> - 2016-03-30 18:00 +0200
[PATCH v4 3/5] printk/nmi: warn when some message has been lost in NMI context Petr Mladek <pmladek@suse.com> - 2016-03-30 18:00 +0200
[PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic Petr Mladek <pmladek@suse.com> - 2016-03-30 18:00 +0200
Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic kbuild test robot <lkp@intel.com> - 2016-03-30 18:40 +0200
Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic Petr Mladek <pmladek@suse.com> - 2016-03-31 14:40 +0200
Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-04-04 07:00 +0200
[PATCH v4 4/5] printk/nmi: increase the size of NMI buffer and make it configurable Petr Mladek <pmladek@suse.com> - 2016-03-30 18:00 +0200
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-03-30 18:00 +0200 |
| Subject | [PATCH v4 0/5] Cleaning printk stuff in NMI context |
| Message-ID | <riqHg-7AW-3@gated-at.bofh.it> |
This patch set generalizes the already existing solution for
printing NMI messages. The main idea comes from Peter Zijlstra.
v4 adds one more patch that flushes NNI buffers when the system
is panicing. Otherwise, it is almost the same as the last version
in the -mm tree, see changes below for more details
There is a trivial conflict with Sergey's v8 of async printk,
see http://thread.gmane.org/gmane.linux.kernel/2183611
In short, we must handle console in vprintk_emit() neither in sched
nor in nmi. Therefore we need the line
if (!in_sched && !deferred_console_in_nmi()) {
There are move conflicts with the nmi_backtrace improvements
from Chris Metcalf, see
http://marc.info/?l=linux-kernel&m=145866814901740&w=2
Feel free to ask me to resolve them.
Changes against v3:
+ merged all small changes from -mm tree, including commit
descriptions
+ disabled interrupts when taking the read_lock in __printk_nmi_flush();
printk_nmi_flush() might be called from any context; reported
by lockdep
+ never introduce NEED_PRINTK_NMI; in -mm tree was introduced
in 1st patch and removed in the 4th one
+ flush NMI buffers when the system goes down (new 5th patch);
addresses Daniel's concerns
Changes against v2:
+ fixed compilation problems reported by 0-day build robot
+ MN10300 and Xtensa architectures will get handled separately
+ dropped the patch that printed NMI messages directly when Oops
in progress; it made the solution less reliable
+ made the size of the buffer configurable; use real numbers
instead of PAGE_SIZE
Changes against v1:
+ rebased on top of 4.4-rc2; there the old implementation was
moved to lib/nmi_backtrace.c and used also on arm; I hope that
I got the arm side correctly; I was not able to test on arm :-(
+ defined HAVE_NMI on arm for !CPU_V7M instead of !CPU_V7;
handle_fiq_as_nmi() is called from entry-armv.S that
is compiled when !CPU_V7M
+ defined HAVE_NMI also on mips; it calls nmi_enter() and
seems to have real NMIs (or am I wrong?)
+ serialized backtraces when printing directly
(oops_in_progress)
Petr Mladek (5):
printk/nmi: generic solution for safe printk in NMI
printk/nmi: use IRQ work only when ready
printk/nmi: warn when some message has been lost in NMI context
printk/nmi: increase the size of NMI buffer and make it configurable
printk/nmi: flush NMI messages on the system panic
arch/Kconfig | 4 +
arch/arm/Kconfig | 1 +
arch/arm/kernel/smp.c | 2 +
arch/avr32/Kconfig | 1 +
arch/blackfin/Kconfig | 1 +
arch/cris/Kconfig | 1 +
arch/mips/Kconfig | 1 +
arch/powerpc/Kconfig | 1 +
arch/s390/Kconfig | 1 +
arch/sh/Kconfig | 1 +
arch/sparc/Kconfig | 1 +
arch/tile/Kconfig | 1 +
arch/x86/Kconfig | 1 +
arch/x86/kernel/apic/hw_nmi.c | 1 -
include/linux/hardirq.h | 2 +
include/linux/percpu.h | 3 -
include/linux/printk.h | 16 ++-
init/Kconfig | 27 +++++
init/main.c | 1 +
kernel/kexec_core.c | 1 +
kernel/panic.c | 6 +-
kernel/printk/Makefile | 1 +
kernel/printk/internal.h | 57 ++++++++++
kernel/printk/nmi.c | 258 ++++++++++++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 43 +++----
lib/nmi_backtrace.c | 89 +--------------
26 files changed, 411 insertions(+), 111 deletions(-)
create mode 100644 kernel/printk/internal.h
create mode 100644 kernel/printk/nmi.c
--
1.8.5.6
[toc] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-03-30 18:00 +0200 |
| Subject | [PATCH v4 3/5] printk/nmi: warn when some message has been lost in NMI context |
| Message-ID | <riqHg-7AW-17@gated-at.bofh.it> |
| In reply to | #1367318 |
We could not resize the temporary buffer in NMI context. Let's warn if a
message is lost.
This is rather theoretical. printk() should not be used in NMI. The only
sensible use is when we want to print backtrace from all CPUs. The
current buffer should be enough for this purpose.
[akpm@linux-foundation.org: whitespace fixlet]
Signed-off-by: Petr Mladek <pmladek@suse.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Jiri Kosina <jkosina@suse.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
kernel/printk/internal.h | 11 +++++++++++
kernel/printk/nmi.c | 5 ++++-
kernel/printk/printk.c | 10 ++++++++++
3 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 2de99faedfc1..341bedccc065 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -34,6 +34,12 @@ 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)
@@ -41,4 +47,9 @@ 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 */
diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c
index 303cf0d15e57..572f94922230 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/nmi.c
@@ -39,6 +39,7 @@
*/
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
static int printk_nmi_irq_ready;
+atomic_t nmi_message_lost;
#define NMI_LOG_BUF_LEN (4096 - sizeof(atomic_t) - sizeof(struct irq_work))
@@ -64,8 +65,10 @@ static int vprintk_nmi(const char *fmt, va_list args)
again:
len = atomic_read(&s->len);
- if (len >= sizeof(s->buffer))
+ if (len >= sizeof(s->buffer)) {
+ atomic_inc(&nmi_message_lost);
return 0;
+ }
/*
* Make sure that all old data have been read before the buffer was
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 71eba0607034..e38579d730f4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1617,6 +1617,7 @@ asmlinkage int vprintk_emit(int facility, int level,
unsigned long flags;
int this_cpu;
int printed_len = 0;
+ int nmi_message_lost;
bool in_sched = false;
/* cpu currently holding logbuf_lock in this function */
static unsigned int logbuf_cpu = UINT_MAX;
@@ -1667,6 +1668,15 @@ asmlinkage int vprintk_emit(int facility, int level,
strlen(recursion_msg));
}
+ nmi_message_lost = get_nmi_message_lost();
+ if (unlikely(nmi_message_lost)) {
+ text_len = scnprintf(textbuf, sizeof(textbuf),
+ "BAD LUCK: lost %d message(s) from NMI context!",
+ nmi_message_lost);
+ printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
+ NULL, 0, textbuf, text_len);
+ }
+
/*
* The printf needs to come first; we need the syslog
* prefix which might be passed-in as a parameter.
--
1.8.5.6
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-03-30 18:00 +0200 |
| Subject | [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic |
| Message-ID | <riqHh-7AW-21@gated-at.bofh.it> |
| In reply to | #1367318 |
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
we do not want to call consoles in this case. They might use internal
locks and we could not prevent a deadlock easily. We only want to have the
messages in the main ring buffer for crash dump and kmsg_dump(). The
consoles are explicitly called later by console_flush_on_panic().
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 4 ++++
kernel/kexec_core.c | 1 +
kernel/panic.c | 6 +++++-
kernel/printk/internal.h | 2 ++
kernel/printk/nmi.c | 35 +++++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 14 +++++++++++---
6 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 51dd6b824fe2..2da06c2a63c3 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -123,15 +123,19 @@ void early_printk(const char *s, ...) { }
#endif
#ifdef CONFIG_PRINTK_NMI
+#define deferred_console_in_nmi() in_nmi()
extern void printk_nmi_init(void);
extern void printk_nmi_enter(void);
extern void printk_nmi_exit(void);
extern void printk_nmi_flush(void);
+extern void printk_nmi_flush_on_panic(void);
#else
+#define deferred_console_in_nmi() 0
static inline void printk_nmi_init(void) { }
static inline void printk_nmi_enter(void) { }
static inline void printk_nmi_exit(void) { }
static inline void printk_nmi_flush(void) { }
+static inline void printk_nmi_flush_on_panic(void) { }
#endif /* PRINTK_NMI */
#ifdef CONFIG_PRINTK
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 8d34308ea449..1dc3fe8495e0 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -893,6 +893,7 @@ void crash_kexec(struct pt_regs *regs)
old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
if (old_cpu == PANIC_CPU_INVALID) {
/* This is the 1st CPU which comes here, so go ahead. */
+ printk_nmi_flush_on_panic();
__crash_kexec(regs);
/*
diff --git a/kernel/panic.c b/kernel/panic.c
index 535c96510a44..8aa74497cc5a 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -160,8 +160,10 @@ void panic(const char *fmt, ...)
*
* Bypass the panic_cpu check and call __crash_kexec directly.
*/
- if (!crash_kexec_post_notifiers)
+ if (!crash_kexec_post_notifiers) {
+ printk_nmi_flush_on_panic();
__crash_kexec(NULL);
+ }
/*
* Note smp_send_stop is the usual smp shutdown function, which
@@ -176,6 +178,8 @@ void panic(const char *fmt, ...)
*/
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
+ /* Call flush even twice. It tries harder with a single online CPU */
+ printk_nmi_flush_on_panic();
kmsg_dump(KMSG_DUMP_PANIC);
/*
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 341bedccc065..7fd2838fa417 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -22,6 +22,8 @@ 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.
diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c
index bf08557d7e3d..69b0c67ca2b2 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/nmi.c
@@ -194,6 +194,41 @@ void printk_nmi_flush(void)
__printk_nmi_flush(&per_cpu(nmi_print_seq, cpu).work);
}
+/**
+ * printk_nmi_flush_on_panic - flush all per-cpu nmi buffers when the system
+ * goes down.
+ *
+ * Similar to printk_nmi_flush() but it can be called even in NMI context when
+ * the system goes down. It does the best effort to get NMI messages into
+ * the main ring buffer.
+ *
+ * Note that it could try harder when there is only one CPU online.
+ */
+void printk_nmi_flush_on_panic(void)
+{
+ if (in_nmi()) {
+ /*
+ * Make sure that we could access the main ring buffer.
+ * Do not risk a double release when more CPUs are up.
+ */
+ if (raw_spin_is_locked(&logbuf_lock)) {
+ if (num_online_cpus() > 1)
+ return;
+
+ debug_locks_off();
+ raw_spin_lock_init(&logbuf_lock);
+ }
+
+ /*
+ * Flush the messages using the default printk handler
+ * to store them into the main ring buffer.
+ */
+ this_cpu_write(printk_func, vprintk_default);
+ }
+
+ printk_nmi_flush();
+}
+
void __init printk_nmi_init(void)
{
int cpu;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e38579d730f4..bf84df2eb3b6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -245,7 +245,7 @@ __packed __aligned(4)
* within the scheduler's rq lock. It must be released before calling
* console_unlock() or anything else that might wake up a process.
*/
-static DEFINE_RAW_SPINLOCK(logbuf_lock);
+DEFINE_RAW_SPINLOCK(logbuf_lock);
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
@@ -1764,8 +1764,16 @@ asmlinkage int vprintk_emit(int facility, int level,
lockdep_on();
local_irq_restore(flags);
- /* If called from the scheduler, we can not call up(). */
- if (!in_sched) {
+ /*
+ * Console calls must be deferred when called from the scheduler.
+ *
+ * Many architectures never call vprintk_emit() in NMI context,
+ * see vprintk_nmi(). The only exception is when the NMI buffers
+ * are flushed on panic. In this case, the consoles are called
+ * later explicitly only when crashdump does not work, see
+ * console_flush_on_panic().
+ */
+ if (!in_sched && !deferred_console_in_nmi()) {
lockdep_off();
/*
* Try to acquire and then immediately release the console
--
1.8.5.6
[toc] | [prev] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2016-03-30 18:40 +0200 |
| Subject | Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic |
| Message-ID | <rirjZ-87s-33@gated-at.bofh.it> |
| In reply to | #1367323 |
[Multipart message — attachments visible in raw view] — view raw
Hi Petr,
[auto build test ERROR on v4.6-rc1]
[cannot apply to tip/x86/core next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Petr-Mladek/Cleaning-printk-stuff-in-NMI-context/20160330-235818
config: i386-randconfig-s1-201613 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
kernel/printk/nmi.c: In function 'printk_nmi_flush_on_panic':
>> kernel/printk/nmi.c:218:4: error: implicit declaration of function 'debug_locks_off' [-Werror=implicit-function-declaration]
debug_locks_off();
^
cc1: some warnings being treated as errors
vim +/debug_locks_off +218 kernel/printk/nmi.c
212 * Do not risk a double release when more CPUs are up.
213 */
214 if (raw_spin_is_locked(&logbuf_lock)) {
215 if (num_online_cpus() > 1)
216 return;
217
> 218 debug_locks_off();
219 raw_spin_lock_init(&logbuf_lock);
220 }
221
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-03-31 14:40 +0200 |
| Subject | Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic |
| Message-ID | <riK3g-531-11@gated-at.bofh.it> |
| In reply to | #1367394 |
On Thu 2016-03-31 00:33:54, kbuild test robot wrote:
> Hi Petr,
>
> [auto build test ERROR on v4.6-rc1]
> [cannot apply to tip/x86/core next-20160330]
> [if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
>
> url: https://github.com/0day-ci/linux/commits/Petr-Mladek/Cleaning-printk-stuff-in-NMI-context/20160330-235818
> config: i386-randconfig-s1-201613 (attached as .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> kernel/printk/nmi.c: In function 'printk_nmi_flush_on_panic':
> >> kernel/printk/nmi.c:218:4: error: implicit declaration of function 'debug_locks_off' [-Werror=implicit-function-declaration]
> debug_locks_off();
> ^
> cc1: some warnings being treated as errors
Fixed by adding #include <linux/debug_locks.h> into kernel/printk/nmi.c
Please, find the updated patch below.
From 52cc5fee3909e8955bd78a8c63b9a610dc5c11fe Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Thu, 24 Mar 2016 15:10:21 +0100
Subject: [PATCH] printk/nmi: flush NMI messages on the system panic
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
we do not want to call consoles in this case. They might use internal
locks and we could not prevent a deadlock easily. We only want to have the
messages in the main ring buffer for crash dump and kmsg_dump(). The
consoles are explicitly called later by console_flush_on_panic().
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 4 ++++
kernel/kexec_core.c | 1 +
kernel/panic.c | 6 +++++-
kernel/printk/internal.h | 2 ++
kernel/printk/nmi.c | 36 ++++++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 14 +++++++++++---
6 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 51dd6b824fe2..2da06c2a63c3 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -123,15 +123,19 @@ void early_printk(const char *s, ...) { }
#endif
#ifdef CONFIG_PRINTK_NMI
+#define deferred_console_in_nmi() in_nmi()
extern void printk_nmi_init(void);
extern void printk_nmi_enter(void);
extern void printk_nmi_exit(void);
extern void printk_nmi_flush(void);
+extern void printk_nmi_flush_on_panic(void);
#else
+#define deferred_console_in_nmi() 0
static inline void printk_nmi_init(void) { }
static inline void printk_nmi_enter(void) { }
static inline void printk_nmi_exit(void) { }
static inline void printk_nmi_flush(void) { }
+static inline void printk_nmi_flush_on_panic(void) { }
#endif /* PRINTK_NMI */
#ifdef CONFIG_PRINTK
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 8d34308ea449..1dc3fe8495e0 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -893,6 +893,7 @@ void crash_kexec(struct pt_regs *regs)
old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
if (old_cpu == PANIC_CPU_INVALID) {
/* This is the 1st CPU which comes here, so go ahead. */
+ printk_nmi_flush_on_panic();
__crash_kexec(regs);
/*
diff --git a/kernel/panic.c b/kernel/panic.c
index 535c96510a44..8aa74497cc5a 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -160,8 +160,10 @@ void panic(const char *fmt, ...)
*
* Bypass the panic_cpu check and call __crash_kexec directly.
*/
- if (!crash_kexec_post_notifiers)
+ if (!crash_kexec_post_notifiers) {
+ printk_nmi_flush_on_panic();
__crash_kexec(NULL);
+ }
/*
* Note smp_send_stop is the usual smp shutdown function, which
@@ -176,6 +178,8 @@ void panic(const char *fmt, ...)
*/
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
+ /* Call flush even twice. It tries harder with a single online CPU */
+ printk_nmi_flush_on_panic();
kmsg_dump(KMSG_DUMP_PANIC);
/*
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 341bedccc065..7fd2838fa417 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -22,6 +22,8 @@ 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.
diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c
index bf08557d7e3d..6dc3ff80ae89 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/nmi.c
@@ -17,6 +17,7 @@
#include <linux/preempt.h>
#include <linux/spinlock.h>
+#include <linux/debug_locks.h>
#include <linux/smp.h>
#include <linux/cpumask.h>
#include <linux/irq_work.h>
@@ -194,6 +195,41 @@ void printk_nmi_flush(void)
__printk_nmi_flush(&per_cpu(nmi_print_seq, cpu).work);
}
+/**
+ * printk_nmi_flush_on_panic - flush all per-cpu nmi buffers when the system
+ * goes down.
+ *
+ * Similar to printk_nmi_flush() but it can be called even in NMI context when
+ * the system goes down. It does the best effort to get NMI messages into
+ * the main ring buffer.
+ *
+ * Note that it could try harder when there is only one CPU online.
+ */
+void printk_nmi_flush_on_panic(void)
+{
+ if (in_nmi()) {
+ /*
+ * Make sure that we could access the main ring buffer.
+ * Do not risk a double release when more CPUs are up.
+ */
+ if (raw_spin_is_locked(&logbuf_lock)) {
+ if (num_online_cpus() > 1)
+ return;
+
+ debug_locks_off();
+ raw_spin_lock_init(&logbuf_lock);
+ }
+
+ /*
+ * Flush the messages using the default printk handler
+ * to store them into the main ring buffer.
+ */
+ this_cpu_write(printk_func, vprintk_default);
+ }
+
+ printk_nmi_flush();
+}
+
void __init printk_nmi_init(void)
{
int cpu;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e38579d730f4..bf84df2eb3b6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -245,7 +245,7 @@ __packed __aligned(4)
* within the scheduler's rq lock. It must be released before calling
* console_unlock() or anything else that might wake up a process.
*/
-static DEFINE_RAW_SPINLOCK(logbuf_lock);
+DEFINE_RAW_SPINLOCK(logbuf_lock);
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
@@ -1764,8 +1764,16 @@ asmlinkage int vprintk_emit(int facility, int level,
lockdep_on();
local_irq_restore(flags);
- /* If called from the scheduler, we can not call up(). */
- if (!in_sched) {
+ /*
+ * Console calls must be deferred when called from the scheduler.
+ *
+ * Many architectures never call vprintk_emit() in NMI context,
+ * see vprintk_nmi(). The only exception is when the NMI buffers
+ * are flushed on panic. In this case, the consoles are called
+ * later explicitly only when crashdump does not work, see
+ * console_flush_on_panic().
+ */
+ if (!in_sched && !deferred_console_in_nmi()) {
lockdep_off();
/*
* Try to acquire and then immediately release the console
--
1.8.5.6
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-04-04 07:00 +0200 |
| Subject | Re: [PATCH v4 5/5] printk/nmi: flush NMI messages on the system panic |
| Message-ID | <rk4Mi-6fk-3@gated-at.bofh.it> |
| In reply to | #1368243 |
Hello,
On (03/31/16 14:36), Petr Mladek wrote:
[..]
> #ifdef CONFIG_PRINTK_NMI
> +#define deferred_console_in_nmi() in_nmi()
> #else
> +#define deferred_console_in_nmi() 0
[..]
> + if (!in_sched && !deferred_console_in_nmi()) {
> lockdep_off();
> /*
> * Try to acquire and then immediately release the console
or use SCHED level for nmi messages instead of defining deferred_console_in_nmi()?
so !in_sched will work for both SCHED and NMI messages.
-ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-03-30 18:00 +0200 |
| Subject | [PATCH v4 4/5] printk/nmi: increase the size of NMI buffer and make it configurable |
| Message-ID | <riqHh-7AW-31@gated-at.bofh.it> |
| In reply to | #1367318 |
Testing has shown that the backtrace sometimes does not fit into the 4kB
temporary buffer that is used in NMI context. The warnings are gone when
I double the temporary buffer size.
This patch doubles the buffer size and makes it configurable.
Note that this problem existed even in the x86-specific implementation
that was added by the commit a9edc8809328 ("x86/nmi: Perform a safe NMI
stack trace on all CPUs"). Nobody noticed it because it did not print any
warnings.
Signed-off-by: Petr Mladek <pmladek@suse.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Cc: Jiri Kosina <jkosina@suse.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
init/Kconfig | 22 ++++++++++++++++++++++
kernel/printk/nmi.c | 3 ++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/init/Kconfig b/init/Kconfig
index fd10deeefc22..1c9be9396a4a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -861,6 +861,28 @@ config LOG_CPU_MAX_BUF_SHIFT
13 => 8 KB for each CPU
12 => 4 KB for each CPU
+config NMI_LOG_BUF_SHIFT
+ int "Temporary per-CPU NMI log buffer size (12 => 4KB, 13 => 8KB)"
+ range 10 21
+ default 13
+ depends on PRINTK_NMI
+ help
+ Select the size of a per-CPU buffer where NMI messages are temporary
+ stored. They are copied to the main log buffer in a safe context
+ to avoid a deadlock. The value defines the size as a power of 2.
+
+ NMI messages are rare and limited. The largest one is when
+ a backtrace is printed. It usually fits into 4KB. Select
+ 8KB if you want to be on the safe side.
+
+ Examples:
+ 17 => 128 KB for each CPU
+ 16 => 64 KB for each CPU
+ 15 => 32 KB for each CPU
+ 14 => 16 KB for each CPU
+ 13 => 8 KB for each CPU
+ 12 => 4 KB for each CPU
+
#
# Architectures with an unreliable sched_clock() should select this:
#
diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c
index 572f94922230..bf08557d7e3d 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/nmi.c
@@ -41,7 +41,8 @@ DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
static int printk_nmi_irq_ready;
atomic_t nmi_message_lost;
-#define NMI_LOG_BUF_LEN (4096 - sizeof(atomic_t) - sizeof(struct irq_work))
+#define NMI_LOG_BUF_LEN ((1 << CONFIG_NMI_LOG_BUF_SHIFT) - \
+ sizeof(atomic_t) - sizeof(struct irq_work))
struct nmi_seq_buf {
atomic_t len; /* length of written data */
--
1.8.5.6
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web