From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB3A547CC9E for ; Tue, 14 Jul 2026 14:23:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784039019; cv=none; b=B9hiJ3N5YckRPa8eBNrgV+Tfu9FofFZ388LpnorgUlzTWtSrY0X0CfIceu6t8aoMULSKqzK336rR4Hwt9LcmCok2cIphVbG/1h+S5ug6Ks/WMVI9xfH6djiq5eY9HXiok8DIBEJts4W9Y5CeISnClsgifsDZ6PP+Ez2k+W5JXn8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784039019; c=relaxed/simple; bh=dityCapnkX0dnB6lVmH6gMHk8LLo1CrsWMw4QOEUqLU=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=Gd/5ctxWnnv2ZgR2kaLlvmuxgizT5wI+24XyZApVCTAyr3B7TJqH3WBvhlikhUe88HKBE4PBgIocI5BP6w6yVaL08XBYHapJJrNdbpUj6Rokpcmi3O+XRtNTQwYrC4jlE9aX66ORrESUIDpQqAjEuTYbmhRZyfcZaLnKTMA+b30= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com; spf=pass smtp.mailfrom=suse.com; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b=abYvCCkx; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=suse.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com header.b="abYvCCkx" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-47d70879764so2857780f8f.2 for ; Tue, 14 Jul 2026 07:23:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=google; t=1784039015; x=1784643815; darn=vger.kernel.org; h=in-reply-to:content-disposition:content-type:mime-version :references:message-id:subject:cc:to:from:date:from:to:cc:subject :date:message-id:reply-to:content-type; bh=OeFYIh73w11igdbh1JNar5M4ic0IH8OyJ8SAgpZk8oQ=; b=abYvCCkx47T78TYhuoEORFkK3lizsmQl7dWgK7DOj+lVvFxTWgHBFRquNnfseLpUse Yzv9A+/6N9vbHVhJStC+x6pqY4aXZQ5dvyeL5xu4n47BpFbjEk9g+Ax3fK9Gq/iDmr8n QXm1FMddW3EF8PMIKMjSMbHeggYBWXE0hH1ZhBx7WEQlsvmNdiK6bPhXQ4gq/80efNee qT6ZMPxNEXWH9q/wPeL4ntCtJSuevJsv4PcnmhwGYynf36bA0EHSpKYH9e08WhEX97Pe o00BGCzDA9aeQQ+YdbpTr1GbUcjrotcO16+7WattRMpoeEHOuFSx+q9+NSfN0fRW3cOC PE/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784039015; x=1784643815; h=in-reply-to:content-disposition:content-type:mime-version :references:message-id:subject:cc:to:from:date:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=OeFYIh73w11igdbh1JNar5M4ic0IH8OyJ8SAgpZk8oQ=; b=FUmmnDr3jXME8wfeJF8ccWA1mt36TQ9yy5Ij3R2etvtDvWnjxjzyWROr596XPGqdqk 8HAfTGLyQzgj3nRXLRTWpbRT184xctwUikc8mMPFtOBJwmHgPcuAmXVVmRp/MLGB9fY5 87Re2VHP2iEe+DeeRdTpweISKnT00iyGegnf8PgPD3TiReaXP9Qz4gv39vE/iHfG1mUK ThEjN9oK27/s5QMuPgUZYVJBB1ZYA1Q2Pq3ONDNLqIjKrJonmLOHTXgBck0+pP7+9tT7 09kdIyI0DNLnI+Lnk9/GRCOJnhbTBXfLzzPC5CX/JdqEesVIy4dgUzkHu76/ktgf6xMi cfUQ== X-Forwarded-Encrypted: i=1; AHgh+RrvdTEmYxQvhg/oPH3DAthrDnbvBTXFA1SuJdDhJUlouxJfd3bKFZuQSIXHAp/BsTw8hZpQKYPd6SAMXGY=@vger.kernel.org X-Gm-Message-State: AOJu0Yyct2elpuUO/kkGjTzkXOrFKNkyx+MF7LefHxiQ0B9st8CiMivk Bpwzl/mQPsLLWVyl35Ruc+Kn8PmJF+MxydXbKLZ2x9WZBHia6alInGfmymyE8acsrf0= X-Gm-Gg: AfdE7ckV0tKfD4JfYLFmklrpO5X7/rDbSgyUc7psEBNpYQD9Dx67+PP7x7JHG6l8o4N jjq0k/lIhdmRJm53MilbUeCk2CdVruPrORWSEjJ+sK/xlNOfA/N0/Rf2+2U2yn/kzlhjx0XSun/ HZd+WbnXdJBO8uxCTYwsakfI8w5ORxPJMvH/1jzvNyy2YlYmGxBx4DndGVZIcdKEOBhpghynJEK f8VzR3TAmVZi+9asOtLhTgaHAif5ZLFst1c5HLlwCoA/bC285q6m2EUNOFZeFmyAHwaixFZGHAg xvnWEOnTRRSDqJktGNDMvuBfL0NFr9MptW2of9xDppAJQpchiPzu1onIzPbSAhBYqsd9PUuzMt7 x06WlLRfUxn45wXSV2kqxO10Sr8Xds+irQzwjRlrn6HOiMlnvs89Ea6GRd4uRHILR00SsXLOrNB YN+kXizRwgEutXkJE= X-Received: by 2002:a05:600c:348e:b0:492:40a1:1e16 with SMTP id 5b1f17b1804b1-493f87dc629mr133599805e9.8.1784039015071; Tue, 14 Jul 2026 07:23:35 -0700 (PDT) Received: from pathway.suse.cz ([176.114.240.130]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-493f2a2e499sm378854155e9.0.2026.07.14.07.23.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Jul 2026 07:23:33 -0700 (PDT) Date: Tue, 14 Jul 2026 16:23:31 +0200 From: Petr Mladek To: John Ogness Cc: Sergey Senozhatsky , Steven Rostedt , Andrew Murray , Chris Down , linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: Re: [PATCH printk 1/3] printk: Introduce console sync mode Message-ID: References: <20260710144609.194487-1-john.ogness@linutronix.de> <20260710144609.194487-2-john.ogness@linutronix.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20260710144609.194487-2-john.ogness@linutronix.de> On Fri 2026-07-10 16:51:51, John Ogness wrote: > 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. > > --- 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), My first feeling was that this was an overhead. But it might make sense to keep only one console synchronous, ... > 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 > @@ -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; They have to use the legacy loop when boot consoles are still registered, see below. > + } 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)) { > /* > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -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(); Again. we should not do this when boot consoles are still registered. Also I think that we need to flush it in many more situations. In general, it should be needed everywhere printk_get_console_flush_type() is called for nbcon consoles in a context with NBCON_PRIO_NORMAL, see below. BTW: I wonder if this would work when more CPUs are adding messages in parallel. I guess that they would fight for the printing context. But I guess that they will eventually finish the printing. It is a bit different from the best effort approach used by the legacy loop. Synchronous nbcon console will cause that printk() might serialize CPUs... It might be acceptable because this mode should not be normally used. But we should at least document it. > if (ft.nbcon_offload) > nbcon_kthreads_wake(); I think that we should integrate this into printk_get_console_flush_type(). We could solve the problem with per-console flags the same way as for other flags, by global variables: + have_nbcon_sync_console + have_nbcon_async_console I wondered how it might look like. And I wanted to try AI. I came with the following patch on top of this patchset. The first version was generated by Claude, including the commit message. Later, I modified the code a lot, and the commit message a bit, by hand. It is relatively complex. But I think that it is the prize for the feature. And I think that the modification of printk_get_console_flush_type() better fits the existing design and helps to make sure that we handle it well in all situations. Feel free to integrate it into the first patch. Or maybe, we could add the two have_nbcon* variables in a separate patch, first, ... Here is the patch: >From 4b1fb1806c69465dd71321f564fcdec700c13d88 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Tue, 14 Jul 2026 13:53:01 +0200 Subject: [RFC] printk: Centralize nbcon sync console flush decision in console_flush_type The ad-hoc have_sync_console check in vprintk_emit() bypassed printk_get_console_flush_type() to call nbcon_sync_flush_pending() directly. This meant the sync-flush decision was scattered rather than centralized, and was missing from all other call sites such as console_cpu_notify(), __pr_flush(), printk_trigger_flush(), and console_try_replay_all(). Introduce a new nbcon_atomic_sync field in struct console_flush_type to represent the case where sync nbcon consoles (CON_SYNC) should be flushed atomically in the caller's context. To support this, add a companion global flag have_nbcon_async_console that tracks whether any non-sync nbcon console is registered, maintained symmetrically with have_sync_console in register_console() and unregister_console_locked(). Also rename the flag have_sync_console to have_nbcon_sync_console to make it more symmetrical with have_nbcon_async_console. Update printk_get_console_flush_type() NBCON_PRIO_NORMAL to set nbcon_atomic_sync and nbcon_offload independently based on which console types are present: - kthreads running: nbcon_offload if non-sync nbcon consoles exist, nbcon_atomic_sync if sync consoles exist (both can be set) - kthreads not running: nbcon_atomic if non-sync consoles exist (covers all nbcon including sync), else nbcon_atomic_sync nbcon_atomic_sync is never set when nbcon_atomic is set because nbcon_atomic already covers all nbcon consoles. Update all printk_get_console_flush_type() call sites to handle nbcon_atomic_sync by calling nbcon_sync_flush_pending(). Update the legacy loop and legacy kthread skip conditions to correctly exclude only the console type that is being handled atomically or offloaded, rather than all nbcon consoles unconditionally. Fix the loop condition in nbcon_atomic_flush_pending_con() to also loop when nbcon_atomic_sync is set, because the printer thread never handles sync consoles even when nbcon_offload is true. Assisted-by: claude-sonnet-4.6 Signed-off-by: Petr Mladek --- kernel/printk/internal.h | 22 ++++++++++++--- kernel/printk/nbcon.c | 24 ++++++++-------- kernel/printk/printk.c | 60 ++++++++++++++++++++++++++++------------ 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 1c1e0e97e3a0..3acea42b8720 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -169,19 +169,26 @@ static inline void nbcon_kthreads_wake(void) { } extern bool have_boot_console; extern bool have_nbcon_console; extern bool have_legacy_console; +extern bool have_nbcon_sync_console; +extern bool have_nbcon_async_console; extern bool legacy_allow_panic_sync; /** * struct console_flush_type - Define available console flush methods * @nbcon_atomic: Flush directly using nbcon_atomic() callback + * @nbcon_atomic_sync: Flush sync consoles (CON_SYNC) using nbcon_atomic() callback * @nbcon_offload: Offload flush to printer thread * @legacy_direct: Call the legacy loop in this context * @legacy_offload: Offload the legacy loop into IRQ or legacy thread * * Note that the legacy loop also flushes the nbcon consoles. + * + * @nbcon_atomic_sync is never set when @nbcon_atomic is set because + * @nbcon_atomic already covers all nbcon consoles including sync ones. */ struct console_flush_type { bool nbcon_atomic; + bool nbcon_atomic_sync; bool nbcon_offload; bool legacy_direct; bool legacy_offload; @@ -200,10 +207,17 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft) switch (nbcon_get_default_prio()) { case NBCON_PRIO_NORMAL: if (have_nbcon_console && !have_boot_console) { - if (printk_kthreads_running && !console_irqwork_blocked) - ft->nbcon_offload = true; - else - ft->nbcon_atomic = true; + if (printk_kthreads_running && !console_irqwork_blocked) { + if (have_nbcon_async_console) + ft->nbcon_offload = true; + if (have_nbcon_sync_console) + ft->nbcon_atomic_sync = true; + } else { + if (have_nbcon_async_console) + ft->nbcon_atomic = true; + else + ft->nbcon_atomic_sync = true; + } } /* Legacy consoles are flushed directly when possible. */ diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 77abb9804264..093683ee7262 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -1623,6 +1623,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) { struct console_flush_type ft; + short flags; int err; again: @@ -1642,10 +1643,11 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) /* * If flushing was successful but more records are available, this * context must flush those remaining records if the printer thread - * is not available do it. + * is not available to do it or the console is explicitely synchronous. */ printk_get_console_flush_type(&ft); - if (!ft.nbcon_offload && + flags = console_srcu_read_flags(con); + if ((!ft.nbcon_offload || flags & CON_SYNC) && prb_read_valid(prb, nbcon_seq_read(con), NULL)) { stop_seq = prb_next_reserve_seq(prb); goto again; @@ -1937,21 +1939,17 @@ void nbcon_device_release(struct console *con) /* * This context must flush any new records added while the console - * was locked if the printer thread is not available to do it. The - * console_srcu_read_lock must be taken to ensure the console is - * usable throughout flushing. + * was locked if the printer thread is not available to do it or + * when the console is explicitely synchonous. + * + * The console_srcu_read_lock must be taken to ensure the console + * is usable throughout flushing. */ cookie = console_srcu_read_lock(); 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); - } + printk_get_console_flush_type(&ft); if (console_is_usable(con, flags, true) && - !ft.nbcon_offload && + (!ft.nbcon_offload || flags & CON_SYNC) && prb_read_valid(prb, nbcon_seq_read(con), NULL)) { /* * If nbcon_atomic flushing is not available, fallback to diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e53ac5554e5e..96da8ac04856 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -454,11 +454,18 @@ 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. + * Specifies if an nbcon 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; +bool have_nbcon_sync_console; + +/* + * Specifies if an nbcon console without sync mode is registered. It there are + * any such consoles then printk() has to wake up the related kthreads when + * possible. + */ +bool have_nbcon_async_console; /* * Specifies if a boot console is registered. If boot consoles are present, @@ -2463,7 +2470,7 @@ asmlinkage int vprintk_emit(int facility, int level, if (ft.nbcon_atomic) nbcon_atomic_flush_pending(); - else if (have_sync_console) + if (ft.nbcon_atomic_sync) nbcon_sync_flush_pending(); if (ft.nbcon_offload) @@ -2954,6 +2961,8 @@ static int console_cpu_notify(unsigned int cpu) printk_get_console_flush_type(&ft); if (ft.nbcon_atomic) nbcon_atomic_flush_pending(); + if (ft.nbcon_atomic_sync) + nbcon_sync_flush_pending(); if (ft.legacy_direct) { if (console_trylock()) console_unlock(); @@ -3339,7 +3348,8 @@ static bool console_flush_one_record(bool do_cond_resched, u64 *next_seq, bool * * nbcon consoles when the nbcon consoles cannot print via * their atomic or threaded flushing. */ - if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload)) + if ((flags & CON_NBCON) && + (ft.nbcon_atomic || ft.nbcon_atomic_sync || ft.nbcon_offload)) continue; if (!console_is_usable(con, flags, !do_cond_resched)) @@ -3753,7 +3763,8 @@ static bool legacy_kthread_should_wakeup(void) * consoles when the nbcon consoles cannot print via their * atomic or threaded flushing. */ - if ((flags & CON_NBCON) && (ft.nbcon_atomic || ft.nbcon_offload)) + if ((flags & CON_NBCON) && + (ft.nbcon_atomic || ft.nbcon_atomic_sync || ft.nbcon_offload)) continue; if (!console_is_usable(con, flags, false)) @@ -4239,11 +4250,13 @@ void register_console(struct console *newcon) } } - if (newcon->flags & CON_SYNC) - have_sync_console = true; - if (newcon->flags & CON_NBCON) { have_nbcon_console = true; + if (newcon->flags & CON_SYNC) + have_nbcon_sync_console = true; + else + have_nbcon_async_console = true; + nbcon_seq_force(newcon, init_seq); } else { have_legacy_console = true; @@ -4329,7 +4342,8 @@ 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; + bool found_nbcon_sync_con = false; + bool found_nbcon_async_con = false; unsigned long flags; struct console *c; int res; @@ -4394,13 +4408,15 @@ static int unregister_console_locked(struct console *console) if (c->flags & CON_BOOT) found_boot_con = true; - if (c->flags & CON_NBCON) + if (c->flags & CON_NBCON) { found_nbcon_con = true; - else + if (c->flags & CON_SYNC) + found_nbcon_sync_con = true; + else + found_nbcon_async_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; @@ -4408,8 +4424,10 @@ 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; + if (!found_nbcon_sync_con) + have_nbcon_sync_console = found_nbcon_sync_con; + if (!found_nbcon_async_con) + have_nbcon_async_console = found_nbcon_async_con; /* @have_nbcon_console must be updated before calling nbcon_free(). */ if (console->flags & CON_NBCON) @@ -4595,6 +4613,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre printk_get_console_flush_type(&ft); if (ft.nbcon_atomic) nbcon_atomic_flush_pending(); + if (ft.nbcon_atomic_sync) + nbcon_sync_flush_pending(); if (ft.legacy_direct) { console_lock(); console_unlock(); @@ -4803,6 +4823,8 @@ void printk_trigger_flush(void) printk_get_console_flush_type(&ft); if (ft.nbcon_atomic) nbcon_atomic_flush_pending(); + if (ft.nbcon_atomic_sync) + nbcon_sync_flush_pending(); if (ft.nbcon_offload) nbcon_kthreads_wake(); if (ft.legacy_direct) { @@ -5155,6 +5177,8 @@ void console_try_replay_all(void) __console_rewind_all(); if (ft.nbcon_atomic) nbcon_atomic_flush_pending(); + if (ft.nbcon_atomic_sync) + nbcon_sync_flush_pending(); if (ft.nbcon_offload) nbcon_kthreads_wake(); if (ft.legacy_offload) -- 2.55.0