219 lines
6.9 KiB
Diff
219 lines
6.9 KiB
Diff
From d0da2306d4d604ad861515b6b391bda5f4016622 Mon Sep 17 00:00:00 2001
|
|
From: John Ogness <john.ogness@linutronix.de>
|
|
Date: Tue, 26 Sep 2023 12:44:07 +0000
|
|
Subject: [PATCH 139/196] printk: Avoid console_lock dance if no legacy or boot
|
|
consoles
|
|
|
|
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(-)
|
|
|
|
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
|
|
index c4417fc48b7e..e2675981dfc5 100644
|
|
--- 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(struct console *con, short flags)
|
|
#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
|
|
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
|
|
index 8a023a6db7c9..26958c8b2810 100644
|
|
--- a/kernel/printk/printk.c
|
|
+++ b/kernel/printk/printk.c
|
|
@@ -463,6 +463,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
|
|
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
|
|
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
|
|
@@ -2345,7 +2352,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
|
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_flush_mode mode)
|
|
|
|
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 *newcon)
|
|
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(struct console *console)
|
|
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 *con, int timeout_ms, bool reset_on_progre
|
|
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 *con, int timeout_ms, bool reset_on_progre
|
|
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 *con, int timeout_ms, bool reset_on_progre
|
|
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 *con, int timeout_ms, bool reset_on_progre
|
|
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)
|
|
--
|
|
2.43.2
|
|
|