diff options
Diffstat (limited to 'debian/patches-rt/0096-printk-Disable-passing-console-lock-owner-completely.patch')
-rw-r--r-- | debian/patches-rt/0096-printk-Disable-passing-console-lock-owner-completely.patch | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/debian/patches-rt/0096-printk-Disable-passing-console-lock-owner-completely.patch b/debian/patches-rt/0096-printk-Disable-passing-console-lock-owner-completely.patch new file mode 100644 index 0000000000..d5dcdcdccc --- /dev/null +++ b/debian/patches-rt/0096-printk-Disable-passing-console-lock-owner-completely.patch @@ -0,0 +1,107 @@ +From: Petr Mladek <pmladek@suse.com> +Date: Fri, 13 Oct 2023 14:12:05 +0000 +Subject: [PATCH 096/134] printk: Disable passing console lock owner completely + during panic() +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patches-6.6.7-rt18.tar.xz + +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(+) + +--- 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 + { + 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; |