printk/nmi: flush NMI messages on the system panic
[cascardo/linux.git] / kernel / printk / nmi.c
index bf08557..b69eb8a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/preempt.h>
 #include <linux/spinlock.h>
+#include <linux/debug_locks.h>
 #include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/irq_work.h>
@@ -106,7 +107,16 @@ static void print_nmi_seq_line(struct nmi_seq_buf *s, int start, int end)
 {
        const char *buf = s->buffer + start;
 
-       printk("%.*s", (end - start) + 1, buf);
+       /*
+        * The buffers are flushed in NMI only on panic.  The messages must
+        * go only into the ring buffer at this stage.  Consoles will get
+        * explicitly called later when a crashdump is not generated.
+        */
+       if (in_nmi())
+               printk_deferred("%.*s", (end - start) + 1, buf);
+       else
+               printk("%.*s", (end - start) + 1, buf);
+
 }
 
 /*
@@ -194,6 +204,33 @@ void printk_nmi_flush(void)
                __printk_nmi_flush(&per_cpu(nmi_print_seq, cpu).work);
 }
 
+/**
+ * printk_nmi_flush_on_panic - flush all per-cpu nmi buffers when the system
+ *     goes down.
+ *
+ * Similar to printk_nmi_flush() but it can be called even in NMI context when
+ * the system goes down. It does the best effort to get NMI messages into
+ * the main ring buffer.
+ *
+ * Note that it could try harder when there is only one CPU online.
+ */
+void printk_nmi_flush_on_panic(void)
+{
+       /*
+        * Make sure that we could access the main ring buffer.
+        * Do not risk a double release when more CPUs are up.
+        */
+       if (in_nmi() && raw_spin_is_locked(&logbuf_lock)) {
+               if (num_online_cpus() > 1)
+                       return;
+
+               debug_locks_off();
+               raw_spin_lock_init(&logbuf_lock);
+       }
+
+       printk_nmi_flush();
+}
+
 void __init printk_nmi_init(void)
 {
        int cpu;