aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2016-05-20 20:00:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-20 20:58:30 -0400
commitb522deabc6f18e4f938d93a84f345f2cbf3347d1 (patch)
tree297c5f13ffcb3521ea57f7f44bf78f6319de098d /kernel/printk
parent42a0bb3f71383b457a7db362f1c69e7afb96732b (diff)
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: 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> Cc: Daniel Thompson <daniel.thompson@linaro.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/printk')
-rw-r--r--kernel/printk/internal.h11
-rw-r--r--kernel/printk/nmi.c5
-rw-r--r--kernel/printk/printk.c10
3 files changed, 25 insertions, 1 deletions
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)
34 return this_cpu_read(printk_func)(fmt, args); 34 return this_cpu_read(printk_func)(fmt, args);
35} 35}
36 36
37extern atomic_t nmi_message_lost;
38static inline int get_nmi_message_lost(void)
39{
40 return atomic_xchg(&nmi_message_lost, 0);
41}
42
37#else /* CONFIG_PRINTK_NMI */ 43#else /* CONFIG_PRINTK_NMI */
38 44
39static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) 45static 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 return vprintk_default(fmt, args); 47 return vprintk_default(fmt, args);
42} 48}
43 49
50static inline int get_nmi_message_lost(void)
51{
52 return 0;
53}
54
44#endif /* CONFIG_PRINTK_NMI */ 55#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 @@
39 */ 39 */
40DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default; 40DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
41static int printk_nmi_irq_ready; 41static int printk_nmi_irq_ready;
42atomic_t nmi_message_lost;
42 43
43#define NMI_LOG_BUF_LEN (4096 - sizeof(atomic_t) - sizeof(struct irq_work)) 44#define NMI_LOG_BUF_LEN (4096 - sizeof(atomic_t) - sizeof(struct irq_work))
44 45
@@ -64,8 +65,10 @@ static int vprintk_nmi(const char *fmt, va_list args)
64again: 65again:
65 len = atomic_read(&s->len); 66 len = atomic_read(&s->len);
66 67
67 if (len >= sizeof(s->buffer)) 68 if (len >= sizeof(s->buffer)) {
69 atomic_inc(&nmi_message_lost);
68 return 0; 70 return 0;
71 }
69 72
70 /* 73 /*
71 * Make sure that all old data have been read before the buffer was 74 * 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,
1617 unsigned long flags; 1617 unsigned long flags;
1618 int this_cpu; 1618 int this_cpu;
1619 int printed_len = 0; 1619 int printed_len = 0;
1620 int nmi_message_lost;
1620 bool in_sched = false; 1621 bool in_sched = false;
1621 /* cpu currently holding logbuf_lock in this function */ 1622 /* cpu currently holding logbuf_lock in this function */
1622 static unsigned int logbuf_cpu = UINT_MAX; 1623 static unsigned int logbuf_cpu = UINT_MAX;
@@ -1667,6 +1668,15 @@ asmlinkage int vprintk_emit(int facility, int level,
1667 strlen(recursion_msg)); 1668 strlen(recursion_msg));
1668 } 1669 }
1669 1670
1671 nmi_message_lost = get_nmi_message_lost();
1672 if (unlikely(nmi_message_lost)) {
1673 text_len = scnprintf(textbuf, sizeof(textbuf),
1674 "BAD LUCK: lost %d message(s) from NMI context!",
1675 nmi_message_lost);
1676 printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
1677 NULL, 0, textbuf, text_len);
1678 }
1679
1670 /* 1680 /*
1671 * The printf needs to come first; we need the syslog 1681 * The printf needs to come first; we need the syslog
1672 * prefix which might be passed-in as a parameter. 1682 * prefix which might be passed-in as a parameter.