[PATCH 05/10] printk: Try hard to print Oops message in NMI context

From: Petr Mladek
Date: Mon May 25 2015 - 08:47:12 EST


Oops messages are important for debugging. We should try harder to get
them into the ring buffer and print them to the console. This is
problematic in NMI context because the needed locks might
already be taken.

What we can do, though, is to zap all printk locks. We already do this
when a printk recursion is detected. This should be safe because
the system is crashing and there shouldn't be any printk caller
that would cause the deadlock.

Signed-off-by: Petr Mladek <pmladek@xxxxxxx>
---
kernel/printk/printk.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c2ae9ff388ae..8fb0aaaa6258 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1672,14 +1672,20 @@ static size_t cont_print_text(char *text, size_t size)
*/
#define TRY_LOCKBUF_LOCK_MAX_DELAY_NS 100000UL

-/* We must be careful in NMI when we managed to preempt a running printk */
+/*
+ * We must be careful in NMI when we managed to preempt a running printk.
+ * Special case are Oops messages from NMI context. We try hard to print
+ * them and forcefully drop existing locks.
+ */
static int try_logbuf_lock_in_nmi(void)
{
u64 start_time, current_time;
int this_cpu = smp_processor_id();

- /* no way if we are already locked on this CPU */
- if (logbuf_cpu == this_cpu)
+ if (oops_in_progress)
+ zap_locks();
+ else if (logbuf_cpu == this_cpu)
+ /* no way if we are already locked on this CPU */
return 0;

/* try hard to get the lock but do not wait forever */
@@ -1876,8 +1882,13 @@ asmlinkage int vprintk_emit(int facility, int level,
/*
* If called from the scheduler or NMI context, we can not get console
* without a possible deadlock.
+ *
+ * The only exception are Oops messages from NMI context where all
+ * relevant locks have been forcefully dropped in
+ * try_logbuf_lock_in_nmi(). We have to try to get the console,
+ * otherwise the last messages would get lost.
*/
- if (in_sched || in_nmi()) {
+ if (in_sched || (in_nmi() && !oops_in_progress)) {
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
} else {
--
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/