blob: ff2ab2cdd7f1d9d77ddf18360c9c2ebd398842e9 [file] [log] [blame]
Subject: printk-kill.patch
From: Ingo Molnar <mingo@elte.hu>
Date: Fri, 22 Jul 2011 17:58:40 +0200
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/printk.h | 3 +
kernel/printk.c | 79 ++++++++++++++++++++++++++++++++++---------------
kernel/watchdog.c | 15 ++++++++-
3 files changed, 71 insertions(+), 26 deletions(-)
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -101,9 +101,11 @@ int no_printk(const char *fmt, ...)
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
void early_vprintk(const char *fmt, va_list ap);
+extern void printk_kill(void);
#else
static inline __printf(1, 2) __cold
void early_printk(const char *s, ...) { }
+static inline void printk_kill(void) { }
#endif
#ifdef CONFIG_PRINTK
@@ -137,7 +139,6 @@ extern int __printk_ratelimit(const char
#define printk_ratelimit() __printk_ratelimit(__func__)
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
unsigned int interval_msec);
-
extern int printk_delay_msec;
extern int dmesg_restrict;
extern int kptr_restrict;
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1493,6 +1493,55 @@ static size_t cont_print_text(char *text
return textlen;
}
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+void early_vprintk(const char *fmt, va_list ap)
+{
+ if (early_console) {
+ char buf[512];
+ int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+ early_console->write(early_console, buf, n);
+ }
+}
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ early_vprintk(fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * This is independent of any log levels - a global
+ * kill switch that turns off all of printk.
+ *
+ * Used by the NMI watchdog if early-printk is enabled.
+ */
+static bool __read_mostly printk_killswitch;
+
+void printk_kill(void)
+{
+ printk_killswitch = true;
+}
+
+static int forced_early_printk(const char *fmt, va_list ap)
+{
+ if (!printk_killswitch)
+ return 0;
+ early_vprintk(fmt, ap);
+ return 1;
+}
+#else
+static inline int forced_early_printk(const char *fmt, va_list ap)
+{
+ return 0;
+}
+#endif
+
asmlinkage int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
const char *fmt, va_list args)
@@ -1506,6 +1555,13 @@ asmlinkage int vprintk_emit(int facility
int this_cpu;
int printed_len = 0;
+ /*
+ * Fall back to early_printk if a debugging subsystem has
+ * killed printk output
+ */
+ if (unlikely(forced_early_printk(fmt, args)))
+ return 1;
+
boot_delay_msec(level);
printk_delay();
@@ -1728,29 +1784,6 @@ static size_t cont_print_text(char *text
#endif /* CONFIG_PRINTK */
-#ifdef CONFIG_EARLY_PRINTK
-struct console *early_console;
-
-void early_vprintk(const char *fmt, va_list ap)
-{
- if (early_console) {
- char buf[512];
- int n = vscnprintf(buf, sizeof(buf), fmt, ap);
-
- early_console->write(early_console, buf, n);
- }
-}
-
-asmlinkage void early_printk(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- early_vprintk(fmt, ap);
- va_end(ap);
-}
-#endif
-
static int __add_preferred_console(char *name, int idx, char *options,
char *brl_options)
{
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -205,6 +205,8 @@ static int is_softlockup(unsigned long t
#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static DEFINE_RAW_SPINLOCK(watchdog_output_lock);
+
static struct perf_event_attr wd_hw_attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
@@ -239,10 +241,19 @@ static void watchdog_overflow_callback(s
if (__this_cpu_read(hard_watchdog_warn) == true)
return;
- if (hardlockup_panic)
+ /*
+ * If early-printk is enabled then make sure we do not
+ * lock up in printk() and kill console logging:
+ */
+ printk_kill();
+
+ if (hardlockup_panic) {
panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
- else
+ } else {
+ raw_spin_lock(&watchdog_output_lock);
WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+ raw_spin_unlock(&watchdog_output_lock);
+ }
__this_cpu_write(hard_watchdog_warn, true);
return;