Skip to contentSkip to conversation

printk: nbcon: deprecate boot_delay in favour of printk_delay

PATCH Superseded Andrew Murray 5 participants 31 messages Jun 30 – Jul 9

Subsystems (8)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover printk: nbcon: deprecate boot_delay in favour of printk_delay

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

boot_delay provides a kernel parameter for delaying printk output from kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is configurable only via sysctl and thus is only used post boot.

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console, especially for slow consoles.

To address these issues, let's deprecate boot_delay, extend printk_delay to be useable from kernel start and ensure that delays occur at the point where console messages are printed rather than queued.

Please note that this patchset results in delays occuring after a message is printed rather than, as it is now, before.

---
Please see the following related work for additional context:

- https://lore.kernel.org/all/[email protected]/
- https://lore.kernel.org/all/[email protected]/
- https://lore.kernel.org/r/20260601-deprecate_boot_delay-v1-0-c34c187142a6@thegoodpenguin.co.uk (v1)

---
Changes in v2:
- Rebased onto v7.2-rc1
- Correctly handle negative values for printk_delay_msec (patch 2)
- Add missing newline in pr_warn (patch 2)
- Improved patch descriptions for (patches 2 and 3)
- Use new emitted flag in nbcon_context/nbcon_write_context in place of backlog && wctxt.len checks (patch 3)
- Use unsigned char for unsafe_takeover field instead of bool in nbcon_write_context (patch 3)
- Move printk_delay_msec and printk_delay from printk.h to internal.h (patch 3)
- Revert regression added in v1 to __nbcon_atomic_flush_pending_con (patch 3)
- Move printk_delay later in console_emit_next_record ensuring delay is always after emit (across nbcon/legacy) (patch 3)
- Fixed typo in documentation s/boot_delay/printk_delay/g in printk_delay= section (patch 4)
- Link to v1: https://lore.kernel.org/r/20260601-deprecate_boot_delay-v1-0-c34c187142a6@thegoodpenguin.co.uk

---
Andrew Murray (4):
printk: remove BOOT_PRINTK_DELAY config option
printk: deprecate boot_delay in favour of printk_delay
printk: nbcon: move printk_delay to console emiting code Documentation/kernel-parameters: add/update printk_delay/boot_delay

 Documentation/admin-guide/kernel-parameters.txt | 31 +++++++--
 arch/arm/configs/bcm2835_defconfig              |  1 -
 include/linux/console.h                         |  5 +-
 include/linux/printk.h                          |  1 -
 kernel/printk/internal.h                        |  6 ++
 kernel/printk/nbcon.c                           | 13 ++++
 kernel/printk/printk.c                          | 84 +++++++++++++++----------
 lib/Kconfig.debug                               | 18 ------
 8 files changed, 101 insertions(+), 58 deletions(-)

---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260515-deprecate_boot_delay-72516da3845a

Best regards,

Signature · 1 line
Andrew Murray <[email protected]>
#1 lore raw

PATCH v2 1/4 printk: remove BOOT_PRINTK_DELAY config option

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

In preparation of combining them into a single configurable feature, let's first remove the kconfig option BOOT_PRINTK_DELAY.

---
 Documentation/admin-guide/kernel-parameters.txt |  2 +-
 arch/arm/configs/bcm2835_defconfig              |  1 -
 kernel/printk/printk.c                          |  2 +-
 lib/Kconfig.debug                               | 18 ------------------
 4 files changed, 2 insertions(+), 21 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +1 -1
index b5493a7f8f22812833308b22f2cc35b0a42e55b2..2884103b93bca7b76cd3a93946276074cf62d0a1 100644
@@ -651,7 +651,7 @@ Kernel parameters
 
 	boot_delay=	[KNL,EARLY]
 			Milliseconds to delay each printk during boot.
-			Only works if CONFIG_BOOT_PRINTK_DELAY is enabled,
+			Only works if GENERIC_CALIBRATE_DELAY is enabled,
 			and you may also have to specify "lpj=".  Boot_delay
 			values larger than 10 seconds (10000) are assumed
 			erroneous and ignored.
arch/arm/configs/bcm2835_defconfig +0 -1
index 4a8ac09843d73280cc42dbbf63fe3cc9f31dacd2..51a1e94d5aa6c22202778082b877a202a6b9c04d 100644
@@ -174,7 +174,6 @@ CONFIG_NLS_UTF8=y
 CONFIG_DMA_CMA=y
 CONFIG_CMA_SIZE_MBYTES=32
 CONFIG_PRINTK_TIME=y
-CONFIG_BOOT_PRINTK_DELAY=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 # CONFIG_ENABLE_MUST_CHECK is not set
kernel/printk/printk.c +1 -1
index 2fe9a963c823a41e7df10c29939a2abb55462859..77f53eaed13216c6c3946adabc0c8fdba6401d91 100644
@@ -1289,7 +1289,7 @@ static bool suppress_message_printing(int level)
 	return (level >= console_loglevel && !ignore_loglevel);
 }
 
-#ifdef CONFIG_BOOT_PRINTK_DELAY
+#ifdef CONFIG_GENERIC_CALIBRATE_DELAY
 
 static int boot_delay; /* msecs delay after each printk during bootup */
 static unsigned long long loops_per_msec;	/* based on boot_delay */
lib/Kconfig.debug +0 -18
index 1244dcac2294ad99fda37fa6767c9e76f16a4d14..b552ea51cd53b79cf5d58b8c4deff409b1982862 100644
@@ -99,24 +99,6 @@ config MESSAGE_LOGLEVEL_DEFAULT
 	  by default. To change that, use loglevel=<x> in the kernel bootargs,
 	  or pick a different CONSOLE_LOGLEVEL_DEFAULT configuration value.
 
-config BOOT_PRINTK_DELAY
-	bool "Delay each boot printk message by N milliseconds"
-	depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY
-	help
-	  This build option allows you to read kernel boot messages
-	  by inserting a short delay after each one.  The delay is
-	  specified in milliseconds on the kernel command line,
-	  using "boot_delay=N".
-
-	  It is likely that you would also need to use "lpj=M" to preset
-	  the "loops per jiffy" value.
-	  See a previous boot log for the "lpj" value to use for your
-	  system, and then set "lpj=M" before setting "boot_delay=N".
-	  NOTE:  Using this option may adversely affect SMP systems.
-	  I.e., processors other than the first one may not boot up.
-	  BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect
-	  what it believes to be lockup conditions.
-
 config DYNAMIC_DEBUG
 	bool "Enable dynamic printk() support"
 	default n
Signature · 1 line
2.34.1
#2 lore raw

Re: [PATCH v2 1/4] printk: remove BOOT_PRINTK_DELAY config option

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The kernel command line parameter boot_delay can be parsed as a negative integer, which causes a massive integer underflow and a near-infinite loop, resulting in a boot hang. --

commit 7ede3add142d62f673ea88e35c108d0ec8e7599d
Author: Andrew Murray <[email protected]>

printk: remove BOOT_PRINTK_DELAY config option

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message. This commit prepares to combine them by removing the BOOT_PRINTK_DELAY kconfig option.

kernel/printk/printk.c static bool suppress_message_printing(int level) · line 1295

Quoted 13 lines
kernel/printk/printk.c +1 -1
index 2fe9a963c823a..77f53eaed1321 100644
@@ -1289,7 +1289,7 @@ static bool suppress_message_printing(int level)
 	return (level >= console_loglevel && !ignore_loglevel);
 }
 
-#ifdef CONFIG_BOOT_PRINTK_DELAY
+#ifdef CONFIG_GENERIC_CALIBRATE_DELAY
 
 static int boot_delay; /* msecs delay after each printk during bootup */
 static unsigned long long loops_per_msec;	/* based on boot_delay */

[Severity: High]
This is a pre-existing issue, but does expanding the availability of the boot_delay parameter expose a potential boot hang if a negative value is provided on the kernel command line?

When boot_delay is parsed in boot_delay_setup(), the bounds check does not reject negative inputs:

kernel/printk/printk.c:boot_delay_setup() {
    ...
    get_option(&str, &boot_delay);
    if (boot_delay > 10 * 1000)
        boot_delay = 0;
    ...
}

If a user provides a negative value like boot_delay=-1, could boot_delay_msec() cast this negative integer to an unsigned type, resulting in an immense timeout?

kernel/printk/printk.c:boot_delay_msec() {
    ...
    k = (unsigned long long)loops_per_msec * boot_delay;

    timeout = jiffies + msecs_to_jiffies(boot_delay);
    ...
}

Because msecs_to_jiffies() casts the negative value to an unsigned int, this could result in spinning in cpu_relax() almost indefinitely.

Might it be safer to add a check in boot_delay_setup() to ensure boot_delay is not less than zero?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b@thegoodpenguin.co.uk?part=1
#3 lore raw

PATCH v2 2/4 printk: deprecate boot_delay in favour of printk_delay

In reply to Andrew Murray

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

boot_delay provides a kernel parameter for delaying printk output from kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is configurable only via sysctl and thus is only used post boot.

Let's deprecate the boot_delay feature in favour of printk_delay. In order to preserve functionality, we'll also extend printk_delay such that it can additionally configured via an early kernel parameter.

Behavior change:

The delay enabled by both "boot_delay" and "printk_delay" continues working even in SYSTEM_RUNNING state. It must be explicitly stopped by setting printk_delay=0 via sysctl.

The delay is skipped when the message is suppressed in all system states. It used to skipped only for the boot_delay.

---
 kernel/printk/printk.c | 77 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 28 deletions(-)
kernel/printk/printk.c +49 -28
index 77f53eaed13216c6c3946adabc0c8fdba6401d91..cc203327247aa4f81f55b907c66ac88f30ce6da8 100644
@@ -1291,40 +1291,28 @@ static bool suppress_message_printing(int level)
 
 #ifdef CONFIG_GENERIC_CALIBRATE_DELAY
 
