From: John Ogness <john.ogness@linutronix.de>
To: Petr Mladek <pmladek@suse.com>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>,
Steven Rostedt <rostedt@goodmis.org>,
Andrew Murray <amurray@thegoodpenguin.co.uk>,
Chris Down <chris@chrisdown.name>,
linux-kernel@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH printk 1/3] printk: Introduce console sync mode
Date: Fri, 10 Jul 2026 16:51:51 +0206 [thread overview]
Message-ID: <20260710144609.194487-2-john.ogness@linutronix.de> (raw)
In-Reply-To: <20260710144609.194487-1-john.ogness@linutronix.de>
Sometimes it is desirable that console printing occurs synchronously
in the context of the printk() caller. Introduce a "sync mode" for
nbcon consoles that provide safe atomic_write() implementations. A
new console flag CON_SYNC shows if a console is operating in this
mode.
When in sync mode, a console will flush directly within vprintk_emit()
using the same mechanism as emergency printing. If the console
hardware is currently owned by another context, the flushing will
occur when that context releases ownership (just as is the case with
non-panic emergency printing).
If CON_SYNC is set for a legacy console driver or a nbcon console
driver that does not provide a safe atomic_write(), the flag is
cleared upon console registration and a message is logged that the
console does not support sync mode.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
include/linux/console.h | 2 ++
kernel/printk/internal.h | 2 ++
kernel/printk/nbcon.c | 42 ++++++++++++++++++++++++++++++++++------
kernel/printk/printk.c | 25 ++++++++++++++++++++++++
4 files changed, 65 insertions(+), 6 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index d624200cfc170..0f69e52bc3b6b 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -180,6 +180,7 @@ static inline void con_debug_leave(void) { }
* constraints.
* @CON_NBCON_ATOMIC_UNSAFE: The write_atomic() callback is not safe and is
* therefore only used by nbcon_atomic_flush_unsafe().
+ * @CON_SYNC: Print using write_atomic() from the printk() calling context.
*/
enum cons_flags {
CON_PRINTBUFFER = BIT(0),
@@ -192,6 +193,7 @@ enum cons_flags {
CON_SUSPENDED = BIT(7),
CON_NBCON = BIT(8),
CON_NBCON_ATOMIC_UNSAFE = BIT(9),
+ CON_SYNC = BIT(10),
};
/**
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 85fbf1801cbe0..1c1e0e97e3a04 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -105,6 +105,7 @@ bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
enum nbcon_prio nbcon_get_default_prio(void);
void nbcon_atomic_flush_pending(void);
+void nbcon_sync_flush_pending(void);
bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
int cookie, bool use_atomic);
bool nbcon_kthread_create(struct console *con);
@@ -157,6 +158,7 @@ static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
static inline void nbcon_atomic_flush_pending(void) { }
+static inline void nbcon_sync_flush_pending(void) { }
static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
int cookie, bool use_atomic) { return false; }
static inline void nbcon_kthread_wake(struct console *con) { }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 4b03b019cd5ee..77abb98042648 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1200,7 +1200,10 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex
cookie = console_srcu_read_lock();
flags = console_srcu_read_flags(con);
- if (console_is_usable(con, flags, false)) {
+ if (unlikely(flags & CON_SYNC)) {
+ /* Sync consoles never print from the printer thread. */
+ ;
+ } else if (console_is_usable(con, flags, false)) {
/* Bring the sequence in @ctxt up to date */
ctxt->seq = nbcon_seq_read(con);
@@ -1653,8 +1656,9 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
* __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
* write_atomic() callback
* @stop_seq: Flush up until this record
+ * @sync_only: Only flush sync consoles (CON_SYNC)
*/
-static void __nbcon_atomic_flush_pending(u64 stop_seq)
+static void __nbcon_atomic_flush_pending(u64 stop_seq, bool sync_only)
{
struct console *con;
int cookie;
@@ -1666,6 +1670,9 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
if (!(flags & CON_NBCON))
continue;
+ if (sync_only && !(flags & CON_SYNC))
+ continue;
+
if (!console_is_usable(con, flags, true))
continue;
@@ -1688,7 +1695,22 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
*/
void nbcon_atomic_flush_pending(void)
{
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
+}
+
+/**
+ * nbcon_sync_flush_pending - Flush all nbcon sync consoles (CON_SYNC)
+ * using their write_atomic() callback
+ *
+ * Flush the backlog of all sync consoles up through the currently newest
+ * record. This is the same as nbcon_atomic_flush_pending() except only
+ * for sync (CON_SYNC) consoles.
+ *
+ * See nbcon_atomic_flush_pending() for more details.
+ */
+void nbcon_sync_flush_pending(void)
+{
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
}
/**
@@ -1701,7 +1723,7 @@ void nbcon_atomic_flush_pending(void)
void nbcon_atomic_flush_unsafe(void)
{
panic_nbcon_allow_unsafe_takeover = true;
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
panic_nbcon_allow_unsafe_takeover = false;
}
@@ -1905,6 +1927,7 @@ void nbcon_device_release(struct console *con)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
struct console_flush_type ft;
+ short flags;
int cookie;
if (!nbcon_context_exit_unsafe(ctxt))
@@ -1919,8 +1942,15 @@ void nbcon_device_release(struct console *con)
* usable throughout flushing.
*/
cookie = console_srcu_read_lock();
- printk_get_console_flush_type(&ft);
- if (console_is_usable(con, console_srcu_read_flags(con), true) &&
+ flags = console_srcu_read_flags(con);
+ if (unlikely(flags & CON_SYNC)) {
+ /* Sync consoles will always perform nbcon_atomic flushing. */
+ memset(&ft, 0, sizeof(ft));
+ ft.nbcon_atomic = true;
+ } else {
+ printk_get_console_flush_type(&ft);
+ }
+ if (console_is_usable(con, flags, true) &&
!ft.nbcon_offload &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
/*
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823a..e82e864a4d672 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -453,6 +453,13 @@ bool have_legacy_console;
*/
bool have_nbcon_console;
+/*
+ * Specifies if a console is running in sync mode. If any consoles are running
+ * in sync mode, printk() will immediately flush such consoles using their
+ * write_atomic() callback.
+ */
+bool have_sync_console;
+
/*
* Specifies if a boot console is registered. If boot consoles are present,
* nbcon consoles cannot print simultaneously and must be synchronized by
@@ -2456,6 +2463,8 @@ asmlinkage int vprintk_emit(int facility, int level,
if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
+ else if (have_sync_console)
+ nbcon_sync_flush_pending();
if (ft.nbcon_offload)
nbcon_kthreads_wake();
@@ -4144,6 +4153,16 @@ void register_console(struct console *newcon)
newcon->dropped = 0;
init_seq = get_init_console_seq(newcon, bootcon_registered);
+ if (newcon->flags & CON_SYNC) {
+ if (!(newcon->flags & CON_NBCON) || (newcon->flags & CON_NBCON_ATOMIC_UNSAFE)) {
+ newcon->flags &= ~CON_SYNC;
+ con_printk(KERN_INFO, newcon, "sync mode unsupported\n");
+ }
+ }
+
+ if (newcon->flags & CON_SYNC)
+ have_sync_console = true;
+
if (newcon->flags & CON_NBCON) {
have_nbcon_console = true;
nbcon_seq_force(newcon, init_seq);
@@ -4231,6 +4250,7 @@ static int unregister_console_locked(struct console *console)
bool found_legacy_con = false;
bool found_nbcon_con = false;
bool found_boot_con = false;
+ bool found_sync_con = false;
unsigned long flags;
struct console *c;
int res;
@@ -4299,6 +4319,9 @@ static int unregister_console_locked(struct console *console)
found_nbcon_con = true;
else
found_legacy_con = true;
+
+ if (c->flags & CON_SYNC)
+ found_sync_con = true;
}
if (!found_boot_con)
have_boot_console = found_boot_con;
@@ -4306,6 +4329,8 @@ static int unregister_console_locked(struct console *console)
have_legacy_console = found_legacy_con;
if (!found_nbcon_con)
have_nbcon_console = found_nbcon_con;
+ if (!found_sync_con)
+ have_sync_console = found_sync_con;
/* @have_nbcon_console must be updated before calling nbcon_free(). */
if (console->flags & CON_NBCON)
--
2.47.3
next prev parent reply other threads:[~2026-07-10 14:46 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 14:45 [PATCH printk 0/3] Introduce " John Ogness
2026-07-10 14:45 ` John Ogness [this message]
2026-07-14 14:23 ` [PATCH printk 1/3] printk: Introduce console " Petr Mladek
2026-07-10 14:45 ` [PATCH printk 2/3] proc: Add console sync support for /proc/consoles John Ogness
2026-07-14 15:03 ` Petr Mladek
2026-07-10 14:45 ` [PATCH printk 3/3] printk: Support setting console sync mode via console= John Ogness
2026-07-15 12:23 ` Petr Mladek
2026-07-10 21:05 ` [PATCH printk 0/3] Introduce sync mode John Ogness
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260710144609.194487-2-john.ogness@linutronix.de \
--to=john.ogness@linutronix.de \
--cc=amurray@thegoodpenguin.co.uk \
--cc=chris@chrisdown.name \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=senozhatsky@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®