summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-07-22 17:58:40 +0200
committerClark Williams <williams@redhat.com>2012-04-10 16:40:09 -0500
commit380adfc71a6a9c88f4c843ad51d48bdde2aac959 (patch)
tree788afb5540fda4037c14801c24be81a7affb0f60
parent7d77369a3c89b65eeeb1b030d23c6abee3c36982 (diff)
printk-kill.patch
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/printk.h3
-rw-r--r--kernel/printk.c33
-rw-r--r--kernel/watchdog.c15
3 files changed, 48 insertions, 3 deletions
diff --git a/include/linux/printk.h b/include/linux/printk.h
index c8d7f7be2e5b..d5e6eed93fb7 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -91,9 +91,11 @@ int no_printk(const char *fmt, ...)
#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
+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
extern int printk_needs_cpu(int cpu);
@@ -119,7 +121,6 @@ extern int __printk_ratelimit(const char *func);
#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;
diff --git a/kernel/printk.c b/kernel/printk.c
index c4426061e228..5a172f9e5027 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -538,6 +538,32 @@ asmlinkage void early_printk(const char *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
static bool __read_mostly ignore_loglevel;
@@ -862,6 +888,13 @@ asmlinkage int vprintk(const char *fmt, va_list args)
size_t plen;
char special;
+ /*
+ * 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();
printk_delay();
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index df30ee08bdd4..de08263ff8ae 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -201,6 +201,8 @@ static int is_softlockup(unsigned long touch_ts)
#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,
@@ -235,10 +237,19 @@ static void watchdog_overflow_callback(struct perf_event *event,
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;