-static int boot_delay; /* msecs delay after each printk during bootup */
 static unsigned long long loops_per_msec;	/* based on boot_delay */
 
-static int __init boot_delay_setup(char *str)
+static void __init printk_delay_calculate(void)
 {
 	unsigned long lpj;
 
 	lpj = preset_lpj ? preset_lpj : 1000000;	/* some guess */
 	loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
 
-	get_option(&str, &boot_delay);
-	if (boot_delay > 10 * 1000)
-		boot_delay = 0;
-
-	pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
+	pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
 		"HZ: %d, loops_per_msec: %llu\n",
-		boot_delay, preset_lpj, lpj, HZ, loops_per_msec);
-	return 0;
+		printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);
 }
-early_param("boot_delay", boot_delay_setup);
 
-static void boot_delay_msec(int level)
+static void early_boot_delay_msec(void)
 {
 	unsigned long long k;
 	unsigned long timeout;
-	bool suppress = !is_printk_force_console() &&
-			suppress_message_printing(level);
-
-	if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING) || suppress)
-		return;
 
-	k = (unsigned long long)loops_per_msec * boot_delay;
+	k = (unsigned long long)loops_per_msec * printk_delay_msec;
 
-	timeout = jiffies + msecs_to_jiffies(boot_delay);
+	timeout = jiffies + msecs_to_jiffies(printk_delay_msec);
 	while (k) {
 		k--;
 		cpu_relax();
@@ -1339,11 +1327,34 @@ static void boot_delay_msec(int level)
 	}
 }
 #else
-static inline void boot_delay_msec(int level)
+static inline void __init printk_delay_calculate(void)
+{
+}
+
+static inline void early_boot_delay_msec(void)
 {
 }
 #endif
 
+static int __init printk_delay_setup(char *str)
+{
+	get_option(&str, &printk_delay_msec);
+	if (printk_delay_msec > 10 * 1000)
+		printk_delay_msec = 0;
+
+	printk_delay_calculate();
+
+	return 0;
+}
+early_param("printk_delay", printk_delay_setup);
+
+static int __init boot_delay_setup(char *str)
+{
+	pr_warn("boot_delay will soon be deprecated, please use printk_delay instead\n");
+	return printk_delay_setup(str);
+}
+early_param("boot_delay", boot_delay_setup);
+
 static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME);
 module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
 
@@ -2117,20 +2128,30 @@ static u8 *__printk_recursion_counter(void)
 		local_irq_restore(flags);		\
 	} while (0)
 
-int printk_delay_msec __read_mostly;
+unsigned int printk_delay_msec __read_mostly;
+
+static inline void late_boot_delay_msec(void)
+{
+	unsigned int m = printk_delay_msec;
+
+	while (m--) {
+		mdelay(1);
+		touch_nmi_watchdog();
+	}
+}
 
 static inline void printk_delay(int level)
 {
-	boot_delay_msec(level);
+	bool suppress = !is_printk_force_console() &&
+			suppress_message_printing(level);
 
-	if (unlikely(printk_delay_msec)) {
-		int m = printk_delay_msec;
+	if (likely(!printk_delay_msec) || suppress)
+		return;
 
-		while (m--) {
-			mdelay(1);
-			touch_nmi_watchdog();
-		}
-	}
+	if (system_state < SYSTEM_RUNNING)
+		early_boot_delay_msec();
+	else
+		late_boot_delay_msec();
 }
 
 #define CALLER_ID_MASK 0x80000000
Signature · 1 line
2.34.1
#4 lore raw

Re: [PATCH v2 2/4] printk: deprecate boot_delay in favour of printk_delay

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Low] Sysctl handler `proc_dointvec_minmax` is incorrectly used for an `unsigned int` variable. - [Low]…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] Sysctl handler proc_dointvec_minmax is incorrectly used for an unsigned int variable.
- [Low] Passing an incompatible pointer type (unsigned int *) to get_option(), which expects an int *. --

commit 75c913a5c205c791c2728e8990c05d9b6634f1b5
Author: Andrew Murray <[email protected]>

printk: deprecate boot_delay in favour of printk_delay

This commit deprecates the boot_delay kernel parameter in favor of printk_delay. It extends printk_delay to be configurable via an early kernel parameter, allowing it to function during both boot and runtime. The delay is now skipped when messages are suppressed across all system states.

Quoted 4 lines
kernel/printk/printk.c +0 -0
index 77f53eaed1321..cc203327247aa 100644

[ ... ]

Quoted 7 lines
kernel/printk/printk.c +1 -1
@@ -1339,11 +1327,34 @@ static void boot_delay_msec(int level)
 	}
 }
 #else
-static inline void boot_delay_msec(int level)
+static inline void __init printk_delay_calculate(void)
 {

kernel/printk/printk.c static void boot_delay_msec(int level) · line 1341

Quoted 10 lines
kernel/printk/printk.c +4 -0
 }
 
+static inline void early_boot_delay_msec(void)
 {
 }
 #endif
 
+static int __init printk_delay_setup(char *str)
+{
+	get_option(&str, &printk_delay_msec);

[Severity: Low]
Does this pointer sign mismatch introduce a build regression?

The get_option() function expects an int * for its second argument, but printk_delay_msec was changed to an unsigned int in this patch. This triggers a -Wincompatible-pointer-types warning, which is often treated as an error by modern compilers.

[ ... ]

kernel/printk/printk.c static u8 *__printk_recursion_counter(void) · line 2131

Quoted 6 lines
kernel/printk/printk.c +1 -1
@@ -2117,20 +2128,30 @@ static u8 *__printk_recursion_counter(void)
 		local_irq_restore(flags);		\
 	} while (0)
 
-int printk_delay_msec __read_mostly;
+unsigned int printk_delay_msec __read_mostly;

[Severity: Low]
Is the sysctl handler for printk_delay_msec still correct?

In kernel/printk/sysctl.c, the sysctl entry for printk_delay_msec uses the proc_dointvec_minmax handler, which expects a pointer to a signed int. Since printk_delay_msec is now an unsigned int, should this be updated to proc_douintvec_minmax to prevent an API regression?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b@thegoodpenguin.co.uk?part=2
maintainer Reviewed-by on v2 2/4
#5 lore raw

Re: [PATCH v2 2/4] printk: deprecate boot_delay in favour of printk_delay

In reply to Andrew Murray
Quoted 14 lines · Andrew Murray

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

boot_delay provides a kernel parameter for delaying printk output from kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is configurable only via sysctl and thus is only used post boot.

Let's deprecate the boot_delay feature in favour of printk_delay. In order to preserve functionality, we'll also extend printk_delay such that it can additionally configured via an early kernel parameter.

Behavior change:

Quoted 8 lines

The delay enabled by both "boot_delay" and "printk_delay" continues working even in SYSTEM_RUNNING state. It must be explicitly stopped by setting printk_delay=0 via sysctl.

The delay is skipped when the message is suppressed in all system states. It used to skipped only for the boot_delay.

Looks good to me:

Note that Sashiko AI warns about possible problems with negative printk_delay values, see
https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b%40thegoodpenguin.co.uk

But they should be handled in both the early parameter and sysctl interface by the "10 * 1000" and "&ten_thousand" limits.

The only potential problem might be a warning about possible "sign" mismatch from the compiler. But I do not see any even with make W=2.

Best Regards,
Petr

#6 lore raw

Re: [PATCH v2 2/4] printk: deprecate boot_delay in favour of printk_delay

Hi Petr,

Quoted 29 lines · Petr Mladek
Quoted 14 lines · Andrew Murray

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

boot_delay provides a kernel parameter for delaying printk output from kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is configurable only via sysctl and thus is only used post boot.

Let's deprecate the boot_delay feature in favour of printk_delay. In order to preserve functionality, we'll also extend printk_delay such that it can additionally configured via an early kernel parameter.

Behavior change:

Quoted 8 lines

The delay enabled by both "boot_delay" and "printk_delay" continues working even in SYSTEM_RUNNING state. It must be explicitly stopped by setting printk_delay=0 via sysctl.

The delay is skipped when the message is suppressed in all system states. It used to skipped only for the boot_delay.

Looks good to me:

Quoted 7 lines

Note that Sashiko AI warns about possible problems with negative printk_delay values, see
https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b%40thegoodpenguin.co.uk

But they should be handled in both the early parameter and sysctl interface by the "10 * 1000" and "&ten_thousand" limits.

Yes, that was my also view.

Quoted 4 lines

The only potential problem might be a warning about possible "sign" mismatch from the compiler. But I do not see any even with make W=2.

I suspect this will come up everytime a change is made in this area, or perhaps some W=2 errors will pop up via kernelci or similar. I propose updating the patch as follows:

kernel/printk/printk.c +6 -3
index 5278d9cb19e4..fbb67f10c21e 100644
@@ -1338,10 +1338,13 @@ static inline void early_boot_delay_msec(void)
 
 static int __init printk_delay_setup(char *str)
 {
-       get_option(&str, &printk_delay_msec);
-       if (printk_delay_msec > 10 * 1000)
-               printk_delay_msec = 0;
+       int printk_delay_val = 0;
 
+       get_option(&str, &printk_delay_val);
+       if (printk_delay_val < 0 || printk_delay_val > 10 * 1000)
+               return 0;
+
+       printk_delay_msec = (unsigned int)printk_delay_val;
        printk_delay_calculate();
 
        return 0;
kernel/printk/sysctl.c +1 -1
index f15732e93c2e..f256fc05faaf 100644
@@ -46,7 +46,7 @@ static const struct ctl_table printk_sysctls[] = {
                .data           = &printk_delay_msec,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = proc_douintvec_minmax,
                .extra1         = SYSCTL_ZERO,
                .extra2         = (void *)&ten_thousand,
        },

This makes the cast explict, verifies the range before casting (I guess a range of negative values could result in a postive value within the 10,000 range) and also uses the correct proc_handler.

This has the side effect of not showing the following pr_debug for the lpj calculation when a delay is not set. Though loops_per_msec is only used during boot, so I don't think there is any loss here.

        pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
                "HZ: %d, loops_per_msec: %llu\n",
                printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);

Can I keep your Reviewed-By with these changes?

Thanks,

Andrew Murray

Quoted 3 lines

Best Regards,
Petr

maintainer
#7 lore raw

Re: [PATCH v2 2/4] printk: deprecate boot_delay in favour of printk_delay

Quoted 78 lines · Andrew Murray

Hi Petr,

Quoted 29 lines · Petr Mladek
Quoted 14 lines · Andrew Murray

The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl are two distinct mechanisms for providing similar functionality which add a delay prior to each printed printk message.

boot_delay provides a kernel parameter for delaying printk output from kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is configurable only via sysctl and thus is only used post boot.

Let's deprecate the boot_delay feature in favour of printk_delay. In order to preserve functionality, we'll also extend printk_delay such that it can additionally configured via an early kernel parameter.

Behavior change:

Quoted 8 lines

The delay enabled by both "boot_delay" and "printk_delay" continues working even in SYSTEM_RUNNING state. It must be explicitly stopped by setting printk_delay=0 via sysctl.

The delay is skipped when the message is suppressed in all system states. It used to skipped only for the boot_delay.

Looks good to me:

Quoted 7 lines

Note that Sashiko AI warns about possible problems with negative printk_delay values, see
https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b%40thegoodpenguin.co.uk

But they should be handled in both the early parameter and sysctl interface by the "10 * 1000" and "&ten_thousand" limits.

Yes, that was my also view.

Quoted 4 lines

The only potential problem might be a warning about possible "sign" mismatch from the compiler. But I do not see any even with make W=2.

I suspect this will come up everytime a change is made in this area, or perhaps some W=2 errors will pop up via kernelci or similar. I propose updating the patch as follows:

kernel/printk/printk.c +6 -3
index 5278d9cb19e4..fbb67f10c21e 100644
@@ -1338,10 +1338,13 @@ static inline void early_boot_delay_msec(void)
 
 static int __init printk_delay_setup(char *str)
 {
-       get_option(&str, &printk_delay_msec);
-       if (printk_delay_msec > 10 * 1000)
-               printk_delay_msec = 0;
+       int printk_delay_val = 0;
 
+       get_option(&str, &printk_delay_val);
+       if (printk_delay_val < 0 || printk_delay_val > 10 * 1000)
+               return 0;
+
+       printk_delay_msec = (unsigned int)printk_delay_val;
        printk_delay_calculate();
 
        return 0;
kernel/printk/sysctl.c +0 -0
index f15732e93c2e..f256fc05faaf 100644

kernel/printk/sysctl.c static const struct ctl_table printk_sysctls[] = { · line 47

Quoted 2 lines
kernel/printk/sysctl.c +0 -0
@@ -46,7 +46,7 @@ static const struct ctl_table printk_sysctls[] = {
                .data           = &printk_delay_msec,
                .maxlen         = sizeof(int),

I would change this to sizeof(unsigned int) as well.

kernel/printk/sysctl.c static const struct ctl_table printk_sysctls[] = { · line 52

Quoted 6 lines
kernel/printk/sysctl.c +1 -1
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = proc_douintvec_minmax,
                .extra1         = SYSCTL_ZERO,
                .extra2         = (void *)&ten_thousand,
        },

Otherwise, it looks good to me.

Quoted 1 line

This makes the cast explict, verifies the range before casting

Yup.

Quoted 2 lines

(I guess a range of negative values could result in a postive value within the 10,000 range) and also uses the correct proc_handler.

IMHO, this should not happen. I have never seen int smaller than 4 bytes. If I count it correctly, positive numbers should be up to 32767.

Quoted 3 lines

This has the side effect of not showing the following pr_debug for the lpj calculation when a delay is not set. Though loops_per_msec is only used during boot, so I don't think there is any loss here.

I agree that it should not harm. But please mention this in the commit message.

Quoted 5 lines
        pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
                "HZ: %d, loops_per_msec: %llu\n",
                printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);

Can I keep your Reviewed-By with these changes?

Feel free to keep it. That said, please put at least the change of the ctl_table into a separate patch. I would rather put both new changes into separate file. It is never a good idea to hide such changes in a complex patch which mostly reshuffles an existing code.

Best Regards,
Petr

#8 lore raw

Re: [PATCH v2 2/4] printk: deprecate boot_delay in favour of printk_delay

Hi Petr,

Quoted 9 lines

I would change this to sizeof(unsigned int) as well.

Quoted 6 lines
                .mode           = 0644,
kernel/printk/sysctl.c +1 -1
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = proc_douintvec_minmax,
                .extra1         = SYSCTL_ZERO,
                .extra2         = (void *)&ten_thousand,
        },

OK.

Quoted 14 lines

Otherwise, it looks good to me.

Quoted 1 line

This makes the cast explict, verifies the range before casting

Yup.

Quoted 2 lines

(I guess a range of negative values could result in a postive value within the 10,000 range) and also uses the correct proc_handler.

IMHO, this should not happen. I have never seen int smaller than 4 bytes. If I count it correctly, positive numbers should be up to 32767.

Quoted 6 lines
Quoted 3 lines

This has the side effect of not showing the following pr_debug for the lpj calculation when a delay is not set. Though loops_per_msec is only used during boot, so I don't think there is any loss here.

I agree that it should not harm. But please mention this in the commit message.

Yes, sure.

Quoted 5 lines
Quoted 5 lines
        pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
                "HZ: %d, loops_per_msec: %llu\n",
                printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);
Quoted 7 lines
Quoted 1 line

Can I keep your Reviewed-By with these changes?

Feel free to keep it. That said, please put at least the change of the ctl_table into a separate patch. I would rather put both new changes into separate file. It is never a good idea to hide such changes in a complex patch which mostly reshuffles an existing code.

Yes, that's a fair point.

Thanks,

Andrew Murray

Quoted 3 lines

Best Regards,
Petr

#9 lore raw

PATCH v2 3/4 printk: nbcon: move printk_delay to console emiting code

In reply to Andrew Murray

The printk_delay and boot_delay features are helpful for debugging as kernel output can be slowed down during boot allowing messages to be seen before scrolling off the screen, or to correlate timing between some physical event and console output.

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console.

Let's address this by moving the printk delay from the calling code to the console emiting code instead. Whilst this ensures that delays are still observed (especially for slower consoles), it doesn't improve the use-case of using boot_delay/printk_delay to correlate timings between physical events and console output.

Behavior change:

Please note that printk delays now occur after messages are emitted rather than before.

---
 include/linux/console.h  |  5 ++++-
 include/linux/printk.h   |  1 -
 kernel/printk/internal.h |  6 ++++++
 kernel/printk/nbcon.c    | 13 +++++++++++++
 kernel/printk/printk.c   | 15 +++++++--------
 5 files changed, 30 insertions(+), 10 deletions(-)
include/linux/console.h +4 -1
index d624200cfc1708bf73925892a466efe0c95c5586..3478b556c0eb9579530409dc6fbb9b5a8bff581c 100644
@@ -290,6 +290,8 @@ struct nbcon_context {
  * @outbuf:		Pointer to the text buffer for output
  * @len:		Length to write
  * @unsafe_takeover:	If a hostile takeover in an unsafe state has occurred
+ * @emitted:		The write context attempted to emit the message. Might
+ *			be incomplete.
  * @cpu:		CPU on which the message was generated
  * @pid:		PID of the task that generated the message
  * @comm:		Name of the task that generated the message
@@ -298,7 +300,8 @@ struct nbcon_write_context {
 	struct nbcon_context	__private ctxt;
 	char			*outbuf;
 	unsigned int		len;
-	bool			unsafe_takeover;
+	unsigned char		unsafe_takeover : 1;
+	unsigned char		emitted		: 1;
 #ifdef CONFIG_PRINTK_EXECUTION_CTX
 	int			cpu;
 	pid_t			pid;
include/linux/printk.h +0 -1
index f594c1266bfd411f2238b45374e8a71222f0407c..8885e11367d50ea1cd7642249852d011e589adb4 100644
@@ -188,7 +188,6 @@ extern int __printk_ratelimit(const char *func);
 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 				   unsigned int interval_msec);
 
-extern int printk_delay_msec;
 extern int dmesg_restrict;
 
 extern void wake_up_klogd(void);
kernel/printk/internal.h +6 -0
index 85fbf1801cbe070ad96d253bccdf775a11bf945a..c3586f8b8360208902bbbd4607413997bcbd5fb9 100644
@@ -33,6 +33,8 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
 # define force_legacy_kthread()	(false)
 #endif
 
+extern unsigned int printk_delay_msec;
+
 #ifdef CONFIG_PRINTK
 
 #ifdef CONFIG_PRINTK_CALLER
@@ -131,6 +133,8 @@ static inline void nbcon_kthread_wake(struct console *con)
 	rcuwait_wake_up(&con->rcuwait); /* LMM(nbcon_kthread_wake:A) */
 }
 
+void printk_delay(bool use_atomic);
+
 #else
 
 #define PRINTK_PREFIX_MAX	0
@@ -162,6 +166,8 @@ static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *hand
 static inline void nbcon_kthread_wake(struct console *con) { }
 static inline void nbcon_kthreads_wake(void) { }
 
+static inline void printk_delay(bool use_atomic) { }
+
 #endif /* CONFIG_PRINTK */
 
 extern bool have_boot_console;
kernel/printk/nbcon.c +13 -0
index 4b03b019cd5ee25d68e9ace84392045e91241a7f..ae45cb0589c0effafc66f1756bdaecd1c1e53ab9 100644
@@ -1069,6 +1069,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	else
 		con->write_thread(con, wctxt);
 
+	wctxt->emitted = 1;
+
 	if (!wctxt->outbuf) {
 		/*
 		 * Ownership was lost and reacquired by the driver. Handle it
@@ -1267,11 +1269,16 @@ static int nbcon_kthread_func(void *__console)
 
 		con_flags = console_srcu_read_flags(con);
 
+		wctxt.emitted = 0;
+
 		if (console_is_usable(con, con_flags, false))
 			backlog = nbcon_emit_one(&wctxt, false);
 
 		console_srcu_read_unlock(cookie);
 
+		if (backlog && wctxt.emitted)
+			printk_delay(false);
+
 		cond_resched();
 
 	} while (backlog);
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
 	}
 
 	progress = nbcon_emit_one(&wctxt, use_atomic);
+	if (progress && wctxt.emitted)
+		printk_delay(use_atomic);
 
 	if (use_atomic) {
 		start_critical_timings();
@@ -1584,6 +1593,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 			if (!nbcon_context_try_acquire(ctxt, false))
 				return -EPERM;
 
+			wctxt.emitted = 0;
+
 			/*
 			 * nbcon_emit_next_record() returns false when
 			 * the console was handed over or taken over.
@@ -1600,6 +1611,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 			if (nbcon_seq_read(con) < stop_seq)
 				err = -ENOENT;
 			break;
+		} else if (wctxt.emitted > 0) {
+			printk_delay(true);
 		}
 	}
 
kernel/printk/printk.c +7 -8
index cc203327247aa4f81f55b907c66ac88f30ce6da8..5278d9cb19e4177a00998fba5c1438251e033578 100644
@@ -2140,18 +2140,17 @@ static inline void late_boot_delay_msec(void)
 	}
 }
 
-static inline void printk_delay(int level)
+void printk_delay(bool use_atomic)
 {
-	bool suppress = !is_printk_force_console() &&
-			suppress_message_printing(level);
-
-	if (likely(!printk_delay_msec) || suppress)
+	if (likely(!printk_delay_msec))
 		return;
 
 	if (system_state < SYSTEM_RUNNING)
 		early_boot_delay_msec();
-	else
+	else if (use_atomic)
 		late_boot_delay_msec();
+	else
+		msleep(printk_delay_msec);
 }
 
 #define CALLER_ID_MASK 0x80000000
@@ -2471,8 +2470,6 @@ asmlinkage int vprintk_emit(int facility, int level,
 		ft.legacy_direct = false;
 	}
 
-	printk_delay(level);
-
 	printed_len = vprintk_store(facility, level, dev_info, fmt, args);
 
 	if (ft.nbcon_atomic)
@@ -3211,6 +3208,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		*handover = console_lock_spinning_disable_and_check(cookie);
 		printk_safe_exit_irqrestore(flags);
 	}
+	printk_delay(true);
+
 skip:
 	return true;
 }
Signature · 1 line
2.34.1
#10 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] printk_delay(use_atomic) causes massive IRQ latency by busy-waiting with local interrupts disabled in nbcon_legacy_emit_next_record().
- [Medium] printk_delay() bypasses its intended rate-limiting function when a console lock handover occurs in console_emit_next_record().
- [Medium] Moving printk_delay() into the console flush loops incorrectly multiplies the delay by the number of active consoles.

Pre-existing issues:
- [Critical] Use-after-free of the con pointer in console_flush_all() due to an expanded race window when printk_delay() is called. --

commit e90407202970d9d83dc93dd60ca58eb802e88311
Author: Andrew Murray <[email protected]>

printk: nbcon: move printk_delay to console emiting code

This commit moves the printk delay from the caller of printk to the console emitting code. This ensures delays are observed even when messages are emitted asynchronously to the console.

Quoted 3 lines
kernel/printk/nbcon.c +0 -0

[ ... ]

kernel/printk/nbcon.c bool nbcon_legacy_emit_next_record(struct console *con, bool *handover, · line 1536

Quoted 6 lines
kernel/printk/nbcon.c +2 -0
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
 	}
 
 	progress = nbcon_emit_one(&wctxt, use_atomic);
+	if (progress && wctxt.emitted)
+		printk_delay(use_atomic);

[Severity: High]
Does calling printk_delay() here cause massive IRQ latency?

In nbcon_legacy_emit_next_record(), when use_atomic is true, local interrupts are explicitly disabled via printk_safe_enter_irqsave() just before this block:

	if (use_atomic) {
		printk_safe_enter_irqsave(flags);
		console_lock_spinning_enable();
		stop_critical_timings();
	}

Calling printk_delay(use_atomic) while IRQs are disabled will execute late_boot_delay_msec() which busy-loops.

Could this stall the CPU with interrupts disabled for hundreds of milliseconds per message, potentially dropping hardware interrupts or triggering the NMI watchdog?

Quoted 2 lines
kernel/printk/nbcon.c +0 -0
 	if (use_atomic) {
 		start_critical_timings();

[ ... ]

Quoted 3 lines
kernel/printk/printk.c +0 -0

[ ... ]

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3212

Quoted 6 lines
kernel/printk/printk.c +2 -0
@@ -3211,6 +3208,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		*handover = console_lock_spinning_disable_and_check(cookie);
 		printk_safe_exit_irqrestore(flags);
 	}
+	printk_delay(true);
+

[Severity: Critical]
This isn't a bug introduced by this patch, but does the expanded delay create a use-after-free window for the con pointer in console_flush_all()?

In console_emit_next_record(), if a lock handover occurs, console_lock_spinning_disable_and_check() releases the SRCU read lock. This patch inserts printk_delay(true) immediately after this lock release, adding a multi-millisecond busy-wait delay.

During this expanded window, another CPU can unregister and free the console because the SRCU lock is no longer held.

When console_emit_next_record() returns to console_flush_all(), it unconditionally dereferences con->seq before checking if a handover occurred:

		if (!console_emit_next_record(con, &handover, cookie))
			continue;
		printk_seq = con->seq;

Could this massive delay guarantee a use-after-free if a console is unregistered under contention?

[Severity: Medium]
Also regarding this delay placement, if a console lock handover occurs, is the intended rate limiting bypassed?

When multiple CPUs attempt to print, console_lock_spinning_disable_and_check() yields the lock to a waiting CPU before the delay begins.

The waiting CPU will immediately acquire the lock and begin printing the next message without waiting for the first CPU's delay to finish.

Does this result in messages being emitted in an immediate burst under lock contention, bypassing the intended pacing?

[Severity: Medium]
Additionally, does moving printk_delay() here multiply the delay by the number of active consoles?

Previously, vprintk_emit() called printk_delay() once per message.

Because console_emit_next_record() is called sequentially for each registered console within the for_each_console_srcu(con) loop in console_flush_all():

	for_each_console_srcu(con) {
		...
		if (!console_emit_next_record(con, &handover, cookie))
			continue;
		...
	}

Will the delay now be executed N times per message, where N is the number of active consoles?

Quoted 3 lines
kernel/printk/printk.c +0 -0
 skip:
 	return true;
 }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b@thegoodpenguin.co.uk?part=3
maintainer
#11 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 29 lines · On 2026-06-30, [email protected] wrote:
Quoted 3 lines
kernel/printk/printk.c +0 -0

[ ... ]

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3212

Quoted 6 lines
kernel/printk/printk.c +2 -0
@@ -3211,6 +3208,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		*handover = console_lock_spinning_disable_and_check(cookie);
 		printk_safe_exit_irqrestore(flags);
 	}
+	printk_delay(true);
+

[Severity: Critical]
This isn't a bug introduced by this patch, but does the expanded delay create a use-after-free window for the con pointer in console_flush_all()?

In console_emit_next_record(), if a lock handover occurs, console_lock_spinning_disable_and_check() releases the SRCU read lock.

This patch inserts printk_delay(true) immediately after this lock release, adding a multi-millisecond busy-wait delay.

During this expanded window, another CPU can unregister and free the console because the SRCU lock is no longer held.

When console_emit_next_record() returns to console_flush_all(), it unconditionally dereferences con->seq before checking if a handover occurred:

Quoted 6 lines
		if (!console_emit_next_record(con, &handover, cookie))
			continue;
		printk_seq = con->seq;

Could this massive delay guarantee a use-after-free if a console is unregistered under contention?

This is a legitimate bug report (even without this series). I will post a patch for this.

John Ogness

maintainer
#12 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

In reply to Andrew Murray

Hi,

Sorry I am so late to this party.

Quoted 14 lines · Andrew Murray
include/linux/console.h +2 -0
index d624200cfc1708bf73925892a466efe0c95c5586..3478b556c0eb9579530409dc6fbb9b5a8bff581c 100644
@@ -290,6 +290,8 @@ struct nbcon_context {
  * @outbuf:		Pointer to the text buffer for output
  * @len:		Length to write
  * @unsafe_takeover:	If a hostile takeover in an unsafe state has occurred
+ * @emitted:		The write context attempted to emit the message. Might
+ *			be incomplete.
  * @cpu:		CPU on which the message was generated
  * @pid:		PID of the task that generated the message
  * @comm:		Name of the task that generated the message

include/linux/console.h struct nbcon_write_context { · line 304

Quoted 6 lines
include/linux/console.h +2 -1
@@ -298,7 +300,8 @@ struct nbcon_write_context {
 	struct nbcon_context	__private ctxt;
 	char			*outbuf;
 	unsigned int		len;
-	bool			unsafe_takeover;
+	unsigned char		unsafe_takeover : 1;
+	unsigned char		emitted		: 1;

This is the wrong structure to add this flag. This structure is for the nbcon drivers.

struct nbcon_context would be the correct structure.

kernel/printk/nbcon.c bool nbcon_legacy_emit_next_record(struct console *con, bool *handover, · line 1539

Quoted 13 lines
kernel/printk/nbcon.c +2 -0
index 4b03b019cd5ee25d68e9ace84392045e91241a7f..ae45cb0589c0effafc66f1756bdaecd1c1e53ab9 100644
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
 	}
 
 	progress = nbcon_emit_one(&wctxt, use_atomic);
+	if (progress && wctxt.emitted)
+		printk_delay(use_atomic);
 
 	if (use_atomic) {
 		start_critical_timings();

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

Quoted 10 lines
kernel/printk/nbcon.c +2 -0
@@ -1584,6 +1593,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 			if (!nbcon_context_try_acquire(ctxt, false))
 				return -EPERM;
 
+			wctxt.emitted = 0;
+
 			/*
 			 * nbcon_emit_next_record() returns false when
 			 * the console was handed over or taken over.

kernel/printk/nbcon.c static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) · line 1615

Quoted 5 lines
kernel/printk/nbcon.c +2 -0
@@ -1600,6 +1611,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
 			if (nbcon_seq_read(con) < stop_seq)
 				err = -ENOENT;
 			break;
+		} else if (wctxt.emitted > 0) {
+			printk_delay(true);

@emitted is a flag:

		} else if (wctxt.emitted) {

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3212

Quoted 10 lines
kernel/printk/printk.c +2 -0
index cc203327247aa4f81f55b907c66ac88f30ce6da8..5278d9cb19e4177a00998fba5c1438251e033578 100644
@@ -3211,6 +3208,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		*handover = console_lock_spinning_disable_and_check(cookie);
 		printk_safe_exit_irqrestore(flags);
 	}
+	printk_delay(true);
+

Again, too deep. Let console_flush_all() and legacy_kthread_func() perform the delay appropriately between each message.

John Ogness

maintainer
#13 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 20 lines · John Ogness

Hi,

Sorry I am so late to this party.

Quoted 15 lines · Andrew Murray
include/linux/console.h +2 -0
index d624200cfc1708bf73925892a466efe0c95c5586..3478b556c0eb9579530409dc6fbb9b5a8bff581c 100644
@@ -290,6 +290,8 @@ struct nbcon_context {
  * @outbuf:		Pointer to the text buffer for output
  * @len:		Length to write
  * @unsafe_takeover:	If a hostile takeover in an unsafe state has occurred
+ * @emitted:		The write context attempted to emit the message. Might
+ *			be incomplete.
  * @cpu:		CPU on which the message was generated
  * @pid:		PID of the task that generated the message
  * @comm:		Name of the task that generated the message
@@ -298,7 +300,8 @@ struct nbcon_write_context {
 	struct nbcon_context	__private ctxt;
Quoted 8 lines

include/linux/console.h struct nbcon_write_context { · line 304

Quoted 5 lines
include/linux/console.h +2 -1
 	char			*outbuf;
 	unsigned int		len;
-	bool			unsafe_takeover;
+	unsigned char		unsafe_takeover : 1;
+	unsigned char		emitted		: 1;

This is the wrong structure to add this flag. This structure is for the nbcon drivers.

Good point. I see:

+ "struct nbcon_write_context" is intended for passing information down to the console drivers via .write_thread() and .write_atomic() callbacks.

+ "struct nbcon_contex" aleady contains section
"members set by emit".

Quoted 13 lines

struct nbcon_context would be the correct structure.

Quoted 11 lines
kernel/printk/nbcon.c +2 -0
index 4b03b019cd5ee25d68e9ace84392045e91241a7f..ae45cb0589c0effafc66f1756bdaecd1c1e53ab9 100644
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
 	}
 
 	progress = nbcon_emit_one(&wctxt, use_atomic);
+	if (progress && wctxt.emitted)
+		printk_delay(use_atomic);
 
Quoted 7 lines

kernel/printk/nbcon.c bool nbcon_legacy_emit_next_record(struct console *con, bool *handover, · line 1539

Quoted 2 lines
kernel/printk/nbcon.c +0 -0
 	if (use_atomic) {
 		start_critical_timings();

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

True. The question is if the proper solution is worth the complexity. We would need to pass the information down two level of the API. It would require adding a new (output) parameter to console_flush_one_record(), nbcon_legacy_emit_next_record(), and console_emit_next_record().

It is not that complicated but these functions are already hairy enough so we should be careful.

Best Regards,
Petr

maintainer
#14 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 5 lines · Petr Mladek
Quoted 4 lines

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

Quoted 7 lines

True. The question is if the proper solution is worth the complexity. We would need to pass the information down two level of the API. It would require adding a new (output) parameter to console_flush_one_record(), nbcon_legacy_emit_next_record(), and console_emit_next_record().

It is not that complicated but these functions are already hairy enough so we should be careful.

Fair enough. But then it should be consistent and console_emit_next_record() should perform the delay before allowing the handover. Something like this:

kernel/printk/printk.c +3 -0
index 2fe9a963c823a..62fd6a5ebef66 100644
@@ -3161,6 +3161,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		 */
 
 		con->write(con, outbuf, pmsg.outbuf_len);
+		printk_delay(false);
+
 		con->seq = pmsg.seq + 1;
 	} else {
 		/*
@@ -3182,6 +3184,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		printk_legacy_allow_spinlock_enter();
 		con->write(con, outbuf, pmsg.outbuf_len);
 		printk_legacy_allow_spinlock_exit();
+		printk_delay(true);
 
 		start_critical_timings();
 

John

maintainer
#15 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 11 lines · John Ogness
Quoted 10 lines · Petr Mladek
Quoted 4 lines

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

True. The question is if the proper solution is worth the complexity. We would need to pass the information down two level of the API. It would require adding a new (output) parameter to console_flush_one_record(), nbcon_legacy_emit_next_record(), and console_emit_next_record().

Quoted 6 lines
Quoted 2 lines

It is not that complicated but these functions are already hairy enough so we should be careful.

Fair enough. But then it should be consistent and console_emit_next_record() should perform the delay before allowing the handover. Something like this:

Great catch!

Quoted 14 lines
kernel/printk/printk.c +2 -0
index 2fe9a963c823a..62fd6a5ebef66 100644
@@ -3161,6 +3161,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		 */
 
 		con->write(con, outbuf, pmsg.outbuf_len);
+		printk_delay(false);
+
 		con->seq = pmsg.seq + 1;
 	} else {
 		/*

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3187

Quoted 4 lines
kernel/printk/printk.c +1 -0
@@ -3182,6 +3184,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 		printk_legacy_allow_spinlock_enter();
 		con->write(con, outbuf, pmsg.outbuf_len);
 		printk_legacy_allow_spinlock_exit();
+		printk_delay(true);

It is pity that this is inside printk_safe context with IRQs disabled. A solution might be to call it before the write.

But maybe, this is good enough. This code path is called from vprintk_emit() and it might be in an atomic context anyway. Also it increases the chance of successful handover which might help as well.

Anyway, it would be nice to mention these pitfalls into commit message.

Quoted 5 lines
kernel/printk/printk.c +0 -0
 		start_critical_timings();
 
 

John

#16 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 8 lines · Petr Mladek
Quoted 6 lines · John Ogness
Quoted 5 lines · Petr Mladek
Quoted 4 lines

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

True. The question is if the proper solution is worth the complexity. We would need to pass the information down two level of the API. It would require adding a new (output) parameter to console_flush_one_record(), nbcon_legacy_emit_next_record(), and console_emit_next_record().

It is not that complicated but these functions are already hairy enough so we should be careful.

Indeed - It would have been nice to put the delay in console_flush_one_record, but nbcon_legacy_emit_next_record and console_emit_next_record don't provide an easy way of knowing if the record was actually printed.

Quoted 6 lines
Quoted 4 lines

Fair enough. But then it should be consistent and console_emit_next_record() should perform the delay before allowing the handover. Something like this:

Great catch!

I'll update the series to reflect this.

Quoted 8 lines
Quoted 8 lines
kernel/printk/printk.c +0 -0
index 2fe9a963c823a..62fd6a5ebef66 100644
@@ -3161,6 +3161,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
               */
 
Quoted 14 lines

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3187

Quoted 11 lines
kernel/printk/printk.c +3 -0
              con->write(con, outbuf, pmsg.outbuf_len);
+             printk_delay(false);
+
              con->seq = pmsg.seq + 1;
      } else {
              /*
@@ -3182,6 +3184,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
              printk_legacy_allow_spinlock_enter();
              con->write(con, outbuf, pmsg.outbuf_len);
              printk_legacy_allow_spinlock_exit();
+             printk_delay(true);

It is pity that this is inside printk_safe context with IRQs disabled. A solution might be to call it before the write.

I tried to be consistent about always performing the delay before or after the emit. As part of this series I moved the delay so it now occurs after the emit. This made it easier to know if the message was actually emitted (rather than delaying, and then a handover occurring before actually emitting).

Quoted 7 lines

But maybe, this is good enough. This code path is called from vprintk_emit() and it might be in an atomic context anyway. Also it increases the chance of successful handover which might help as well.

Anyway, it would be nice to mention these pitfalls into commit message.

Sure.

Thanks for the feedback Petr, John, Benedikt!

Andrew Murray

Quoted 6 lines
Quoted 6 lines
kernel/printk/printk.c +0 -0
              start_critical_timings();
 
 

John

#17 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

In reply to John Ogness
Quoted 30 lines · John Ogness

Hi,

Sorry I am so late to this party.

Quoted 14 lines · Andrew Murray
include/linux/console.h +2 -0
index d624200cfc1708bf73925892a466efe0c95c5586..3478b556c0eb9579530409dc6fbb9b5a8bff581c 100644
@@ -290,6 +290,8 @@ struct nbcon_context {
  * @outbuf:          Pointer to the text buffer for output
  * @len:             Length to write
  * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
+ * @emitted:         The write context attempted to emit the message. Might
+ *                   be incomplete.
  * @cpu:             CPU on which the message was generated
  * @pid:             PID of the task that generated the message
  * @comm:            Name of the task that generated the message

include/linux/console.h struct nbcon_write_context { · line 304

Quoted 6 lines
include/linux/console.h +2 -1
@@ -298,7 +300,8 @@ struct nbcon_write_context {
      struct nbcon_context    __private ctxt;
      char                    *outbuf;
      unsigned int            len;
-     bool                    unsafe_takeover;
+     unsigned char           unsafe_takeover : 1;
+     unsigned char           emitted         : 1;

This is the wrong structure to add this flag. This structure is for the nbcon drivers.

Quoted 1 line

struct nbcon_context would be the correct structure.

That's no problem, I'll update on the next series.

Quoted 38 lines
Quoted 6 lines
kernel/printk/nbcon.c +0 -0
index 4b03b019cd5ee25d68e9ace84392045e91241a7f..ae45cb0589c0effafc66f1756bdaecd1c1e53ab9 100644

kernel/printk/nbcon.c bool nbcon_legacy_emit_next_record(struct console *con, bool *handover, · line 1539

Quoted 8 lines
kernel/printk/nbcon.c +2 -0
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
      }
 
      progress = nbcon_emit_one(&wctxt, use_atomic);
+     if (progress && wctxt.emitted)
+             printk_delay(use_atomic);
 
      if (use_atomic) {
              start_critical_timings();

This is too deep (also pointed out by Sashiko) because it multiplies the delay times the number of consoles. For the legacy printing, it would be more appropriate to put the delay inside console_flush_all() and legacy_kthread_func().

Quoted 10 lines
kernel/printk/nbcon.c +2 -0
@@ -1584,6 +1593,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
                      if (!nbcon_context_try_acquire(ctxt, false))
                              return -EPERM;
 
+                     wctxt.emitted = 0;
+
                      /*
                       * nbcon_emit_next_record() returns false when
                       * the console was handed over or taken over.

kernel/printk/nbcon.c static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) · line 1615

Quoted 5 lines
kernel/printk/nbcon.c +2 -0
@@ -1600,6 +1611,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
                      if (nbcon_seq_read(con) < stop_seq)
                              err = -ENOENT;
                      break;
+             } else if (wctxt.emitted > 0) {
+                     printk_delay(true);

@emitted is a flag:

Quoted 2 lines
                } else if (wctxt.emitted) {

Good spot, that was sloppy of me. I'll fix.

Thanks,

Andrew Murray

Quoted 15 lines

kernel/printk/printk.c static bool console_emit_next_record(struct console *con, bool *handover, int co · line 3212

Quoted 10 lines
kernel/printk/printk.c +2 -0
index cc203327247aa4f81f55b907c66ac88f30ce6da8..5278d9cb19e4177a00998fba5c1438251e033578 100644
@@ -3211,6 +3208,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
              *handover = console_lock_spinning_disable_and_check(cookie);
              printk_safe_exit_irqrestore(flags);
      }
+     printk_delay(true);
+

Again, too deep. Let console_flush_all() and legacy_kthread_func() perform the delay appropriately between each message.

John Ogness

#18 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

In reply to Andrew Murray
Quoted 4 lines · On Tue, 30 Jun 2026 17:35:59 +0100 Andrew Murray…

The printk_delay and boot_delay features are helpful for debugging as kernel output can be slowed down during boot allowing messages to be seen before scrolling off the screen, or to correlate timing between some physical event and console output.

By now, it slows down the boot process, which is the handy part of that feature.

Quoted 6 lines

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console.

Using this feature to slow down the boot/suspend/resume process and implicit make printk() happen, is the usefull part of that feature. Imagine this sequence (which hit me on suspend/resume on i.MX after shutting down all secondary CPUs)

printk("A");
(do some stuff)
printk("B");
read from peripheral --> system got stuck here since peripheral was not clocked or powered or both any more.

The delay (and later on a ugly patch to make printk() synchrounous) helped to locate where the failed access happend. JTAG did not help, since the CPU got stuck --> no JTAG communication to that CPU.

With your purposed change you *may* see "A", but never "B". Quite challenging...

So please leave the delay on the calling side - it is helpfull there.

Regards
Bene Spranger

#19 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Hi Benedikt,

Quoted 28 lines · Benedikt Spranger
Quoted 4 lines · On Tue, 30 Jun 2026 17:35:59 +0100 Andrew Murray…

The printk_delay and boot_delay features are helpful for debugging as kernel output can be slowed down during boot allowing messages to be seen before scrolling off the screen, or to correlate timing between some physical event and console output.

By now, it slows down the boot process, which is the handy part of that feature.

Quoted 6 lines

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console.

Using this feature to slow down the boot/suspend/resume process and implicit make printk() happen, is the usefull part of that feature. Imagine this sequence (which hit me on suspend/resume on i.MX after shutting down all secondary CPUs)

printk("A");
(do some stuff)
printk("B");
read from peripheral --> system got stuck here since peripheral was not clocked or powered or both any more.

Quoted 3 lines

The delay (and later on a ugly patch to make printk() synchrounous) helped to locate where the failed access happend. JTAG did not help, since the CPU got stuck --> no JTAG communication to that CPU.

I understand the use-case, you sprinkle printk's so you can find the point where a read to a register causes the CPU to stop. This requires that the printk happens before the read, and the output from the printk is printed before the read.

Quoted 3 lines

With your purposed change you *may* see "A", but never "B". Quite challenging...

At present you may see 'A' and you may see 'B'.

Prior to the changes in this patchset, and assuming an nbcon console (which may not be your usecase, but is perhaps representative of future use-cases), then the printk delay will always happen within the call to printk (and always before emitting). However, depending on the context, that printk call may return (and proceed to your CPU halting register read), before the message is actually emitted to the console. I.e. it's a race.

This series moves the delay to the emit side, as well as moving the delay after the emit. Thus the calling code may make progress more quickly, but depending on the context, it may also flush/emit before returning from printk.

In my view, with or without this series, there are no guarantees that you will see 'A' and 'B'. And in any case, achieving the functionality for debugging required you to modify the printk anyway.

Quoted 2 lines

So please leave the delay on the calling side - it is helpfull there.

If you want to ensure printk is synchronous, perhaps you could call nbcon_cpu_emergency_enter() prior to your printk, or perhaps there are already printk wrappers that do somthing similar whilst debugging? Would that provide a more reliable way to guarantee output?

Thanks,

Andrew Murray

Quoted 3 lines

Regards
Bene Spranger

maintainer
#20 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 4 lines · Andrew Murray

If you want to ensure printk is synchronous, perhaps you could call nbcon_cpu_emergency_enter() prior to your printk, or perhaps there are already printk wrappers that do somthing similar whilst debugging? Would that provide a more reliable way to guarantee output?

Note that it is planned (at least on my TODO list) to introduce a "sync" option for consoles for exactly this purpose. I talked about it here [0].

John

[0] https://lore.kernel.org/lkml/[email protected]

#21 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

In reply to Andrew Murray

On Mon, 6 Jul 2026 18:05:06 +0100
Andrew Murray <[email protected]> wrote:

Hi Andrew,

Quoted 28 lines
Quoted 26 lines · Benedikt Spranger
Quoted 4 lines · On Tue, 30 Jun 2026 17:35:59 +0100 Andrew Murray…

The printk_delay and boot_delay features are helpful for debugging as kernel output can be slowed down during boot allowing messages to be seen before scrolling off the screen, or to correlate timing between some physical event and console output.

By now, it slows down the boot process, which is the handy part of that feature.

Quoted 6 lines

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console.

Using this feature to slow down the boot/suspend/resume process and implicit make printk() happen, is the usefull part of that feature. Imagine this sequence (which hit me on suspend/resume on i.MX after shutting down all secondary CPUs)

printk("A");
(do some stuff)
printk("B");
read from peripheral --> system got stuck here since peripheral
was not clocked or powered or both any more.

Quoted 8 lines
Quoted 3 lines

The delay (and later on a ugly patch to make printk() synchrounous) helped to locate where the failed access happend. JTAG did not help, since the CPU got stuck --> no JTAG communication to that CPU.

I understand the use-case, you sprinkle printk's so you can find the point where a read to a register causes the CPU to stop. This requires that the printk happens before the read, and the output from the printk is printed before the read.

Enabling existing debug features in the kernel was a good start.

Quoted 3 lines
Quoted 2 lines

With your purposed change you *may* see "A", but never "B". Quite challenging...

At present you may see 'A' and you may see 'B'.

That's correct.

Quoted 1 line

Prior to the changes in this patchset, and assuming an nbcon console

iMX swtched over to nbcon, so your assumption is correct.

Quoted 3 lines

(which may not be your usecase, but is perhaps representative of future use-cases), then the printk delay will always happen within the call to printk (and always before emitting).

Which is quite good, but can be better. (See the missing sync feature mentioned in Johns reply)

Quoted 3 lines

However, depending on the context, that printk call may return (and proceed to your CPU halting register read), before the message is actually emitted to the console. I.e. it's a race.

I am aware of that.

Quoted 4 lines

This series moves the delay to the emit side, as well as moving the delay after the emit. Thus the calling code may make progress more quickly, but depending on the context, it may also flush/emit before returning from printk.

Unfortunately it makes things worse.

Quoted 3 lines

In my view, with or without this series, there are no guarantees that you will see 'A' and 'B'. And in any case, achieving the functionality for debugging required you to modify the printk anyway.

The "sync" feature is on the TODO list as John mentioned.

Quoted 6 lines
Quoted 2 lines

So please leave the delay on the calling side - it is helpfull there.

If you want to ensure printk is synchronous, perhaps you could call nbcon_cpu_emergency_enter() prior to your printk, or perhaps there are already printk wrappers that do somthing similar whilst debugging?

As said I did an ugly hack and forced printk() to be synchronous.

Quoted 1 line

Would that provide a more reliable way to guarantee output?

It does.

Regards
Benedikt Spranger

maintainer
#22 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 36 lines · Benedikt Spranger

On Mon, 6 Jul 2026 18:05:06 +0100
Andrew Murray <[email protected]> wrote:

Hi Andrew,

Quoted 31 lines
Quoted 29 lines · Benedikt Spranger
Quoted 4 lines · On Tue, 30 Jun 2026 17:35:59 +0100 Andrew Murray…

The printk_delay and boot_delay features are helpful for debugging as kernel output can be slowed down during boot allowing messages to be seen before scrolling off the screen, or to correlate timing between some physical event and console output.

By now, it slows down the boot process, which is the handy part of that feature.

Quoted 6 lines

However, since the introduction of nbcon and the legacy printer thread for PREEMPT_RT kernels, printk records are now emited to the console asynchronously to the caller of printk. Thus, any printk delay added by boot_delay/printk_delay continues to slow down the calling process but may not have any impact to the rate in which records are emited to the console.

Using this feature to slow down the boot/suspend/resume process and implicit make printk() happen, is the usefull part of that feature. Imagine this sequence (which hit me on suspend/resume on i.MX after shutting down all secondary CPUs)

printk("A");
(do some stuff)
printk("B");
read from peripheral --> system got stuck here since peripheral
was not clocked or powered or both any more.

The delay (and later on a ugly patch to make printk() synchrounous) helped to locate where the failed access happend. JTAG did not help, since the CPU got stuck --> no JTAG communication to that CPU.

First, it is great to know that people are actually using the boot_delay and printk_delay features.

Quoted 39 lines
Quoted 4 lines

I understand the use-case, you sprinkle printk's so you can find the point where a read to a register causes the CPU to stop. This requires that the printk happens before the read, and the output from the printk is printed before the read.

Enabling existing debug features in the kernel was a good start.

Quoted 3 lines
Quoted 2 lines

With your purposed change you *may* see "A", but never "B". Quite challenging...

At present you may see 'A' and you may see 'B'.

That's correct.

Quoted 1 line

Prior to the changes in this patchset, and assuming an nbcon console

iMX swtched over to nbcon, so your assumption is correct.

Quoted 3 lines

(which may not be your usecase, but is perhaps representative of future use-cases), then the printk delay will always happen within the call to printk (and always before emitting).

Which is quite good, but can be better. (See the missing sync feature mentioned in Johns reply)

Quoted 3 lines

However, depending on the context, that printk call may return (and proceed to your CPU halting register read), before the message is actually emitted to the console. I.e. it's a race.

I am aware of that.

Quoted 4 lines

This series moves the delay to the emit side, as well as moving the delay after the emit. Thus the calling code may make progress more quickly, but depending on the context, it may also flush/emit before returning from printk.

Unfortunately it makes things worse.

Quoted 3 lines

In my view, with or without this series, there are no guarantees that you will see 'A' and 'B'. And in any case, achieving the functionality for debugging required you to modify the printk anyway.

The "sync" feature is on the TODO list as John mentioned.

Quoted 3 lines
Quoted 2 lines

So please leave the delay on the calling side - it is helpfull there.

Quoted 7 lines
Quoted 3 lines

If you want to ensure printk is synchronous, perhaps you could call nbcon_cpu_emergency_enter() prior to your printk, or perhaps there are already printk wrappers that do somthing similar whilst debugging?

As said I did an ugly hack and forced printk() to be synchronous.

Quoted 1 line

Would that provide a more reliable way to guarantee output?

It does.

To summarize this discussion:

+ Benedikt would prefer to add the synchronous mode before moving the delay from the printk() caller to the console emit code path.

+ The delay in the printk() caller code path did not guarantee the output but it increased the chance to see it.

+ The synchronous mode will be even more reliable than the delay in printk() caller path.

Please, let me know if I did not get it right,

John, did you have any plan how to add the synchronous mode, please? Does it look complicated?

I guess that we would somehow need to "mis-use" the emergency priority and force it everywhere by some global system setting.

Best Regards,
Petr

maintainer
#23 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 12 lines · Petr Mladek

To summarize this discussion:

+ Benedikt would prefer to add the synchronous mode before moving the delay from the printk() caller to the console emit code path.

+ The delay in the printk() caller code path did not guarantee the output but it increased the chance to see it.

+ The synchronous mode will be even more reliable than the delay in printk() caller path.

Quoted 7 lines

Please, let me know if I did not get it right,

John, did you have any plan how to add the synchronous mode, please? Does it look complicated?

I guess that we would somehow need to "mis-use" the emergency priority and force it everywhere by some global system setting.

The synchronous mode would rely on the driver being nbcon. I envision something like this:

---- BEGIN SYNC IDEA ----

kernel/printk/printk.c +2 -0
index 2fe9a963c823a..beb5bb3c037b5 100644
@@ -2456,6 +2456,8 @@ asmlinkage int vprintk_emit(int facility, int level,
 
 	if (ft.nbcon_atomic)
 		nbcon_atomic_flush_pending();
+	else if (have_nbcon_console_sync)
+		nbcon_atomic_flush_sync_pending();
 
 	if (ft.nbcon_offload)
 		nbcon_kthreads_wake();
kernel/printk/nbcon.c +12 -4
index 4b03b019cd5ee..8f8f29f757614 100644
@@ -1200,7 +1200,7 @@ 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 (!(flags & CON_SYNC) &&  console_is_usable(con, flags, false)) {
 		/* Bring the sequence in @ctxt up to date */
 		ctxt->seq = nbcon_seq_read(con);
 
@@ -1654,7 +1654,7 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
  *					write_atomic() callback
  * @stop_seq:			Flush up until this record
  */
-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 +1666,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 +1691,12 @@ 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);
+}
+
+void nbcon_atomic_flush_sync_pending(void)
+{
+	__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
 }
 
 /**
@@ -1701,7 +1709,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;
 }
 

---- END SYNC IDEA ----

BTW: The sync mode is the final piece so that PeterZ can start using mainline code for debugging by serial instead of his own workaround [0].

John

[0] https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/log/?h=debug/experimental

maintainer
#24 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 15 lines · John Ogness
Quoted 14 lines · Petr Mladek

To summarize this discussion:

+ Benedikt would prefer to add the synchronous mode before moving the delay from the printk() caller to the console emit code path.

+ The delay in the printk() caller code path did not guarantee the output but it increased the chance to see it.

+ The synchronous mode will be even more reliable than the delay in printk() caller path.

Please, let me know if I did not get it right,

Quoted 8 lines
Quoted 5 lines

John, did you have any plan how to add the synchronous mode, please? Does it look complicated?

I guess that we would somehow need to "mis-use" the emergency priority and force it everywhere by some global system setting.

The synchronous mode would rely on the driver being nbcon. I envision something like this:

Thanks for sharing the code.

kernel/printk/nbcon.c static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex · line 1203

Quoted 9 lines

---- BEGIN SYNC IDEA ----

kernel/printk/nbcon.c +1 -1
@@ -1200,7 +1200,7 @@ 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 (!(flags & CON_SYNC) &&  console_is_usable(con, flags, false)) {

The dependency on con->flags means that the sync mode can be entered only in task context where synchronize_srcu() can be called. It might be good enough. But I am afraid that people are creative and would like to have even atomic variant sooner or later.

Also it will do the flush in NORMAL_PRIO which is good. But it might fail to get the context ownership when it is blocked, for example, by uart_port_lock() which might be even sleepable context in PREEMPT_RT kernel.

Quoted 9 lines
kernel/printk/nbcon.c +0 -1
 		/* Bring the sequence in @ctxt up to date */
 		ctxt->seq = nbcon_seq_read(con);
 
