Skip to content

Commit

Permalink
printk/nmi: warn when some message has been lost in NMI context
Browse files Browse the repository at this point in the history
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.

[[email protected]: whitespace fixlet]
Signed-off-by: Petr Mladek <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Russell King <[email protected]>
Cc: Daniel Thompson <[email protected]>
Cc: Jiri Kosina <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: David Miller <[email protected]>
Cc: Daniel Thompson <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
pmladek authored and torvalds committed May 21, 2016
1 parent 42a0bb3 commit b522dea
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
11 changes: 11 additions & 0 deletions kernel/printk/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@ 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 */
5 changes: 4 additions & 1 deletion kernel/printk/nmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions kernel/printk/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit b522dea

Please sign in to comment.