Patch "printk: Disable passing console lock owner completely during panic()" has been added to the 6.7-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    printk: Disable passing console lock owner completely during panic()

to the 6.7-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     printk-disable-passing-console-lock-owner-completely.patch
and it can be found in the queue-6.7 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit c7dbe73fe45a844f69aaafabe760331f73f40956
Author: Petr Mladek <pmladek@xxxxxxxx>
Date:   Wed Feb 7 14:47:00 2024 +0106

    printk: Disable passing console lock owner completely during panic()
    
    [ Upstream commit d04d5882cd678b898a9d7c5aee6afbe9e6e77fcd ]
    
    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: John Ogness <john.ogness@xxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20240207134103.1357162-12-john.ogness@xxxxxxxxxxxxx
    Signed-off-by: Petr Mladek <pmladek@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b7e50f8438df3..72f6a564e832f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1869,10 +1869,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_);
 }
@@ -1897,6 +1910,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;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux