* [PATCH v2] printk: Remove remaining boot consoles when a real console exists @ 2026-08-05 8:48 Xiaochun Li 2026-08-20 15:13 ` Petr Mladek 0 siblings, 1 reply; 3+ messages in thread From: Xiaochun Li @ 2026-08-05 8:48 UTC (permalink / raw) To: pmladek; +Cc: rostedt, john.ogness, senozhatsky, linux-kernel, Xiaochun Li Boot consoles are temporary and should be removed once a real console is available. However, the late init cleanup currently only unregisters boot consoles that use init section memory. Other boot consoles are expected to be removed when the real preferred console is registered. This does not cover cases where a real console has registered, but the boot console was not removed because the real console did not become the preferred console. For example, with multiple console= parameters using the same driver, a real 8250 console may be enabled while the early console remains registered. The result is duplicate printk output from both consoles. In the mailing list discussion, two possible approaches were suggested to fix this problem [1]. This patch implements the first one: during printk_late_init(), check whether at least one real console is already registered. If so, unregister all remaining boot consoles. If no real console exists yet, keep the existing behavior and unregister only boot consoles that reference init section memory, avoiding a period with no console output while waiting for a deferred or modular real console. Suggested-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/lkml/ahBsSW2bB2CRfW-k@pathway.suse.cz/ # [1] Signed-off-by: Xiaochun Li <lixiaochun@open-hieco.net> --- kernel/printk/printk.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 2fe9a963c823..5a5ec7ac99bd 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -4420,36 +4420,48 @@ void __init console_init(void) * be a brief interval in which no messages are logged to the console, which * makes it difficult to diagnose problems that occur during this time. * - * To mitigate this problem somewhat, only unregister consoles whose memory - * intersects with the init section. Note that all other boot consoles will - * get unregistered when the real preferred console is registered. + * If a real console has already registered, remove all remaining boot consoles. + * Otherwise, mitigate the no-console interval by removing only boot consoles + * whose memory intersects with the init section. */ static int __init printk_late_init(void) { + bool realcon_registered = false; struct hlist_node *tmp; struct console *con; int ret; console_list_lock(); + for_each_console(con) { + if (!(con->flags & CON_BOOT)) { + realcon_registered = true; + break; + } + } + hlist_for_each_entry_safe(con, tmp, &console_list, node) { if (!(con->flags & CON_BOOT)) continue; - /* Check addresses that might be used for enabled consoles. */ - if (init_section_intersects(con, sizeof(*con)) || - init_section_contains(con->write, 0) || - init_section_contains(con->read, 0) || - init_section_contains(con->device, 0) || - init_section_contains(con->unblank, 0) || - init_section_contains(con->data, 0)) { + if (!realcon_registered) { + /* Check addresses that might be used for enabled consoles. */ + if (!init_section_intersects(con, sizeof(*con)) && + !init_section_contains(con->write, 0) && + !init_section_contains(con->read, 0) && + !init_section_contains(con->device, 0) && + !init_section_contains(con->unblank, 0) && + !init_section_contains(con->data, 0)) + continue; + /* * Please, consider moving the reported consoles out * of the init section. */ pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", con->name, con->index); - unregister_console_locked(con); } + + unregister_console_locked(con); } console_list_unlock(); -- 2.18.2 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] printk: Remove remaining boot consoles when a real console exists 2026-08-05 8:48 [PATCH v2] printk: Remove remaining boot consoles when a real console exists Xiaochun Li @ 2026-08-20 15:13 ` Petr Mladek 2026-08-21 2:10 ` Xiaochun Li 0 siblings, 1 reply; 3+ messages in thread From: Petr Mladek @ 2026-08-20 15:13 UTC (permalink / raw) To: Xiaochun Li; +Cc: rostedt, john.ogness, senozhatsky, linux-kernel On Wed 2026-08-05 16:48:46, Xiaochun Li wrote: > Boot consoles are temporary and should be removed once a real console is > available. However, the late init cleanup currently only unregisters boot > consoles that use init section memory. Other boot consoles are expected > to be removed when the real preferred console is registered. > > This does not cover cases where a real console has registered, but the > boot console was not removed because the real console did not become the > preferred console. For example, with multiple console= parameters using > the same driver, a real 8250 console may be enabled while the early > console remains registered. The result is duplicate printk output from > both consoles. > > In the mailing list discussion, two possible approaches were suggested > to fix this problem [1]. This patch implements the first one: during > printk_late_init(), check whether at least one real console is already > registered. If so, unregister all remaining boot consoles. If no real > console exists yet, keep the existing behavior and unregister only boot > consoles that reference init section memory, avoiding a period with no > console output while waiting for a deferred or modular real console. > > Suggested-by: Petr Mladek <pmladek@suse.com> > Link: https://lore.kernel.org/lkml/ahBsSW2bB2CRfW-k@pathway.suse.cz/ # [1] > Signed-off-by: Xiaochun Li <lixiaochun@open-hieco.net> > --- > kernel/printk/printk.c | 34 +++++++++++++++++++++++----------- > 1 file changed, 23 insertions(+), 11 deletions(-) > > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c > index 2fe9a963c823..5a5ec7ac99bd 100644 > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -4420,36 +4420,48 @@ void __init console_init(void) > * be a brief interval in which no messages are logged to the console, which > * makes it difficult to diagnose problems that occur during this time. > * > - * To mitigate this problem somewhat, only unregister consoles whose memory > - * intersects with the init section. Note that all other boot consoles will > - * get unregistered when the real preferred console is registered. > + * If a real console has already registered, remove all remaining boot consoles. > + * Otherwise, mitigate the no-console interval by removing only boot consoles > + * whose memory intersects with the init section. > */ > static int __init printk_late_init(void) > { > + bool realcon_registered = false; Nit: I would call the variable "have_real_console" to follow the existing naming scheme, see have_boot_console, have_legacy_console, ... Please, change it in v2 if we need it, ... > struct hlist_node *tmp; > struct console *con; > int ret; > > console_list_lock(); > + for_each_console(con) { > + if (!(con->flags & CON_BOOT)) { > + realcon_registered = true; > + break; > + } > + } Sashiko AI worries: | Can this cause a period of missing console output if a non-visible console | (like netconsole or pstore) registers early? I do not agree. Users are able to read the messages on netconsole or pstore, so I consider them valid real consoles. | It looks like this checks only for the absence of CON_BOOT to consider a | real console present. If a real hardware serial console is deferred or | loaded as a module later, wouldn't we need to check for CON_CONSDEV to | ensure the preferred hardware console is actually available before dropping | the boot console? It does not make much sense. The CON_CONSDEV flag does not guarantee anything. It is just the best effort to mart console which will get used by /dev/console. > hlist_for_each_entry_safe(con, tmp, &console_list, node) { > if (!(con->flags & CON_BOOT)) > continue; > > - /* Check addresses that might be used for enabled consoles. */ > - if (init_section_intersects(con, sizeof(*con)) || > - init_section_contains(con->write, 0) || > - init_section_contains(con->read, 0) || > - init_section_contains(con->device, 0) || > - init_section_contains(con->unblank, 0) || > - init_section_contains(con->data, 0)) { > + if (!realcon_registered) { > + /* Check addresses that might be used for enabled consoles. */ > + if (!init_section_intersects(con, sizeof(*con)) && > + !init_section_contains(con->write, 0) && > + !init_section_contains(con->read, 0) && > + !init_section_contains(con->device, 0) && > + !init_section_contains(con->unblank, 0) && > + !init_section_contains(con->data, 0)) > + continue; > + > /* > * Please, consider moving the reported consoles out > * of the init section. > */ > pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", > con->name, con->index); > - unregister_console_locked(con); > } > + > + unregister_console_locked(con); Another comment from Sashiko AI: | Does this unconditional unregistration bypass the keep_bootcon command-line | parameter? | | If a user boots with keep_bootcon to preserve early boot consoles for | debugging, it appears this code will bypass the keep_bootcon flag check | traditionally used in register_console() and unexpectedly unregister the | debugging consoles once a real console registers. This one describes a real problem. We have to check the "keep_bootcon" flag. I suggest something like: --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -4420,36 +4420,51 @@ void __init console_init(void) * be a brief interval in which no messages are logged to the console, which * makes it difficult to diagnose problems that occur during this time. * - * To mitigate this problem somewhat, only unregister consoles whose memory - * intersects with the init section. Note that all other boot consoles will - * get unregistered when the real preferred console is registered. + * If a real console has already registered, remove all remaining boot consoles. + * Otherwise, mitigate the no-console interval by removing only boot consoles + * whose memory intersects with the init section. */ static int __init printk_late_init(void) { + bool have_real_console = false; struct hlist_node *tmp; struct console *con; int ret; console_list_lock(); + for_each_console(con) { + if (!(con->flags & CON_BOOT)) { + have_real_console = true; + break; + } + } + hlist_for_each_entry_safe(con, tmp, &console_list, node) { if (!(con->flags & CON_BOOT)) continue; - /* Check addresses that might be used for enabled consoles. */ - if (init_section_intersects(con, sizeof(*con)) || - init_section_contains(con->write, 0) || - init_section_contains(con->read, 0) || - init_section_contains(con->device, 0) || - init_section_contains(con->unblank, 0) || - init_section_contains(con->data, 0)) { + /* + * Keep the boot console when requested or as a fallback + * unless it is using an init section. + */ + if (keep_bootcon || !have_real_console) { + if (!init_section_intersects(con, sizeof(*con)) && + !init_section_contains(con->write, 0) && + !init_section_contains(con->read, 0) && + !init_section_contains(con->device, 0) && + !init_section_contains(con->unblank, 0) && + !init_section_contains(con->data, 0)) + continue; + /* * Please, consider moving the reported consoles out * of the init section. */ pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", con->name, con->index); - unregister_console_locked(con); } + + unregister_console_locked(con); } console_list_unlock(); Best Regards, Petr ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] printk: Remove remaining boot consoles when a real console exists 2026-08-20 15:13 ` Petr Mladek @ 2026-08-21 2:10 ` Xiaochun Li 0 siblings, 0 replies; 3+ messages in thread From: Xiaochun Li @ 2026-08-21 2:10 UTC (permalink / raw) To: Petr Mladek; +Cc: rostedt, john.ogness, senozhatsky, linux-kernel On 8/20/2026 11:13 PM, Petr Mladek wrote: > On Wed 2026-08-05 16:48:46, Xiaochun Li wrote: >> Boot consoles are temporary and should be removed once a real console is >> available. However, the late init cleanup currently only unregisters boot >> consoles that use init section memory. Other boot consoles are expected >> to be removed when the real preferred console is registered. >> >> This does not cover cases where a real console has registered, but the >> boot console was not removed because the real console did not become the >> preferred console. For example, with multiple console= parameters using >> the same driver, a real 8250 console may be enabled while the early >> console remains registered. The result is duplicate printk output from >> both consoles. >> >> In the mailing list discussion, two possible approaches were suggested >> to fix this problem [1]. This patch implements the first one: during >> printk_late_init(), check whether at least one real console is already >> registered. If so, unregister all remaining boot consoles. If no real >> console exists yet, keep the existing behavior and unregister only boot >> consoles that reference init section memory, avoiding a period with no >> console output while waiting for a deferred or modular real console. >> >> Suggested-by: Petr Mladek <pmladek@suse.com> >> Link: https://lore.kernel.org/lkml/ahBsSW2bB2CRfW-k@pathway.suse.cz/ # [1] >> Signed-off-by: Xiaochun Li <lixiaochun@open-hieco.net> >> --- >> kernel/printk/printk.c | 34 +++++++++++++++++++++++----------- >> 1 file changed, 23 insertions(+), 11 deletions(-) >> >> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c >> index 2fe9a963c823..5a5ec7ac99bd 100644 >> --- a/kernel/printk/printk.c >> +++ b/kernel/printk/printk.c >> @@ -4420,36 +4420,48 @@ void __init console_init(void) >> * be a brief interval in which no messages are logged to the console, which >> * makes it difficult to diagnose problems that occur during this time. >> * >> - * To mitigate this problem somewhat, only unregister consoles whose memory >> - * intersects with the init section. Note that all other boot consoles will >> - * get unregistered when the real preferred console is registered. >> + * If a real console has already registered, remove all remaining boot consoles. >> + * Otherwise, mitigate the no-console interval by removing only boot consoles >> + * whose memory intersects with the init section. >> */ >> static int __init printk_late_init(void) >> { >> + bool realcon_registered = false; > > Nit: I would call the variable "have_real_console" to follow the > existing naming scheme, see have_boot_console, > have_legacy_console, ... > > Please, change it in v2 if we need it, ... > > >> struct hlist_node *tmp; >> struct console *con; >> int ret; >> >> console_list_lock(); >> + for_each_console(con) { >> + if (!(con->flags & CON_BOOT)) { >> + realcon_registered = true; >> + break; >> + } >> + } > > Sashiko AI worries: > > | Can this cause a period of missing console output if a non-visible console > | (like netconsole or pstore) registers early? > > I do not agree. Users are able to read the messages on netconsole > or pstore, so I consider them valid real consoles. > > | It looks like this checks only for the absence of CON_BOOT to consider a > | real console present. If a real hardware serial console is deferred or > | loaded as a module later, wouldn't we need to check for CON_CONSDEV to > | ensure the preferred hardware console is actually available before dropping > | the boot console? > > It does not make much sense. The CON_CONSDEV flag does not > guarantee anything. It is just the best effort to mart console > which will get used by /dev/console. > >> hlist_for_each_entry_safe(con, tmp, &console_list, node) { >> if (!(con->flags & CON_BOOT)) >> continue; >> >> - /* Check addresses that might be used for enabled consoles. */ >> - if (init_section_intersects(con, sizeof(*con)) || >> - init_section_contains(con->write, 0) || >> - init_section_contains(con->read, 0) || >> - init_section_contains(con->device, 0) || >> - init_section_contains(con->unblank, 0) || >> - init_section_contains(con->data, 0)) { >> + if (!realcon_registered) { >> + /* Check addresses that might be used for enabled consoles. */ >> + if (!init_section_intersects(con, sizeof(*con)) && >> + !init_section_contains(con->write, 0) && >> + !init_section_contains(con->read, 0) && >> + !init_section_contains(con->device, 0) && >> + !init_section_contains(con->unblank, 0) && >> + !init_section_contains(con->data, 0)) >> + continue; >> + >> /* >> * Please, consider moving the reported consoles out >> * of the init section. >> */ >> pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", >> con->name, con->index); >> - unregister_console_locked(con); >> } >> + >> + unregister_console_locked(con); > > Another comment from Sashiko AI: > > | Does this unconditional unregistration bypass the keep_bootcon command-line > | parameter? > | > | If a user boots with keep_bootcon to preserve early boot consoles for > | debugging, it appears this code will bypass the keep_bootcon flag check > | traditionally used in register_console() and unexpectedly unregister the > | debugging consoles once a real console registers. > > This one describes a real problem. We have to check the "keep_bootcon" > flag. I suggest something like: > > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -4420,36 +4420,51 @@ void __init console_init(void) > * be a brief interval in which no messages are logged to the console, which > * makes it difficult to diagnose problems that occur during this time. > * > - * To mitigate this problem somewhat, only unregister consoles whose memory > - * intersects with the init section. Note that all other boot consoles will > - * get unregistered when the real preferred console is registered. > + * If a real console has already registered, remove all remaining boot consoles. > + * Otherwise, mitigate the no-console interval by removing only boot consoles > + * whose memory intersects with the init section. > */ > static int __init printk_late_init(void) > { > + bool have_real_console = false; > struct hlist_node *tmp; > struct console *con; > int ret; > > console_list_lock(); > + for_each_console(con) { > + if (!(con->flags & CON_BOOT)) { > + have_real_console = true; > + break; > + } > + } > + > hlist_for_each_entry_safe(con, tmp, &console_list, node) { > if (!(con->flags & CON_BOOT)) > continue; > > - /* Check addresses that might be used for enabled consoles. */ > - if (init_section_intersects(con, sizeof(*con)) || > - init_section_contains(con->write, 0) || > - init_section_contains(con->read, 0) || > - init_section_contains(con->device, 0) || > - init_section_contains(con->unblank, 0) || > - init_section_contains(con->data, 0)) { > + /* > + * Keep the boot console when requested or as a fallback > + * unless it is using an init section. > + */ > + if (keep_bootcon || !have_real_console) { > + if (!init_section_intersects(con, sizeof(*con)) && > + !init_section_contains(con->write, 0) && > + !init_section_contains(con->read, 0) && > + !init_section_contains(con->device, 0) && > + !init_section_contains(con->unblank, 0) && > + !init_section_contains(con->data, 0)) > + continue; > + > /* > * Please, consider moving the reported consoles out > * of the init section. > */ > pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n", > con->name, con->index); > - unregister_console_locked(con); > } > + > + unregister_console_locked(con); > } > console_list_unlock(); > > > Best Regards, > Petr Thanks for your detailed review and for helping to clarify the questions raised (including those regarding Sashiko AI). I will send a V3 that incorporates your suggestions. Best regards, Xiaochun Li ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-21 2:15 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-05 8:48 [PATCH v2] printk: Remove remaining boot consoles when a real console exists Xiaochun Li 2026-08-20 15:13 ` Petr Mladek 2026-08-21 2:10 ` Xiaochun Li
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.