summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0113-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/patches-rt/0113-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch211
1 files changed, 211 insertions, 0 deletions
diff --git a/debian/patches-rt/0113-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch b/debian/patches-rt/0113-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch
new file mode 100644
index 000000000..a73363867
--- /dev/null
+++ b/debian/patches-rt/0113-printk-Avoid-console_lock-dance-if-no-legacy-or-boot.patch
@@ -0,0 +1,211 @@
+From: John Ogness <john.ogness@linutronix.de>
+Date: Tue, 26 Sep 2023 12:44:07 +0000
+Subject: [PATCH 113/134] printk: Avoid console_lock dance if no legacy or boot
+ consoles
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patches-6.6.7-rt18.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.
+
+Also, if boot consoles are registered, nbcon consoles must
+perform their atomic printing under the console lock in order
+to be synchronized with boot consoles.
+
+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>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/printk/internal.h | 12 +++++++++
+ kernel/printk/printk.c | 59 +++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 56 insertions(+), 15 deletions(-)
+
+--- a/kernel/printk/internal.h
++++ b/kernel/printk/internal.h
+@@ -44,6 +44,16 @@ enum printk_info_flags {
+ };
+
+ extern struct printk_ringbuffer *prb;
++extern bool have_legacy_console;
++extern 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)
+
+ __printf(4, 0)
+ int vprintk_store(int facility, int level,
+@@ -122,6 +132,8 @@ static inline bool console_is_usable(str
+ #define PRINTK_MESSAGE_MAX 0
+ #define PRINTKRB_RECORD_MAX 0
+
++#define printing_via_unlock (false)
++
+ /*
+ * In !PRINTK builds we still export console_sem
+ * semaphore and some of console functions (console_unlock()/etc.), so
+--- 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/console_unlock dance
++ * whenever console flushing should occur.
++ */
++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
+@@ -2345,7 +2352,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
+@@ -2646,7 +2653,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 +3196,8 @@ void console_flush_on_panic(enum con_flu
+
+ nbcon_atomic_flush_all();
+
+- console_flush_all(false, &next_seq, &handover);
++ if (printing_via_unlock)
++ console_flush_all(false, &next_seq, &handover);
+ }
+
+ /*
+@@ -3514,8 +3522,11 @@ void register_console(struct console *ne
+ newcon->dropped = 0;
+ console_init_seq(newcon, bootcon_registered);
+
+- if (newcon->flags & CON_NBCON)
++ if (newcon->flags & CON_NBCON) {
+ nbcon_init(newcon);
++ } else {
++ have_legacy_console = true;
++ }
+
+ if (newcon->flags & CON_BOOT)
+ have_boot_console = true;
+@@ -3572,6 +3583,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;
+ struct console *c;
+ int res;
+@@ -3628,9 +3640,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 = false;
++ if (!found_legacy_con)
++ have_legacy_console = false;
+
+ return res;
+ }
+@@ -3782,6 +3798,7 @@ static bool __pr_flush(struct console *c
+ u64 last_diff = 0;
+ u64 printk_seq;
+ short flags;
++ bool locked;
+ int cookie;
+ u64 diff;
+ u64 seq;
+@@ -3791,22 +3808,28 @@ 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;
+
++ locked = false;
+ diff = 0;
+
+- /*
+- * 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();
++ if (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.
++ */
++ console_lock();
++ locked = true;
++ }
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+@@ -3826,6 +3849,7 @@ static bool __pr_flush(struct console *c
+ if (flags & CON_NBCON) {
+ printk_seq = nbcon_seq_read(c);
+ } else {
++ WARN_ON_ONCE(!locked);
+ printk_seq = c->seq;
+ }
+
+@@ -3837,7 +3861,8 @@ static bool __pr_flush(struct console *c
+ if (diff != last_diff && reset_on_progress)
+ remaining_jiffies = timeout_jiffies;
+
+- console_unlock();
++ if (locked)
++ console_unlock();
+
+ /* Note: @diff is 0 if there are no usable consoles. */
+ if (diff == 0 || remaining_jiffies == 0)
+@@ -3959,7 +3984,11 @@ void defer_console_output(void)
+ * New messages may have been added directly to the ringbuffer
+ * using vprintk_store(), so wake any waiters as well.
+ */
+- __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
++ int val = PRINTK_PENDING_WAKEUP;
++
++ if (printing_via_unlock)
++ val |= PRINTK_PENDING_OUTPUT;
++ __wake_up_klogd(val);
+ }
+
+ void printk_trigger_flush(void)