mirror of
https://github.com/OpenVoiceOS/OpenVoiceOS
synced 2025-02-08 07:58:47 +01:00
113 lines
3.9 KiB
Diff
113 lines
3.9 KiB
Diff
From 26cfcd2b7ac7c9cec2b1e881132832009a13e3e3 Mon Sep 17 00:00:00 2001
|
|
From: Petr Mladek <pmladek@suse.com>
|
|
Date: Fri, 13 Oct 2023 14:12:05 +0000
|
|
Subject: [PATCH 123/195] printk: Disable passing console lock owner completely
|
|
during panic()
|
|
|
|
The commit d51507098ff91 ("printk: disable optimistic spin
|
|
during panic") added checks to avoid becoming a console waiter
|
|
if a panic is in progress.
|
|
|
|
However, the transition to panic can occur while there is
|
|
already a waiter. The current owner should not pass the lock to
|
|
the waiter because it might get stopped or blocked anytime.
|
|
|
|
Also the panic context might pass the console lock owner to an
|
|
already stopped waiter by mistake. It might happen when
|
|
console_flush_on_panic() ignores the current lock owner, for
|
|
example:
|
|
|
|
CPU0 CPU1
|
|
---- ----
|
|
console_lock_spinning_enable()
|
|
console_trylock_spinning()
|
|
[CPU1 now console waiter]
|
|
NMI: panic()
|
|
panic_other_cpus_shutdown()
|
|
[stopped as console waiter]
|
|
console_flush_on_panic()
|
|
console_lock_spinning_enable()
|
|
[print 1 record]
|
|
console_lock_spinning_disable_and_check()
|
|
[handover to stopped CPU1]
|
|
|
|
This results in panic() not flushing the panic messages.
|
|
|
|
Fix these problems by disabling all spinning operations
|
|
completely during panic().
|
|
|
|
Another advantage is that it prevents possible deadlocks caused
|
|
by "console_owner_lock". The panic() context does not need to
|
|
take it any longer. The lockless checks are safe because the
|
|
functions become NOPs when they see the panic in progress. All
|
|
operations manipulating the state are still synchronized by the
|
|
lock even when non-panic CPUs would notice the panic
|
|
synchronously.
|
|
|
|
The current owner might stay spinning. But non-panic() CPUs
|
|
would get stopped anyway and the panic context will never start
|
|
spinning.
|
|
|
|
Fixes: dbdda842fe96 ("printk: Add console owner and waiter logic to load balance console writes")
|
|
Signed-off-by: Petr Mladek <pmladek@suse.com>
|
|
Signed-off-by: John Ogness <john.ogness@linutronix.de>
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
kernel/printk/printk.c | 29 +++++++++++++++++++++++++++++
|
|
1 file changed, 29 insertions(+)
|
|
|
|
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
|
|
index e7b9a22f9a3a..2a45097c9a4c 100644
|
|
--- a/kernel/printk/printk.c
|
|
+++ b/kernel/printk/printk.c
|
|
@@ -1870,10 +1870,23 @@ static bool console_waiter;
|
|
*/
|
|
static void console_lock_spinning_enable(void)
|
|
{
|
|
+ /*
|
|
+ * Do not use spinning in panic(). The panic CPU wants to keep the lock.
|
|
+ * Non-panic CPUs abandon the flush anyway.
|
|
+ *
|
|
+ * Just keep the lockdep annotation. The panic-CPU should avoid
|
|
+ * taking console_owner_lock because it might cause a deadlock.
|
|
+ * This looks like the easiest way how to prevent false lockdep
|
|
+ * reports without handling races a lockless way.
|
|
+ */
|
|
+ if (panic_in_progress())
|
|
+ goto lockdep;
|
|
+
|
|
raw_spin_lock(&console_owner_lock);
|
|
console_owner = current;
|
|
raw_spin_unlock(&console_owner_lock);
|
|
|
|
+lockdep:
|
|
/* The waiter may spin on us after setting console_owner */
|
|
spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_);
|
|
}
|
|
@@ -1898,6 +1911,22 @@ static int console_lock_spinning_disable_and_check(int cookie)
|
|
{
|
|
int waiter;
|
|
|
|
+ /*
|
|
+ * Ignore spinning waiters during panic() because they might get stopped
|
|
+ * or blocked at any time,
|
|
+ *
|
|
+ * It is safe because nobody is allowed to start spinning during panic
|
|
+ * in the first place. If there has been a waiter then non panic CPUs
|
|
+ * might stay spinning. They would get stopped anyway. The panic context
|
|
+ * will never start spinning and an interrupted spin on panic CPU will
|
|
+ * never continue.
|
|
+ */
|
|
+ if (panic_in_progress()) {
|
|
+ /* Keep lockdep happy. */
|
|
+ spin_release(&console_owner_dep_map, _THIS_IP_);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
raw_spin_lock(&console_owner_lock);
|
|
waiter = READ_ONCE(console_waiter);
|
|
console_owner = NULL;
|
|
--
|
|
2.43.0
|
|
|