[RFC][PATCHv5 09/13] printk: add auto-emergency enforcement mechanism

Sergey Senozhatsky
2017-08-15T03:00:40Z

Do not blindly offload printing, but check if offloading has
been successful. If we can't offload from this CPU for some
time, then we declare printk emergency and switch to old
printk behaviour (print all the pending messages with out
any offloading).

Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
kernel/printk/printk.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 12284aa30025..71950bd85eac 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -558,6 +558,15 @@ static inline void adj_atomic_print_limit(void)
#endif
}

+static inline unsigned long emergency_timeout(unsigned long ts)
+{
+#ifdef CONFIG_LOCKUP_DETECTOR
+ if (watchdog_thresh)
+ return ts + 2 * watchdog_thresh;
+#endif
+ return ts + 10 * atomic_print_limit;
+}
+
/*
* Under heavy printing load or with a slow serial console (or both)
* console_unlock() can stall CPUs, which can result in soft/hard-lockups,
@@ -571,6 +580,7 @@ static inline bool console_offload_printing(void)
{
static struct task_struct *printing_task;
static unsigned long printing_start_ts;
+ static unsigned long saved_csw;
unsigned long now = local_clock() >> 30LL; /* seconds */

if (printk_kthread_should_stop())
@@ -585,6 +595,7 @@ static inline bool console_offload_printing(void)
/* A new task - reset the counters. */
if (printing_task != current) {
printing_start_ts = local_clock() >> 30LL;
+ saved_csw = current->nvcsw + current->nivcsw;
printing_task = current;
return false;
}
@@ -598,6 +609,17 @@ static inline bool console_offload_printing(void)
if (!time_after_eq(now, printing_start_ts + atomic_print_limit))
return false;

+ /*
+ * A trivial emergency enforcement - give up on printk_kthread if
+ * we can't wake it up.
+ */
+ if (time_after_eq(now, emergency_timeout(printing_start_ts)) &&
+ saved_csw == (current->nvcsw + current->nivcsw)) {
+ printk_enforce_emergency = true;
+ pr_crit("Declaring printk emergency mode.\n");
+ return true;
+ }
+
/*
* We try to set `printk_kthread' CPU affinity to any online CPU
* except for this_cpu. Because otherwise `printk_kthread' may be
--
2.14.1