diff options
Diffstat (limited to 'debian/patches-rt/0022-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch')
-rw-r--r-- | debian/patches-rt/0022-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/debian/patches-rt/0022-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch b/debian/patches-rt/0022-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch new file mode 100644 index 0000000000..1cfd27dd5d --- /dev/null +++ b/debian/patches-rt/0022-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch @@ -0,0 +1,207 @@ +From: John Ogness <john.ogness@linutronix.de> +Date: Tue, 26 Sep 2023 12:44:07 +0000 +Subject: [PATCH 22/46] printk: Avoid console_lock dance if no legacy or boot + consoles +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.9/older/patches-6.9-rt5.tar.xz + +Currently the console lock is used to attempt legacy-type +printing even if there are no legacy or boot consoles registered. +If no such consoles are registered, the console lock does not +need to be taken. + +Add tracking of legacy console registration and use it with +boot console tracking to avoid unnecessary code paths, i.e. +do not use the console lock if there are no boot consoles +and no legacy consoles. + +Signed-off-by: John Ogness <john.ogness@linutronix.de> +Reviewed-by: Petr Mladek <pmladek@suse.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + kernel/printk/printk.c | 78 +++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 63 insertions(+), 15 deletions(-) + +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -464,6 +464,13 @@ static int console_msg_format = MSG_FORM + static DEFINE_MUTEX(syslog_lock); + + /* ++ * Specifies if a legacy console is registered. If legacy consoles are ++ * present, it is necessary to perform the console lock/unlock dance ++ * whenever console flushing should occur. ++ */ ++static bool have_legacy_console; ++ ++/* + * Specifies if a boot console is registered. If boot consoles are present, + * nbcon consoles cannot print simultaneously and must be synchronized by + * the console lock. This is because boot consoles and nbcon consoles may +@@ -471,6 +478,14 @@ static DEFINE_MUTEX(syslog_lock); + */ + static bool have_boot_console; + ++/* ++ * Specifies if the console lock/unlock dance is needed for console ++ * printing. If @have_boot_console is true, the nbcon consoles will ++ * be printed serially along with the legacy consoles because nbcon ++ * consoles cannot print simultaneously with boot consoles. ++ */ ++#define printing_via_unlock (have_legacy_console || have_boot_console) ++ + #ifdef CONFIG_PRINTK + DECLARE_WAIT_QUEUE_HEAD(log_wait); + /* All 3 protected by @syslog_lock. */ +@@ -2339,7 +2354,7 @@ asmlinkage int vprintk_emit(int facility + printed_len = vprintk_store(facility, level, dev_info, fmt, args); + + /* If called from the scheduler, we can not call up(). */ +- if (!in_sched) { ++ if (!in_sched && printing_via_unlock) { + /* + * The caller may be holding system-critical or + * timing-sensitive locks. Disable preemption during +@@ -2648,7 +2663,7 @@ void resume_console(void) + */ + static int console_cpu_notify(unsigned int cpu) + { +- if (!cpuhp_tasks_frozen) { ++ if (!cpuhp_tasks_frozen && printing_via_unlock) { + /* If trylock fails, someone else is doing the printing */ + if (console_trylock()) + console_unlock(); +@@ -3189,7 +3204,8 @@ void console_flush_on_panic(enum con_flu + + nbcon_atomic_flush_pending(); + +- console_flush_all(false, &next_seq, &handover); ++ if (printing_via_unlock) ++ console_flush_all(false, &next_seq, &handover); + } + + /* +@@ -3538,6 +3554,7 @@ void register_console(struct console *ne + if (newcon->flags & CON_NBCON) { + nbcon_init(newcon, init_seq); + } else { ++ have_legacy_console = true; + newcon->seq = init_seq; + } + +@@ -3613,6 +3630,7 @@ EXPORT_SYMBOL(register_console); + /* Must be called under console_list_lock(). */ + static int unregister_console_locked(struct console *console) + { ++ bool found_legacy_con = false; + bool found_boot_con = false; + unsigned long flags; + struct console *c; +@@ -3680,9 +3698,13 @@ static int unregister_console_locked(str + for_each_console(c) { + if (c->flags & CON_BOOT) + found_boot_con = true; ++ if (!(c->flags & CON_NBCON)) ++ found_legacy_con = true; + } + if (!found_boot_con) + have_boot_console = found_boot_con; ++ if (!found_legacy_con) ++ have_legacy_console = found_legacy_con; + + return res; + } +@@ -3843,22 +3865,34 @@ static bool __pr_flush(struct console *c + seq = prb_next_reserve_seq(prb); + + /* Flush the consoles so that records up to @seq are printed. */ +- console_lock(); +- console_unlock(); ++ if (printing_via_unlock) { ++ console_lock(); ++ console_unlock(); ++ } + + for (;;) { + unsigned long begin_jiffies; + unsigned long slept_jiffies; +- +- diff = 0; ++ bool use_console_lock = printing_via_unlock; + + /* +- * Hold the console_lock to guarantee safe access to +- * console->seq. Releasing console_lock flushes more +- * records in case @seq is still not printed on all +- * usable consoles. ++ * Ensure the compiler does not optimize @use_console_lock to ++ * be @printing_via_unlock since the latter can change at any ++ * time. + */ +- console_lock(); ++ barrier(); ++ ++ diff = 0; ++ ++ if (use_console_lock) { ++ /* ++ * Hold the console_lock to guarantee safe access to ++ * console->seq. Releasing console_lock flushes more ++ * records in case @seq is still not printed on all ++ * usable consoles. ++ */ ++ console_lock(); ++ } + + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { +@@ -3878,6 +3912,7 @@ static bool __pr_flush(struct console *c + if (flags & CON_NBCON) { + printk_seq = nbcon_seq_read(c); + } else { ++ WARN_ON_ONCE(!use_console_lock); + printk_seq = c->seq; + } + +@@ -3889,7 +3924,8 @@ static bool __pr_flush(struct console *c + if (diff != last_diff && reset_on_progress) + remaining_jiffies = timeout_jiffies; + +- console_unlock(); ++ if (use_console_lock) ++ console_unlock(); + + /* Note: @diff is 0 if there are no usable consoles. */ + if (diff == 0 || remaining_jiffies == 0) +@@ -3959,6 +3995,7 @@ static void __wake_up_klogd(int val) + return; + + preempt_disable(); ++ + /* + * Guarantee any new records can be seen by tasks preparing to wait + * before this context checks if the wait queue is empty. +@@ -3970,11 +4007,22 @@ static void __wake_up_klogd(int val) + * + * This pairs with devkmsg_read:A and syslog_print:A. + */ +- if (wq_has_sleeper(&log_wait) || /* LMM(__wake_up_klogd:A) */ +- (val & PRINTK_PENDING_OUTPUT)) { ++ if (!wq_has_sleeper(&log_wait)) /* LMM(__wake_up_klogd:A) */ ++ val &= ~PRINTK_PENDING_WAKEUP; ++ ++ /* ++ * Simple read is safe. register_console() would flush a newly ++ * registered legacy console when writing the message about it ++ * being enabled. ++ */ ++ if (!printing_via_unlock) ++ val &= ~PRINTK_PENDING_OUTPUT; ++ ++ if (val) { + this_cpu_or(printk_pending, val); + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); + } ++ + preempt_enable(); + } + |