Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

printk: Add per-console suspended state

Currently the global @console_suspended is used to determine if
consoles are in a suspended state. Its primary purpose is to allow
usage of the console_lock when suspended without causing console
printing. It is synchronized by the console_lock.

Rather than relying on the console_lock to determine suspended
state, make it an official per-console state that is set within
console->flags. This allows the state to be queried via SRCU.

Remove @console_suspended. Console printing will still be avoided
when suspended because console_is_usable() returns false when
the new suspended flag is set for that console.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20230717194607.145135-7-john.ogness@linutronix.de

authored by

John Ogness and committed by
Petr Mladek
9e70a5e1 696ffaf5

+47 -30
+3
include/linux/console.h
··· 154 154 * receiving the printk spam for obvious reasons. 155 155 * @CON_EXTENDED: The console supports the extended output format of 156 156 * /dev/kmesg which requires a larger output buffer. 157 + * @CON_SUSPENDED: Indicates if a console is suspended. If true, the 158 + * printing callbacks must not be called. 157 159 */ 158 160 enum cons_flags { 159 161 CON_PRINTBUFFER = BIT(0), ··· 165 163 CON_ANYTIME = BIT(4), 166 164 CON_BRL = BIT(5), 167 165 CON_EXTENDED = BIT(6), 166 + CON_SUSPENDED = BIT(7), 168 167 }; 169 168 170 169 /**
+44 -30
kernel/printk/printk.c
··· 86 86 static DEFINE_MUTEX(console_mutex); 87 87 88 88 /* 89 - * console_sem protects updates to console->seq and console_suspended, 89 + * console_sem protects updates to console->seq 90 90 * and also provides serialization for console printing. 91 91 */ 92 92 static DEFINE_SEMAPHORE(console_sem); ··· 359 359 * paths in the console code where we end up in places I want 360 360 * locked without the console semaphore held). 361 361 */ 362 - static int console_locked, console_suspended; 362 + static int console_locked; 363 363 364 364 /* 365 365 * Array of consoles built from command line options (console=) ··· 2549 2549 */ 2550 2550 void suspend_console(void) 2551 2551 { 2552 + struct console *con; 2553 + 2552 2554 if (!console_suspend_enabled) 2553 2555 return; 2554 2556 pr_info("Suspending console(s) (use no_console_suspend to debug)\n"); 2555 2557 pr_flush(1000, true); 2556 - console_lock(); 2557 - console_suspended = 1; 2558 - up_console_sem(); 2558 + 2559 + console_list_lock(); 2560 + for_each_console(con) 2561 + console_srcu_write_flags(con, con->flags | CON_SUSPENDED); 2562 + console_list_unlock(); 2563 + 2564 + /* 2565 + * Ensure that all SRCU list walks have completed. All printing 2566 + * contexts must be able to see that they are suspended so that it 2567 + * is guaranteed that all printing has stopped when this function 2568 + * completes. 2569 + */ 2570 + synchronize_srcu(&console_srcu); 2559 2571 } 2560 2572 2561 2573 void resume_console(void) 2562 2574 { 2575 + struct console *con; 2576 + 2563 2577 if (!console_suspend_enabled) 2564 2578 return; 2565 - down_console_sem(); 2566 - console_suspended = 0; 2567 - console_unlock(); 2579 + 2580 + console_list_lock(); 2581 + for_each_console(con) 2582 + console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED); 2583 + console_list_unlock(); 2584 + 2585 + /* 2586 + * Ensure that all SRCU list walks have completed. All printing 2587 + * contexts must be able to see they are no longer suspended so 2588 + * that they are guaranteed to wake up and resume printing. 2589 + */ 2590 + synchronize_srcu(&console_srcu); 2591 + 2568 2592 pr_flush(1000, true); 2569 2593 } 2570 2594 ··· 2647 2623 msleep(1000); 2648 2624 2649 2625 down_console_sem(); 2650 - if (console_suspended) 2651 - return; 2652 2626 console_locked = 1; 2653 2627 console_may_schedule = 1; 2654 2628 } ··· 2667 2645 return 0; 2668 2646 if (down_trylock_console_sem()) 2669 2647 return 0; 2670 - if (console_suspended) { 2671 - up_console_sem(); 2672 - return 0; 2673 - } 2674 2648 console_locked = 1; 2675 2649 console_may_schedule = 0; 2676 2650 return 1; ··· 2690 2672 short flags = console_srcu_read_flags(con); 2691 2673 2692 2674 if (!(flags & CON_ENABLED)) 2675 + return false; 2676 + 2677 + if ((flags & CON_SUSPENDED)) 2693 2678 return false; 2694 2679 2695 2680 if (!con->write) ··· 3012 2991 bool handover; 3013 2992 bool flushed; 3014 2993 u64 next_seq; 3015 - 3016 - if (console_suspended) { 3017 - up_console_sem(); 3018 - return; 3019 - } 3020 2994 3021 2995 /* 3022 2996 * Console drivers are called with interrupts disabled, so ··· 3742 3726 3743 3727 /* 3744 3728 * Hold the console_lock to guarantee safe access to 3745 - * console->seq and to prevent changes to @console_suspended 3746 - * until all consoles have been processed. 3729 + * console->seq. 3747 3730 */ 3748 3731 console_lock(); 3749 3732 ··· 3750 3735 for_each_console_srcu(c) { 3751 3736 if (con && con != c) 3752 3737 continue; 3738 + /* 3739 + * If consoles are not usable, it cannot be expected 3740 + * that they make forward progress, so only increment 3741 + * @diff for usable consoles. 3742 + */ 3753 3743 if (!console_is_usable(c)) 3754 3744 continue; 3755 3745 printk_seq = c->seq; ··· 3763 3743 } 3764 3744 console_srcu_read_unlock(cookie); 3765 3745 3766 - /* 3767 - * If consoles are suspended, it cannot be expected that they 3768 - * make forward progress, so timeout immediately. @diff is 3769 - * still used to return a valid flush status. 3770 - */ 3771 - if (console_suspended) 3772 - remaining = 0; 3773 - else if (diff != last_diff && reset_on_progress) 3746 + if (diff != last_diff && reset_on_progress) 3774 3747 remaining = timeout_ms; 3775 3748 3776 3749 console_unlock(); 3777 3750 3751 + /* Note: @diff is 0 if there are no usable consoles. */ 3778 3752 if (diff == 0 || remaining == 0) 3779 3753 break; 3780 3754 ··· 3802 3788 * printer has been seen to make some forward progress. 3803 3789 * 3804 3790 * Context: Process context. May sleep while acquiring console lock. 3805 - * Return: true if all enabled printers are caught up. 3791 + * Return: true if all usable printers are caught up. 3806 3792 */ 3807 3793 static bool pr_flush(int timeout_ms, bool reset_on_progress) 3808 3794 {