summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch')
-rw-r--r--debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch174
1 files changed, 174 insertions, 0 deletions
diff --git a/debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch b/debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch
new file mode 100644
index 000000000..54f3d96d2
--- /dev/null
+++ b/debian/patches-rt/0057-printk-Add-a-printk-kill-switch.patch
@@ -0,0 +1,174 @@
+From 0450159a3552782546de4c88cbeae98683079ee9 Mon Sep 17 00:00:00 2001
+From: Ingo Molnar <mingo@elte.hu>
+Date: Fri, 22 Jul 2011 17:58:40 +0200
+Subject: [PATCH 057/347] printk: Add a printk kill switch
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.246-rt110.tar.xz
+
+Add a prinkt-kill-switch. This is used from (NMI) watchdog to ensure that
+it does not dead-lock with the early printk code.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+---
+ include/linux/printk.h | 2 ++
+ kernel/printk/printk.c | 79 +++++++++++++++++++++++++++++++-----------
+ kernel/watchdog_hld.c | 10 ++++++
+ 3 files changed, 71 insertions(+), 20 deletions(-)
+
+diff --git a/include/linux/printk.h b/include/linux/printk.h
+index 6dd867e39365..b9d050428456 100644
+--- a/include/linux/printk.h
++++ b/include/linux/printk.h
+@@ -140,9 +140,11 @@ struct va_format {
+ #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
+
+ #ifdef CONFIG_PRINTK_NMI
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+index 2ba16c426ba5..963c20ab9548 100644
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -407,6 +407,58 @@ DEFINE_RAW_SPINLOCK(logbuf_lock);
+ printk_safe_exit_irqrestore(flags); \
+ } while (0)
+
++#ifdef CONFIG_EARLY_PRINTK
++struct console *early_console;
++
++static 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;
++}
++
++#ifdef CONFIG_PRINTK
++static int forced_early_printk(const char *fmt, va_list ap)
++{
++ if (!printk_killswitch)
++ return 0;
++ early_vprintk(fmt, ap);
++ return 1;
++}
++#endif
++
++#else
++static inline int forced_early_printk(const char *fmt, va_list ap)
++{
++ return 0;
++}
++#endif
++
+ #ifdef CONFIG_PRINTK
+ DECLARE_WAIT_QUEUE_HEAD(log_wait);
+ /* the next printk record to read by syslog(READ) or /proc/kmsg */
+@@ -1935,6 +1987,13 @@ asmlinkage int vprintk_emit(int facility, int level,
+ unsigned long flags;
+ u64 curr_log_seq;
+
++ /*
++ * Fall back to early_printk if a debugging subsystem has
++ * killed printk output
++ */
++ if (unlikely(forced_early_printk(fmt, args)))
++ return 1;
++
+ if (level == LOGLEVEL_SCHED) {
+ level = LOGLEVEL_DEFAULT;
+ in_sched = true;
+@@ -2079,26 +2138,6 @@ static bool suppress_message_printing(int level) { return false; }
+
+ #endif /* CONFIG_PRINTK */
+
+-#ifdef CONFIG_EARLY_PRINTK
+-struct console *early_console;
+-
+-asmlinkage __visible void early_printk(const char *fmt, ...)
+-{
+- va_list ap;
+- char buf[512];
+- int n;
+-
+- if (!early_console)
+- return;
+-
+- va_start(ap, fmt);
+- n = vscnprintf(buf, sizeof(buf), fmt, ap);
+- va_end(ap);
+-
+- early_console->write(early_console, buf, n);
+-}
+-#endif
+-
+ static int __add_preferred_console(char *name, int idx, char *options,
+ char *brl_options)
+ {
+diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
+index 71381168dede..685443375dc0 100644
+--- a/kernel/watchdog_hld.c
++++ b/kernel/watchdog_hld.c
+@@ -24,6 +24,8 @@ static DEFINE_PER_CPU(bool, hard_watchdog_warn);
+ static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+ static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+ static DEFINE_PER_CPU(struct perf_event *, dead_event);
++static DEFINE_RAW_SPINLOCK(watchdog_output_lock);
++
+ static struct cpumask dead_events_mask;
+
+ static unsigned long hardlockup_allcpu_dumped;
+@@ -134,6 +136,13 @@ static void watchdog_overflow_callback(struct perf_event *event,
+ /* only print hardlockups once */
+ if (__this_cpu_read(hard_watchdog_warn) == true)
+ return;
++ /*
++ * If early-printk is enabled then make sure we do not
++ * lock up in printk() and kill console logging:
++ */
++ printk_kill();
++
++ raw_spin_lock(&watchdog_output_lock);
+
+ pr_emerg("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+ print_modules();
+@@ -151,6 +160,7 @@ static void watchdog_overflow_callback(struct perf_event *event,
+ !test_and_set_bit(0, &hardlockup_allcpu_dumped))
+ trigger_allbutself_cpu_backtrace();
+
++ raw_spin_unlock(&watchdog_output_lock);
+ if (hardlockup_panic)
+ nmi_panic(regs, "Hard LOCKUP");
+
+--
+2.36.1
+