[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20250915-printk_legacy_thread_console_lock-v1-2-f34d42a9bcb3@thegoodpenguin.co.uk>
Date: Mon, 15 Sep 2025 13:43:06 +0100
From: Andrew Murray <amurray@...goodpenguin.co.uk>
To: Petr Mladek <pmladek@...e.com>, Steven Rostedt <rostedt@...dmis.org>,
John Ogness <john.ogness@...utronix.de>,
Sergey Senozhatsky <senozhatsky@...omium.org>
Cc: linux-kernel@...r.kernel.org,
Andrew Murray <amurray@...goodpenguin.co.uk>
Subject: [PATCH RFC 2/2] printk: Use console_flush_one_record for legacy
printer kthread
The legacy printer kthread uses console_lock and
__console_flush_and_unlock to flush records to the console. This
approach results in the console_lock being held for the entire
duration of a flush. This can result in large waiting times for
those waiting for console_lock especially where there is a large
volume of records or where the console is slow (e.g. serial). This
contention is observed during boot, as the call to filp_open in
console_on_rootfs will delay progression to userspace until any
in-flight flush is completed.
Let's instead use __console_flush_unlocked which releases and
reacquires console_lock between records.
Signed-off-by: Andrew Murray <amurray@...goodpenguin.co.uk>
---
kernel/printk/printk.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 75a3c47e9c0e645a3198c5f56e47df2a8d1871e6..53daab5cdee537c2ff55702104e495005352db1b 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3301,6 +3301,46 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
return any_usable;
}
+/*
+ * Print out all remaining records to all consoles.
+ *
+ * @next_seq is set to the sequence number after the last available record.
+ * The value is valid only when this function returns true. It means that all
+ * usable consoles are completely flushed.
+ *
+ * @handover will be set to true if a printk waiter has taken over the
+ * console_lock, in which case the caller is no longer holding the
+ * console_lock. Otherwise it is set to false.
+ *
+ * Returns true when there was at least one usable console and all messages
+ * were flushed to all usable consoles. A returned false informs the caller
+ * that everything was not flushed (either there were no usable consoles or
+ * another context has taken over printing or it is a panic situation and this
+ * is not the panic CPU). Regardless the reason, the caller should assume it
+ * is not useful to immediately try again.
+ */
+static bool console_flush_all_unlocked(u64 *next_seq, bool *handover)
+{
+ bool any_usable;
+ bool any_progress;
+
+ *next_seq = 0;
+ *handover = false;
+
+ do {
+ console_lock();
+ any_progress = console_flush_one_record(true, next_seq, handover, &any_usable);
+
+ if (*handover)
+ return false;
+
+ __console_unlock();
+
+ } while (any_progress);
+
+ return any_usable;
+}
+
static void __console_flush_and_unlock(void)
{
bool do_cond_resched;
@@ -3346,6 +3386,17 @@ static void __console_flush_and_unlock(void)
} while (prb_read_valid(prb, next_seq, NULL) && console_trylock());
}
+static void __console_flush_unlocked(void)
+{
+ bool handover;
+ bool flushed;
+ u64 next_seq;
+
+ do {
+ flushed = console_flush_all_unlocked(&next_seq, &handover);
+ } while (flushed && !handover && prb_read_valid(prb, next_seq, NULL));
+}
+
/**
* console_unlock - unblock the legacy console subsystem from printing
*
@@ -3676,8 +3727,7 @@ static int legacy_kthread_func(void *unused)
if (kthread_should_stop())
break;
- console_lock();
- __console_flush_and_unlock();
+ __console_flush_unlocked();
}
return 0;
--
2.34.1
Powered by blists - more mailing lists