---- END SYNC IDEA ----

BTW: The sync mode is the final piece so that PeterZ can start using mainline code for debugging by serial instead of his own workaround [0].

[0] https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/log/?h=debug/experimental

I see.

Best Regards,
Petr

maintainer
#25 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 9 lines · Petr Mladek
Quoted 9 lines

The synchronous mode would rely on the driver being nbcon. I envision something like this:

---- BEGIN SYNC IDEA ----

kernel/printk/nbcon.c +0 -0
@@ -1200,7 +1200,7 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex
 	cookie = console_srcu_read_lock();
 
Quoted 8 lines

kernel/printk/nbcon.c static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex · line 1203

Quoted 3 lines
kernel/printk/nbcon.c +1 -1
 	flags = console_srcu_read_flags(con);
-	if (console_is_usable(con, flags, false)) {
+	if (!(flags & CON_SYNC) &&  console_is_usable(con, flags, false)) {

The dependency on con->flags means that the sync mode can be entered only in task context where synchronize_srcu() can be called. It might be good enough. But I am afraid that people are creative and would like to have even atomic variant sooner or later.

You mean it can only be _modified_ in task context. Yes. I expect it is either specified as a boot arg or modified via some sysfs interface.

Quoted 4 lines

Also it will do the flush in NORMAL_PRIO which is good. But it might fail to get the context ownership when it is blocked, for example, by uart_port_lock() which might be even sleepable context in PREEMPT_RT kernel.

Indeed. This is the same limitation of the atomic printing in general. But I do not think this can be worked around during normal operation. Ignoring locks is not an option.

John

maintainer
#26 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 19 lines · John Ogness
Quoted 9 lines · Petr Mladek
Quoted 9 lines

The synchronous mode would rely on the driver being nbcon. I envision something like this:

---- BEGIN SYNC IDEA ----

kernel/printk/nbcon.c +0 -0
@@ -1200,7 +1200,7 @@ static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex
 	cookie = console_srcu_read_lock();
 
Quoted 8 lines

kernel/printk/nbcon.c static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_contex · line 1203

Quoted 3 lines
kernel/printk/nbcon.c +1 -1
 	flags = console_srcu_read_flags(con);
-	if (console_is_usable(con, flags, false)) {
+	if (!(flags & CON_SYNC) &&  console_is_usable(con, flags, false)) {

The dependency on con->flags means that the sync mode can be entered only in task context where synchronize_srcu() can be called. It might be good enough. But I am afraid that people are creative and would like to have even atomic variant sooner or later.

Quoted 2 lines

You mean it can only be _modified_ in task context. Yes. I expect it is either specified as a boot arg or modified via some sysfs interface.

Makes sense.

Quoted 8 lines
Quoted 4 lines

Also it will do the flush in NORMAL_PRIO which is good. But it might fail to get the context ownership when it is blocked, for example, by uart_port_lock() which might be even sleepable context in PREEMPT_RT kernel.

Indeed. This is the same limitation of the atomic printing in general. But I do not think this can be worked around during normal operation. Ignoring locks is not an option.

Let's see how it works in practice. But it might work pretty well.

Now, the question is how to move forward. It would be nice to have the sync mode available before we add this boot/printk_delay clean up.

Would you have time to prepare and send a patch anytime soon, please?

Or I wonder whether Andrew Murray might try to create a patch based on your "SYNC IDEA".

Best Regards,
Petr

maintainer
#27 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Quoted 5 lines · Petr Mladek

Now, the question is how to move forward. It would be nice to have the sync mode available before we add this boot/printk_delay clean up.

Would you have time to prepare and send a patch anytime soon, please?

I can work on this this week.

Quoted 2 lines

Or I wonder whether Andrew Murray might try to create a patch based on your "SYNC IDEA".

I expect that the two series will not conflict. I am just adding another atomic printing path, but the Andrew's delay is implemented deeper.

John

#28 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

In reply to John Ogness

Hi John,

Quoted 16 lines · John Ogness
Quoted 14 lines · Petr Mladek

To summarize this discussion:

+ Benedikt would prefer to add the synchronous mode before moving the delay from the printk() caller to the console emit code path.

+ The delay in the printk() caller code path did not guarantee the output but it increased the chance to see it.

+ The synchronous mode will be even more reliable than the delay in printk() caller path.

Please, let me know if I did not get it right,

Quoted 8 lines
Quoted 5 lines

John, did you have any plan how to add the synchronous mode, please? Does it look complicated?

I guess that we would somehow need to "mis-use" the emergency priority and force it everywhere by some global system setting.

The synchronous mode would rely on the driver being nbcon. I envision something like this:

Is it possible to apply synchronous mode for both nbcon and legacy consoles? For the debugging case Benedikt suggested (is this the main use case for this feature?), it would be helpful if a developer could indicate a preference for synchronous mode without first determining the console type. Though I'm not sure what means you propose to indicate such a preference.

Quoted 7 lines

---- BEGIN SYNC IDEA ----

kernel/printk/printk.c +0 -0
index 2fe9a963c823a..beb5bb3c037b5 100644

kernel/printk/printk.c asmlinkage int vprintk_emit(int facility, int level, · line 2463

Quoted 8 lines
kernel/printk/printk.c +2 -0
@@ -2456,6 +2456,8 @@ asmlinkage int vprintk_emit(int facility, int level,
 
        if (ft.nbcon_atomic)
                nbcon_atomic_flush_pending();
+       else if (have_nbcon_console_sync)
+               nbcon_atomic_flush_sync_pending();
 
        if (ft.nbcon_offload)
                nbcon_kthreads_wake();

My interest in misusing (not proposing that as a solution) the emergency mode, is that the flush mode is nicely abstracted by printk_get_console_flush_type. Depending on how you trigger the sync mode, could printk_get_console_flush_type be expanded to look at a flag and return ft.legacy_direct, ft.legacy_offload or ft.nbcon_atomic_sync ? I.e. if a sync flag isn't set then printk_get_console_flush_type returns based on NBCON_PRIO_type but if it is, then it shortcuts to ft.legacy_direct, ft.legacy_offload or ft.nbcon_atomic_sync?

I'm not familiar with this area of printk, so please forgive any obvious issues with this. But as someone that happily uses printk to debug the kernel, it would be nice to have an easy way to do this without the friction of figuring out what console I have.

Quoted 57 lines
kernel/printk/nbcon.c +12 -5
index 4b03b019cd5ee..8f8f29f757614 100644
@@ -1200,7 +1200,7 @@ 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 (!(flags & CON_SYNC) &&  console_is_usable(con, flags, false)) {
                /* Bring the sequence in @ctxt up to date */
                ctxt->seq = nbcon_seq_read(con);
 
@@ -1654,7 +1654,7 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
  *                                     write_atomic() callback
  * @stop_seq:                  Flush up until this record
  */
-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 +1666,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 +1691,12 @@ 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);
+}
+
+void nbcon_atomic_flush_sync_pending(void)
+{
+       __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
 }
 
 /**
@@ -1701,7 +1709,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;
 }
 
---- END SYNC IDEA ----
Quoted 4 lines

BTW: The sync mode is the final piece so that PeterZ can start using mainline code for debugging by serial instead of his own workaround [0].

John

Thanks,

Andrew Murray

Quoted 2 lines

[0] https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/log/?h=debug/experimental

maintainer
#29 lore raw

Re: [PATCH v2 3/4] printk: nbcon: move printk_delay to console emiting code

Hi Andrew,

Quoted 5 lines · Andrew Murray
Quoted 2 lines

The synchronous mode would rely on the driver being nbcon. I envision something like this:

Is it possible to apply synchronous mode for both nbcon and legacy consoles?

For !RT, legacy consoles are already "somewhat best effort" synchronous. I really do not want to try to somehow improve on that. Our goal is not to improve legacy, but to get rid of it.

Quoted 4 lines

For the debugging case Benedikt suggested (is this the main use case for this feature?), it would be helpful if a developer could indicate a preference for synchronous mode without first determining the console type.

The developer is free to add ",sync" regardless if it is an nbcon or not. My sync series (which I am currently testing) will simply give a boot message that the console does not support sync mode.

Quoted 12 lines
Quoted 12 lines

---- BEGIN SYNC IDEA ----

kernel/printk/printk.c +2 -0
index 2fe9a963c823a..beb5bb3c037b5 100644
@@ -2456,6 +2456,8 @@ asmlinkage int vprintk_emit(int facility, int level,
 
        if (ft.nbcon_atomic)
                nbcon_atomic_flush_pending();
+       else if (have_nbcon_console_sync)
+               nbcon_atomic_flush_sync_pending();
 
Quoted 9 lines

kernel/printk/printk.c asmlinkage int vprintk_emit(int facility, int level, · line 2463

Quoted 2 lines
kernel/printk/printk.c +0 -0
        if (ft.nbcon_offload)
                nbcon_kthreads_wake();

My interest in misusing (not proposing that as a solution) the emergency mode, is that the flush mode is nicely abstracted by printk_get_console_flush_type. Depending on how you trigger the sync mode, could printk_get_console_flush_type be expanded to look at a flag and return ft.legacy_direct, ft.legacy_offload or ft.nbcon_atomic_sync ?

Yes, I could do this, although it would only be "usable" for the vprintk_emit() case. For the other two call sites:

nbcon_kthread_should_wakeup()
nbcon_device_release()

it would still need to be a @flags check because it is about a particular console.

Of course, we could make printk_get_console_flush_type() per-console, but that would be a considerable semantic change that would require quite a bit of refactoring.

We can continue this conversation once I have posted my sync series.

John

#30 lore raw

PATCH v2 4/4 Documentation/kernel-parameters: add/update printk_delay/boot_delay

In reply to Andrew Murray

boot_delay has been deprecated in favour of an extended printk_delay, let's update kernel-parameters to reflect the addition of printk_delay and the deprecation of boot_delay.

---
 Documentation/admin-guide/kernel-parameters.txt | 31 +++++++++++++++++++++----
 1 file changed, 26 insertions(+), 5 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +26 -5
index 2884103b93bca7b76cd3a93946276074cf62d0a1..1118feda87b1b04543b1da0bd52c090b1fddaeac 100644
@@ -650,11 +650,19 @@ Kernel parameters
 			See Documentation/block/cmdline-partition.rst
 
 	boot_delay=	[KNL,EARLY]
-			Milliseconds to delay each printk during boot.
-			Only works if GENERIC_CALIBRATE_DELAY is enabled,
-			and you may also have to specify "lpj=".  Boot_delay
-			values larger than 10 seconds (10000) are assumed
-			erroneous and ignored.
+			Milliseconds to delay each printk during and post boot.
+			Boot time delays only work if GENERIC_CALIBRATE_DELAY
+			is enabled.
+
+			Once booted the delay can be removed or adjusted via
+			the printk_delay sysctl.
+
+			Please note that you may also have to specify "lpj=".
+			Boot_delay values larger than 10 seconds (10000) are
+			assumed erroneous and ignored.
+
+			This will soon be deprecated, please use printk_delay
+			instead.
 			Format: integer
 
 	bootconfig	[KNL,EARLY]
@@ -5468,6 +5476,19 @@ Kernel parameters
 	printk.time=	Show timing data prefixed to each printk message line
 			Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 
+	printk_delay=	[KNL,EARLY]
+			Milliseconds to delay each printk during and post boot.
+			Boot time delays only work if GENERIC_CALIBRATE_DELAY
+			is enabled.
+
+			Once booted the delay can be removed or adjusted via
+			the printk_delay sysctl.
+
+			Please note that you may also have to specify "lpj=".
+			printk_delay values larger than 10 seconds (10000) are
+			assumed erroneous and ignored.
+			Format: integer
+
 	proc_mem.force_override= [KNL]
 			Format: {always | ptrace | never}
 			Traditionally /proc/pid/mem allows memory permissions to be
Signature · 1 line
2.34.1