提交 b522deab 编写于 作者: P Petr Mladek 提交者: Linus Torvalds

printk/nmi: warn when some message has been lost in NMI context

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: NPetr 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>
Cc: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 42a0bb3f
...@@ -34,6 +34,12 @@ static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) ...@@ -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); 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 */ #else /* CONFIG_PRINTK_NMI */
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) 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) ...@@ -41,4 +47,9 @@ static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
return vprintk_default(fmt, args); return vprintk_default(fmt, args);
} }
static inline int get_nmi_message_lost(void)
{
return 0;
}
#endif /* CONFIG_PRINTK_NMI */ #endif /* CONFIG_PRINTK_NMI */
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
*/ */
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default; DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
static int printk_nmi_irq_ready; 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 (4096 - sizeof(atomic_t) - sizeof(struct irq_work))
...@@ -64,8 +65,10 @@ static int vprintk_nmi(const char *fmt, va_list args) ...@@ -64,8 +65,10 @@ static int vprintk_nmi(const char *fmt, va_list args)
again: again:
len = atomic_read(&s->len); len = atomic_read(&s->len);
if (len >= sizeof(s->buffer)) if (len >= sizeof(s->buffer)) {
atomic_inc(&nmi_message_lost);
return 0; return 0;
}
/* /*
* Make sure that all old data have been read before the buffer was * Make sure that all old data have been read before the buffer was
......
...@@ -1617,6 +1617,7 @@ asmlinkage int vprintk_emit(int facility, int level, ...@@ -1617,6 +1617,7 @@ asmlinkage int vprintk_emit(int facility, int level,
unsigned long flags; unsigned long flags;
int this_cpu; int this_cpu;
int printed_len = 0; int printed_len = 0;
int nmi_message_lost;
bool in_sched = false; bool in_sched = false;
/* cpu currently holding logbuf_lock in this function */ /* cpu currently holding logbuf_lock in this function */
static unsigned int logbuf_cpu = UINT_MAX; static unsigned int logbuf_cpu = UINT_MAX;
...@@ -1667,6 +1668,15 @@ asmlinkage int vprintk_emit(int facility, int level, ...@@ -1667,6 +1668,15 @@ asmlinkage int vprintk_emit(int facility, int level,
strlen(recursion_msg)); 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 * The printf needs to come first; we need the syslog
* prefix which might be passed-in as a parameter. * prefix which might be passed-in as a parameter.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册