[PATCH] kgdb: Fix broken handling of printk() in NMI context
From: Sumit Garg
Date: Tue May 12 2020 - 04:49:13 EST
Since commit 42a0bb3f7138 ("printk/nmi: generic solution for safe printk
in NMI"), kgdb entry in NMI context defaults to use safe NMI printk()
which involves CPU specific buffers and deferred printk() until exit from
NMI context.
But kgdb being a stop-the-world debugger, we don't want to defer printk()
especially backtrace on corresponding CPUs. So instead switch to normal
printk() mode in kgdb_cpu_enter() if entry is in NMI context.
Signed-off-by: Sumit Garg <sumit.garg@xxxxxxxxxx>
---
Similar change was posted earlier specific to arm64 here [1]. But after
discussions it emerged out that this broken handling of printk() in NMI
context should be a common problem that is relevant to other archs as well.
So fix this handling in kgdb_cpu_enter() as there can be multiple entry
points to kgdb in NMI context.
[1] https://lkml.org/lkml/2020/4/24/328
kernel/debug/debug_core.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index 2b7c9b6..ab2933f 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -567,6 +567,15 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
kgdb_info[ks->cpu].enter_kgdb++;
kgdb_info[ks->cpu].exception_state |= exception_state;
+ /*
+ * kgdb entry in NMI context defaults to use safe NMI printk() which
+ * involves CPU specific buffers and deferred printk() until exit from
+ * NMI context. But kgdb being a stop-the-world debugger, we don't want
+ * to defer printk(). So instead switch to normal printk() mode here.
+ */
+ if (in_nmi())
+ printk_nmi_exit();
+
if (exception_state == DCPU_WANT_MASTER)
atomic_inc(&masters_in_kgdb);
else
@@ -635,6 +644,8 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
atomic_dec(&slaves_in_kgdb);
dbg_touch_watchdogs();
local_irq_restore(flags);
+ if (in_nmi())
+ printk_nmi_enter();
return 0;
}
cpu_relax();
@@ -772,6 +783,8 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
raw_spin_unlock(&dbg_master_lock);
dbg_touch_watchdogs();
local_irq_restore(flags);
+ if (in_nmi())
+ printk_nmi_enter();
return kgdb_info[cpu].ret_state;
}
--
2.7.4