aboutsummaryrefslogtreecommitdiffstats
path: root/features/rt/printk-track-limit-recursion.patch
diff options
context:
space:
mode:
Diffstat (limited to 'features/rt/printk-track-limit-recursion.patch')
-rw-r--r--features/rt/printk-track-limit-recursion.patch142
1 files changed, 142 insertions, 0 deletions
diff --git a/features/rt/printk-track-limit-recursion.patch b/features/rt/printk-track-limit-recursion.patch
new file mode 100644
index 00000000..0eba8c25
--- /dev/null
+++ b/features/rt/printk-track-limit-recursion.patch
@@ -0,0 +1,142 @@
+From 23b2babe079f76add633021e717676da7f238ff8 Mon Sep 17 00:00:00 2001
+From: John Ogness <john.ogness@linutronix.de>
+Date: Fri, 11 Dec 2020 00:55:25 +0106
+Subject: [PATCH 021/191] printk: track/limit recursion
+
+Limit printk() recursion to 1 level. This is enough to print a
+stacktrace for the printk call, should a WARN or BUG occur.
+
+Signed-off-by: John Ogness <john.ogness@linutronix.de>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/printk/printk.c | 74 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 71 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
+index 523621889a72..008a0ede8b05 100644
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -1940,6 +1940,65 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
+ }
+ }
+
++#ifdef CONFIG_PRINTK_NMI
++#define NUM_RECURSION_CTX 2
++#else
++#define NUM_RECURSION_CTX 1
++#endif
++
++struct printk_recursion {
++ char count[NUM_RECURSION_CTX];
++};
++
++static DEFINE_PER_CPU(struct printk_recursion, percpu_printk_recursion);
++static char printk_recursion_count[NUM_RECURSION_CTX];
++
++static char *printk_recursion_counter(void)
++{
++ struct printk_recursion *rec;
++ char *count;
++
++ if (!printk_percpu_data_ready()) {
++ count = &printk_recursion_count[0];
++ } else {
++ rec = this_cpu_ptr(&percpu_printk_recursion);
++
++ count = &rec->count[0];
++ }
++
++#ifdef CONFIG_PRINTK_NMI
++ if (in_nmi())
++ count++;
++#endif
++
++ return count;
++}
++
++static bool printk_enter_irqsave(unsigned long *flags)
++{
++ char *count;
++
++ local_irq_save(*flags);
++ count = printk_recursion_counter();
++ /* Only 1 level of recursion allowed. */
++ if (*count > 1) {
++ local_irq_restore(*flags);
++ return false;
++ }
++ (*count)++;
++
++ return true;
++}
++
++static void printk_exit_irqrestore(unsigned long flags)
++{
++ char *count;
++
++ count = printk_recursion_counter();
++ (*count)--;
++ local_irq_restore(flags);
++}
++
+ int printk_delay_msec __read_mostly;
+
+ static inline void printk_delay(void)
+@@ -2040,11 +2099,13 @@ int vprintk_store(int facility, int level,
+ struct prb_reserved_entry e;
+ enum log_flags lflags = 0;
+ struct printk_record r;
++ unsigned long irqflags;
+ u16 trunc_msg_len = 0;
+ char prefix_buf[8];
+ u16 reserve_size;
+ va_list args2;
+ u16 text_len;
++ int ret = 0;
+ u64 ts_nsec;
+
+ /*
+@@ -2055,6 +2116,9 @@ int vprintk_store(int facility, int level,
+ */
+ ts_nsec = local_clock();
+
++ if (!printk_enter_irqsave(&irqflags))
++ return 0;
++
+ /*
+ * The sprintf needs to come first since the syslog prefix might be
+ * passed in as a parameter. An extra byte must be reserved so that
+@@ -2092,7 +2156,8 @@ int vprintk_store(int facility, int level,
+ prb_commit(&e);
+ }
+
+- return text_len;
++ ret = text_len;
++ goto out;
+ }
+ }
+
+@@ -2108,7 +2173,7 @@ int vprintk_store(int facility, int level,
+
+ prb_rec_init_wr(&r, reserve_size + trunc_msg_len);
+ if (!prb_reserve(&e, prb, &r))
+- return 0;
++ goto out;
+ }
+
+ /* fill message */
+@@ -2130,7 +2195,10 @@ int vprintk_store(int facility, int level,
+ else
+ prb_final_commit(&e);
+
+- return (text_len + trunc_msg_len);
++ ret = text_len + trunc_msg_len;
++out:
++ printk_exit_irqrestore(irqflags);
++ return ret;
+ }
+
+ asmlinkage int vprintk_emit(int facility, int level,
+--
+2.19.1
+