linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 00/21] printk: console: Per-console loglevels
@ 2025-11-27 19:43 Chris Down
  2025-11-27 19:43 ` [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression Chris Down
                   ` (21 more replies)
  0 siblings, 22 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

v8:

- Fully resolve loglevel before printk_delay to aid LOGLEVEL_DEFAULT
- Prioritise user-specified console options over SPCR/DT
- Synchronise console unregistration against atomic flushers in nbcon
- Optimise printk_delay to avoid SRCU walk when no delay set
- Restored accidentally deleted comment in console_srcu_read_flags
- Removed extra put_device() in console unregistration
- Changed open coded console_srcu_read_lock usage to functions
- Removed redundant newcon->classdev = NULL initialisation
- Fixed off-by-one errors in loglevel examples in docs (4 vs >4)
- In docs clarified "messages won't appear" edge case
- In docs, rewrote performance impact section per Petr
- In docs, removed obsolete minimum_console_loglevel section
- Removed redundant newcon->level init in try_enable_preferred_console
- Split up commits some more where reasonable (with tags kept)
- Make SYSLOG_ACTION_CONSOLE_{ON,OFF} only restore IPCL when they did it
- Drop sysrq loglevel overrides, just use ignore_per_console_loglevel
- Set options to NULL if empty so drivers keep baud
- Copy console= option strings before stripping loglevel for mips/jazz
- Initialise consoles with LOGLEVEL_DEFAULT so sysfs never exposes 0
- Clamp sysrq loglevels

v7:

- Disallow writing -1 to the global console_loglevel sysctl
- Change printk_get_next_message() to take effective loglevel
- Update suppress_message_printing() to take effective loglevel
- Use CONSOLE_LOGLEVEL_MOTORMOUTH for devkmsg_read()
- Fix documentation per Petr's review comments
- Add console_srcu_read_loglevel() for lockless reading
- Rename per_console_loglevel_is_set() to has_per_console_loglevel()
- Refactor API to take int con_level for better lockdep checking
- Update callers to read con_level using console_srcu_read_loglevel()
- Remove hierarchy comment since it's obvious from the code
- Use LOGLEVEL_DEFAULT as base level instead of hardcoded -1
- Use pr_warn_once() in sysrq handling instead of manual warned variable
- Split sysrq handling into separate commit
- Update code/ABI documentation to change loglevel bounds from 0 to 1
- Remove 'enabled' attribute from sysfs interface
- Move #ifdefs out of sysfs.c
- Fix console_clamp_loglevel() to use documented bounds
- Initialise classdev and level in try_enable_default_console()
- Fix race condition, use console_list_lock() in console_setup_class()
- Remove NULL check before device_unregister()
- Add data_race() annotations to READ_ONCE/WRITE_ONCE for KCSAN
- Remove pr_warn() for unknown loglevel source
- Add error handling for kzalloc() failure
- Make console_class constant via class_register() per Greg
- Export do_proc_dointvec() and do_proc_dointvec_conv()
- Refactor to use @conv callback approach
- Rename printk_console_loglevel() to proc_dointvec_console_loglevel()
- Simplify level assignment to `newcon->level = c->level;` per Petr
- Add missing loglevel= parameter documentation
- Change printk_sysctl_deprecated to proc_dointvec_printk_deprecated
- Add missing kernel parameter documentation for ignore_loglevel
- Reject KERN_EMERG (0) consistently
- Add comprehensive usage examples to per-console-loglevel.rst
- Add troubleshooting section with common issues and solutions
- Update ABI documentation with error conditions and permissions
- Document new struct console fields (level and classdev)
- Rename clamp_loglevel() to console_clamp_loglevel() for clarity
- Add kernel doc comments for internal API functions where it helps
- Initialise classdev in try_enable_default_console() explicitly
- Mark console devices with device_set_pm_not_required()
- Add syslog_lock around SYSLOG_ACTION_CONSOLE_{OFF,ON}

v6:

- Add .rst suffix to documentation in do_syslog
- Add loglevel table to per-console-loglevel.rst and serial-console.rst
- Add newlines between multiline bullets in per-console-loglevel.rst
- Make effective_loglevel doc more clear
- Remove ignore_per_console_loglevel doc, it's not shown in sysfs now
- Use READ_ONCE/WRITE_ONCE for con->level
- Ignore/restore per console loglevel in sysrq
- Add new fields to comment above struct console
- Remove now unused flags field on console_cmdline
- Remove WARN_ON_ONCE(!con) in effective loglevel checks
- Avoid underflow in find_and_remove_console_option if val_buf_size == 0
- Better error message on oversize in find_and_remove_loglevel_option
- Reject if clamped in find_and_remove_loglevel_option
- Clarify level setting logic in __add_preferred_console
- Move console emission check to printk_delay itself
- Use console_src_read_flags in enabled_show
- Infer if extended from con in printk_get_next_message, don't pass args
- Remove misleading comment about early consoles in console_init
- Use a goto in loglevel_store to avoid setting level in multiple places
- Mention only @flags and @level are valid in printk_get_next_message
- Use LOGLEVEL_DEBUG for max clamp in sysctls
- Update for class_create interface changes
- Move sysctl functionality out to sysfs.c
- Purge default_console_loglevel
- Update sysctl docs for kernel.printk deprecation

v5:

- Fix syntax in boot_delay

v4:

- Change base to Linus' master
- Use SRCU iterators for console walks
- Override per-console loglevels on magic sysrq
- Fix htmldocs
- Fix mistaken __user annotation in sysctl callbacks
- Consistently use indexed names (eg. ttyS0 instead of ttyS)
- Remove "The loglevel for a console can be set in many places" comment
- Remove CON_LOGLEVEL flag and infer based on >0
- Open code our dev_get_drvdata console stashing
- Split out console_effective_loglevel functions per Petr's suggestion
- Make boot_delay_msec/printk_delay check if it would be emitted
- Simplify warning on SYSLOG_ACTION_CONSOLE_LEVEL
- Save/restore ignore_per_console_loglevel on syslog console actions
- Unify min/max level checks across sysfs/proc/syslog
- Add find_and_remove_console_option to avoid affecting io/mmio options

v3:

- Update to work with John's kthread patches
- Remove force_console_loglevel, now we only have global and local levels
- Remove minimum_console_loglevel control and document how to change it
- The minimum loglevel is now only honoured on setting global/local level
- Add ignore_per_console_loglevel
- Return -EINVAL if trying to set below minimum console level
- Add parser for named console= options
- Fix docs around ignore_loglevel: it can be changed at runtime
- Fix ordering in "in order of authority" docs
- Remove duplicated default_console_loglevel doc
- Only warn once on syslog() use

v2:

- Dynamically allocate struct device*
- Document sysfs attributes in Documentation/ABI/
- Use sysfs_emit() instead of sprintf() in dev sysfs files
- Remove WARN_ON() for device_add/IS_ERR(console_class)
- Remove "soon" comment for kernel.printk
- Fix !CONFIG_PRINTK build
- Fix device_unregister() NULL dereference if called before class setup
- Add new documentation to MAINTAINERS

Chris Down (21):
  printk: Fully resolve loglevel before deciding printk delay
    suppression
  printk: Avoid spuriously delaying messages not solicited by any
    console
  printk: Prioritise user-specified configuration over SPCR/DT
  printk: Use effective loglevel for suppression and extended console
    state
  printk: console: Add per-console loglevel support to struct console
  printk: nbcon: Synchronise console unregistration against atomic
    flushers
  printk: Introduce per-console loglevel support
  printk: Iterate registered consoles for delay suppression decisions
  printk: Optimise printk_delay() to avoid walking consoles under SRCU
  printk: Add synchronisation for concurrent console state changes
  printk: Add ignore_per_console_loglevel module parameter
  printk: Ensure sysrq output bypasses per-console filtering
  printk: Toggle ignore_per_console_loglevel via syslog
  printk: console: Introduce sysfs interface for per-console loglevels
  printk: sysrq: Clamp console loglevel to valid range
  printk: Constrain hardware-addressed console checks to name position
  printk: Support setting initial console loglevel via console= on
    cmdline
  printk: Deconstruct kernel.printk into discrete sysctl controls
  printk: docs: Add comprehensive guidance for per-console loglevels
  printk: Deprecate the kernel.printk sysctl interface
  printk: Purge default_console_loglevel

 Documentation/ABI/testing/sysfs-class-console |  58 +++
 Documentation/admin-guide/index.rst           |   1 +
 .../admin-guide/kernel-parameters.txt         |  31 +-
 .../admin-guide/per-console-loglevel.rst      | 252 +++++++++
 Documentation/admin-guide/serial-console.rst  |  37 +-
 Documentation/admin-guide/sysctl/kernel.rst   |  25 +-
 Documentation/core-api/printk-basics.rst      |  35 +-
 Documentation/networking/netconsole.rst       |  16 +
 MAINTAINERS                                   |   2 +
 drivers/tty/sysrq.c                           |   8 +-
 include/linux/console.h                       |  40 ++
 include/linux/printk.h                        |   4 +-
 include/linux/sysctl.h                        |   7 +
 kernel/printk/Makefile                        |   2 +-
 kernel/printk/console_cmdline.h               |   1 +
 kernel/printk/internal.h                      |  20 +-
 kernel/printk/nbcon.c                         |  34 +-
 kernel/printk/printk.c                        | 489 ++++++++++++++++--
 kernel/printk/sysctl.c                        |  77 ++-
 kernel/printk/sysfs.c                         | 290 +++++++++++
 kernel/sysctl.c                               |  18 +-
 21 files changed, 1362 insertions(+), 85 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-console
 create mode 100644 Documentation/admin-guide/per-console-loglevel.rst
 create mode 100644 kernel/printk/sysfs.c


base-commit: a9f349e3c0bebe7ae97750b32a72f452bdf707e2
-- 
2.51.2


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-12-09 16:40   ` Petr Mladek
  2025-11-27 19:43 ` [PATCH v8 02/21] printk: Avoid spuriously delaying messages not solicited by any console Chris Down
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

When printk_delay() is called from vprintk_emit(), the level argument
may be LOGLEVEL_DEFAULT (-1) if the loglevel was not explicitly provided
by the caller.

If printk_delay() relies on comparing level against the console loglevel
(e.g. for suppression), receiving -1 results in incorrect behaviour
because -1 is treated as a high priority (so not suppressed), causing
unnecessary delays for default-level messages.

Parse the format string prefix to resolve the actual loglevel before
passing it to printk_delay().

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 5aee9ffb16b9..f002744b9a90 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2179,6 +2179,32 @@ u16 printk_parse_prefix(const char *text, int *level,
 	return prefix_len;
 }
 
+/**
+ * printk_resolve_loglevel - Resolve the effective loglevel for a message
+ *
+ * @facility:	The log facility (0 for kernel messages)
+ * @level:	The initial loglevel, may be LOGLEVEL_DEFAULT
+ * @fmt:	The format string, potentially containing a loglevel prefix
+ *
+ * Determines the actual loglevel to use for a printk message. If the level
+ * is LOGLEVEL_DEFAULT and the facility indicates a kernel message, parses
+ * the format string prefix to extract an embedded loglevel. If no loglevel
+ * is found, falls back to the default_message_loglevel.
+ *
+ * Return: The resolved loglevel value
+ */
+static inline int printk_resolve_loglevel(int facility, int level,
+					  const char *fmt)
+{
+	if (facility == 0 && level == LOGLEVEL_DEFAULT && fmt)
+		printk_parse_prefix(fmt, &level, NULL);
+
+	if (level == LOGLEVEL_DEFAULT)
+		level = default_message_loglevel;
+
+	return level;
+}
+
 __printf(5, 0)
 static u16 printk_sprint(char *text, u16 size, int facility,
 			 enum printk_info_flags *flags, const char *fmt,
@@ -2394,7 +2420,7 @@ asmlinkage int vprintk_emit(int facility, int level,
 		ft.legacy_direct = false;
 	}
 
-	printk_delay(level);
+	printk_delay(printk_resolve_loglevel(facility, level, fmt));
 
 	printed_len = vprintk_store(facility, level, dev_info, fmt, args);
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 02/21] printk: Avoid spuriously delaying messages not solicited by any console
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
  2025-11-27 19:43 ` [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT Chris Down
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

printk_delay() may introduce delays even when no console wants to emit
the message, which is unnecessary and may hold back messages we actually
care about. Add a check in printk_delay() to determine if any console
will print the message to avoid introducing unnecessary delays. This
change aligns with the existing behaviour of boot-delayed printk
messages, which already have a similar check.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index f002744b9a90..a3072ea39e5e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1307,14 +1307,12 @@ static int __init boot_delay_setup(char *str)
 }
 early_param("boot_delay", boot_delay_setup);
 
-static void boot_delay_msec(int level)
+static void 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)
+	if (boot_delay == 0 || system_state >= SYSTEM_RUNNING)
 		return;
 
 	k = (unsigned long long)loops_per_msec * boot_delay;
@@ -1334,7 +1332,7 @@ static void boot_delay_msec(int level)
 	}
 }
 #else
-static inline void boot_delay_msec(int level)
+static inline void boot_delay_msec(void)
 {
 }
 #endif
@@ -2116,7 +2114,11 @@ int printk_delay_msec __read_mostly;
 
 static inline void printk_delay(int level)
 {
-	boot_delay_msec(level);
+	/* If the message is forced (e.g. panic), we must delay */
+	if (!is_printk_force_console() && suppress_message_printing(level))
+		return;
+
+	boot_delay_msec();
 
 	if (unlikely(printk_delay_msec)) {
 		int m = printk_delay_msec;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
  2025-11-27 19:43 ` [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression Chris Down
  2025-11-27 19:43 ` [PATCH v8 02/21] printk: Avoid spuriously delaying messages not solicited by any console Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-12-10 14:38   ` Petr Mladek
  2025-11-27 19:43 ` [PATCH v8 04/21] printk: Use effective loglevel for suppression and extended console state Chris Down
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

ACPI firmware routinely calls add_preferred_console() via
acpi_parse_spcr() before we ever look at the kernel command line. After
that first registration we short-circuit on every duplicate name/index
match, so the subsequent console=ttyS0,... parameter never refreshes the
UART options that the firmware supplied.

Historically that just meant you couldn't tweak baud/flow control for a
firmware-provided serial console unless you picked a different device
name, but the per-console loglevel plumbing in this series relies on
those later console= entries being able to update the stored option
string. Without that, console=ttyS0,loglevel:5 simply never takes effect
on machines that get their console from SPCR/DT.

Teach __add_preferred_console() to update the existing slot when the
same console is mentioned again: we keep the original slot, but replace
its option string (and re-run braille option parsing) so that later
callers can override what firmware seeded. This keeps today's behaviour
unchanged for drivers, while allowing the cmdline UART parameters (and
soon the loglevel hints) to override the ACPI defaults.

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index a3072ea39e5e..447d9c28f180 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2560,7 +2560,12 @@ static int __add_preferred_console(const char *name, const short idx,
 		    (devname && strcmp(c->devname, devname) == 0)) {
 			if (!brl_options)
 				preferred_console = i;
+
+			if (options)
+				c->options = options;
+
 			set_user_specified(c, user_specified);
+			braille_set_options(c, brl_options);
 			return 0;
 		}
 	}
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 04/21] printk: Use effective loglevel for suppression and extended console state
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (2 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 05/21] printk: console: Add per-console loglevel support to struct console Chris Down
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

In preparation for supporting per-console loglevels, modify
printk_get_next_message() to accept the effective console loglevel
instead of individual arguments that mimic console fields. This keeps
the function console-agnostic and lockless as intended, while still
allowing per-console loglevel support to be added in later patches.

devkmsg_read() uses CONSOLE_LOGLEVEL_MOTORMOUTH to never suppress
messages. All other consoles pass their effective loglevel (currently
console_loglevel, will be per-console in later patches).

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/internal.h |  2 +-
 kernel/printk/nbcon.c    |  2 +-
 kernel/printk/printk.c   | 22 +++++++++++++---------
 3 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index f72bbfa266d6..1ed86577896c 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -333,7 +333,7 @@ struct printk_message {
 };
 
 bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
-			     bool is_extended, bool may_supress);
+			     bool is_extended, int con_eff_level);
 
 #ifdef CONFIG_PRINTK
 void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped);
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 558ef3177976..eb4c8faa213d 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -993,7 +993,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	if (!nbcon_context_enter_unsafe(ctxt))
 		return false;
 
-	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, true);
+	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, console_loglevel);
 	if (!ctxt->backlog)
 		return nbcon_context_exit_unsafe(ctxt);
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 447d9c28f180..9f40ebfac0c1 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -807,7 +807,8 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
 	if (ret)
 		return ret;
 
-	if (!printk_get_next_message(&pmsg, atomic64_read(&user->seq), true, false)) {
+	if (!printk_get_next_message(&pmsg, atomic64_read(&user->seq), true,
+				     CONSOLE_LOGLEVEL_MOTORMOUTH)) {
 		if (file->f_flags & O_NONBLOCK) {
 			ret = -EAGAIN;
 			goto out;
@@ -825,7 +826,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
 		 */
 		ret = wait_event_interruptible(log_wait,
 				printk_get_next_message(&pmsg, atomic64_read(&user->seq), true,
-							false)); /* LMM(devkmsg_read:A) */
+							CONSOLE_LOGLEVEL_MOTORMOUTH)); /* LMM(devkmsg_read:A) */
 		if (ret)
 			goto out;
 	}
@@ -1279,9 +1280,9 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 
-static bool suppress_message_printing(int level)
+static bool suppress_message_printing(int level, int con_eff_level)
 {
-	return (level >= console_loglevel && !ignore_loglevel);
+	return (level >= con_eff_level && !ignore_loglevel);
 }
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
@@ -2115,7 +2116,7 @@ int printk_delay_msec __read_mostly;
 static inline void printk_delay(int level)
 {
 	/* If the message is forced (e.g. panic), we must delay */
-	if (!is_printk_force_console() && suppress_message_printing(level))
+	if (!is_printk_force_console() && suppress_message_printing(level, console_loglevel))
 		return;
 
 	boot_delay_msec();
@@ -2977,14 +2978,15 @@ void console_prepend_replay(struct printk_message *pmsg)
  * @is_extended specifies if the message should be formatted for extended
  * console output.
  *
- * @may_supress specifies if records may be skipped based on loglevel.
+ * @con_eff_level is the effective console loglevel to use for suppression
+ * checks.
  *
  * Returns false if no record is available. Otherwise true and all fields
  * of @pmsg are valid. (See the documentation of struct printk_message
  * for information about the @pmsg fields.)
  */
 bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
-			     bool is_extended, bool may_suppress)
+			     bool is_extended, int con_eff_level)
 {
 	struct printk_buffers *pbufs = pmsg->pbufs;
 	const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
@@ -3013,13 +3015,14 @@ bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
 
 	pmsg->seq = r.info->seq;
 	pmsg->dropped = r.info->seq - seq;
+
 	force_con = r.info->flags & LOG_FORCE_CON;
 
 	/*
 	 * Skip records that are not forced to be printed on consoles and that
 	 * has level above the console loglevel.
 	 */
-	if (!force_con && may_suppress && suppress_message_printing(r.info->level))
+	if (!force_con && suppress_message_printing(r.info->level, con_eff_level))
 		goto out;
 
 	if (is_extended) {
@@ -3095,7 +3098,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 
 	*handover = false;
 
-	if (!printk_get_next_message(&pmsg, con->seq, is_extended, true))
+	if (!printk_get_next_message(&pmsg, con->seq, is_extended,
+				     console_loglevel))
 		return false;
 
 	con->dropped += pmsg.dropped;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 05/21] printk: console: Add per-console loglevel support to struct console
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (3 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 04/21] printk: Use effective loglevel for suppression and extended console state Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers Chris Down
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The printk subsystem currently uses a single global console_loglevel
to control which messages are emitted to all consoles. This works well
when all consoles have similar characteristics, but consoles can have
vastly different latencies and throughputs.

For example, writing a message to the serial console can take on the
order of tens of milliseconds to get the UART to successfully write a
message. While this is fine for a single, one-off message, this can
cause significant application-level stalls when the kernel writes large
amounts of information to the console.

In preparation for allowing each console to filter messages at its own
loglevel, this commit adds the basic infrastructure to support that.
Each struct console now has a level field, and a new
console_srcu_read_loglevel() helper is added to safely read it under
SRCU.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 include/linux/console.h | 36 ++++++++++++++++++++++++++++++++++++
 kernel/printk/printk.c  |  3 +++
 2 files changed, 39 insertions(+)

diff --git a/include/linux/console.h b/include/linux/console.h
index 8f10d0a85bb4..a670c40623ad 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -314,6 +314,8 @@ struct nbcon_write_context {
  * @match:		Callback for matching a console (Optional)
  * @flags:		Console flags. See enum cons_flags
  * @index:		Console index, e.g. port number
+ * @level:		Per-console loglevel. -1 means use global console_loglevel,
+ *			values > 0 specify console-specific filtering level
  * @cflag:		TTY control mode flags
  * @ispeed:		TTY input speed
  * @ospeed:		TTY output speed
@@ -342,6 +344,7 @@ struct console {
 	int			(*match)(struct console *co, char *name, int idx, char *options);
 	short			flags;
 	short			index;
+	int			level;
 	int			cflag;
 	uint			ispeed;
 	uint			ospeed;
@@ -544,6 +547,39 @@ static inline void console_srcu_write_flags(struct console *con, short flags)
 	WRITE_ONCE(con->flags, flags);
 }
 
+/**
+ * console_srcu_read_loglevel - Locklessly read the console specific loglevel
+ *				of a possibly registered console
+ * @con:	struct console pointer of console to read loglevel from
+ *
+ * Locklessly reading @con->level provides a consistent read value because
+ * there is at most one CPU modifying @con->level and that CPU is using only
+ * read-modify-write operations to do so.
+ *
+ * Requires console_srcu_read_lock to be held, which implies that @con might
+ * be a registered console. The purpose of holding console_srcu_read_lock is
+ * to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
+ * and that no exit/cleanup routines will run if the console is currently
+ * undergoing unregistration.
+ *
+ * If the caller is holding the console_list_lock or it is _certain_ that
+ * @con is not and will not become registered, the caller may read
+ * @con->level directly instead.
+ *
+ * Context: Any context.
+ * Return: The current value of the @con->level field.
+ */
+static inline int console_srcu_read_loglevel(const struct console *con)
+{
+	WARN_ON_ONCE(!console_srcu_read_lock_is_held());
+
+	/*
+	 * The READ_ONCE() matches the WRITE_ONCE() when @level is modified
+	 * for registered consoles.
+	 */
+	return data_race(READ_ONCE(con->level));
+}
+
 /* Variant of console_is_registered() when the console_list_lock is held. */
 static inline bool console_is_registered_locked(const struct console *con)
 {
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 9f40ebfac0c1..c6b56f4d8072 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3848,6 +3848,9 @@ static int try_enable_preferred_console(struct console *newcon,
 			if (newcon->index < 0)
 				newcon->index = c->index;
 
+			/* TODO: will be configurable in a later patch */
+			newcon->level = LOGLEVEL_DEFAULT;
+
 			if (_braille_register_console(newcon, c))
 				return 0;
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (4 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 05/21] printk: console: Add per-console loglevel support to struct console Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-12-10 15:12   ` Petr Mladek
  2025-11-27 19:43 ` [PATCH v8 07/21] printk: Introduce per-console loglevel support Chris Down
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The nbcon atomic flush path in __nbcon_atomic_flush_pending_con() calls
nbcon_emit_next_record(), which uses console_srcu_read_flags() to read
the console flags. console_srcu_read_flags() expects to be called under
console_srcu_read_lock(), but the atomic flush path does not hold this
lock.

While console_srcu_read_flags() works without the lock in practice, this
violates the SRCU contract: without holding the lock,
unregister_console() cannot properly synchronise against concurrent
atomic flushers, since synchronize_srcu() would not wait for them.

Wrap the atomic flush critical section with console_srcu_read_lock() and
console_srcu_read_unlock(). This ensures that:

1. unregister_console() can safely synchronise against atomic flushers
   via synchronize_srcu() before proceeding with console teardown.

2. The SRCU protection guarantees that console state remains valid
   (CON_SUSPENDED/CON_ENABLED) and that exit/cleanup routines will not
   run while the atomic flusher is operating.

The locking is placed around the entire flush operation rather than just
the flags read, as future changes will add additional SRCU-protected
reads in this path.

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/nbcon.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index eb4c8faa213d..493c9e8b2dd5 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1498,15 +1498,29 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
 {
 	struct nbcon_write_context wctxt = { };
 	struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
+	bool ctx_acquired = false;
 	int err = 0;
+	int cookie;
 
 	ctxt->console			= con;
 	ctxt->spinwait_max_us		= 2000;
 	ctxt->prio			= nbcon_get_default_prio();
 	ctxt->allow_unsafe_takeover	= allow_unsafe_takeover;
 
-	if (!nbcon_context_try_acquire(ctxt, false))
-		return -EPERM;
+	/*
+	 * Match the console_srcu_read_lock()/unlock expectation embedded in
+	 * console_srcu_read_flags(), which is called from nbcon_emit_next_record().
+	 * Without this, unregister_console() cannot synchronise against the
+	 * atomic flusher.
+	 */
+	cookie = console_srcu_read_lock();
+
+	if (!nbcon_context_try_acquire(ctxt, false)) {
+		err = -EPERM;
+		goto out_unlock;
+	}
+
+	ctx_acquired = true;
 
 	while (nbcon_seq_read(con) < stop_seq) {
 		/*
@@ -1514,8 +1528,11 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
 		 * handed over or taken over. In both cases the context is no
 		 * longer valid.
 		 */
-		if (!nbcon_emit_next_record(&wctxt, true))
-			return -EAGAIN;
+		if (!nbcon_emit_next_record(&wctxt, true)) {
+			err = -EAGAIN;
+			ctx_acquired = false;
+			goto out_unlock;
+		}
 
 		if (!ctxt->backlog) {
 			/* Are there reserved but not yet finalized records? */
@@ -1525,7 +1542,10 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
 		}
 	}
 
-	nbcon_context_release(ctxt);
+out_unlock:
+	if (ctx_acquired)
+		nbcon_context_release(ctxt);
+	console_srcu_read_unlock(cookie);
 	return err;
 }
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 07/21] printk: Introduce per-console loglevel support
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (5 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 08/21] printk: Iterate registered consoles for delay suppression decisions Chris Down
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

Implement the logic to determine which loglevel should be used for
message filtering on each console.

The effective loglevel for a console is determined by a hierarchy of
controls:

1. ignore_loglevel (highest priority), which prints all messages regardless
   of level, overriding both global and per-console settings.

2. The per-console loglevel. If set to a valid value (> 0), the console
   uses this level instead of the global console_loglevel.

3. Global console_loglevel (fallback). This is used when per-console
   loglevel is not set (LOGLEVEL_DEFAULT, i.e. -1).

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/internal.h | 10 +++++
 kernel/printk/nbcon.c    | 10 +++--
 kernel/printk/printk.c   | 86 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 101 insertions(+), 5 deletions(-)

diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 1ed86577896c..f2ebaa2a6aa2 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -15,6 +15,16 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
 #define printk_sysctl_init() do { } while (0)
 #endif
 
+enum loglevel_source {
+	LLS_GLOBAL,
+	LLS_LOCAL,
+	LLS_IGNORE_LOGLEVEL,
+};
+
+enum loglevel_source
+console_effective_loglevel_source(int con_level);
+int console_effective_loglevel(int con_level);
+
 #define con_printk(lvl, con, fmt, ...)				\
 	printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt),		\
 		(con->flags & CON_NBCON) ? "" : "legacy ",	\
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 493c9e8b2dd5..a61a607a5159 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -961,6 +961,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
 	struct console *con = ctxt->console;
 	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
+	int con_level = console_srcu_read_loglevel(con);
 	struct printk_message pmsg = {
 		.pbufs = ctxt->pbufs,
 	};
@@ -993,7 +994,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	if (!nbcon_context_enter_unsafe(ctxt))
 		return false;
 
-	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, console_loglevel);
+	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended,
+						console_effective_loglevel(con_level));
 	if (!ctxt->backlog)
 		return nbcon_context_exit_unsafe(ctxt);
 
@@ -1509,9 +1511,9 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
 
 	/*
 	 * Match the console_srcu_read_lock()/unlock expectation embedded in
-	 * console_srcu_read_flags(), which is called from nbcon_emit_next_record().
-	 * Without this, unregister_console() cannot synchronise against the
-	 * atomic flusher.
+	 * console_srcu_read_loglevel()/console_srcu_read_flags(), both of which
+	 * are called from nbcon_emit_next_record(). Without this,
+	 * unregister_console() cannot synchronise against the atomic flusher.
 	 */
 	cookie = console_srcu_read_lock();
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c6b56f4d8072..d9c1bc4a32c4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1280,6 +1280,89 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 
+/**
+ * is_valid_per_console_loglevel - Check if a loglevel is valid for per-console
+ *
+ * @con_level: The loglevel to check
+ *
+ * Per-console loglevels must be strictly positive (> 0). Level 0 (KERN_EMERG)
+ * is reserved for emergency messages that should go to all consoles (and so is
+ * disallowed), and -1 (LOGLEVEL_DEFAULT) means use the global console_loglevel.
+ *
+ * Return: true if con_level is a valid per-console loglevel (> 0), false
+ * otherwise
+ */
+static bool is_valid_per_console_loglevel(int con_level)
+{
+	return (con_level > 0);
+}
+
+/**
+ * console_effective_loglevel_source - Determine the source of effective loglevel
+ *
+ * @con_level: The console's per-console loglevel value
+ *
+ * This function determines which loglevel authority is in effect for a console,
+ * based on the hierarchy of controls:
+ *
+ * 1. ignore_loglevel (overrides everything - prints all messages)
+ * 2. per-console loglevel (if set and not ignored)
+ * 3. global console_loglevel (fallback)
+ *
+ * Return: The loglevel source (LLS_IGNORE_LOGLEVEL, LLS_LOCAL, or LLS_GLOBAL)
+ */
+enum loglevel_source
+console_effective_loglevel_source(int con_level)
+{
+	if (ignore_loglevel)
+		return LLS_IGNORE_LOGLEVEL;
+
+	if (is_valid_per_console_loglevel(con_level))
+		return LLS_LOCAL;
+
+	return LLS_GLOBAL;
+}
+
+/**
+ * console_effective_loglevel - Get the effective loglevel for a console
+ *
+ * @con_level: The console's per-console loglevel value
+ *
+ * This function returns the actual loglevel value that should be used for
+ * message filtering for a console, taking into account all loglevel controls
+ * (global, per-console, and ignore_loglevel).
+ *
+ * The effective loglevel is used to determine which messages get printed to
+ * the console. Messages with priority less than the effective level are printed.
+ *
+ * Return: The effective loglevel value to use for filtering
+ */
+int console_effective_loglevel(int con_level)
+{
+	enum loglevel_source source;
+	int level;
+
+	source = console_effective_loglevel_source(con_level);
+
+	switch (source) {
+	case LLS_IGNORE_LOGLEVEL:
+		level = CONSOLE_LOGLEVEL_MOTORMOUTH;
+		break;
+	case LLS_LOCAL:
+		level = con_level;
+		break;
+	case LLS_GLOBAL:
+		level = console_loglevel;
+		break;
+	default:
+		pr_warn("Unhandled console loglevel source: %d", source);
+		level = console_loglevel;
+		break;
+	}
+
+	return level;
+}
+
 static bool suppress_message_printing(int level, int con_eff_level)
 {
 	return (level >= con_eff_level && !ignore_loglevel);
@@ -3090,6 +3173,7 @@ struct printk_buffers printk_shared_pbufs;
 static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
 {
 	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
+	int con_level = console_srcu_read_loglevel(con);
 	char *outbuf = &printk_shared_pbufs.outbuf[0];
 	struct printk_message pmsg = {
 		.pbufs = &printk_shared_pbufs,
@@ -3099,7 +3183,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 	*handover = false;
 
 	if (!printk_get_next_message(&pmsg, con->seq, is_extended,
-				     console_loglevel))
+				     console_effective_loglevel(con_level)))
 		return false;
 
 	con->dropped += pmsg.dropped;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 08/21] printk: Iterate registered consoles for delay suppression decisions
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (6 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 07/21] printk: Introduce per-console loglevel support Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU Chris Down
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The printk_delay() function applies boot_delay and printk_delay_msec
delays when messages are printed. Currently it decides whether to skip
the delay by checking if the message would be suppressed based on the
global console_loglevel only. This means delays are applied even for
messages that no console will actually print.

With per-console loglevels, different consoles can have different
filtering thresholds. A message might be suppressed on one console, but
printed on another. In such cases, applying delays based solely on the
global loglevel would be incorrect: we should only delay if at least one
console will actually print the message.

Introduce suppress_message_printing_everywhere() which iterates over all
registered consoles and checks whether the message would be suppressed
on all of them. The delay is now skipped only if the message would not
be printed anywhere.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index d9c1bc4a32c4..0d7f3dac8177 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1368,6 +1368,41 @@ static bool suppress_message_printing(int level, int con_eff_level)
 	return (level >= con_eff_level && !ignore_loglevel);
 }
 
+/**
+ * suppress_message_printing_everywhere - Check if message is suppressed on all consoles
+ *
+ * @level:	The loglevel of the message to check
+ *
+ * Iterates over all registered consoles and determines whether the message
+ * would be suppressed on every one of them based on their effective loglevels.
+ *
+ * This is used by printk_delay() to avoid applying delays for messages that
+ * no console will actually print.
+ *
+ * Return: true if the message would be suppressed on all consoles, false if
+ * at least one console would print it
+ */
+static bool suppress_message_printing_everywhere(int level)
+{
+	bool suppress_everywhere = true;
+	struct console *con;
+	int cookie;
+
+	cookie = console_srcu_read_lock();
+
+	for_each_console_srcu(con) {
+		int con_level = console_srcu_read_loglevel(con);
+
+		if (!suppress_message_printing(level, console_effective_loglevel(con_level))) {
+			suppress_everywhere = false;
+			break;
+		}
+	}
+	console_srcu_read_unlock(cookie);
+
+	return suppress_everywhere;
+}
+
 #ifdef CONFIG_BOOT_PRINTK_DELAY
 
 static int boot_delay; /* msecs delay after each printk during bootup */
@@ -2199,7 +2234,8 @@ int printk_delay_msec __read_mostly;
 static inline void printk_delay(int level)
 {
 	/* If the message is forced (e.g. panic), we must delay */
-	if (!is_printk_force_console() && suppress_message_printing(level, console_loglevel))
+	if (!is_printk_force_console() &&
+	    suppress_message_printing_everywhere(level))
 		return;
 
 	boot_delay_msec();
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (7 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 08/21] printk: Iterate registered consoles for delay suppression decisions Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-12-11 14:37   ` Petr Mladek
  2025-11-27 19:43 ` [PATCH v8 10/21] printk: Add synchronisation for concurrent console state changes Chris Down
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

As part of the per-console loglevel implementation, printk_delay()
introduces a call to suppress_message_printing_everywhere() within
printk_delay(). This check acquires the console SRCU lock and iterates
through all registered consoles to determine if the message implies a
delay based on per-console loglevels.

Since printk_delay() is called in the hotpath of vprintk_emit(), this
introduces measurable overhead (locking and pointer chasing) for every
printk message, even on systems where no delay is configured.

Optimise this by short-circuiting the function. If neither a boot delay
nor a runtime printk_delay_msec is configured, return immediately. This
avoids the expensive console list iteration in the common case where
delays are disabled.

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 0d7f3dac8177..13e17d892ec9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2233,20 +2233,31 @@ int printk_delay_msec __read_mostly;
 
 static inline void printk_delay(int level)
 {
+	bool boot_delay_active = false;
+	int m;
+
+#ifdef CONFIG_BOOT_PRINTK_DELAY
+	boot_delay_active = boot_delay && system_state < SYSTEM_RUNNING;
+#endif
+
+	if (!boot_delay_active && !READ_ONCE(printk_delay_msec))
+		return;
+
 	/* If the message is forced (e.g. panic), we must delay */
 	if (!is_printk_force_console() &&
 	    suppress_message_printing_everywhere(level))
 		return;
 
-	boot_delay_msec();
+	if (boot_delay_active)
+		boot_delay_msec();
 
-	if (unlikely(printk_delay_msec)) {
-		int m = printk_delay_msec;
+	m = READ_ONCE(printk_delay_msec);
+	if (!m)
+		return;
 
-		while (m--) {
-			mdelay(1);
-			touch_nmi_watchdog();
-		}
+	while (m--) {
+		mdelay(1);
+		touch_nmi_watchdog();
 	}
 }
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 10/21] printk: Add synchronisation for concurrent console state changes
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (8 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 11/21] printk: Add ignore_per_console_loglevel module parameter Chris Down
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The syslog actions SYSLOG_ACTION_CONSOLE_OFF and
SYSLOG_ACTION_CONSOLE_ON currently run without any locking. This creates
a race condition if two processes attempt to toggle the console state
simultaneously.

While this race has existed for donkey's years, it was previously
somewhat tolerable because it involved only a single integer variable
(saved_console_loglevel). However, upcoming changes will introduce a
second piece of state (saved_ignore_per_console_loglevel) to be saved
and restored. With two variables, this can result in saved state getting
lost.

Here is a demonstration:

 CPU 0 (SYSLOG_ACTION_CONSOLE_OFF)        CPU 1 (SYSLOG_ACTION_CONSOLE_ON)
 ---------------------------------        --------------------------------
 // saved_console_loglevel is DEFAULT
 if (saved == DEFAULT) (True)
   saved = console_loglevel (7)
                                          // Race triggers here
                                          if (saved != DEFAULT) (True)
                                            loglevel = saved (7)
                                            saved = DEFAULT
   // CPU 0 continues, unaware saved
   // was just reset by CPU 1
   loglevel = minimum_console_loglevel (1)

The result is that the console is now set to the minimum loglevel, but
saved_console_loglevel is LOGLEVEL_DEFAULT. A subsequent CONSOLE_ON call
will see saved == LOGLEVEL_DEFAULT and thus refuse to restore the
original loglevel. The console is effectively stuck in quiet mode until
manually reset via sysctl. Oh dear.

The callers of do_syslog are syscalls (so user context) or procfs write
handlers. These contexts are allowed to sleep, so acquiring a mutex is
safe. We also already make use of syslog_lock in
SYSLOG_ACTION_SIZE_UNREAD and SYSLOG_ACTION_READ, so this is consistent.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 13e17d892ec9..98d2f4466aad 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1894,16 +1894,20 @@ int do_syslog(int type, char __user *buf, int len, int source)
 		break;
 	/* Disable logging to console */
 	case SYSLOG_ACTION_CONSOLE_OFF:
+		mutex_lock(&syslog_lock);
 		if (saved_console_loglevel == LOGLEVEL_DEFAULT)
 			saved_console_loglevel = console_loglevel;
 		console_loglevel = minimum_console_loglevel;
+		mutex_unlock(&syslog_lock);
 		break;
 	/* Enable logging to console */
 	case SYSLOG_ACTION_CONSOLE_ON:
+		mutex_lock(&syslog_lock);
 		if (saved_console_loglevel != LOGLEVEL_DEFAULT) {
 			console_loglevel = saved_console_loglevel;
 			saved_console_loglevel = LOGLEVEL_DEFAULT;
 		}
+		mutex_unlock(&syslog_lock);
 		break;
 	/* Set level of messages printed to console */
 	case SYSLOG_ACTION_CONSOLE_LEVEL:
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 11/21] printk: Add ignore_per_console_loglevel module parameter
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (9 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 10/21] printk: Add synchronisation for concurrent console state changes Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:43 ` [PATCH v8 12/21] printk: Ensure sysrq output bypasses per-console filtering Chris Down
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

With per-console loglevels now functional, there are scenarios where
administrators need to quickly disable them and revert to the global
console_loglevel for all consoles. This is useful for debugging message
emission issues or when needing to break glass in emergencies.

This commit introduces the ignore_per_console_loglevel parameter which
can be set via the kernel command line or at runtime through
/sys/module/printk/parameters/ignore_per_console_loglevel or on the
kernel command line. When set, per-console loglevels are bypassed and
the global console_loglevel is used for all consoles.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/admin-guide/kernel-parameters.txt |  7 +++++++
 include/linux/printk.h                          |  2 ++
 kernel/printk/printk.c                          | 17 ++++++++++++++++-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3edc5ce0e2a3..7b62a99489b8 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2177,6 +2177,13 @@
 			could change it dynamically, usually by
 			/sys/module/printk/parameters/ignore_loglevel.
 
+	ignore_per_console_loglevel [KNL,EARLY]
+			Ignore all per-console loglevel settings
+			and use only the global console_loglevel for all
+			consoles. This can also be set at runtime via
+			/sys/module/printk/parameters/ignore_per_console_loglevel.
+			See Documentation/admin-guide/per-console-loglevel.rst.
+
 	ignore_rlimit_data
 			Ignore RLIMIT_DATA setting for data mappings,
 			print warning at first misuse.  Can be changed via
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 45c663124c9b..0aa8cb8ddc09 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -73,6 +73,8 @@ extern int console_printk[];
 #define minimum_console_loglevel (console_printk[2])
 #define default_console_loglevel (console_printk[3])
 
+extern bool ignore_per_console_loglevel;
+
 extern void console_verbose(void);
 
 /* strlen("ratelimit") + 1 */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 98d2f4466aad..e5b6a926135e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -104,6 +104,9 @@ DEFINE_STATIC_SRCU(console_srcu);
  */
 int __read_mostly suppress_printk;
 
+/* The sysrq infrastructure needs this even on !CONFIG_PRINTK. */
+bool __read_mostly ignore_per_console_loglevel;
+
 #ifdef CONFIG_LOCKDEP
 static struct lockdep_map console_lock_dep_map = {
 	.name = "console_lock"
@@ -1280,6 +1283,18 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 
+static int __init ignore_per_console_loglevel_setup(char *str)
+{
+	ignore_per_console_loglevel = true;
+	return 0;
+}
+
+early_param("ignore_per_console_loglevel", ignore_per_console_loglevel_setup);
+module_param(ignore_per_console_loglevel, bool, 0644);
+MODULE_PARM_DESC(
+	ignore_per_console_loglevel,
+	"ignore per-console loglevel setting (only respect global console loglevel)");
+
 /**
  * is_valid_per_console_loglevel - Check if a loglevel is valid for per-console
  *
@@ -1317,7 +1332,7 @@ console_effective_loglevel_source(int con_level)
 	if (ignore_loglevel)
 		return LLS_IGNORE_LOGLEVEL;
 
-	if (is_valid_per_console_loglevel(con_level))
+	if (!ignore_per_console_loglevel && is_valid_per_console_loglevel(con_level))
 		return LLS_LOCAL;
 
 	return LLS_GLOBAL;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 12/21] printk: Ensure sysrq output bypasses per-console filtering
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (10 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 11/21] printk: Add ignore_per_console_loglevel module parameter Chris Down
@ 2025-11-27 19:43 ` Chris Down
  2025-11-27 19:44 ` [PATCH v8 13/21] printk: Toggle ignore_per_console_loglevel via syslog Chris Down
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:43 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

During sysrq handling, per-console loglevels are temporarily disabled
to ensure all requisite messages are printed to the console. This is
necessary because sysrq is often used in dire circumstances where
access to /sys/class/console may not be trivially possible, and all
diagnostic output needs to reach the operator regardless of per-console
filtering.

The implementation saves and restores the ignore_per_console_loglevel
flag around the sysrq handler, similar to how suppress_printk is
already handled.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 drivers/tty/sysrq.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 97f8a9a52285..1d5ae9997e79 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -51,6 +51,7 @@
 #include <linux/syscalls.h>
 #include <linux/of.h>
 #include <linux/rcupdate.h>
+#include <linux/printk.h>
 
 #include <asm/ptrace.h>
 #include <asm/irq_regs.h>
@@ -583,12 +584,16 @@ static void __sysrq_put_key_op(u8 key, const struct sysrq_key_op *op_p)
 void __handle_sysrq(u8 key, bool check_mask)
 {
 	const struct sysrq_key_op *op_p;
+	bool orig_ignore_per_console_loglevel;
 	int orig_suppress_printk;
 	int i;
 
 	orig_suppress_printk = suppress_printk;
 	suppress_printk = 0;
 
+	orig_ignore_per_console_loglevel = ignore_per_console_loglevel;
+	ignore_per_console_loglevel = true;
+
 	rcu_sysrq_start();
 	rcu_read_lock();
 	/*
@@ -634,6 +639,7 @@ void __handle_sysrq(u8 key, bool check_mask)
 	rcu_read_unlock();
 	rcu_sysrq_end();
 
+	ignore_per_console_loglevel = orig_ignore_per_console_loglevel;
 	suppress_printk = orig_suppress_printk;
 }
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 13/21] printk: Toggle ignore_per_console_loglevel via syslog
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (11 preceding siblings ...)
  2025-11-27 19:43 ` [PATCH v8 12/21] printk: Ensure sysrq output bypasses per-console filtering Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-11-27 19:44 ` [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels Chris Down
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The syslog() system call provides SYSLOG_ACTION_CONSOLE_OFF and
SYSLOG_ACTION_CONSOLE_ON to disable and re-enable console logging.
These actions save and restore the global console_loglevel.

With per-console loglevels, simply setting console_loglevel to
minimum_console_loglevel during CONSOLE_OFF is insufficient - consoles
with explicit per-console loglevels would continue printing based on
their local settings.

Augment these actions to also save and restore the state of
ignore_per_console_loglevel. When console logging is disabled via
syslog(), ignore_per_console_loglevel is set to true so that the
minimum_console_loglevel applies to all consoles. When logging is
re-enabled, the previous ignore_per_console_loglevel state is restored.

A forced flag tracks whether this code path actually set
ignore_per_console_loglevel. This prevents blindly restoring stale
state if other contexts (sysrq, module parameter writes) legitimately
modified the flag in parallel.

SYSLOG_ACTION_CONSOLE_LEVEL now emits a one-time warning when
per-console loglevels are active, informing administrators that their
level change only affects consoles using the global loglevel. The
level change also properly restores ignore_per_console_loglevel state
if it was forced by a previous CONSOLE_OFF.

These changes allow userspace tools like dmesg to properly control
console output even in the presence of per-console loglevels.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 53 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 8 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e5b6a926135e..1d28887e7218 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1869,6 +1869,8 @@ int do_syslog(int type, char __user *buf, int len, int source)
 	struct printk_info info;
 	bool clear = false;
 	static int saved_console_loglevel = LOGLEVEL_DEFAULT;
+	static bool saved_ignore_per_console_loglevel;
+	static bool saved_ignore_per_console_loglevel_forced;
 	int error;
 
 	error = check_syslog_permissions(type, source);
@@ -1910,9 +1912,23 @@ int do_syslog(int type, char __user *buf, int len, int source)
 	/* Disable logging to console */
 	case SYSLOG_ACTION_CONSOLE_OFF:
 		mutex_lock(&syslog_lock);
-		if (saved_console_loglevel == LOGLEVEL_DEFAULT)
+		if (saved_console_loglevel == LOGLEVEL_DEFAULT) {
 			saved_console_loglevel = console_loglevel;
+			saved_ignore_per_console_loglevel = ignore_per_console_loglevel;
+			saved_ignore_per_console_loglevel_forced = false;
+		}
 		console_loglevel = minimum_console_loglevel;
+		if (!ignore_per_console_loglevel) {
+			/*
+			 * Only remember the saved value if this path actually
+			 * forced the override. Other contexts (sysrq, module
+			 * parameter writes, etc.) can legitimately toggle the
+			 * flag in parallel, so blindly restoring it later would
+			 * resurrect stale state.
+			 */
+			ignore_per_console_loglevel = true;
+			saved_ignore_per_console_loglevel_forced = true;
+		}
 		mutex_unlock(&syslog_lock);
 		break;
 	/* Enable logging to console */
@@ -1920,20 +1936,41 @@ int do_syslog(int type, char __user *buf, int len, int source)
 		mutex_lock(&syslog_lock);
 		if (saved_console_loglevel != LOGLEVEL_DEFAULT) {
 			console_loglevel = saved_console_loglevel;
+			if (saved_ignore_per_console_loglevel_forced)
+				ignore_per_console_loglevel = saved_ignore_per_console_loglevel;
 			saved_console_loglevel = LOGLEVEL_DEFAULT;
+			saved_ignore_per_console_loglevel_forced = false;
 		}
 		mutex_unlock(&syslog_lock);
 		break;
 	/* Set level of messages printed to console */
-	case SYSLOG_ACTION_CONSOLE_LEVEL:
-		if (len < 1 || len > 8)
+	case SYSLOG_ACTION_CONSOLE_LEVEL: {
+		int new_level = len;
+
+		if (!ignore_per_console_loglevel)
+			pr_warn_once(
+				"SYSLOG_ACTION_CONSOLE_LEVEL is ignored by consoles with an explicitly set per-console loglevel, see Documentation/admin-guide/per-console-loglevel.rst\n");
+		if (new_level < 1 || new_level > 8)
 			return -EINVAL;
-		if (len < minimum_console_loglevel)
-			len = minimum_console_loglevel;
-		console_loglevel = len;
-		/* Implicitly re-enable logging to console */
-		saved_console_loglevel = LOGLEVEL_DEFAULT;
+		if (new_level < minimum_console_loglevel)
+			new_level = minimum_console_loglevel;
+
+		mutex_lock(&syslog_lock);
+		console_loglevel = new_level;
+		/*
+		 * If SYSLOG_ACTION_CONSOLE_OFF forced ignore_per_console_loglevel,
+		 * restore the previous setting so per-console loglevels continue
+		 * to work after administrators re-enable logging via syslog().
+		 */
+		if (saved_console_loglevel != LOGLEVEL_DEFAULT) {
+			if (saved_ignore_per_console_loglevel_forced)
+				ignore_per_console_loglevel = saved_ignore_per_console_loglevel;
+			saved_console_loglevel = LOGLEVEL_DEFAULT;
+			saved_ignore_per_console_loglevel_forced = false;
+		}
+		mutex_unlock(&syslog_lock);
 		break;
+	}
 	/* Number of chars in the log buffer */
 	case SYSLOG_ACTION_SIZE_UNREAD:
 		mutex_lock(&syslog_lock);
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (12 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 13/21] printk: Toggle ignore_per_console_loglevel via syslog Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 14:04   ` Petr Mladek
  2025-11-27 19:44 ` [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range Chris Down
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

A sysfs interface under /sys/class/console/ is created that permits
viewing and configuring per-console attributes. This is the main
interface with which we expect users to interact with and configure
per-console loglevels.

Each console device now has its own directory (for example,
/sys/class/console/ttyS0/) containing the following attributes:

- effective_loglevel (ro): The effective loglevel for the console after
  considering all loglevel authorities (e.g., global loglevel,
  per-console loglevel).
- effective_loglevel_source (ro): The source of the effective loglevel
  (e.g., local, global, ignore_loglevel).
- loglevel (rw): The per-console loglevel. Writing a value between 0
  (KERN_EMERG) and 8 (KERN_DEBUG + 1) sets the per-console loglevel.
  Writing -1 disables the per-console loglevel.

In terms of technical implementation, we embed a device pointer in the
console struct, and register each console using it so we can expose
attributes in sysfs. We currently expose the following attributes:

    % ls -l /sys/class/console/ttyS0/
    total 0
    lrwxrwxrwx 1 root root    0 Oct 23 13:17 subsystem -> ../../../../class/console/
    -r--r--r-- 1 root root 4096 Oct 23 13:18 effective_loglevel
    -r--r--r-- 1 root root 4096 Oct 23 13:18 effective_loglevel_source
    -rw-r--r-- 1 root root 4096 Oct 23 13:18 loglevel
    -rw-r--r-- 1 root root 4096 Oct 23 13:17 uevent

The lifecycle of this classdev looks like this on registration:

    register_console(con)/printk_late_init()
      console_register_device(con)
        device_initialize(con->classdev) # kref_init: refcount = 1
        device_add(con->classdev)
          get_device(con->classdev)      # temporary: refcount++ (to 2)
          ...
          put_device(con->classdev)      # drop temporary refcount-- (to 1)

At steady state the class device holds a single persistent reference.

Unregistration:

    unregister_console_locked(con)
      struct device *dev = console->classdev;
      console->classdev = NULL;
      device_unregister(dev)
        device_del(dev)
          device_remove_class_symlinks(dev)
            sysfs_delete_link()
              kernfs_remove_by_name_ns()
                __kernfs_remove()
                  kernfs_drain()
                    kernfs_drain_open_files() # waits for open file handles
          ...
          kobject_del(&dev->kobj) # removes from sysfs
        put_device(dev)           # final kref_put: refcount-- (1 -> 0)
          kobject_release()
            kobject_cleanup()
              device_release()
                console_classdev_release(dev)
                  kfree(dev)

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/ABI/testing/sysfs-class-console |  58 ++++
 Documentation/core-api/printk-basics.rst      |  35 ++-
 Documentation/networking/netconsole.rst       |  12 +
 MAINTAINERS                                   |   1 +
 include/linux/console.h                       |   4 +
 kernel/printk/Makefile                        |   2 +-
 kernel/printk/internal.h                      |   8 +
 kernel/printk/printk.c                        |  32 ++
 kernel/printk/sysfs.c                         | 290 ++++++++++++++++++
 9 files changed, 424 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-console
 create mode 100644 kernel/printk/sysfs.c

diff --git a/Documentation/ABI/testing/sysfs-class-console b/Documentation/ABI/testing/sysfs-class-console
new file mode 100644
index 000000000000..8c0f0cf3f6c5
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-console
@@ -0,0 +1,58 @@
+What:		/sys/class/console/
+Date:		November 2025
+Contact:	Chris Down <chris@chrisdown.name>
+Description:	Interface for viewing and setting per-console attributes, like
+		the per-console loglevel. For a high-level document describing
+		the motivations for this interface and related non-sysfs
+		controls, see
+		Documentation/admin-guide/per-console-loglevel.rst.
+
+What:		/sys/class/console/<C>/effective_loglevel
+Date:		November 2025
+Contact:	Chris Down <chris@chrisdown.name>
+Permissions:	0444 (world readable)
+Description:	Read only. The currently effective loglevel for this console.
+		All messages emitted with a loglevel below the effective value
+		will be emitted to the console.
+
+What:		/sys/class/console/<C>/effective_loglevel_source
+Date:		November 2025
+Contact:	Chris Down <chris@chrisdown.name>
+Permissions:	0444 (world readable)
+Description:	Read only. The currently effective loglevel source for this
+		console -- for example, whether it was set globally, or whether
+		it was set locally for this console.
+
+		Possible values are:
+			=============== ============================================
+			local           The loglevel comes from the console's
+			                per-console loglevel setting.
+			global          The loglevel comes from the global
+			                console_loglevel.
+			ignore_loglevel Both the per-console loglevel and global
+			                loglevel are ignored as ignore_loglevel is
+			                present on the kernel command line.
+			=============== ============================================
+
+What:		/sys/class/console/<C>/loglevel
+Date:		November 2025
+Contact:	Chris Down <chris@chrisdown.name>
+Permissions:	0644 (root read/write, user read)
+Description:	Read write. The current per-console loglevel, which will take
+		effect if not overridden by other non-sysfs controls (see
+		Documentation/admin-guide/per-console-loglevel.rst).
+
+		Valid values:
+			1-8:  LOGLEVEL_ALERT (1) to LOGLEVEL_DEBUG + 1 (8)
+			-1:   Use global console_loglevel (default)
+			0:    Explicitly rejected (KERN_EMERG not allowed)
+
+		Error codes:
+			EINVAL: Non-numeric input
+			ERANGE: Value out of valid range (< 1 or > 8, excluding -1)
+			ERANGE: Value is 0 (KERN_EMERG not allowed for per-console)
+			ERANGE: Value below system minimum_console_loglevel
+
+		The special value -1 disables the per-console loglevel, making
+		the console use the global loglevel instead.
+
diff --git a/Documentation/core-api/printk-basics.rst b/Documentation/core-api/printk-basics.rst
index 2dde24ca7d9f..bfad359505bb 100644
--- a/Documentation/core-api/printk-basics.rst
+++ b/Documentation/core-api/printk-basics.rst
@@ -54,32 +54,33 @@ string, the log level is not a separate argument). The available log levels are:
 
 The log level specifies the importance of a message. The kernel decides whether
 to show the message immediately (printing it to the current console) depending
-on its log level and the current *console_loglevel* (a kernel variable). If the
-message priority is higher (lower log level value) than the *console_loglevel*
-the message will be printed to the console.
+on its log level and the current global *console_loglevel* or local per-console
+loglevel (kernel variables). If the message priority is higher (lower log level
+value) than the effective loglevel the message will be printed to the console.
 
 If the log level is omitted, the message is printed with ``KERN_DEFAULT``
 level.
 
-You can check the current *console_loglevel* with::
+You can check the current console's loglevel -- for example if you want to
+check the loglevel for serial consoles:
 
-  $ cat /proc/sys/kernel/printk
-  4        4        1        7
+  $ cat /sys/class/console/ttyS0/effective_loglevel
+  6
+  $ cat /sys/class/console/ttyS0/effective_loglevel_source
+  local
 
-The result shows the *current*, *default*, *minimum* and *boot-time-default* log
-levels.
+To change the default loglevel for all consoles, simply write the desired level
+to ``/proc/sys/kernel/console_loglevel``. For example::
 
-To change the current console_loglevel simply write the desired level to
-``/proc/sys/kernel/printk``. For example, to print all messages to the console::
+  # echo 5 > /proc/sys/kernel/console_loglevel
 
-  # echo 8 > /proc/sys/kernel/printk
+This sets the console_loglevel to print KERN_WARNING (4) or more severe
+messages to console. Consoles with a per-console loglevel set will ignore it
+unless ``ignore_per_console_loglevel`` is set on the kernel command line or at
+``/sys/module/printk/parameters/ignore_per_console_loglevel``.
 
-Another way, using ``dmesg``::
-
-  # dmesg -n 5
-
-sets the console_loglevel to print KERN_WARNING (4) or more severe messages to
-console. See ``dmesg(1)`` for more information.
+For more information on per-console loglevels, see
+Documentation/admin-guide/per-console-loglevel.rst.
 
 As an alternative to printk() you can use the ``pr_*()`` aliases for
 logging. This family of macros embed the log level in the macro names. For
diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst
index 59cb9982afe6..5ff12e88e5b8 100644
--- a/Documentation/networking/netconsole.rst
+++ b/Documentation/networking/netconsole.rst
@@ -78,6 +78,18 @@ Built-in netconsole starts immediately after the TCP stack is
 initialized and attempts to bring up the supplied dev at the supplied
 address.
 
+You can also set a loglevel at runtime::
+
+  $ ls -l /sys/class/console/netcon0/
+  total 0
+  lrwxrwxrwx 1 root root    0 May 18 13:28 subsystem -> ../../../../class/console/
+  -r--r--r-- 1 root root 4096 May 18 13:28 effective_loglevel
+  -r--r--r-- 1 root root 4096 May 18 13:28 effective_loglevel_source
+  -rw-r--r-- 1 root root 4096 May 18 13:28 loglevel
+  -rw-r--r-- 1 root root 4096 May 18 13:28 uevent
+
+See Documentation/admin-guide/per-console-loglevel.rst for more information.
+
 The remote host has several options to receive the kernel messages,
 for example:
 
diff --git a/MAINTAINERS b/MAINTAINERS
index e56494c7a956..2e6faa647b43 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20505,6 +20505,7 @@ R:	John Ogness <john.ogness@linutronix.de>
 R:	Sergey Senozhatsky <senozhatsky@chromium.org>
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
+F:	Documentation/ABI/testing/sysfs-class-console
 F:	Documentation/core-api/printk-basics.rst
 F:	include/linux/printk.h
 F:	kernel/printk/
diff --git a/include/linux/console.h b/include/linux/console.h
index a670c40623ad..a97235550668 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -16,6 +16,7 @@
 
 #include <linux/atomic.h>
 #include <linux/bits.h>
+#include <linux/device.h>
 #include <linux/irq_work.h>
 #include <linux/rculist.h>
 #include <linux/rcuwait.h>
@@ -323,6 +324,8 @@ struct nbcon_write_context {
  * @dropped:		Number of unreported dropped ringbuffer records
  * @data:		Driver private data
  * @node:		hlist node for the console list
+ * @classdev:		sysfs class device for this console, used to expose
+ *			per-console controls in /sys/class/console/<name>/
  *
  * @nbcon_state:	State for nbcon consoles
  * @nbcon_seq:		Sequence number of the next record for nbcon to print
@@ -352,6 +355,7 @@ struct console {
 	unsigned long		dropped;
 	void			*data;
 	struct hlist_node	node;
+	struct device		*classdev;
 
 	/* nbcon console specific members */
 
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
index f8004ac3983d..19e4919a13a7 100644
--- a/kernel/printk/Makefile
+++ b/kernel/printk/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y	= printk.o
-obj-$(CONFIG_PRINTK)	+= printk_safe.o nbcon.o
+obj-$(CONFIG_PRINTK)	+= sysfs.o printk_safe.o nbcon.o
 obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)	+= braille.o
 obj-$(CONFIG_PRINTK_INDEX)	+= index.o
 
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index f2ebaa2a6aa2..3b3a3c982412 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -21,6 +21,8 @@ enum loglevel_source {
 	LLS_IGNORE_LOGLEVEL,
 };
 
+int console_clamp_loglevel(int level);
+
 enum loglevel_source
 console_effective_loglevel_source(int con_level);
 int console_effective_loglevel(int con_level);
@@ -46,6 +48,9 @@ int console_effective_loglevel(int con_level);
 
 #ifdef CONFIG_PRINTK
 
+void console_register_device(struct console *new);
+void console_setup_class(void);
+
 #ifdef CONFIG_PRINTK_CALLER
 #define PRINTK_PREFIX_MAX	48
 #else
@@ -217,6 +222,9 @@ static inline void nbcon_kthreads_wake(void) { }
 static inline bool console_is_usable(struct console *con, short flags,
 				     bool use_atomic) { return false; }
 
+static inline void console_register_device(struct console *new) { }
+static inline void console_setup_class(void) { }
+
 #endif /* CONFIG_PRINTK */
 
 extern bool have_boot_console;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 1d28887e7218..605e0811cfc6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -200,6 +200,24 @@ static int __init control_devkmsg(char *str)
 }
 __setup("printk.devkmsg=", control_devkmsg);
 
+/**
+ * console_clamp_loglevel - Clamp a loglevel to valid console loglevel range
+ *
+ * @level: The loglevel to clamp
+ *
+ * Console loglevels must be within the range [LOGLEVEL_ALERT, LOGLEVEL_DEBUG + 1].
+ * This function clamps a given level to this valid range.
+ *
+ * Note: This does not allow LOGLEVEL_EMERG (0) for per-console loglevels, as
+ * level 0 is reserved for emergency messages that should always go to all consoles.
+ *
+ * Return: The clamped loglevel value
+ */
+int console_clamp_loglevel(int level)
+{
+	return clamp(level, LOGLEVEL_ALERT, LOGLEVEL_DEBUG + 1);
+}
+
 char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE] = "ratelimit";
 #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
 int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
@@ -4185,6 +4203,9 @@ void register_console(struct console *newcon)
 	u64 init_seq;
 	int err;
 
+	if (newcon->level == 0)
+		newcon->level = LOGLEVEL_DEFAULT;
+
 	console_list_lock();
 
 	for_each_console(con) {
@@ -4314,6 +4335,7 @@ void register_console(struct console *newcon)
 	if (use_device_lock)
 		newcon->device_unlock(newcon, flags);
 
+	console_register_device(newcon);
 	console_sysfs_notify();
 
 	/*
@@ -4429,6 +4451,13 @@ static int unregister_console_locked(struct console *console)
 	if (console->flags & CON_NBCON)
 		nbcon_free(console);
 
+	if (console->classdev) {
+		struct device *dev = console->classdev;
+
+		console->classdev = NULL;
+		device_unregister(dev);
+	}
+
 	console_sysfs_notify();
 
 	if (console->exit)
@@ -4578,6 +4607,9 @@ static int __init printk_late_init(void)
 					console_cpu_notify, NULL);
 	WARN_ON(ret < 0);
 	printk_sysctl_init();
+
+	console_setup_class();
+
 	return 0;
 }
 late_initcall(printk_late_init);
diff --git a/kernel/printk/sysfs.c b/kernel/printk/sysfs.c
new file mode 100644
index 000000000000..38d03046c45d
--- /dev/null
+++ b/kernel/printk/sysfs.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+/**
+ * console_sysfs_read_loglevel - Locklessly read the console specific loglevel
+ *				 when accessing the related sysfs interface
+ * @con:	struct console pointer of console to read loglevel from
+ *
+ * Locklessly reading @con->level provides a consistent read value because
+ * there is at most one CPU modifying @con->level and that CPU is using only
+ * read-modify-write operations to do so.
+ *
+ * Only use this function to read the loglevel via the related sysfs interface.
+ * The sysfs API makes sure that the structure cannot disappear while the
+ * interface is used.
+ *
+ * Context: Sysfs interface for the given console.
+ * Return: The current value of the @con->level field.
+ */
+static inline int console_sysfs_read_loglevel(const struct console *con)
+{
+	/*
+	 * The READ_ONCE() matches the WRITE_ONCE() when @level is modified
+	 * for registered consoles.
+	 */
+	return data_race(READ_ONCE(con->level));
+}
+
+/**
+ * console_sysfs_write_loglevel - Write the console specific loglevel via
+ *				  sysfs interface.
+ * @con:	struct console pointer of console to write loglevel to
+ * @con_level:	new loglevel value to write
+ *
+ * Only use this function to write the loglevel via the related sysfs interface.
+ * The sysfs API makes sure that the structure cannot disappear while the
+ * interface is used.
+ *
+ * Context: Any context.
+ */
+static inline void console_sysfs_write_loglevel(struct console *con, int con_level)
+{
+	/* This matches the READ_ONCE() in console_sysfs_read_loglevel(). */
+	WRITE_ONCE(con->level, con_level);
+}
+
+/**
+ * console_effective_loglevel_source_str - Get string name of loglevel source
+ *
+ * @con:	The console to query
+ *
+ * Returns a human-readable string describing the source of the console's
+ * effective loglevel (e.g., "local", "global", "ignore_loglevel").
+ *
+ * Return: String name of the loglevel source
+ */
+static const char *
+console_effective_loglevel_source_str(const struct console *con)
+{
+	enum loglevel_source source;
+	const char *str;
+	int con_level;
+
+	con_level = console_sysfs_read_loglevel(con);
+	source = console_effective_loglevel_source(con_level);
+
+	switch (source) {
+	case LLS_IGNORE_LOGLEVEL:
+		str = "ignore_loglevel";
+		break;
+	case LLS_LOCAL:
+		str = "local";
+		break;
+	case LLS_GLOBAL:
+		str = "global";
+		break;
+	default:
+		str = "unknown";
+		break;
+	}
+
+	return str;
+}
+
+static ssize_t effective_loglevel_source_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct console *con = dev_get_drvdata(dev);
+	const char *str;
+
+	str = console_effective_loglevel_source_str(con);
+	return sysfs_emit(buf, "%s\n", str);
+}
+
+static DEVICE_ATTR_RO(effective_loglevel_source);
+
+static ssize_t effective_loglevel_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct console *con = dev_get_drvdata(dev);
+	int con_level;
+
+	con_level = console_sysfs_read_loglevel(con);
+	return sysfs_emit(buf, "%d\n", console_effective_loglevel(con_level));
+}
+
+static DEVICE_ATTR_RO(effective_loglevel);
+
+static ssize_t loglevel_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct console *con = dev_get_drvdata(dev);
+	int con_level;
+
+	con_level = console_sysfs_read_loglevel(con);
+	return sysfs_emit(buf, "%d\n", con_level);
+}
+
+static ssize_t loglevel_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	struct console *con = dev_get_drvdata(dev);
+	ssize_t ret;
+	int level;
+
+	ret = kstrtoint(buf, 10, &level);
+	if (ret < 0)
+		return ret;
+
+	/* -1 means "use global loglevel" */
+	if (level == -1)
+		goto out;
+
+	/*
+	 * Reject level 0 (KERN_EMERG) - per-console loglevel must be > 0.
+	 * Emergency messages should go to all consoles, so they cannot be
+	 * filtered per-console.
+	 */
+	if (level == 0)
+		return -ERANGE;
+
+	if (console_clamp_loglevel(level) != level)
+		return -ERANGE;
+
+	/*
+	 * If the system has a minimum console loglevel set (via sysctl or
+	 * kernel parameter), enforce it. This prevents setting per-console
+	 * loglevels below the system minimum.
+	 */
+	if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
+	    level < minimum_console_loglevel)
+		return -ERANGE;
+
+out:
+	console_sysfs_write_loglevel(con, level);
+	return size;
+}
+
+static DEVICE_ATTR_RW(loglevel);
+
+static struct attribute *console_sysfs_attrs[] = {
+	&dev_attr_loglevel.attr,
+	&dev_attr_effective_loglevel_source.attr,
+	&dev_attr_effective_loglevel.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(console_sysfs);
+
+static const struct class console_class = {
+	.name = "console",
+	.dev_groups = console_sysfs_groups,
+};
+static bool console_class_registered;
+
+/**
+ * console_classdev_release - Release callback for console class devices
+ *
+ * @dev:	The device being released
+ *
+ * Called when the last reference to a console class device is dropped.
+ * Frees the memory allocated for the device structure.
+ */
+static void console_classdev_release(struct device *dev)
+{
+	kfree(dev);
+}
+
+/**
+ * console_register_device - Register a console's sysfs class device
+ *
+ * @con:	The console to register
+ *
+ * Creates a sysfs class device for the given console under /sys/class/console/.
+ * This enables userspace access to per-console attributes like loglevel.
+ *
+ * If called before the console class is registered (during early boot),
+ * this function returns early and the device will be registered later
+ * by console_setup_class().
+ */
+void console_register_device(struct console *con)
+{
+	/*
+	 * We might be called from register_console() before the class is
+	 * registered. If that happens, we'll take care of it in
+	 * printk_late_init.
+	 */
+	if (!console_class_registered)
+		return;
+
+	if (WARN_ON(con->classdev))
+		return;
+
+	con->classdev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	if (!con->classdev)
+		return;
+
+	device_initialize(con->classdev);
+	con->classdev->release = console_classdev_release;
+	con->classdev->class = &console_class;
+	dev_set_drvdata(con->classdev, con);
+	if (dev_set_name(con->classdev, "%s%d", con->name, con->index)) {
+		put_device(con->classdev);
+		con->classdev = NULL;
+		return;
+	}
+
+	/*
+	 * This class device exists solely to expose attributes (like loglevel)
+	 * and does not control physical power states. Power is managed by the
+	 * underlying hardware device. Disable PM entirely to prevent the
+	 * creation of confusing and unused power sysfs attributes.
+	 */
+	device_set_pm_not_required(con->classdev);
+
+	if (device_add(con->classdev)) {
+		put_device(con->classdev);
+		con->classdev = NULL;
+	}
+}
+
+/**
+ * console_setup_class - Initialize the console sysfs class
+ *
+ * Registers the console class with sysfs and creates class devices for all
+ * currently registered consoles. Called during late init after sysfs is
+ * available.
+ *
+ * Consoles registered before this function is called will have their class
+ * devices created here. Consoles registered afterwards will have their
+ * devices created by console_register_device() during register_console().
+ */
+void console_setup_class(void)
+{
+	struct console *con;
+	int cookie;
+	int err;
+
+	/*
+	 * printk exists for the lifetime of the kernel, it cannot be unloaded,
+	 * so we should never end up back in here.
+	 */
+	if (WARN_ON(console_class_registered))
+		return;
+
+	err = class_register(&console_class);
+	if (err) {
+		pr_err("console: failed to register class: %pe\n", ERR_PTR(err));
+		return;
+	}
+
+	/*
+	 * Take console_list_lock() before exposing the class globally.
+	 * This ensures register_console() (which holds the lock) cannot
+	 * see the class until it's fully initialised with dev_groups.
+	 */
+	console_list_lock();
+	console_class_registered = true;
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(con)
+		console_register_device(con);
+	console_srcu_read_unlock(cookie);
+	console_list_unlock();
+}
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (13 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 14:10   ` Petr Mladek
  2025-11-27 19:44 ` [PATCH v8 16/21] printk: Constrain hardware-addressed console checks to name position Chris Down
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The sysrq loglevel handler (keys 0-9) directly assigns the numeric key
value to console_loglevel without any validation. This creates an
inconsistency with other interfaces: the new kernel.console_loglevel
sysctl, the per-console sysfs loglevel interface, and the
SYSLOG_ACTION_CONSOLE_LEVEL syslog command all clamp or reject values
outside the valid range.

In particular, sysrq 0 sets console_loglevel to 0 (LOGLEVEL_EMERG),
which is problematic because:

1. LOGLEVEL_EMERG (0) is reserved for emergency messages that should
   always reach all consoles. Setting console_loglevel to 0 would mean
   only KERN_EMERG messages print, which is likely never intended.

2. The per-console loglevel infrastructure explicitly rejects level 0
   for this reason, creating an inconsistency where sysrq can set a
   value that other interfaces refuse.

3. CONSOLE_LOGLEVEL_MIN is defined as 1, indicating the minimum valid
   console loglevel, yet sysrq ignores this.

Similarly, sysrq 9 sets console_loglevel to 9, which is above
LOGLEVEL_DEBUG (7) and serves no useful purpose since no messages have
a level that high.

Use console_clamp_loglevel() to clamp the requested loglevel to the
valid range [1, 8]. This ensures consistent behaviour across all
loglevel-setting interfaces.

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 drivers/tty/sysrq.c    | 2 +-
 include/linux/printk.h | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 1d5ae9997e79..e9d97ec28432 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -101,7 +101,7 @@ __setup("sysrq_always_enabled", sysrq_always_enabled_setup);
 
 static void sysrq_handle_loglevel(u8 key)
 {
-	u8 loglevel = key - '0';
+	u8 loglevel = console_clamp_loglevel(key - '0');
 
 	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
 	pr_info("Loglevel set to %u\n", loglevel);
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 0aa8cb8ddc09..5a8c4aca729f 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -65,6 +65,7 @@ static inline const char *printk_skip_headers(const char *buffer)
 int match_devname_and_update_preferred_console(const char *match,
 					       const char *name,
 					       const short idx);
+int console_clamp_loglevel(int level);
 
 extern int console_printk[];
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 16/21] printk: Constrain hardware-addressed console checks to name position
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (14 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-11-27 19:44 ` [PATCH v8 17/21] printk: Support setting initial console loglevel via console= on cmdline Chris Down
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

Commit 7640f1a44eba ("printk: Add
match_devname_and_update_preferred_console()") adds support for
DEVNAME:n:n style console= registration. It determines whether or not
this is a hardware-addressed console by looking at whether the console=
string has a colon in it. However, this interferes with loglevel:n and
potentially other future named options, which also make use of the
character.

In order to avoid this, only search positions before options.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 kernel/printk/printk.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 605e0811cfc6..32ea9b69f515 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2813,6 +2813,7 @@ static int __init console_setup(char *str)
 	char *devname = NULL;
 	char *options;
 	char *s;
+	char *first_delim;
 	int idx;
 
 	/*
@@ -2828,8 +2829,13 @@ static int __init console_setup(char *str)
 	if (_braille_console_setup(&str, &brl_options))
 		return 1;
 
-	/* For a DEVNAME:0.0 style console the character device is unknown early */
-	if (strchr(str, ':'))
+	/*
+	 * For a DEVNAME:0.0 style console the character device is unknown
+	 * early. We must restrict this to before any comma to avoid interfering
+	 * with named options, like "loglevel".
+	 */
+	first_delim = strpbrk(str, ":,");
+	if (first_delim && *first_delim == ':')
 		devname = buf;
 	else
 		ttyname = buf;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 17/21] printk: Support setting initial console loglevel via console= on cmdline
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (15 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 16/21] printk: Constrain hardware-addressed console checks to name position Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-11-27 19:44 ` [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls Chris Down
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

Extend the console= kernel command line parameter to support specifying
per-console loglevels at boot time. This is achieved by introducing a
new loglevel option that can be passed as a loglevel option within a
console= stanza.

For example, this is an example of how one might configure netconsole
devices to print messages with a higher priority than loglevel 3
(KERN_ERR) at startup:

    console=netcon0,loglevel:3

Reviewed-by: Petr Mladek <pmladek@suse.com>
Tested-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 .../admin-guide/kernel-parameters.txt         |  24 ++-
 Documentation/admin-guide/serial-console.rst  |  37 +++-
 Documentation/networking/netconsole.rst       |   6 +-
 kernel/printk/console_cmdline.h               |   1 +
 kernel/printk/printk.c                        | 168 +++++++++++++++++-
 5 files changed, 219 insertions(+), 17 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 7b62a99489b8..dec9e29ba8d2 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -819,13 +819,18 @@
 		ttyS<n>[,options]
 		ttyUSB0[,options]
 			Use the specified serial port.  The options are of
-			the form "bbbbpnf", where "bbbb" is the baud rate,
-			"p" is parity ("n", "o", or "e"), "n" is number of
-			bits, and "f" is flow control ("r" for RTS or
-			omit it).  Default is "9600n8".
+			the form "bbbbpnf,extra", where "bbbb" is the baud
+			rate, "p" is parity ("n", "o", or "e"), "n" is
+			number of bits, and "f" is flow control ("r" for RTS
+			or omit it). Default is "9600n8".
 
-			See Documentation/admin-guide/serial-console.rst for more
-			information.  See
+			At present the only extra option is "loglevel" to
+			set the per-console loglevel. For example:
+
+				console=ttyS0,9600n8,loglevel:3
+
+			See Documentation/admin-guide/serial-console.rst for
+			more information.  See
 			Documentation/networking/netconsole.rst for an
 			alternative.
 
@@ -3411,8 +3416,11 @@
 	loglevel=	[KNL,EARLY]
 			All Kernel Messages with a loglevel smaller than the
 			console loglevel will be printed to the console. It can
-			also be changed with klogd or other programs. The
-			loglevels are defined as follows:
+			also be changed with klogd or other programs. Note that
+			this can be overridden per-console, see
+			Documentation/admin-guide/per-console-loglevel.rst.
+
+			The loglevels are defined as follows:
 
 			0 (KERN_EMERG)		system is unusable
 			1 (KERN_ALERT)		action must be taken immediately
diff --git a/Documentation/admin-guide/serial-console.rst b/Documentation/admin-guide/serial-console.rst
index 1609e7479249..b8163e6eb95a 100644
--- a/Documentation/admin-guide/serial-console.rst
+++ b/Documentation/admin-guide/serial-console.rst
@@ -32,6 +32,33 @@ The format of this option is::
 			and F is flow control ('r' for RTS). Default is
 			9600n8. The maximum baudrate is 115200.
 
+			One can also specify the per-console loglevel for this
+			console by providing a loglevel parameter, for example
+			"loglevel:4" to set this console's loglevel to 4. The
+			value provided can be from 1 (LOGLEVEL_ALERT) to 8
+			(LOGLEVEL_DEBUG + 1), and messages below that will be
+			emitted onto the console as they become available.
+
+The available loglevels are defined thus:
+
++---+--------------+-----------------------------------+
+| 0 | KERN_EMERG   | system is unusable                |
++---+--------------+-----------------------------------+
+| 1 | KERN_ALERT   | action must be taken immediately  |
++---+--------------+-----------------------------------+
+| 2 | KERN_CRIT    | critical conditions               |
++---+--------------+-----------------------------------+
+| 3 | KERN_ERR     | error conditions                  |
++---+--------------+-----------------------------------+
+| 4 | KERN_WARNING | warning conditions                |
++---+--------------+-----------------------------------+
+| 5 | KERN_NOTICE  | normal but significant condition  |
++---+--------------+-----------------------------------+
+| 6 | KERN_INFO    | informational                     |
++---+--------------+-----------------------------------+
+| 7 | KERN_DEBUG   | debug-level messages              |
++---+--------------+-----------------------------------+
+
 You can specify multiple console= options on the kernel command line.
 
 The behavior is well defined when each device type is mentioned only once.
@@ -39,11 +66,14 @@ In this case, the output will appear on all requested consoles. And
 the last device will be used when you open ``/dev/console``.
 So, for example::
 
-	console=ttyS1,9600 console=tty0
+	console=ttyS1,9600,loglevel:5 console=tty0
 
 defines that opening ``/dev/console`` will get you the current foreground
-virtual console, and kernel messages will appear on both the VGA
-console and the 2nd serial port (ttyS1 or COM2) at 9600 baud.
+virtual console, and kernel messages will appear on both the VGA console and
+the 2nd serial port (ttyS1 or COM2) at 9600 baud. The optional loglevel "5"
+indicates that this console will emit messages more serious than
+LOGLEVEL_NOTICE (that is, LOGLEVEL_WARNING and below, since more serious
+messages have lower ordering).
 
 The behavior is more complicated when the same device type is defined more
 times. In this case, there are the following two rules:
@@ -145,3 +175,4 @@ Replace the sample values as needed.
    the integration of these patches into m68k, ppc and alpha.
 
 Miquel van Smoorenburg <miquels@cistron.nl>, 11-Jun-2000
+Chris Down <chris@chrisdown.name>, 18-Nov-2025
diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst
index 5ff12e88e5b8..1bcb56151b14 100644
--- a/Documentation/networking/netconsole.rst
+++ b/Documentation/networking/netconsole.rst
@@ -78,7 +78,11 @@ Built-in netconsole starts immediately after the TCP stack is
 initialized and attempts to bring up the supplied dev at the supplied
 address.
 
-You can also set a loglevel at runtime::
+You can also set a loglevel at boot time on the kernel command line::
+
+  console=netcon0,loglevel:2
+
+This can also be changed at runtime::
 
   $ ls -l /sys/class/console/netcon0/
   total 0
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
index 0ab573b6d4dc..cb3b99d31d80 100644
--- a/kernel/printk/console_cmdline.h
+++ b/kernel/printk/console_cmdline.h
@@ -7,6 +7,7 @@ struct console_cmdline
 	char	name[16];			/* Name of the driver	    */
 	int	index;				/* Minor dev. to use	    */
 	char	devname[32];			/* DEVNAME:0.0 style device name */
+	int	level;				/* Log level to use */
 	bool	user_specified;			/* Specified by command line vs. platform */
 	char	*options;			/* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 32ea9b69f515..cb796af0b867 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -42,6 +42,7 @@
 #include <linux/cpu.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
+#include <linux/slab.h>
 #include <linux/irq_work.h>
 #include <linux/ctype.h>
 #include <linux/uio.h>
@@ -2735,6 +2736,160 @@ static void set_user_specified(struct console_cmdline *c, bool user_specified)
 	console_set_on_cmdline = 1;
 }
 
+/**
+ * find_and_remove_console_option - Find and remove a named option from console options string
+ * @options: The console options string (will be modified in-place)
+ * @key: The option name to find (e.g., "loglevel")
+ * @val_buf: Buffer to store the option value (if present)
+ * @val_buf_size: Size of @val_buf
+ *
+ * This function searches for a named option in a comma-separated options string
+ * (e.g., "9600n8,loglevel:3,other:value"). If found, it extracts the value
+ * (the part after ':') and removes the entire option from the string.
+ *
+ * The function modifies @options in-place by:
+ * 1. Temporarily null-terminating option names and values during parsing
+ * 2. Restoring separators if the option isn't found
+ * 3. Removing the found option by shifting the remaining string
+ *
+ * Return: true if the option was found and removed, false otherwise
+ */
+static bool find_and_remove_console_option(char *options, const char *key,
+					   char *val_buf, size_t val_buf_size)
+{
+	bool found = false, first = true;
+	char *option, *next = options;
+
+	if (!val_buf_size)
+		return false;
+
+	while ((option = strsep(&next, ","))) {
+		char *value;
+
+		value = strchr(option, ':');
+		if (value)
+			*(value++) = '\0';
+
+		if (strcmp(option, key) == 0) {
+			found = true;
+			if (value) {
+				if (strlen(value) >= val_buf_size) {
+					pr_warn("Can't copy console option value for %s:%s: not enough space (%zu)\n",
+						option, value, val_buf_size);
+					found = false;
+				} else {
+					strscpy(val_buf, value, val_buf_size);
+				}
+			} else {
+				val_buf[0] = '\0';
+			}
+		}
+
+		if (found)
+			break;
+
+		if (next)
+			*(next - 1) = ',';
+		if (value)
+			*(value - 1) = ':';
+
+		first = false;
+	}
+
+	if (found) {
+		if (next)
+			memmove(option, next, strlen(next) + 1);
+		else if (first)
+			*option = '\0';
+		else
+			*--option = '\0';
+	}
+
+	return found;
+}
+
+/**
+ * find_and_remove_loglevel_option - Extract and remove loglevel option from string
+ *
+ * @options:	The console options string (modified in-place)
+ *
+ * Searches for a "loglevel:N" option in the options string, validates the
+ * value, and removes the option from the string if found.
+ *
+ * Return: The parsed loglevel value (> 0) on success, or a negative error code:
+ *         -ENOENT if no loglevel option was found
+ *         -EINVAL if the loglevel value could not be parsed
+ *         -ERANGE if the loglevel value is out of valid range
+ */
+static int find_and_remove_loglevel_option(char *options)
+{
+	char val[16];
+	int loglevel;
+
+	if (!find_and_remove_console_option(options, "loglevel", val,
+					    sizeof(val)))
+		return -ENOENT;
+
+	if (kstrtoint(val, 10, &loglevel)) {
+		pr_warn("Invalid console loglevel, ignoring: %s\n", val);
+		return -EINVAL;
+	}
+
+	/* Reject level 0 (KERN_EMERG) - per-console loglevel must be > 0 */
+	if (loglevel == 0) {
+		pr_warn("Per-console loglevel 0 (KERN_EMERG) is not allowed, ignoring\n");
+		return -ERANGE;
+	}
+
+	if (console_clamp_loglevel(loglevel) != loglevel) {
+		pr_warn("Per-console loglevel out of range, ignoring: %d\n", loglevel);
+		return -ERANGE;
+	}
+
+	return loglevel;
+}
+
+/**
+ * console_cmdline_set_options - Parse and set options for a console_cmdline entry
+ *
+ * @c:		The console_cmdline entry to configure
+ * @options:	The options string from console= parameter (may be NULL)
+ *
+ * Parses the options string for known named options (currently "loglevel"),
+ * removes them from the string, and stores the remaining options in the
+ * console_cmdline entry. The loglevel option, if present and valid, is stored
+ * in c->level.
+ *
+ * Return: 0 on success, -ENOMEM if memory allocation fails
+ */
+static int console_cmdline_set_options(struct console_cmdline *c, char *options)
+{
+	char *options_buf = NULL;
+	int level = -ENOENT;
+
+	if (options) {
+		options_buf = kstrdup(options, GFP_KERNEL);
+		if (!options_buf)
+			return -ENOMEM;
+
+		level = find_and_remove_loglevel_option(options_buf);
+		if (options_buf && !*options_buf) {
+			kfree(options_buf);
+			options_buf = NULL;
+		}
+	}
+
+	kfree(c->options);
+	c->options = options_buf;
+
+	if (level >= 0)
+		c->level = level;
+	else if (!options || level == -ENOENT)
+		c->level = -1;
+
+	return 0;
+}
+
 static int __add_preferred_console(const char *name, const short idx,
 				   const char *devname, char *options,
 				   char *brl_options, bool user_specified)
@@ -2766,8 +2921,8 @@ static int __add_preferred_console(const char *name, const short idx,
 			if (!brl_options)
 				preferred_console = i;
 
-			if (options)
-				c->options = options;
+			if (console_cmdline_set_options(c, options))
+				return -ENOMEM;
 
 			set_user_specified(c, user_specified);
 			braille_set_options(c, brl_options);
@@ -2782,7 +2937,11 @@ static int __add_preferred_console(const char *name, const short idx,
 		strscpy(c->name, name);
 	if (devname)
 		strscpy(c->devname, devname);
-	c->options = options;
+
+	c->level = -1;
+
+	if (console_cmdline_set_options(c, options))
+		return -ENOMEM;
 	set_user_specified(c, user_specified);
 	braille_set_options(c, brl_options);
 
@@ -4059,8 +4218,7 @@ static int try_enable_preferred_console(struct console *newcon,
 			if (newcon->index < 0)
 				newcon->index = c->index;
 
-			/* TODO: will be configurable in a later patch */
-			newcon->level = LOGLEVEL_DEFAULT;
+			newcon->level = c->level;
 
 			if (_braille_register_console(newcon, c))
 				return 0;
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (16 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 17/21] printk: Support setting initial console loglevel via console= on cmdline Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 15:24   ` Petr Mladek
  2025-11-27 19:44 ` [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels Chris Down
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

Introduce two new sysctl interfaces for configuring global loglevels:

- kernel.console_loglevel: Sets the global console loglevel, determining
  the minimum priority of messages printed to consoles. Messages with a
  loglevel lower than this value will be printed.
- kernel.default_message_loglevel: Sets the default loglevel for
  messages that do not specify an explicit loglevel.

The kernel.printk sysctl was previously used to set multiple loglevel
parameters simultaneously, but it was confusing and lacked proper
validation. By introducing these dedicated sysctl interfaces, we provide
a clearer and more granular way to configure the loglevels.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Tested-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/admin-guide/sysctl/kernel.rst | 17 +++++-
 include/linux/sysctl.h                      |  7 +++
 kernel/printk/sysctl.c                      | 63 +++++++++++++++++++++
 kernel/sysctl.c                             | 18 +++---
 4 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index f3ee807b5d8b..043d5f663b7d 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -1079,6 +1079,20 @@ otherwise the 'doze' mode will be used.
 
 ==============================================================
 
+Some of these settings may be overridden per-console, see
+Documentation/admin-guide/per-console-loglevel.rst. See ``man 2 syslog`` for
+more information on the different loglevels.
+
+console_loglevel
+================
+
+Messages with a higher priority than this will be printed to consoles.
+
+default_message_loglevel
+========================
+
+Messages without an explicit priority will be printed with this priority.
+
 printk
 ======
 
@@ -1087,8 +1101,7 @@ The four values in printk denote: ``console_loglevel``,
 ``default_console_loglevel`` respectively.
 
 These values influence printk() behavior when printing or
-logging error messages. See '``man 2 syslog``' for more info on
-the different loglevels.
+logging error messages.
 
 ======================== =====================================
 console_loglevel         messages with a higher priority than
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 92e9146b1104..c2f72d172f64 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -235,6 +235,13 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
 
 void do_sysctl_args(void);
 bool sysctl_is_alias(char *param);
+int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int *valp,
+			  int write, void *data);
+int do_proc_dointvec(const struct ctl_table *table, int write,
+		     void *buffer, size_t *lenp, loff_t *ppos,
+		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
+				 int write, void *data),
+		     void *data);
 int do_proc_douintvec(const struct ctl_table *table, int write,
 		      void *buffer, size_t *lenp, loff_t *ppos,
 		      int (*conv)(unsigned long *lvalp,
diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
index da77f3f5c1fe..034739939a61 100644
--- a/kernel/printk/sysctl.c
+++ b/kernel/printk/sysctl.c
@@ -11,6 +11,9 @@
 
 static const int ten_thousand = 10000;
 
+static int min_msg_loglevel = LOGLEVEL_EMERG;
+static int max_msg_loglevel = LOGLEVEL_DEBUG;
+
 static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int write,
 				void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -20,6 +23,50 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
 	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 }
 
+static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
+					     int *valp,
+					     int write, void *data)
+{
+	int level, ret;
+
+	/*
+	 * If writing, first do so via a temporary local int so we can
+	 * bounds-check it before touching *valp.
+	 */
+	int *intp = write ? &level : valp;
+
+	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);
+	if (ret)
+		return ret;
+
+	if (write) {
+		if (level != console_clamp_loglevel(level))
+			return -ERANGE;
+
+		/*
+		 * Honour the administrator-configured minimum console
+		 * loglevel (third element of kernel.printk).  This mirrors
+		 * the syslog() and sysfs control paths so that once the floor
+		 * is raised we do not let this sysctl silently bypass it.
+		 */
+		if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
+		    level < minimum_console_loglevel)
+			level = minimum_console_loglevel;
+
+		WRITE_ONCE(*valp, level);
+	}
+
+	return 0;
+}
+
+static int proc_dointvec_console_loglevel(const struct ctl_table *table,
+					  int write, void *buffer, size_t *lenp,
+					  loff_t *ppos)
+{
+	return do_proc_dointvec(table, write, buffer, lenp, ppos,
+			       do_proc_dointvec_console_loglevel, NULL);
+}
+
 static const struct ctl_table printk_sysctls[] = {
 	{
 		.procname	= "printk",
@@ -76,6 +123,22 @@ static const struct ctl_table printk_sysctls[] = {
 		.extra1		= SYSCTL_ZERO,
 		.extra2		= SYSCTL_TWO,
 	},
+	{
+		.procname	= "console_loglevel",
+		.data		= &console_loglevel,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_console_loglevel,
+	},
+	{
+		.procname	= "default_message_loglevel",
+		.data		= &default_message_loglevel,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &min_msg_loglevel,
+		.extra2		= &max_msg_loglevel,
+	},
 };
 
 void __init printk_sysctl_init(void)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index cb6196e3fa99..3ed010b8f6b3 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -354,9 +354,9 @@ static void proc_put_char(void **buf, size_t *size, char c)
 	}
 }
 
-static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
-				 int *valp,
-				 int write, void *data)
+int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
+			  int *valp,
+			  int write, void *data)
 {
 	if (write) {
 		if (*negp) {
@@ -380,6 +380,7 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
 	}
 	return 0;
 }
+EXPORT_SYMBOL(do_proc_dointvec_conv);
 
 static int do_proc_douintvec_conv(unsigned long *lvalp,
 				  unsigned int *valp,
@@ -471,15 +472,16 @@ static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table,
 	return err;
 }
 
-static int do_proc_dointvec(const struct ctl_table *table, int write,
-		  void *buffer, size_t *lenp, loff_t *ppos,
-		  int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
-			      int write, void *data),
-		  void *data)
+int do_proc_dointvec(const struct ctl_table *table, int write,
+		     void *buffer, size_t *lenp, loff_t *ppos,
+		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
+				 int write, void *data),
+		     void *data)
 {
 	return __do_proc_dointvec(table->data, table, write,
 			buffer, lenp, ppos, conv, data);
 }
+EXPORT_SYMBOL(do_proc_dointvec);
 
 static int do_proc_douintvec_w(unsigned int *tbl_data,
 			       const struct ctl_table *table,
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (17 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 15:32   ` Petr Mladek
  2025-11-27 19:44 ` [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface Chris Down
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The per-console loglevel feature documentation could use some practical
guidance. This commit adds:

- Examples section covering runtime configuration, effective loglevel
  checking, and boot-time configuration
- Common use case demonstrating high-performance netconsole with quiet
  serial console fallback
- Performance impact section explaining how per-console loglevels reduce
  latency by filtering messages before slow console writes
- Edge cases section documenting behavior with concurrent writes,
  console unregistration, and global loglevel changes

The guidance interleaves advice about many parts of this patchset, so
let's have it in a distinct commit.

This documentation will help users understand how to effectively use and
debug per-console loglevels.

Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/admin-guide/index.rst           |   1 +
 .../admin-guide/per-console-loglevel.rst      | 252 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 3 files changed, 254 insertions(+)
 create mode 100644 Documentation/admin-guide/per-console-loglevel.rst

diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index 259d79fbeb94..5f0ae9c4017b 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -155,6 +155,7 @@ How to configure your hardware within your Linux system.
    media/index
    nvme-multipath
    parport
+   per-console-loglevel
    pnp
    rapidio
    rtc
diff --git a/Documentation/admin-guide/per-console-loglevel.rst b/Documentation/admin-guide/per-console-loglevel.rst
new file mode 100644
index 000000000000..f2db46c00de3
--- /dev/null
+++ b/Documentation/admin-guide/per-console-loglevel.rst
@@ -0,0 +1,252 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _per_console_loglevel:
+
+Per-console loglevel support
+============================
+
+Motivation
+----------
+
+Consoles can have vastly different latencies and throughputs. For example,
+writing a message to the serial console can take on the order of tens of
+milliseconds to get the UART to successfully write a message. While this might
+be fine for a single, one-off message, this can cause significant
+application-level stalls in situations where the kernel writes large amounts of
+information to the console.
+
+This means that while you might want to send at least INFO level messages to
+(for example) netconsole, which is relatively fast, you may only want to send at
+least WARN level messages to the serial console. This permits debugging
+using the serial console in cases that netconsole doesn't receive messages
+during particularly bad system issues, while still keeping the noise low enough
+to avoid inducing latency in userspace applications.
+
+Loglevel
+--------
+
+Kernel loglevels are defined thus:
+
++---+--------------+-----------------------------------+
+| 0 | KERN_EMERG   | system is unusable                |
++---+--------------+-----------------------------------+
+| 1 | KERN_ALERT   | action must be taken immediately  |
++---+--------------+-----------------------------------+
+| 2 | KERN_CRIT    | critical conditions               |
++---+--------------+-----------------------------------+
+| 3 | KERN_ERR     | error conditions                  |
++---+--------------+-----------------------------------+
+| 4 | KERN_WARNING | warning conditions                |
++---+--------------+-----------------------------------+
+| 5 | KERN_NOTICE  | normal but significant condition  |
++---+--------------+-----------------------------------+
+| 6 | KERN_INFO    | informational                     |
++---+--------------+-----------------------------------+
+| 7 | KERN_DEBUG   | debug-level messages              |
++---+--------------+-----------------------------------+
+
+Tunables
+--------
+
+In order to allow tuning per-console loglevels, the following controls exist:
+
+Global
+~~~~~~
+
+The global loglevel is set by the ``kernel.console_loglevel`` sysctl, which can
+also be set as ``loglevel=`` on the kernel command line.
+
+The printk module also takes two parameters which modify this behaviour
+further:
+
+* ``ignore_loglevel`` on the kernel command line or set in printk parameters:
+  Emit all messages. All other controls are ignored if this is present.
+
+* ``ignore_per_console_loglevel`` on the kernel command line or set in printk
+  parameters: Ignore all per-console loglevels and use the global loglevel.
+
+The default value for ``kernel.console_loglevel`` comes from
+``CONFIG_CONSOLE_LOGLEVEL_DEFAULT``, or ``CONFIG_CONSOLE_LOGLEVEL_QUIET`` if
+``quiet`` is passed on the kernel command line.
+
+Console attributes
+~~~~~~~~~~~~~~~~~~
+
+Registered consoles are exposed at ``/sys/class/console``. For example, if you
+are using ``ttyS0``, the console backing it can be viewed at
+``/sys/class/console/ttyS0/``. The following files are available:
+
+* ``effective_loglevel`` (r): The effective loglevel after considering all
+  loglevel authorities. For example, it shows the value of the console-specific
+  loglevel when a console-specific loglevel is defined, and shows the global
+  console loglevel value when the console-specific one is not defined.
+
+* ``effective_loglevel_source`` (r): The loglevel authority which resulted in
+  the effective loglevel being set. The following values can be present:
+
+    * ``local``: The console-specific loglevel is in effect.
+
+    * ``global``: The global loglevel (``kernel.console_loglevel``) is in
+      effect. Set a console-specific loglevel to override it.
+
+    * ``ignore_loglevel``: ``ignore_loglevel`` was specified on the kernel
+      command line or at ``/sys/module/printk/parameters/ignore_loglevel``.
+      Disable it to use level controls.
+
+* ``loglevel`` (rw): The local, console-specific loglevel for this console.
+  This will be in effect if no other global control overrides it. Look at
+  ``effective_loglevel`` and ``effective_loglevel_source`` to verify that.
+
+Examples
+--------
+
+Setting per-console loglevel at runtime
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set serial console to only show warnings and above (level 4)::
+
+    echo 5 > /sys/class/console/ttyS0/loglevel
+
+Set netconsole to show info and above (level 6)::
+
+    echo 7 > /sys/class/console/netcon0/loglevel
+
+Reset a console to use the global loglevel::
+
+    echo -1 > /sys/class/console/ttyS0/loglevel
+
+Checking effective loglevel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Check what loglevel is actually in effect for a console::
+
+    $ cat /sys/class/console/ttyS0/effective_loglevel
+    4
+    $ cat /sys/class/console/ttyS0/effective_loglevel_source
+    local
+
+If the source shows ``global``, the console is using the global loglevel.
+If it shows ``local``, the console is using its per-console loglevel.
+If it shows ``ignore_loglevel``, all loglevel controls are being ignored.
+
+Boot-time configuration
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set different loglevels for different consoles at boot::
+
+    console=ttyS0,115200n8,loglevel:3 console=tty0,loglevel:5
+
+This sets the serial console (ttyS0) to level 3 (KERN_ERR) and the VGA
+console (tty0) to level 5 (KERN_NOTICE).
+
+For netconsole::
+
+    netconsole=@/,@192.168.1.1/ console=netcon0,loglevel:6
+
+Common use case - high performance with serial fallback
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A common configuration is to set netconsole to a verbose level for normal
+debugging, while keeping the serial console quiet to avoid performance impact,
+but still available for emergencies::
+
+    # Netconsole gets INFO and above (verbose)
+    echo 7 > /sys/class/console/netcon0/loglevel
+
+    # Serial console gets only WARN and above (quiet, for emergencies)
+    echo 5 > /sys/class/console/ttyS0/loglevel
+
+This allows you to see informational messages on the fast netconsole without
+the latency impact of writing them to the slow serial port.
+
+Performance Impact
+------------------
+
+Kernel messages used to be flushed to the consoles immediately even from a
+context where the scheduling is not possible. It increases a chance to see the
+messages even when the system is in a bad state. But it might cause significant
+application-level stalls (e.g., during network debugging or block I/O tracing).
+Note that serial console writes can take tens of milliseconds per message.
+
+The console drivers are being converted to nbcon API (the letter 'N'
+in /proc/consoles output). These drivers write the messages in a dedicated
+kthreads when the system is working properly. It reduces the risk of stalls. But
+the messages are still flushed immediately when the system detects an emergency
+situation, for example Oops, stall, or a warning. Also the messages can get lost
+when the ring buffer is full and the console driver is far behind with flushing.
+
+For example, setting a serial console to WARN level (4) while keeping
+netconsole at INFO level (6) prevents INFO and NOTICE messages from being
+written to the slow serial port. It reduces the risk of application stalls or
+message loses during verbose logging periods.
+
+Troubleshooting
+---------------
+
+Messages not appearing on console despite setting loglevel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Check effective loglevel source::
+
+       cat /sys/class/console/<name>/effective_loglevel_source
+
+   If it shows ``ignore_loglevel``, you have the ``printk.ignore_loglevel``
+   kernel parameter set, which overrides all level controls. Remove it from
+   your kernel command line or set it to N in sysfs::
+
+       echo N > /sys/module/printk/parameters/ignore_loglevel
+
+2. Check if per-console loglevels are being ignored::
+
+       cat /sys/module/printk/parameters/ignore_per_console_loglevel
+
+   If it shows ``Y``, per-console settings are disabled. Set it to N::
+
+       echo N > /sys/module/printk/parameters/ignore_per_console_loglevel
+
+3. Verify the message priority is high enough::
+
+       cat /sys/class/console/<name>/effective_loglevel
+
+   Messages must have priority less than this value to appear. For example,
+   if effective_loglevel is 4, only messages with priority 0-3 (EMERG, ALERT,
+   CRIT, ERR) will be printed. If you want to see WARN messages (priority 4),
+   you need to increase the effective_loglevel to at least 5.
+
+Cannot set loglevel to 0
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Per-console loglevels cannot be set to 0 (KERN_EMERG). This is by design, as
+level 0 is reserved for the most critical system messages that should always
+go to all consoles. To use the global loglevel, set the per-console loglevel
+to -1::
+
+    echo -1 > /sys/class/console/<name>/loglevel
+
+Edge cases
+~~~~~~~~~~
+
+**Setting all consoles to high loglevels**: If you set all consoles to
+very high loglevels (e.g., 1 or 2), most messages won't appear on any
+console. They remain accessible to userspace via ``dmesg`` or ``syslogd``,
+but keep at least one console at a reasonable level for monitoring.
+
+**Console unregistration while sysfs file is open**: If a console is
+unregistered (e.g., module unloaded) while you have its sysfs files open,
+the files will become stale. Close and reopen them, or they will eventually
+return errors.
+
+**Global loglevel changes**: If you change the global console_loglevel
+via sysctl, consoles set to -1 (use global) will immediately reflect the
+new level. Consoles with explicit per-console levels are unaffected.
+
+Deprecated
+~~~~~~~~~~
+
+* ``kernel.printk`` sysctl: this takes four values, setting
+  ``kernel.console_loglevel``, ``kernel.default_message_loglevel``, the minimum
+  console loglevel, and a fourth unused value. The interface is generally
+  considered to be quite confusing, doesn't perform checks on the values given,
+  and is unaware of per-console loglevel semantics.
+
+Chris Down <chris@chrisdown.name>, 18-November-2025
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e6faa647b43..9a509a0bc65a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20506,6 +20506,7 @@ R:	Sergey Senozhatsky <senozhatsky@chromium.org>
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
 F:	Documentation/ABI/testing/sysfs-class-console
+F:	Documentation/admin-guide/per-console-loglevel.rst
 F:	Documentation/core-api/printk-basics.rst
 F:	include/linux/printk.h
 F:	kernel/printk/
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (18 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 15:51   ` Petr Mladek
  2025-11-27 19:44 ` [PATCH v8 21/21] printk: Purge default_console_loglevel Chris Down
  2025-12-12 16:11 ` [PATCH v8 00/21] printk: console: Per-console loglevels Petr Mladek
  21 siblings, 1 reply; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

The kernel.printk sysctl interface is deprecated in favour of more
granular and clearer sysctl interfaces for controlling loglevels, namely
kernel.console_loglevel and kernel.default_message_loglevel.

kernel.printk has a number of fairly significant usability problems:

- It takes four values in a specific order, which is not intuitive.
  Speaking from personal experience, even people working on printk
  sometimes need to look up the order of these values, which doesn't
  suggest much in the way of perspicuity.
- There is no validation on the input values, so users can set them to
  invalid or nonsensical values without receiving any errors or
  warnings. This can lead to unpredictable behaviour.
- One of the four values, default_console_loglevel, is not used in the
  kernel (see below), making it redundant and potentially confusing.
- Overall, the interface is complex, hard to understand, and combines
  multiple controls into a single sysctl, which is not ideal. It should
  be separated into distinct controls for clarity.

Setting kernel.printk now calls printk_sysctl_deprecated, which emits a
pr_warn. The warning informs users about the deprecation and suggests
using the new sysctl interfaces instead.

By deprecating kernel.printk, we aim to:

- Encourage users to adopt the new, dedicated sysctl interfaces
  (kernel.console_loglevel and kernel.default_message_loglevel), which
  are more straightforward and easier to understand.
- Improve input validation and error handling, ensuring that users
  receive appropriate feedback when setting invalid values.
- Simplify the configuration of loglevels by exposing only the controls
  that are necessary and relevant.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/admin-guide/sysctl/kernel.rst |  3 +++
 kernel/printk/sysctl.c                      | 14 +++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index 043d5f663b7d..5ac6db03c2fb 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -1096,6 +1096,9 @@ Messages without an explicit priority will be printed with this priority.
 printk
 ======
 
+This sysctl is deprecated and will be removed in future. Please consider using
+``kernel.console_loglevel`` or ``kernel.default_message_loglevel`` instead.
+
 The four values in printk denote: ``console_loglevel``,
 ``default_message_loglevel``, ``minimum_console_loglevel`` and
 ``default_console_loglevel`` respectively.
diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
index 034739939a61..8df4500bf3ff 100644
--- a/kernel/printk/sysctl.c
+++ b/kernel/printk/sysctl.c
@@ -7,6 +7,7 @@
 #include <linux/printk.h>
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
+#include <linux/console.h>
 #include "internal.h"
 
 static const int ten_thousand = 10000;
@@ -67,13 +68,24 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
 			       do_proc_dointvec_console_loglevel, NULL);
 }
 
+static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
+					   void *buffer, size_t *lenp, loff_t *ppos)
+{
+	int res = proc_dointvec(table, write, buffer, lenp, ppos);
+
+	if (write)
+		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
+
+	return res;
+}
+
 static const struct ctl_table printk_sysctls[] = {
 	{
 		.procname	= "printk",
 		.data		= &console_loglevel,
 		.maxlen		= 4*sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_printk_deprecated,
 	},
 	{
 		.procname	= "printk_ratelimit",
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v8 21/21] printk: Purge default_console_loglevel
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (19 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface Chris Down
@ 2025-11-27 19:44 ` Chris Down
  2025-12-12 16:11 ` [PATCH v8 00/21] printk: console: Per-console loglevels Petr Mladek
  21 siblings, 0 replies; 42+ messages in thread
From: Chris Down @ 2025-11-27 19:44 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

default_console_loglevel (then DEFAULT_LOGLEVEL) was created in Linux
0.99.13 (September 1993) to power what we now call
SYSLOG_ACTION_CONSOLE_{ON,OFF}. It was originally hardcoded to 7.

In Linux 2.3.12 (March 1997), Chris Horn made it configurable by sysctl
through kernel.printk.

Its demise came about in July 2009 in commit 1aaad49e856c ("printk:
Restore previous console_loglevel when re-enabling logging"), which
replaces default_console_loglevel with the previously used
console_loglevel. However, the documentation was never updated, and we
still kept on telling users that this sets the default value for
console_loglevel, even though this hasn't been true for over 15 years.

Purge both the documentation and all remaining references to
default_console_loglevel. It will still be initialised in the sysctl
array.

Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Chris Down <chris@chrisdown.name>
---
 Documentation/admin-guide/sysctl/kernel.rst | 5 ++---
 include/linux/printk.h                      | 1 -
 kernel/printk/printk.c                      | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index 5ac6db03c2fb..37f2f417eaf7 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -1100,8 +1100,8 @@ This sysctl is deprecated and will be removed in future. Please consider using
 ``kernel.console_loglevel`` or ``kernel.default_message_loglevel`` instead.
 
 The four values in printk denote: ``console_loglevel``,
-``default_message_loglevel``, ``minimum_console_loglevel`` and
-``default_console_loglevel`` respectively.
+``default_message_loglevel``, ``minimum_console_loglevel`` and an unused legacy
+value respectively.
 
 These values influence printk() behavior when printing or
 logging error messages.
@@ -1113,7 +1113,6 @@ default_message_loglevel messages without an explicit priority
                          will be printed with this priority
 minimum_console_loglevel minimum (highest) value to which
                          console_loglevel can be set
-default_console_loglevel default value for console_loglevel
 ======================== =====================================
 
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 5a8c4aca729f..fe16ec6c5af1 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -72,7 +72,6 @@ extern int console_printk[];
 #define console_loglevel (console_printk[0])
 #define default_message_loglevel (console_printk[1])
 #define minimum_console_loglevel (console_printk[2])
-#define default_console_loglevel (console_printk[3])
 
 extern bool ignore_per_console_loglevel;
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index cb796af0b867..d7c9a2effeb3 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -67,7 +67,7 @@ int console_printk[4] = {
 	CONSOLE_LOGLEVEL_DEFAULT,	/* console_loglevel */
 	MESSAGE_LOGLEVEL_DEFAULT,	/* default_message_loglevel */
 	CONSOLE_LOGLEVEL_MIN,		/* minimum_console_loglevel */
-	CONSOLE_LOGLEVEL_DEFAULT,	/* default_console_loglevel */
+	/* legacy default console loglevel, unused */
 };
 EXPORT_SYMBOL_GPL(console_printk);
 
-- 
2.51.2


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression
  2025-11-27 19:43 ` [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression Chris Down
@ 2025-12-09 16:40   ` Petr Mladek
  2025-12-11 14:49     ` Petr Mladek
  0 siblings, 1 reply; 42+ messages in thread
From: Petr Mladek @ 2025-12-09 16:40 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:43:12, Chris Down wrote:
> When printk_delay() is called from vprintk_emit(), the level argument
> may be LOGLEVEL_DEFAULT (-1) if the loglevel was not explicitly provided
> by the caller.
> 
> If printk_delay() relies on comparing level against the console loglevel
> (e.g. for suppression), receiving -1 results in incorrect behaviour
> because -1 is treated as a high priority (so not suppressed), causing
> unnecessary delays for default-level messages.

Great catch!

> Parse the format string prefix to resolve the actual loglevel before
> passing it to printk_delay().
> 
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2179,6 +2179,32 @@ u16 printk_parse_prefix(const char *text, int *level,
>  	return prefix_len;
>  }
>  
> +/**
> + * printk_resolve_loglevel - Resolve the effective loglevel for a message
> + *
> + * @facility:	The log facility (0 for kernel messages)
> + * @level:	The initial loglevel, may be LOGLEVEL_DEFAULT
> + * @fmt:	The format string, potentially containing a loglevel prefix
> + *
> + * Determines the actual loglevel to use for a printk message. If the level
> + * is LOGLEVEL_DEFAULT and the facility indicates a kernel message, parses
> + * the format string prefix to extract an embedded loglevel. If no loglevel
> + * is found, falls back to the default_message_loglevel.
> + *
> + * Return: The resolved loglevel value
> + */
> +static inline int printk_resolve_loglevel(int facility, int level,
> +					  const char *fmt)
> +{
> +	if (facility == 0 && level == LOGLEVEL_DEFAULT && fmt)
> +		printk_parse_prefix(fmt, &level, NULL);
> +
> +	if (level == LOGLEVEL_DEFAULT)
> +		level = default_message_loglevel;

This is not ideal:

 1. It more or less duplicates the code from vprintk_store().

 2. It does not handle loglevel passed via parameter, for example, see
    _btrfs_printk() which calls _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf).
    Note that vprintk_store() calls vsnprintf() before checking the loglevel.

> +	return level;
> +}

Alternative solutions:

  A. We might call vsnprintf() one more times here.

     It is ugly but we could do it only when anyone wants a delay.
     Also this is not easy because we would need to check printk_delay_msec,
     boot_delay, and system_state.

     Anyway, this solution would need some refactoring in printk_delay()
     and vprintk_store() to avoid code duplication.


  B. We could move printk_delay().

     It should be called before storing the message. Otherwise, we
     would need to call it from various console flush calls. And there
     are many flush paths. Also the message might get lost when
     consoles fall far behind.

     I though about moving printk_delay() into vprintk_store(). But
     we would need to temporary release IRQs disabled by
     printk_enter_irqsave(recursion_ptr, irqflags). But then the
     process might get migrated to another CPU. And the message
     generated by printk_sprint() need not fit into the reserved space.


I personally prefer the alternative solution A. But I am not sure if
it is worth it.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT
  2025-11-27 19:43 ` [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT Chris Down
@ 2025-12-10 14:38   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-10 14:38 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:43:21, Chris Down wrote:
> ACPI firmware routinely calls add_preferred_console() via
> acpi_parse_spcr() before we ever look at the kernel command line. After
> that first registration we short-circuit on every duplicate name/index
> match, so the subsequent console=ttyS0,... parameter never refreshes the
> UART options that the firmware supplied.
> 
> Historically that just meant you couldn't tweak baud/flow control for a
> firmware-provided serial console unless you picked a different device
> name, but the per-console loglevel plumbing in this series relies on
> those later console= entries being able to update the stored option
> string. Without that, console=ttyS0,loglevel:5 simply never takes effect
> on machines that get their console from SPCR/DT.
> 
> Teach __add_preferred_console() to update the existing slot when the
> same console is mentioned again: we keep the original slot, but replace
> its option string (and re-run braille option parsing) so that later
> callers can override what firmware seeded. This keeps today's behaviour
> unchanged for drivers, while allowing the cmdline UART parameters (and
> soon the loglevel hints) to override the ACPI defaults.

Another great catch!

> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2560,7 +2560,12 @@ static int __add_preferred_console(const char *name, const short idx,
>  		    (devname && strcmp(c->devname, devname) == 0)) {


__add_preferred_console() can be called also after processing the
command line, for example via the device tree:

  + serial8250_init()
    + serial8250_register_ports()
      + uart_add_one_port()
        + serial_ctrl_register_port()
	  + serial_core_register_port()
	    + serial_core_add_one_port()
	      + of_console_check()
	        + add_preferred_console

Or a platform default:

  + hvc_rtas_console_init()
    + add_preferred_console()

I would rather make sure that we update the values only when the
console is defined on the command line:

			/*
			 * Make sure that only command line is allowed
			 * to modify the default preference and options.
			 */
			if (!user_specified)
				return 0;

It probably won't have any effect. For example, of_console_check()
calls add_preferred_console() only when (!console_set_on_cmdline).
And hvc_rtas_console_init() does not pass any @options.

But I would rather be on the safe side and make the logic explicit here.

>  			if (!brl_options)
>  				preferred_console = i;
> +
> +			if (options)
> +				c->options = options;
> +
>  			set_user_specified(c, user_specified);
> +			braille_set_options(c, brl_options);
>  			return 0;
>  		}
>  	}

Otherwise, it looks good to me.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers
  2025-11-27 19:43 ` [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers Chris Down
@ 2025-12-10 15:12   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-10 15:12 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:43:32, Chris Down wrote:
> The nbcon atomic flush path in __nbcon_atomic_flush_pending_con() calls
> nbcon_emit_next_record(), which uses console_srcu_read_flags() to read
> the console flags. console_srcu_read_flags() expects to be called under
> console_srcu_read_lock(), but the atomic flush path does not hold this
> lock.

__nbcon_atomic_flush_pending_con() seems to be called in the following
code paths:

  + __nbcon_atomic_flush_pending()
    + nbcon_atomic_flush_pending_con()
      + __nbcon_atomic_flush_pending_con()

 + nbcon_device_release()
   + __nbcon_atomic_flush_pending_con()

 + kdb_msg_write()		# new in 6.19-rc1
   + nbcon_kdb_release()
     + __nbcon_atomic_flush_pending_con()

And all three callers take console_srcu_read_lock() because
they need it for other reasons. So, we should be on the safe
side and do not need this change.

Or do I miss some code path, please?

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU
  2025-11-27 19:43 ` [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU Chris Down
@ 2025-12-11 14:37   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-11 14:37 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:43:42, Chris Down wrote:
> As part of the per-console loglevel implementation, printk_delay()
> introduces a call to suppress_message_printing_everywhere() within
> printk_delay(). This check acquires the console SRCU lock and iterates
> through all registered consoles to determine if the message implies a
> delay based on per-console loglevels.
> 
> Since printk_delay() is called in the hotpath of vprintk_emit(), this
> introduces measurable overhead (locking and pointer chasing) for every
> printk message, even on systems where no delay is configured.
> 
> Optimise this by short-circuiting the function. If neither a boot delay
> nor a runtime printk_delay_msec is configured, return immediately. This
> avoids the expensive console list iteration in the common case where
> delays are disabled.
> 
> Signed-off-by: Chris Down <chris@chrisdown.name>
> ---
>  kernel/printk/printk.c | 25 ++++++++++++++++++-------
>  1 file changed, 18 insertions(+), 7 deletions(-)
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 0d7f3dac8177..13e17d892ec9 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2233,20 +2233,31 @@ int printk_delay_msec __read_mostly;
>  
>  static inline void printk_delay(int level)
>  {
> +	bool boot_delay_active = false;
> +	int m;
> +
> +#ifdef CONFIG_BOOT_PRINTK_DELAY
> +	boot_delay_active = boot_delay && system_state < SYSTEM_RUNNING;
> +#endif

The same code is used also in boot_delay_msec(). It can be removed
there. But still, it would be better to create a helper function
and avoid the #ifdef in the middle of the function.

> +	if (!boot_delay_active && !READ_ONCE(printk_delay_msec))

There is another READ_ONCE(printk_delay_msec) below. It would
be better to read the value at the beginning of the function
and use it everywhere.

> +		return;
> +
>  	/* If the message is forced (e.g. panic), we must delay */
>  	if (!is_printk_force_console() &&
>  	    suppress_message_printing_everywhere(level))
>  		return;
>  
> -	boot_delay_msec();
> +	if (boot_delay_active)
> +		boot_delay_msec();
>  
> -	if (unlikely(printk_delay_msec)) {
> -		int m = printk_delay_msec;
> +	m = READ_ONCE(printk_delay_msec);
> +	if (!m)
> +		return;
>  
> -		while (m--) {
> -			mdelay(1);
> -			touch_nmi_watchdog();
> -		}
> +	while (m--) {
> +		mdelay(1);
> +		touch_nmi_watchdog();
>  	}
>  }

I played with the code. I am going to send my variant as a reply to
the 1st patch where I proposed 2 alternative solutions, see
https://lore.kernel.org/all/aThQ5mZNIijc1G94@pathway

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression
  2025-12-09 16:40   ` Petr Mladek
@ 2025-12-11 14:49     ` Petr Mladek
  2025-12-11 15:28       ` Petr Mladek
  0 siblings, 1 reply; 42+ messages in thread
From: Petr Mladek @ 2025-12-11 14:49 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Tue 2025-12-09 17:40:11, Petr Mladek wrote:
> On Fri 2025-11-28 03:43:12, Chris Down wrote:
> > When printk_delay() is called from vprintk_emit(), the level argument
> > may be LOGLEVEL_DEFAULT (-1) if the loglevel was not explicitly provided
> > by the caller.
> > 
> > If printk_delay() relies on comparing level against the console loglevel
> > (e.g. for suppression), receiving -1 results in incorrect behaviour
> > because -1 is treated as a high priority (so not suppressed), causing
> > unnecessary delays for default-level messages.
> 
> Great catch!
> 
> > Parse the format string prefix to resolve the actual loglevel before
> > passing it to printk_delay().
> > 
> > --- a/kernel/printk/printk.c
> > +++ b/kernel/printk/printk.c
> > @@ -2179,6 +2179,32 @@ u16 printk_parse_prefix(const char *text, int *level,
> >  	return prefix_len;
> >  }
> >  
> > +/**
> > + * printk_resolve_loglevel - Resolve the effective loglevel for a message
> > + *
> > + * @facility:	The log facility (0 for kernel messages)
> > + * @level:	The initial loglevel, may be LOGLEVEL_DEFAULT
> > + * @fmt:	The format string, potentially containing a loglevel prefix
> > + *
> > + * Determines the actual loglevel to use for a printk message. If the level
> > + * is LOGLEVEL_DEFAULT and the facility indicates a kernel message, parses
> > + * the format string prefix to extract an embedded loglevel. If no loglevel
> > + * is found, falls back to the default_message_loglevel.
> > + *
> > + * Return: The resolved loglevel value
> > + */
> > +static inline int printk_resolve_loglevel(int facility, int level,
> > +					  const char *fmt)
> > +{
> > +	if (facility == 0 && level == LOGLEVEL_DEFAULT && fmt)
> > +		printk_parse_prefix(fmt, &level, NULL);
> > +
> > +	if (level == LOGLEVEL_DEFAULT)
> > +		level = default_message_loglevel;
> 
> This is not ideal:
> 
>  1. It more or less duplicates the code from vprintk_store().
> 
>  2. It does not handle loglevel passed via parameter, for example, see
>     _btrfs_printk() which calls _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf).
>     Note that vprintk_store() calls vsnprintf() before checking the loglevel.
> 
> > +	return level;
> > +}
> 
> Alternative solutions:
> 
>   A. We might call vsnprintf() one more times here.
> 
>      It is ugly but we could do it only when anyone wants a delay.
>      Also this is not easy because we would need to check printk_delay_msec,
>      boot_delay, and system_state.
> 
>      Anyway, this solution would need some refactoring in printk_delay()
>      and vprintk_store() to avoid code duplication.

Even more duplicated code was added by later patches.

I tried to implement this alternative solution and remove all code
duplication. But I think that this is a wrong way after all,
see the patch below for more details.

>   B. We could move printk_delay().
> 
>      It should be called before storing the message. Otherwise, we
>      would need to call it from various console flush calls. And there
>      are many flush paths. Also the message might get lost when
>      consoles fall far behind.
> 
>      I though about moving printk_delay() into vprintk_store(). But
>      we would need to temporary release IRQs disabled by
>      printk_enter_irqsave(recursion_ptr, irqflags). But then the
>      process might get migrated to another CPU. And the message
>      generated by printk_sprint() need not fit into the reserved space.
> 
> I personally prefer the alternative solution A. But I am not sure if
> it is worth it.

I have changed my mind. I think that B is a better way. I am going
to explain it in a separate reply.

Here is the patch implementing variant A. It can be applied on top of
this patchset:

From 5bb33b699fc1668920f1418978589b4a2c2d151f Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Thu, 11 Dec 2025 13:27:32 +0100
Subject: [POC] printk: Remove code duplication in printk_delay() and
 properly resolve loglevel

This is an attempt to clean up several changes related to printk_delay()
done by this patchset:

  + Remove various code duplication.
  + Use only one READ_ONCE().
  + Properly resolve the loglevel even when passed via parameter.

Namely, it does:

  + Replace boot_delay_active local value with helper function.
  + Read printk_delay_msec only once and use the same variable everywhere.
  + Move code which resolves the loglevel into vprintk_analyze()
    helper function and use it in both printk_delay() and vprintk_store().
  + Remove obsolete printk_resolve_loglevel().

But the solution is not good:

  + It adds a lot of code complexity and one more vscnprintf() is needed.

  + One more vscnprintf() call is needed.

  + It still does not work properly. For example, backtraces from
    all CPUs (SysRq l) prints the entire backtrace at once because
    the console flush is delayed. The same problem will happen for
    any delayed messages, e.g. during early boot before the 1st console
    is registered.

A better solution would be to call printk_delay() in the console code
path.

Signed-off-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 118 +++++++++++++++++++++++------------------
 1 file changed, 67 insertions(+), 51 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8af5b1b0023b..ff9c8bd483bc 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1463,14 +1463,16 @@ static int __init boot_delay_setup(char *str)
 }
 early_param("boot_delay", boot_delay_setup);
 
+static bool boot_delay_active(void)
+{
+	return (boot_delay && system_state < SYSTEM_RUNNING);
+}
+
 static void boot_delay_msec(void)
 {
 	unsigned long long k;
 	unsigned long timeout;
 
-	if (boot_delay == 0 || system_state >= SYSTEM_RUNNING)
-		return;
-
 	k = (unsigned long long)loops_per_msec * boot_delay;
 
 	timeout = jiffies + msecs_to_jiffies(boot_delay);
@@ -1488,6 +1490,10 @@ static void boot_delay_msec(void)
 	}
 }
 #else
+static bool boot_delay_active(void)
+{
+	return false;
+}
 static inline void boot_delay_msec(void)
 {
 }
@@ -2309,31 +2315,37 @@ static u8 *__printk_recursion_counter(void)
 
 int printk_delay_msec __read_mostly;
 
-static inline void printk_delay(int level)
+__printf(5, 0)
+void vprintk_analyze(int facility, u16 *size, int *level,
+		     enum printk_info_flags *flags,
+		     const char *fmt, va_list args);
+
+static inline void printk_delay(int facility, int level,
+				const char *fmt, va_list args)
 {
-	bool boot_delay_active = false;
-	int m;
+	int delay;
 
-#ifdef CONFIG_BOOT_PRINTK_DELAY
-	boot_delay_active = boot_delay && system_state < SYSTEM_RUNNING;
-#endif
+	/* Prevent re-reading (optimization) in the loop decrementing it. */
+	delay = READ_ONCE(printk_delay_msec);
 
-	if (!boot_delay_active && !READ_ONCE(printk_delay_msec))
+	if (!boot_delay_active() && !delay)
 		return;
 
+	/* Format the message and resolve the effective message level. */
+	vprintk_analyze(facility, NULL, &level, NULL, fmt, args);
+
 	/* If the message is forced (e.g. panic), we must delay */
 	if (!is_printk_force_console() &&
 	    suppress_message_printing_everywhere(level))
 		return;
 
-	if (boot_delay_active)
+	if (boot_delay_active())
 		boot_delay_msec();
 
-	m = READ_ONCE(printk_delay_msec);
-	if (!m)
+	if (!delay)
 		return;
 
-	while (m--) {
+	while (delay--) {
 		mdelay(1);
 		touch_nmi_watchdog();
 	}
@@ -2391,29 +2403,50 @@ u16 printk_parse_prefix(const char *text, int *level,
 }
 
 /**
- * printk_resolve_loglevel - Resolve the effective loglevel for a message
+ * vprintk_analyze - Analyze the formatted message and return its size,
+ *		     loglevel, and flags.
  *
- * @facility:	The log facility (0 for kernel messages)
- * @level:	The initial loglevel, may be LOGLEVEL_DEFAULT
- * @fmt:	The format string, potentially containing a loglevel prefix
+ * @facility:	Log facility (0 for kernel messages) (input)
+ * @size:	Size of the formatted message, including the trailing '\0'
+ *		(output, optional)
+ * @level:	Initial loglevel, may be LOGLEVEL_DEFAULT. It will get updated
+ *		by the message prefix and system defaults.
+ *		(input/output, required)
+ * @flags:	Internal flags are updated by analyzing the message prefix,
+ *		namely LOG_CONT. (input/output, optional)
+ * @fmt:	Format string, potentially containing a loglevel prefix (input)
+ * @args:	Arguments for the format string. (input)
  *
- * Determines the actual loglevel to use for a printk message. If the level
- * is LOGLEVEL_DEFAULT and the facility indicates a kernel message, parses
- * the format string prefix to extract an embedded loglevel. If no loglevel
- * is found, falls back to the default_message_loglevel.
- *
- * Return: The resolved loglevel value
+ * Format the message. Return its size. Update @level, and @flags by analyzing
+ * the message prefix.
  */
-static inline int printk_resolve_loglevel(int facility, int level,
-					  const char *fmt)
+__printf(5, 0)
+void vprintk_analyze(int facility, u16 *size, int *level,
+		     enum printk_info_flags *flags,
+		     const char *fmt, va_list args)
 {
-	if (facility == 0 && level == LOGLEVEL_DEFAULT && fmt)
-		printk_parse_prefix(fmt, &level, NULL);
+	char prefix_buf[8];
+	va_list args2;
+	int len;
 
-	if (level == LOGLEVEL_DEFAULT)
-		level = default_message_loglevel;
+	if (WARN_ON_ONCE(!level))
+		return;
 
-	return level;
+	/* The syslog prefix might be passed in as a parameter. */
+	va_copy(args2, args);
+	len = vsnprintf(&prefix_buf[0], sizeof(prefix_buf), fmt, args2);
+	va_end(args2);
+
+	/* The trailing '\0' is not counted by vsnprintf(). */
+	if (size)
+		*size = len + 1;
+
+	/* Extract log level or control flags. */
+	if (facility == 0)
+		printk_parse_prefix(&prefix_buf[0], level, flags);
+
+	if (*level == LOGLEVEL_DEFAULT)
+		*level = default_message_loglevel;
 }
 
 __printf(5, 0)
@@ -2452,15 +2485,13 @@ int vprintk_store(int facility, int level,
 		  const struct dev_printk_info *dev_info,
 		  const char *fmt, va_list args)
 {
-	struct prb_reserved_entry e;
 	enum printk_info_flags flags = 0;
+	struct prb_reserved_entry e;
 	struct printk_record r;
 	unsigned long irqflags;
 	u16 trunc_msg_len = 0;
-	char prefix_buf[8];
 	u8 *recursion_ptr;
 	u16 reserve_size;
-	va_list args2;
 	u32 caller_id;
 	u16 text_len;
 	int ret = 0;
@@ -2479,26 +2510,11 @@ int vprintk_store(int facility, int level,
 
 	caller_id = printk_caller_id();
 
-	/*
-	 * The sprintf needs to come first since the syslog prefix might be
-	 * passed in as a parameter. An extra byte must be reserved so that
-	 * later the vscnprintf() into the reserved buffer has room for the
-	 * terminating '\0', which is not counted by vsnprintf().
-	 */
-	va_copy(args2, args);
-	reserve_size = vsnprintf(&prefix_buf[0], sizeof(prefix_buf), fmt, args2) + 1;
-	va_end(args2);
+	vprintk_analyze(facility, &reserve_size, &level, &flags, fmt, args);
 
 	if (reserve_size > PRINTKRB_RECORD_MAX)
 		reserve_size = PRINTKRB_RECORD_MAX;
 
-	/* Extract log level or control flags. */
-	if (facility == 0)
-		printk_parse_prefix(&prefix_buf[0], &level, &flags);
-
-	if (level == LOGLEVEL_DEFAULT)
-		level = default_message_loglevel;
-
 	if (dev_info)
 		flags |= LOG_NEWLINE;
 
@@ -2631,7 +2647,7 @@ asmlinkage int vprintk_emit(int facility, int level,
 		ft.legacy_direct = false;
 	}
 
-	printk_delay(printk_resolve_loglevel(facility, level, fmt));
+	printk_delay(facility, level, fmt, args);
 
 	printed_len = vprintk_store(facility, level, dev_info, fmt, args);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression
  2025-12-11 14:49     ` Petr Mladek
@ 2025-12-11 15:28       ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-11 15:28 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Thu 2025-12-11 15:49:54, Petr Mladek wrote:
> On Tue 2025-12-09 17:40:11, Petr Mladek wrote:
> > On Fri 2025-11-28 03:43:12, Chris Down wrote:
> > > When printk_delay() is called from vprintk_emit(), the level argument
> > > may be LOGLEVEL_DEFAULT (-1) if the loglevel was not explicitly provided
> > > by the caller.
> > > 
> > > If printk_delay() relies on comparing level against the console loglevel
> > > (e.g. for suppression), receiving -1 results in incorrect behaviour
> > > because -1 is treated as a high priority (so not suppressed), causing
> > > unnecessary delays for default-level messages.
> > 
> > Great catch!
> > 
> > > Parse the format string prefix to resolve the actual loglevel before
> > > passing it to printk_delay().
> > > 
> > > --- a/kernel/printk/printk.c
> > > +++ b/kernel/printk/printk.c
> > > @@ -2179,6 +2179,32 @@ u16 printk_parse_prefix(const char *text, int *level,
> > >  	return prefix_len;
> > >  }
> > >  
> > > +/**
> > > + * printk_resolve_loglevel - Resolve the effective loglevel for a message
> > > + *
> > > + * @facility:	The log facility (0 for kernel messages)
> > > + * @level:	The initial loglevel, may be LOGLEVEL_DEFAULT
> > > + * @fmt:	The format string, potentially containing a loglevel prefix
> > > + *
> > > + * Determines the actual loglevel to use for a printk message. If the level
> > > + * is LOGLEVEL_DEFAULT and the facility indicates a kernel message, parses
> > > + * the format string prefix to extract an embedded loglevel. If no loglevel
> > > + * is found, falls back to the default_message_loglevel.
> > > + *
> > > + * Return: The resolved loglevel value
> > > + */
> > > +static inline int printk_resolve_loglevel(int facility, int level,
> > > +					  const char *fmt)
> > > +{
> > > +	if (facility == 0 && level == LOGLEVEL_DEFAULT && fmt)
> > > +		printk_parse_prefix(fmt, &level, NULL);
> > > +
> > > +	if (level == LOGLEVEL_DEFAULT)
> > > +		level = default_message_loglevel;
> > 
> > This is not ideal:
> > 
> >  1. It more or less duplicates the code from vprintk_store().
> > 
> >  2. It does not handle loglevel passed via parameter, for example, see
> >     _btrfs_printk() which calls _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf).
> >     Note that vprintk_store() calls vsnprintf() before checking the loglevel.
> > 
> > > +	return level;
> > > +}
> > 
> > Alternative solutions:
> > 
> >   A. We might call vsnprintf() one more times here.
> > 
> >      It is ugly but we could do it only when anyone wants a delay.
> >      Also this is not easy because we would need to check printk_delay_msec,
> >      boot_delay, and system_state.
> > 
> >      Anyway, this solution would need some refactoring in printk_delay()
> >      and vprintk_store() to avoid code duplication.
> 
> Even more duplicated code was added by later patches.
> 
> I tried to implement this alternative solution and remove all code
> duplication. But I think that this is a wrong way after all:

The solution is not good:

  + It adds a lot of code complexity and one more vscnprintf() is needed.

  + One more vscnprintf() call is needed.

  + It still does not work properly. For example, backtraces from
    all CPUs (SysRq l) prints the entire backtrace at once because
    the console flush is delayed. The same problem will happen for
    any delayed messages, e.g. during early boot before the 1st console
    is registered.

 >   B. We could move printk_delay().
> > 
> >      It should be called before storing the message. Otherwise, we
> >      would need to call it from various console flush calls. And there
> >      are many flush paths. Also the message might get lost when
> >      consoles fall far behind.

I looked at this variant and I think that it might be much better
after all. IMHO, it should be enough to move printk_delay() from
vprintk_emit() to:

   + console_flush_one_record()
   + nbcon_emit_one()

Note that it is possible only in 6.19. It includes some refactoring
which allows to release locks between each record in both legacy
and nbcon code paths. One piece is still missing, see
https://lore.kernel.org/r/20251202135832.156559-1-pmladek@suse.com

I would suggest to solve this separately. The printk_delay() never
worked correctly. And it seems to be a more complex problem.

I mean. Let's keep this patchset only for adding per-console loglevels.
Do only the bare minimum (like in v7) and remove the rather complex
improvements added in v8.

Or we could move the printk_delay to console emit code paths first.
And rebase the per-console patchset on top of it.

Sigh, I do not want to block the per-console patchset once again.
But the printk_delay()-related changes in v8 are too hacky my taste.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels
  2025-11-27 19:44 ` [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels Chris Down
@ 2025-12-12 14:04   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 14:04 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:44:06, Chris Down wrote:
> A sysfs interface under /sys/class/console/ is created that permits
> viewing and configuring per-console attributes. This is the main
> interface with which we expect users to interact with and configure
> per-console loglevels.
> 
> Each console device now has its own directory (for example,
> /sys/class/console/ttyS0/) containing the following attributes:
> 
> - effective_loglevel (ro): The effective loglevel for the console after
>   considering all loglevel authorities (e.g., global loglevel,
>   per-console loglevel).
> - effective_loglevel_source (ro): The source of the effective loglevel
>   (e.g., local, global, ignore_loglevel).
> - loglevel (rw): The per-console loglevel. Writing a value between 0
>   (KERN_EMERG) and 8 (KERN_DEBUG + 1) sets the per-console loglevel.
>   Writing -1 disables the per-console loglevel.
> 
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -200,6 +200,24 @@ static int __init control_devkmsg(char *str)
>  }
>  __setup("printk.devkmsg=", control_devkmsg);
>  
> +/**
> + * console_clamp_loglevel - Clamp a loglevel to valid console loglevel range
> + *
> + * @level: The loglevel to clamp
> + *
> + * Console loglevels must be within the range [LOGLEVEL_ALERT, LOGLEVEL_DEBUG + 1].
> + * This function clamps a given level to this valid range.
> + *
> + * Note: This does not allow LOGLEVEL_EMERG (0) for per-console loglevels, as
> + * level 0 is reserved for emergency messages that should always go to all consoles.
> + *
> + * Return: The clamped loglevel value
> + */
> +int console_clamp_loglevel(int level)
> +{
> +	return clamp(level, LOGLEVEL_ALERT, LOGLEVEL_DEBUG + 1);
> +}
> +
>  char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE] = "ratelimit";
>  #if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
>  int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
> --- /dev/null
> +++ b/kernel/printk/sysfs.c
[...]
> +static ssize_t loglevel_store(struct device *dev, struct device_attribute *attr,
> +			      const char *buf, size_t size)
> +{
> +	struct console *con = dev_get_drvdata(dev);
> +	ssize_t ret;
> +	int level;
> +
> +	ret = kstrtoint(buf, 10, &level);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* -1 means "use global loglevel" */
> +	if (level == -1)
> +		goto out;
> +
> +	/*
> +	 * Reject level 0 (KERN_EMERG) - per-console loglevel must be > 0.
> +	 * Emergency messages should go to all consoles, so they cannot be
> +	 * filtered per-console.
> +	 */
> +	if (level == 0)
> +		return -ERANGE;

Nit: The above check is not needed. It is handled and explained in
     console_clamp_loglevel() called right below.

> +
> +	if (console_clamp_loglevel(level) != level)
> +		return -ERANGE;
> +
> +	/*
> +	 * If the system has a minimum console loglevel set (via sysctl or
> +	 * kernel parameter), enforce it. This prevents setting per-console
> +	 * loglevels below the system minimum.
> +	 */
> +	if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
> +	    level < minimum_console_loglevel)
> +		return -ERANGE;
> +
> +out:
> +	console_sysfs_write_loglevel(con, level);
> +	return size;
> +}

Otherwise, it looks good to me. With the duplicit check removed:

Reviewed-by: Petr Mladek <pmladek@suse.com>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range
  2025-11-27 19:44 ` [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range Chris Down
@ 2025-12-12 14:10   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 14:10 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:44:10, Chris Down wrote:
> The sysrq loglevel handler (keys 0-9) directly assigns the numeric key
> value to console_loglevel without any validation. This creates an
> inconsistency with other interfaces: the new kernel.console_loglevel
> sysctl, the per-console sysfs loglevel interface, and the
> SYSLOG_ACTION_CONSOLE_LEVEL syslog command all clamp or reject values
> outside the valid range.
> 
> In particular, sysrq 0 sets console_loglevel to 0 (LOGLEVEL_EMERG),
> which is problematic because:
> 
> 1. LOGLEVEL_EMERG (0) is reserved for emergency messages that should
>    always reach all consoles. Setting console_loglevel to 0 would mean
>    only KERN_EMERG messages print, which is likely never intended.
> 
> 2. The per-console loglevel infrastructure explicitly rejects level 0
>    for this reason, creating an inconsistency where sysrq can set a
>    value that other interfaces refuse.
> 
> 3. CONSOLE_LOGLEVEL_MIN is defined as 1, indicating the minimum valid
>    console loglevel, yet sysrq ignores this.
> 
> Similarly, sysrq 9 sets console_loglevel to 9, which is above
> LOGLEVEL_DEBUG (7) and serves no useful purpose since no messages have
> a level that high.
> 
> Use console_clamp_loglevel() to clamp the requested loglevel to the
> valid range [1, 8]. This ensures consistent behaviour across all
> loglevel-setting interfaces.
> 
> Signed-off-by: Chris Down <chris@chrisdown.name>

Great catch! Feel free to use:

Reviewed-by: Petr Mladek <pmladek@suse.com>

See a nit below.

> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -65,6 +65,7 @@ static inline const char *printk_skip_headers(const char *buffer)
>  int match_devname_and_update_preferred_console(const char *match,
>  					       const char *name,
>  					       const short idx);
> +int console_clamp_loglevel(int level);

It makes the same declaration in kernel/printk/internal.h redundant
and it can be removed there.

>  extern int console_printk[];
>  

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls
  2025-11-27 19:44 ` [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls Chris Down
@ 2025-12-12 15:24   ` Petr Mladek
  2025-12-15 10:08     ` Joel Granados
  0 siblings, 1 reply; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 15:24 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Joel Granados,
	Tony Lindgren, kernel-team

Adding Joel into Cc. Joel, see the original patch at
https://lore.kernel.org/all/c3e5cc507eb3fd7db0a002f31d7e47d764cad176.1764272407.git.chris@chrisdown.name/

On Fri 2025-11-28 03:44:25, Chris Down wrote:
> Introduce two new sysctl interfaces for configuring global loglevels:
> 
> - kernel.console_loglevel: Sets the global console loglevel, determining
>   the minimum priority of messages printed to consoles. Messages with a
>   loglevel lower than this value will be printed.
> - kernel.default_message_loglevel: Sets the default loglevel for
>   messages that do not specify an explicit loglevel.
> 
> The kernel.printk sysctl was previously used to set multiple loglevel
> parameters simultaneously, but it was confusing and lacked proper
> validation. By introducing these dedicated sysctl interfaces, we provide
> a clearer and more granular way to configure the loglevels.
> 
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> Tested-by: Petr Mladek <pmladek@suse.com>
> Signed-off-by: Chris Down <chris@chrisdown.name>

This patch requires non-trivial changes when rebased on top of v6.19.
There have been some conflicting changes in the sysctl API, see
https://lore.kernel.org/lkml/20251016-jag-sysctl_conv-v2-0-a2f16529acc4@kernel.org/

> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -235,6 +235,13 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
>  
>  void do_sysctl_args(void);
>  bool sysctl_is_alias(char *param);
> +int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int *valp,
> +			  int write, void *data);
> +int do_proc_dointvec(const struct ctl_table *table, int write,
> +		     void *buffer, size_t *lenp, loff_t *ppos,
> +		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> +				 int write, void *data),
> +		     void *data);
>  int do_proc_douintvec(const struct ctl_table *table, int write,
>  		      void *buffer, size_t *lenp, loff_t *ppos,
>  		      int (*conv)(unsigned long *lvalp,

This hunk can be removed in v6.19. There is another interface in 6.19,
see below.

> diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
> index da77f3f5c1fe..034739939a61 100644
> --- a/kernel/printk/sysctl.c
> +++ b/kernel/printk/sysctl.c
> @@ -11,6 +11,9 @@
>  
>  static const int ten_thousand = 10000;
>  
> +static int min_msg_loglevel = LOGLEVEL_EMERG;
> +static int max_msg_loglevel = LOGLEVEL_DEBUG;
> +
>  static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int write,
>  				void *buffer, size_t *lenp, loff_t *ppos)
>  {
> @@ -20,6 +23,50 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
>  	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
>  }

The new way is to define the needed helpers using macros. We need this:

static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
			      sysctl_kern_to_user_int_conv, false)


> +static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
> +					     int *valp,
> +					     int write, void *data)

There parameters have got renamed and @table is passed instead or @data:

static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *u_ptr,
					     int *k_ptr, int dir,
					     const struct ctl_table *table)


> +{
> +	int level, ret;
> +
> +	/*
> +	 * If writing, first do so via a temporary local int so we can
> +	 * bounds-check it before touching *valp.
> +	 */
> +	int *intp = write ? &level : valp;

The direction is newly checked by macro:

	int *int_ptr = SYSCTL_USER_TO_KERN(dir) ? &level : k_ptr;

> +	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);

The following helper is defined by the above mentioned macros:

	ret = do_proc_int_conv(negp, u_ptr, int_ptr, dir, table);

> +	if (ret)
> +		return ret;
> +
> +	if (write) {

The new way:

	if (SYSCTL_USER_TO_KERN(dir)) {

> +		if (level != console_clamp_loglevel(level))
> +			return -ERANGE;
> +
> +		/*
> +		 * Honour the administrator-configured minimum console
> +		 * loglevel (third element of kernel.printk).  This mirrors
> +		 * the syslog() and sysfs control paths so that once the floor
> +		 * is raised we do not let this sysctl silently bypass it.
> +		 */
> +		if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
> +		    level < minimum_console_loglevel)
> +			level = minimum_console_loglevel;
> +
> +		WRITE_ONCE(*valp, level);

New parameter name:

		WRITE_ONCE(*k_ptr, level);

> +	}
> +
> +	return 0;
> +}
> +
> +static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> +					  int write, void *buffer, size_t *lenp,
> +					  loff_t *ppos)
> +{
> +	return do_proc_dointvec(table, write, buffer, lenp, ppos,
> +			       do_proc_dointvec_console_loglevel, NULL);

There is a new function where the last NULL parameter is not longer passed:

	return proc_dointvec_conv(table, write, buffer, lenp, ppos,
			       do_proc_dointvec_console_loglevel);

> +}
> +
>  static const struct ctl_table printk_sysctls[] = {
>  	{
>  		.procname	= "printk",


Here are the above described changes made by diff:

--- a/kernel/printk/sysctl.c
+++ b/kernel/printk/sysctl.c
@@ -24,9 +24,14 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
 	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
 }
 
-static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
-					     int *valp,
-					     int write, void *data)
+static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
+static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
+static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
+			      sysctl_kern_to_user_int_conv, false)
+
+static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *u_ptr,
+					     int *k_ptr, int dir,
+					     const struct ctl_table *table)
 {
 	int level, ret;
 
@@ -34,13 +39,13 @@ static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
 	 * If writing, first do so via a temporary local int so we can
 	 * bounds-check it before touching *valp.
 	 */
-	int *intp = write ? &level : valp;
+	int *int_ptr = SYSCTL_USER_TO_KERN(dir) ? &level : k_ptr;
 
-	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);
+	ret = do_proc_int_conv(negp, u_ptr, int_ptr, dir, table);
 	if (ret)
 		return ret;
 
-	if (write) {
+	if (SYSCTL_USER_TO_KERN(dir)) {
 		if (level != console_clamp_loglevel(level))
 			return -ERANGE;
 
@@ -54,7 +59,7 @@ static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
 		    level < minimum_console_loglevel)
 			level = minimum_console_loglevel;
 
-		WRITE_ONCE(*valp, level);
+		WRITE_ONCE(*k_ptr, level);
 	}
 
 	return 0;
@@ -64,8 +69,8 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
 					  int write, void *buffer, size_t *lenp,
 					  loff_t *ppos)
 {
-	return do_proc_dointvec(table, write, buffer, lenp, ppos,
-			       do_proc_dointvec_console_loglevel, NULL);
+	return proc_dointvec_conv(table, write, buffer, lenp, ppos,
+			       do_proc_dointvec_console_loglevel);
 }
 
 static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,


>  void __init printk_sysctl_init(void)
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index cb6196e3fa99..3ed010b8f6b3 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -354,9 +354,9 @@ static void proc_put_char(void **buf, size_t *size, char c)
>  	}
>  }
>  
> -static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
> -				 int *valp,
> -				 int write, void *data)
> +int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
> +			  int *valp,
> +			  int write, void *data)
>  {
>  	if (write) {
>  		if (*negp) {
> @@ -380,6 +380,7 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
>  	}
>  	return 0;
>  }
> +EXPORT_SYMBOL(do_proc_dointvec_conv);
>  
>  static int do_proc_douintvec_conv(unsigned long *lvalp,
>  				  unsigned int *valp,
> @@ -471,15 +472,16 @@ static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table,
>  	return err;
>  }
>  
> -static int do_proc_dointvec(const struct ctl_table *table, int write,
> -		  void *buffer, size_t *lenp, loff_t *ppos,
> -		  int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> -			      int write, void *data),
> -		  void *data)
> +int do_proc_dointvec(const struct ctl_table *table, int write,
> +		     void *buffer, size_t *lenp, loff_t *ppos,
> +		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> +				 int write, void *data),
> +		     void *data)
>  {
>  	return __do_proc_dointvec(table->data, table, write,
>  			buffer, lenp, ppos, conv, data);
>  }
> +EXPORT_SYMBOL(do_proc_dointvec);
>  
>  static int do_proc_douintvec_w(unsigned int *tbl_data,
>  			       const struct ctl_table *table,

Also all these changes in kernel/sysctl.c are not loger needed.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels
  2025-11-27 19:44 ` [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels Chris Down
@ 2025-12-12 15:32   ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 15:32 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:44:29, Chris Down wrote:
> The per-console loglevel feature documentation could use some practical
> guidance. This commit adds:
> 
> - Examples section covering runtime configuration, effective loglevel
>   checking, and boot-time configuration
> - Common use case demonstrating high-performance netconsole with quiet
>   serial console fallback
> - Performance impact section explaining how per-console loglevels reduce
>   latency by filtering messages before slow console writes
> - Edge cases section documenting behavior with concurrent writes,
>   console unregistration, and global loglevel changes
> 
> The guidance interleaves advice about many parts of this patchset, so
> let's have it in a distinct commit.
> 
> This documentation will help users understand how to effectively use and
> debug per-console loglevels.
> 
> Signed-off-by: Chris Down <chris@chrisdown.name>

I like this. Thanks for writing so extensive documentation:

Reviewed-by: Petr Mladek <pmladek@suse.com>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-11-27 19:44 ` [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface Chris Down
@ 2025-12-12 15:51   ` Petr Mladek
  2025-12-15  9:52     ` Joel Granados
  0 siblings, 1 reply; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 15:51 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Joel Granados,
	Tony Lindgren, kernel-team

Added Joel into Cc for the sysrq API changes.

On Fri 2025-11-28 03:44:33, Chris Down wrote:
> The kernel.printk sysctl interface is deprecated in favour of more
> granular and clearer sysctl interfaces for controlling loglevels, namely
> kernel.console_loglevel and kernel.default_message_loglevel.
> 
> kernel.printk has a number of fairly significant usability problems:
> 
> - It takes four values in a specific order, which is not intuitive.
>   Speaking from personal experience, even people working on printk
>   sometimes need to look up the order of these values, which doesn't
>   suggest much in the way of perspicuity.
> - There is no validation on the input values, so users can set them to
>   invalid or nonsensical values without receiving any errors or
>   warnings. This can lead to unpredictable behaviour.
> - One of the four values, default_console_loglevel, is not used in the
>   kernel (see below), making it redundant and potentially confusing.
> - Overall, the interface is complex, hard to understand, and combines
>   multiple controls into a single sysctl, which is not ideal. It should
>   be separated into distinct controls for clarity.
> 
> Setting kernel.printk now calls printk_sysctl_deprecated, which emits a
> pr_warn. The warning informs users about the deprecation and suggests
> using the new sysctl interfaces instead.
> 
> By deprecating kernel.printk, we aim to:
> 
> - Encourage users to adopt the new, dedicated sysctl interfaces
>   (kernel.console_loglevel and kernel.default_message_loglevel), which
>   are more straightforward and easier to understand.
> - Improve input validation and error handling, ensuring that users
>   receive appropriate feedback when setting invalid values.
> - Simplify the configuration of loglevels by exposing only the controls
>   that are necessary and relevant.
> 
> --- a/kernel/printk/sysctl.c
> +++ b/kernel/printk/sysctl.c
> @@ -7,6 +7,7 @@
>  #include <linux/printk.h>
>  #include <linux/capability.h>
>  #include <linux/ratelimit.h>
> +#include <linux/console.h>
>  #include "internal.h"
>  
>  static const int ten_thousand = 10000;
> @@ -67,13 +68,24 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
>  			       do_proc_dointvec_console_loglevel, NULL);
>  }
>  
> +static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> +					   void *buffer, size_t *lenp, loff_t *ppos)
> +{
> +	int res = proc_dointvec(table, write, buffer, lenp, ppos);
> +
> +	if (write)
> +		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
> +
> +	return res;
> +}
> +
>  static const struct ctl_table printk_sysctls[] = {
>  	{
>  		.procname	= "printk",
>  		.data		= &console_loglevel,
>  		.maxlen		= 4*sizeof(int),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_printk_deprecated,
>  	},
>  	{
>  		.procname	= "printk_ratelimit",

These changes work because the sysctl API changes were backward
compatible. But it would be nice to follow the new parameter names,
...

I propose to do:

   + renamed @write to @dir
   + use SYSCTL_USER_TO_KERN(dir) macro

I mean to do the following changes on top of this patch:

--- a/kernel/printk/sysctl.c
+++ b/kernel/printk/sysctl.c
@@ -73,12 +73,12 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
 			       do_proc_dointvec_console_loglevel);
 }
 
-static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
+static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int dir,
 					   void *buffer, size_t *lenp, loff_t *ppos)
 {
-	int res = proc_dointvec(table, write, buffer, lenp, ppos);
+	int res = proc_dointvec(table, dir, buffer, lenp, ppos);
 
-	if (write)
+	if (SYSCTL_USER_TO_KERN(dir))
 		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
 
 	return res;


Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 00/21] printk: console: Per-console loglevels
  2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
                   ` (20 preceding siblings ...)
  2025-11-27 19:44 ` [PATCH v8 21/21] printk: Purge default_console_loglevel Chris Down
@ 2025-12-12 16:11 ` Petr Mladek
  21 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-12 16:11 UTC (permalink / raw)
  To: Chris Down
  Cc: linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Fri 2025-11-28 03:43:05, Chris Down wrote:
> v8:
> 
> - Fully resolve loglevel before printk_delay to aid LOGLEVEL_DEFAULT
> - Prioritise user-specified console options over SPCR/DT
> - Synchronise console unregistration against atomic flushers in nbcon
> - Optimise printk_delay to avoid SRCU walk when no delay set
> - Restored accidentally deleted comment in console_srcu_read_flags
> - Removed extra put_device() in console unregistration
> - Changed open coded console_srcu_read_lock usage to functions
> - Removed redundant newcon->classdev = NULL initialisation
> - Fixed off-by-one errors in loglevel examples in docs (4 vs >4)
> - In docs clarified "messages won't appear" edge case
> - In docs, rewrote performance impact section per Petr
> - In docs, removed obsolete minimum_console_loglevel section
> - Removed redundant newcon->level init in try_enable_preferred_console
> - Split up commits some more where reasonable (with tags kept)
> - Make SYSLOG_ACTION_CONSOLE_{ON,OFF} only restore IPCL when they did it
> - Drop sysrq loglevel overrides, just use ignore_per_console_loglevel
> - Set options to NULL if empty so drivers keep baud
> - Copy console= option strings before stripping loglevel for mips/jazz
> - Initialise consoles with LOGLEVEL_DEFAULT so sysfs never exposes 0
> - Clamp sysrq loglevels

Heh, there were more changes than I expected ;-)

I am done with the review. The biggest remanining question is what to
do with printk_delay(). This patchset shows that the current approach
(call it in vprintk_emit()) brings a lot of problems. But it never
worked. And it is an orthogonal problem to the per-console loglevel
feature.

I would suggest to keep it simple and remove most of the
printk_delay()-related patches for now. We should solve this
separately. I would try to move printk_delay() to the console
flush code paths, as proposed at
https://lore.kernel.org/all/aTrjHxZN_RpSw9lK@pathway/
I could implement this approach myself if you would prefer it.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-12 15:51   ` Petr Mladek
@ 2025-12-15  9:52     ` Joel Granados
  2025-12-15 16:06       ` Petr Mladek
  0 siblings, 1 reply; 42+ messages in thread
From: Joel Granados @ 2025-12-15  9:52 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Chris Down, linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

[-- Attachment #1: Type: text/plain, Size: 4957 bytes --]

On Fri, Dec 12, 2025 at 04:51:46PM +0100, Petr Mladek wrote:
> Added Joel into Cc for the sysrq API changes.
Thx. I have just two comments (inline)

> 
> On Fri 2025-11-28 03:44:33, Chris Down wrote:
> > The kernel.printk sysctl interface is deprecated in favour of more
> > granular and clearer sysctl interfaces for controlling loglevels, namely
> > kernel.console_loglevel and kernel.default_message_loglevel.
> > 
> > kernel.printk has a number of fairly significant usability problems:
> > 
> > - It takes four values in a specific order, which is not intuitive.
> >   Speaking from personal experience, even people working on printk
> >   sometimes need to look up the order of these values, which doesn't
> >   suggest much in the way of perspicuity.
> > - There is no validation on the input values, so users can set them to
> >   invalid or nonsensical values without receiving any errors or
> >   warnings. This can lead to unpredictable behaviour.
> > - One of the four values, default_console_loglevel, is not used in the
> >   kernel (see below), making it redundant and potentially confusing.
> > - Overall, the interface is complex, hard to understand, and combines
> >   multiple controls into a single sysctl, which is not ideal. It should
> >   be separated into distinct controls for clarity.
> > 
> > Setting kernel.printk now calls printk_sysctl_deprecated, which emits a
> > pr_warn. The warning informs users about the deprecation and suggests
> > using the new sysctl interfaces instead.
> > 
> > By deprecating kernel.printk, we aim to:
> > 
> > - Encourage users to adopt the new, dedicated sysctl interfaces
> >   (kernel.console_loglevel and kernel.default_message_loglevel), which
> >   are more straightforward and easier to understand.
> > - Improve input validation and error handling, ensuring that users
> >   receive appropriate feedback when setting invalid values.
> > - Simplify the configuration of loglevels by exposing only the controls
> >   that are necessary and relevant.
> > 
> > --- a/kernel/printk/sysctl.c
> > +++ b/kernel/printk/sysctl.c
> > @@ -7,6 +7,7 @@
> >  #include <linux/printk.h>
> >  #include <linux/capability.h>
> >  #include <linux/ratelimit.h>
> > +#include <linux/console.h>
> >  #include "internal.h"
> >  
> >  static const int ten_thousand = 10000;
> > @@ -67,13 +68,24 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> >  			       do_proc_dointvec_console_loglevel, NULL);
> >  }
> >  
> > +static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> > +					   void *buffer, size_t *lenp, loff_t *ppos)
> > +{
> > +	int res = proc_dointvec(table, write, buffer, lenp, ppos);
> > +
> > +	if (write)
This would print out a warning when the user writes to the file.
I have some questions here:
1. Is this sysctl to be completely removed in the future?
2. Shouldn't you warn on read as well (if it is going to be completely
   removed).
3. Is there a plan for when this will be completely removed? Is there a
   date?
4. Should you put that date in the message?


> > +		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
Line seems very long. cut it in two?

> > +
> > +	return res;
> > +}
> > +
> >  static const struct ctl_table printk_sysctls[] = {
> >  	{
> >  		.procname	= "printk",
> >  		.data		= &console_loglevel,
> >  		.maxlen		= 4*sizeof(int),
> >  		.mode		= 0644,
> > -		.proc_handler	= proc_dointvec,
> > +		.proc_handler	= proc_dointvec_printk_deprecated,
> >  	},
> >  	{
> >  		.procname	= "printk_ratelimit",
> 
> These changes work because the sysctl API changes were backward
> compatible. But it would be nice to follow the new parameter names,
> ...
> 
> I propose to do:
> 
>    + renamed @write to @dir
>    + use SYSCTL_USER_TO_KERN(dir) macro
This looks good to me.

> 
> I mean to do the following changes on top of this patch:
> 
> --- a/kernel/printk/sysctl.c
> +++ b/kernel/printk/sysctl.c
> @@ -73,12 +73,12 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
>  			       do_proc_dointvec_console_loglevel);
>  }
>  
> -static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> +static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int dir,
>  					   void *buffer, size_t *lenp, loff_t *ppos)
>  {
> -	int res = proc_dointvec(table, write, buffer, lenp, ppos);
> +	int res = proc_dointvec(table, dir, buffer, lenp, ppos);
>  
> -	if (write)
> +	if (SYSCTL_USER_TO_KERN(dir))
>  		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
>  
>  	return res;
> 
> 
> Best Regards,
> Petr

-- 

Joel Granados

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls
  2025-12-12 15:24   ` Petr Mladek
@ 2025-12-15 10:08     ` Joel Granados
  2025-12-15 16:09       ` Petr Mladek
  0 siblings, 1 reply; 42+ messages in thread
From: Joel Granados @ 2025-12-15 10:08 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Chris Down, linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

[-- Attachment #1: Type: text/plain, Size: 10309 bytes --]

On Fri, Dec 12, 2025 at 04:24:17PM +0100, Petr Mladek wrote:
> Adding Joel into Cc. Joel, see the original patch at
> https://lore.kernel.org/all/c3e5cc507eb3fd7db0a002f31d7e47d764cad176.1764272407.git.chris@chrisdown.name/
Thx for adding me. Please CC me in the next versions of this series as
the interface might change (slightly) again. By having this on my radar
we can better coordinate (if needed) linux-next and PRs for Linus.


> 
> On Fri 2025-11-28 03:44:25, Chris Down wrote:
> > Introduce two new sysctl interfaces for configuring global loglevels:
> > 
> > - kernel.console_loglevel: Sets the global console loglevel, determining
> >   the minimum priority of messages printed to consoles. Messages with a
> >   loglevel lower than this value will be printed.
> > - kernel.default_message_loglevel: Sets the default loglevel for
> >   messages that do not specify an explicit loglevel.
> > 
> > The kernel.printk sysctl was previously used to set multiple loglevel
> > parameters simultaneously, but it was confusing and lacked proper
> > validation. By introducing these dedicated sysctl interfaces, we provide
> > a clearer and more granular way to configure the loglevels.
> > 
> > Reviewed-by: Petr Mladek <pmladek@suse.com>
> > Tested-by: Petr Mladek <pmladek@suse.com>
> > Signed-off-by: Chris Down <chris@chrisdown.name>
> 
> This patch requires non-trivial changes when rebased on top of v6.19.
> There have been some conflicting changes in the sysctl API, see
> https://lore.kernel.org/lkml/20251016-jag-sysctl_conv-v2-0-a2f16529acc4@kernel.org/
> 
> > --- a/include/linux/sysctl.h
> > +++ b/include/linux/sysctl.h
> > @@ -235,6 +235,13 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
> >  
> >  void do_sysctl_args(void);
> >  bool sysctl_is_alias(char *param);
> > +int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int *valp,
> > +			  int write, void *data);
> > +int do_proc_dointvec(const struct ctl_table *table, int write,
> > +		     void *buffer, size_t *lenp, loff_t *ppos,
> > +		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> > +				 int write, void *data),
> > +		     void *data);
> >  int do_proc_douintvec(const struct ctl_table *table, int write,
> >  		      void *buffer, size_t *lenp, loff_t *ppos,
> >  		      int (*conv)(unsigned long *lvalp,
> 
> This hunk can be removed in v6.19. There is another interface in 6.19,
> see below.
> 
> > diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
> > index da77f3f5c1fe..034739939a61 100644
> > --- a/kernel/printk/sysctl.c
> > +++ b/kernel/printk/sysctl.c
> > @@ -11,6 +11,9 @@
> >  
> >  static const int ten_thousand = 10000;
> >  
> > +static int min_msg_loglevel = LOGLEVEL_EMERG;
> > +static int max_msg_loglevel = LOGLEVEL_DEBUG;
> > +
> >  static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int write,
> >  				void *buffer, size_t *lenp, loff_t *ppos)
> >  {
> > @@ -20,6 +23,50 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
> >  	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> >  }
> 
> The new way is to define the needed helpers using macros. We need this:
> 
> static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
> static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
> static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
> 			      sysctl_kern_to_user_int_conv, false)
> 
> 
> > +static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
> > +					     int *valp,
> > +					     int write, void *data)
> 
> There parameters have got renamed and @table is passed instead or @data:
> 
> static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *u_ptr,
> 					     int *k_ptr, int dir,
> 					     const struct ctl_table *table)
> 
> 
> > +{
> > +	int level, ret;
> > +
> > +	/*
> > +	 * If writing, first do so via a temporary local int so we can
> > +	 * bounds-check it before touching *valp.
> > +	 */
> > +	int *intp = write ? &level : valp;
> 
> The direction is newly checked by macro:
> 
> 	int *int_ptr = SYSCTL_USER_TO_KERN(dir) ? &level : k_ptr;
> 
> > +	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);
> 
> The following helper is defined by the above mentioned macros:
> 
> 	ret = do_proc_int_conv(negp, u_ptr, int_ptr, dir, table);
> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (write) {
> 
> The new way:
> 
> 	if (SYSCTL_USER_TO_KERN(dir)) {
> 
> > +		if (level != console_clamp_loglevel(level))
> > +			return -ERANGE;
> > +
> > +		/*
> > +		 * Honour the administrator-configured minimum console
> > +		 * loglevel (third element of kernel.printk).  This mirrors
> > +		 * the syslog() and sysfs control paths so that once the floor
> > +		 * is raised we do not let this sysctl silently bypass it.
> > +		 */
> > +		if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
> > +		    level < minimum_console_loglevel)
> > +			level = minimum_console_loglevel;
> > +
> > +		WRITE_ONCE(*valp, level);
> 
> New parameter name:
> 
> 		WRITE_ONCE(*k_ptr, level);
> 
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> > +					  int write, void *buffer, size_t *lenp,
> > +					  loff_t *ppos)
> > +{
> > +	return do_proc_dointvec(table, write, buffer, lenp, ppos,
> > +			       do_proc_dointvec_console_loglevel, NULL);
> 
> There is a new function where the last NULL parameter is not longer passed:
> 
> 	return proc_dointvec_conv(table, write, buffer, lenp, ppos,
> 			       do_proc_dointvec_console_loglevel);
> 
> > +}
> > +
> >  static const struct ctl_table printk_sysctls[] = {
> >  	{
> >  		.procname	= "printk",
> 
> 
> Here are the above described changes made by diff:
The changes look ok, but there is a lot of context that I'm missing from
just looking at this change. Will there be another version re-based on
top of v19-rc1? 

> 
> --- a/kernel/printk/sysctl.c
> +++ b/kernel/printk/sysctl.c
> @@ -24,9 +24,14 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
>  	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
>  }
>  
> -static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
> -					     int *valp,
> -					     int write, void *data)
> +static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
> +static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
> +static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
> +			      sysctl_kern_to_user_int_conv, false)
> +
> +static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *u_ptr,
> +					     int *k_ptr, int dir,
> +					     const struct ctl_table *table)
>  {
>  	int level, ret;
>  
> @@ -34,13 +39,13 @@ static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
>  	 * If writing, first do so via a temporary local int so we can
>  	 * bounds-check it before touching *valp.
>  	 */
> -	int *intp = write ? &level : valp;
> +	int *int_ptr = SYSCTL_USER_TO_KERN(dir) ? &level : k_ptr;
>  
> -	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);
> +	ret = do_proc_int_conv(negp, u_ptr, int_ptr, dir, table);
>  	if (ret)
>  		return ret;
>  
> -	if (write) {
> +	if (SYSCTL_USER_TO_KERN(dir)) {
>  		if (level != console_clamp_loglevel(level))
>  			return -ERANGE;
>  
> @@ -54,7 +59,7 @@ static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
>  		    level < minimum_console_loglevel)
>  			level = minimum_console_loglevel;
>  
> -		WRITE_ONCE(*valp, level);
> +		WRITE_ONCE(*k_ptr, level);
>  	}
>  
>  	return 0;
> @@ -64,8 +69,8 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
>  					  int write, void *buffer, size_t *lenp,
>  					  loff_t *ppos)
>  {
> -	return do_proc_dointvec(table, write, buffer, lenp, ppos,
> -			       do_proc_dointvec_console_loglevel, NULL);
> +	return proc_dointvec_conv(table, write, buffer, lenp, ppos,
> +			       do_proc_dointvec_console_loglevel);
>  }
>  
>  static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> 
> 
> >  void __init printk_sysctl_init(void)
> > diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> > index cb6196e3fa99..3ed010b8f6b3 100644
> > --- a/kernel/sysctl.c
> > +++ b/kernel/sysctl.c
> > @@ -354,9 +354,9 @@ static void proc_put_char(void **buf, size_t *size, char c)
> >  	}
> >  }
> >  
> > -static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
> > -				 int *valp,
> > -				 int write, void *data)
> > +int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
> > +			  int *valp,
> > +			  int write, void *data)
> >  {
> >  	if (write) {
> >  		if (*negp) {
> > @@ -380,6 +380,7 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
> >  	}
> >  	return 0;
> >  }
> > +EXPORT_SYMBOL(do_proc_dointvec_conv);
> >  
> >  static int do_proc_douintvec_conv(unsigned long *lvalp,
> >  				  unsigned int *valp,
> > @@ -471,15 +472,16 @@ static int __do_proc_dointvec(void *tbl_data, const struct ctl_table *table,
> >  	return err;
> >  }
> >  
> > -static int do_proc_dointvec(const struct ctl_table *table, int write,
> > -		  void *buffer, size_t *lenp, loff_t *ppos,
> > -		  int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> > -			      int write, void *data),
> > -		  void *data)
> > +int do_proc_dointvec(const struct ctl_table *table, int write,
> > +		     void *buffer, size_t *lenp, loff_t *ppos,
> > +		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> > +				 int write, void *data),
> > +		     void *data)
> >  {
> >  	return __do_proc_dointvec(table->data, table, write,
> >  			buffer, lenp, ppos, conv, data);
> >  }
> > +EXPORT_SYMBOL(do_proc_dointvec);
> >  
> >  static int do_proc_douintvec_w(unsigned int *tbl_data,
> >  			       const struct ctl_table *table,
> 
> Also all these changes in kernel/sysctl.c are not loger needed.
> 
> Best Regards,
> Petr

-- 

Joel Granados

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-15  9:52     ` Joel Granados
@ 2025-12-15 16:06       ` Petr Mladek
  2025-12-17 11:47         ` Joel Granados
  0 siblings, 1 reply; 42+ messages in thread
From: Petr Mladek @ 2025-12-15 16:06 UTC (permalink / raw)
  To: Joel Granados
  Cc: Chris Down, linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Mon 2025-12-15 10:52:28, Joel Granados wrote:
> On Fri, Dec 12, 2025 at 04:51:46PM +0100, Petr Mladek wrote:
> > Added Joel into Cc for the sysrq API changes.
> Thx. I have just two comments (inline)
> 
> > 
> > On Fri 2025-11-28 03:44:33, Chris Down wrote:
> > > The kernel.printk sysctl interface is deprecated in favour of more
> > > granular and clearer sysctl interfaces for controlling loglevels, namely
> > > kernel.console_loglevel and kernel.default_message_loglevel.
> > > 
> > > - Encourage users to adopt the new, dedicated sysctl interfaces
> > >   (kernel.console_loglevel and kernel.default_message_loglevel), which
> > >   are more straightforward and easier to understand.
> > > - Improve input validation and error handling, ensuring that users
> > >   receive appropriate feedback when setting invalid values.
> > > - Simplify the configuration of loglevels by exposing only the controls
> > >   that are necessary and relevant.
> > > 
> > > --- a/kernel/printk/sysctl.c
> > > +++ b/kernel/printk/sysctl.c
> > > @@ -67,13 +68,24 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> > >  			       do_proc_dointvec_console_loglevel, NULL);
> > >  }
> > >  
> > > +static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> > > +					   void *buffer, size_t *lenp, loff_t *ppos)
> > > +{
> > > +	int res = proc_dointvec(table, write, buffer, lenp, ppos);
> > > +
> > > +	if (write)
> This would print out a warning when the user writes to the file.
> I have some questions here:
> 1. Is this sysctl to be completely removed in the future?

I hope so.

> 2. Shouldn't you warn on read as well (if it is going to be completely
>    removed).

Makes perfect sense. We should.

> 3. Is there a plan for when this will be completely removed? Is there a
>    date?

Honeslty, I do not have much experience with removing such API.
I am not sure how aggressive we could be.

For example, it seems that it is going to take 15 years to obsolete
automounting of tracefs in debugfs. But they added the warning
10 years after adding tracefs, see commit 9ba817fb7c6afd3
("tracing: Deprecate auto-mounting tracefs in debugfs").

> 4. Should you put that date in the message?

It would be useful. What about doing it in 10 years from now?

> > > +		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
> Line seems very long. cut it in two?

OK, what about the following?

	pr_warn_once("printk: The kernel.printk sysctl is deprecated and will be removed in 2036.\n");
	pr_warn_once("printk: Use kernel.console_loglevel or kernel.default_message_loglevel instead.\n");

> > These changes work because the sysctl API changes were backward
> > compatible. But it would be nice to follow the new parameter names,
> > ...
> > 
> > I propose to do:
> > 
> >    + renamed @write to @dir
> >    + use SYSCTL_USER_TO_KERN(dir) macro
> This looks good to me.

Thanks for checking and feedback.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls
  2025-12-15 10:08     ` Joel Granados
@ 2025-12-15 16:09       ` Petr Mladek
  0 siblings, 0 replies; 42+ messages in thread
From: Petr Mladek @ 2025-12-15 16:09 UTC (permalink / raw)
  To: Joel Granados
  Cc: Chris Down, linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

On Mon 2025-12-15 11:08:12, Joel Granados wrote:
> On Fri, Dec 12, 2025 at 04:24:17PM +0100, Petr Mladek wrote:
> > Adding Joel into Cc. Joel, see the original patch at
> > https://lore.kernel.org/all/c3e5cc507eb3fd7db0a002f31d7e47d764cad176.1764272407.git.chris@chrisdown.name/
> Thx for adding me. Please CC me in the next versions of this series as
> the interface might change (slightly) again. By having this on my radar
> we can better coordinate (if needed) linux-next and PRs for Linus.
> > 
> > On Fri 2025-11-28 03:44:25, Chris Down wrote:
> > > Introduce two new sysctl interfaces for configuring global loglevels:
> > > 
> > > --- a/include/linux/sysctl.h
> > > +++ b/include/linux/sysctl.h
> > > @@ -235,6 +235,13 @@ extern struct ctl_table_header *register_sysctl_mount_point(const char *path);
> > >  
> > >  void do_sysctl_args(void);
> > >  bool sysctl_is_alias(char *param);
> > > +int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int *valp,
> > > +			  int write, void *data);
> > > +int do_proc_dointvec(const struct ctl_table *table, int write,
> > > +		     void *buffer, size_t *lenp, loff_t *ppos,
> > > +		     int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
> > > +				 int write, void *data),
> > > +		     void *data);
> > >  int do_proc_douintvec(const struct ctl_table *table, int write,
> > >  		      void *buffer, size_t *lenp, loff_t *ppos,
> > >  		      int (*conv)(unsigned long *lvalp,
> > 
> > This hunk can be removed in v6.19. There is another interface in 6.19,
> > see below.
> > 
> > > diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
> > > index da77f3f5c1fe..034739939a61 100644
> > > --- a/kernel/printk/sysctl.c
> > > +++ b/kernel/printk/sysctl.c
> > > @@ -11,6 +11,9 @@
> > >  
> > >  static const int ten_thousand = 10000;
> > >  
> > > +static int min_msg_loglevel = LOGLEVEL_EMERG;
> > > +static int max_msg_loglevel = LOGLEVEL_DEBUG;
> > > +
> > >  static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int write,
> > >  				void *buffer, size_t *lenp, loff_t *ppos)
> > >  {
> > > @@ -20,6 +23,50 @@ static int proc_dointvec_minmax_sysadmin(const struct ctl_table *table, int writ
> > >  	return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> > >  }
> > 
> > The new way is to define the needed helpers using macros. We need this:
> > 
> > static SYSCTL_USER_TO_KERN_INT_CONV(, SYSCTL_CONV_IDENTITY)
> > static SYSCTL_KERN_TO_USER_INT_CONV(, SYSCTL_CONV_IDENTITY)
> > static SYSCTL_INT_CONV_CUSTOM(, sysctl_user_to_kern_int_conv,
> > 			      sysctl_kern_to_user_int_conv, false)
> > 
> > 
> > > +static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *lvalp,
> > > +					     int *valp,
> > > +					     int write, void *data)
> > 
> > There parameters have got renamed and @table is passed instead or @data:
> > 
> > static int do_proc_dointvec_console_loglevel(bool *negp, unsigned long *u_ptr,
> > 					     int *k_ptr, int dir,
> > 					     const struct ctl_table *table)
> > 
> > 
> > > +{
> > > +	int level, ret;
> > > +
> > > +	/*
> > > +	 * If writing, first do so via a temporary local int so we can
> > > +	 * bounds-check it before touching *valp.
> > > +	 */
> > > +	int *intp = write ? &level : valp;
> > 
> > The direction is newly checked by macro:
> > 
> > 	int *int_ptr = SYSCTL_USER_TO_KERN(dir) ? &level : k_ptr;
> > 
> > > +	ret = do_proc_dointvec_conv(negp, lvalp, intp, write, data);
> > 
> > The following helper is defined by the above mentioned macros:
> > 
> > 	ret = do_proc_int_conv(negp, u_ptr, int_ptr, dir, table);
> > 
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	if (write) {
> > 
> > The new way:
> > 
> > 	if (SYSCTL_USER_TO_KERN(dir)) {
> > 
> > > +		if (level != console_clamp_loglevel(level))
> > > +			return -ERANGE;
> > > +
> > > +		/*
> > > +		 * Honour the administrator-configured minimum console
> > > +		 * loglevel (third element of kernel.printk).  This mirrors
> > > +		 * the syslog() and sysfs control paths so that once the floor
> > > +		 * is raised we do not let this sysctl silently bypass it.
> > > +		 */
> > > +		if (minimum_console_loglevel > CONSOLE_LOGLEVEL_MIN &&
> > > +		    level < minimum_console_loglevel)
> > > +			level = minimum_console_loglevel;
> > > +
> > > +		WRITE_ONCE(*valp, level);
> > 
> > New parameter name:
> > 
> > 		WRITE_ONCE(*k_ptr, level);
> > 
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> > > +					  int write, void *buffer, size_t *lenp,
> > > +					  loff_t *ppos)
> > > +{
> > > +	return do_proc_dointvec(table, write, buffer, lenp, ppos,
> > > +			       do_proc_dointvec_console_loglevel, NULL);
> > 
> > There is a new function where the last NULL parameter is not longer passed:
> > 
> > 	return proc_dointvec_conv(table, write, buffer, lenp, ppos,
> > 			       do_proc_dointvec_console_loglevel);
> > 
> > > +}
> > > +
> > >  static const struct ctl_table printk_sysctls[] = {
> > >  	{
> > >  		.procname	= "printk",
> > 
> > 
> > Here are the above described changes made by diff:
> The changes look ok,

Great.

> but there is a lot of context that I'm missing from
> just looking at this change. Will there be another version re-based on
> top of v19-rc1? 

Yes, we need v9. Chris, please add Joel into Cc.

Thanks a lot for checking.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-15 16:06       ` Petr Mladek
@ 2025-12-17 11:47         ` Joel Granados
  2025-12-17 14:33           ` Geert Uytterhoeven
  0 siblings, 1 reply; 42+ messages in thread
From: Joel Granados @ 2025-12-17 11:47 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Chris Down, linux-kernel, Greg Kroah-Hartman, Sergey Senozhatsky,
	Steven Rostedt, John Ogness, Geert Uytterhoeven, Tony Lindgren,
	kernel-team

[-- Attachment #1: Type: text/plain, Size: 3539 bytes --]

On Mon, Dec 15, 2025 at 05:06:40PM +0100, Petr Mladek wrote:
> On Mon 2025-12-15 10:52:28, Joel Granados wrote:
> > On Fri, Dec 12, 2025 at 04:51:46PM +0100, Petr Mladek wrote:
> > > Added Joel into Cc for the sysrq API changes.
> > Thx. I have just two comments (inline)
> > 
> > > 
> > > On Fri 2025-11-28 03:44:33, Chris Down wrote:
> > > > The kernel.printk sysctl interface is deprecated in favour of more
> > > > granular and clearer sysctl interfaces for controlling loglevels, namely
> > > > kernel.console_loglevel and kernel.default_message_loglevel.
> > > > 
> > > > - Encourage users to adopt the new, dedicated sysctl interfaces
> > > >   (kernel.console_loglevel and kernel.default_message_loglevel), which
> > > >   are more straightforward and easier to understand.
> > > > - Improve input validation and error handling, ensuring that users
> > > >   receive appropriate feedback when setting invalid values.
> > > > - Simplify the configuration of loglevels by exposing only the controls
> > > >   that are necessary and relevant.
> > > > 
> > > > --- a/kernel/printk/sysctl.c
> > > > +++ b/kernel/printk/sysctl.c
> > > > @@ -67,13 +68,24 @@ static int proc_dointvec_console_loglevel(const struct ctl_table *table,
> > > >  			       do_proc_dointvec_console_loglevel, NULL);
> > > >  }
> > > >  
> > > > +static int proc_dointvec_printk_deprecated(const struct ctl_table *table, int write,
> > > > +					   void *buffer, size_t *lenp, loff_t *ppos)
> > > > +{
> > > > +	int res = proc_dointvec(table, write, buffer, lenp, ppos);
> > > > +
> > > > +	if (write)
> > This would print out a warning when the user writes to the file.
> > I have some questions here:
> > 1. Is this sysctl to be completely removed in the future?
> 
> I hope so.
> 
> > 2. Shouldn't you warn on read as well (if it is going to be completely
> >    removed).
> 
> Makes perfect sense. We should.
> 
> > 3. Is there a plan for when this will be completely removed? Is there a
> >    date?
> 
> Honeslty, I do not have much experience with removing such API.
> I am not sure how aggressive we could be.
> 
> For example, it seems that it is going to take 15 years to obsolete
> automounting of tracefs in debugfs. But they added the warning
> 10 years after adding tracefs, see commit 9ba817fb7c6afd3
> ("tracing: Deprecate auto-mounting tracefs in debugfs").
Indeed, there is no agreed procedure. If you don't have an expected
date, then don't put it in the warn message.

> 
> > 4. Should you put that date in the message?
> 
> It would be useful. What about doing it in 10 years from now?
10 years seems ok to me. But since this is a guess more than a plan, I
would just not put it on the message. Up to you.

> 
> > > > +		pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
> > Line seems very long. cut it in two?
> 
> OK, what about the following?
> 
> 	pr_warn_once("printk: The kernel.printk sysctl is deprecated and will be removed in 2036.\n");
> 	pr_warn_once("printk: Use kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
I meant it more as a long line in the code. Not a long line in the
log. Like this:

  pr_warn_once("printk: The kernel.printk sysctl is deprecated. Instead, use "
               "kernel.console_loglevel or kernel.default_message_loglevel.\n");

Its still long, but more manageable.

Best

-- 

Joel Granados

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-17 11:47         ` Joel Granados
@ 2025-12-17 14:33           ` Geert Uytterhoeven
  2025-12-17 16:04             ` Steven Rostedt
  0 siblings, 1 reply; 42+ messages in thread
From: Geert Uytterhoeven @ 2025-12-17 14:33 UTC (permalink / raw)
  To: Joel Granados
  Cc: Petr Mladek, Chris Down, linux-kernel, Greg Kroah-Hartman,
	Sergey Senozhatsky, Steven Rostedt, John Ogness, Tony Lindgren,
	kernel-team

Hi Joel,

On Wed, 17 Dec 2025 at 12:47, Joel Granados <joel.granados@kernel.org> wrote:
> On Mon, Dec 15, 2025 at 05:06:40PM +0100, Petr Mladek wrote:
> > On Mon 2025-12-15 10:52:28, Joel Granados wrote:
> > > On Fri, Dec 12, 2025 at 04:51:46PM +0100, Petr Mladek wrote:
> > > > > +               pr_warn_once("printk: The kernel.printk sysctl is deprecated. Consider using kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
> > > Line seems very long. cut it in two?
> >
> > OK, what about the following?
> >
> >       pr_warn_once("printk: The kernel.printk sysctl is deprecated and will be removed in 2036.\n");
> >       pr_warn_once("printk: Use kernel.console_loglevel or kernel.default_message_loglevel instead.\n");
> I meant it more as a long line in the code. Not a long line in the
> log. Like this:
>
>   pr_warn_once("printk: The kernel.printk sysctl is deprecated. Instead, use "
>                "kernel.console_loglevel or kernel.default_message_loglevel.\n");
>
> Its still long, but more manageable.

Please do not split long messages, as it makes it harder to find them
in the source tree.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-17 14:33           ` Geert Uytterhoeven
@ 2025-12-17 16:04             ` Steven Rostedt
  2025-12-17 20:23               ` Joel Granados
  0 siblings, 1 reply; 42+ messages in thread
From: Steven Rostedt @ 2025-12-17 16:04 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Joel Granados, Petr Mladek, Chris Down, linux-kernel,
	Greg Kroah-Hartman, Sergey Senozhatsky, John Ogness,
	Tony Lindgren, kernel-team

On Wed, 17 Dec 2025 15:33:42 +0100
Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> > > OK, what about the following?
> > >
> > >       pr_warn_once("printk: The kernel.printk sysctl is deprecated and will be removed in 2036.\n");
> > >       pr_warn_once("printk: Use kernel.console_loglevel or kernel.default_message_loglevel instead.\n");  
> > I meant it more as a long line in the code. Not a long line in the
> > log. Like this:
> >
> >   pr_warn_once("printk: The kernel.printk sysctl is deprecated. Instead, use "
> >                "kernel.console_loglevel or kernel.default_message_loglevel.\n");
> >
> > Its still long, but more manageable.  
> 
> Please do not split long messages, as it makes it harder to find them
> in the source tree.

Right. Linus has stated that strings should not be split just because they
go over the column limit.

-- Steve

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface
  2025-12-17 16:04             ` Steven Rostedt
@ 2025-12-17 20:23               ` Joel Granados
  0 siblings, 0 replies; 42+ messages in thread
From: Joel Granados @ 2025-12-17 20:23 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Geert Uytterhoeven, Petr Mladek, Chris Down, linux-kernel,
	Greg Kroah-Hartman, Sergey Senozhatsky, John Ogness,
	Tony Lindgren, kernel-team

[-- Attachment #1: Type: text/plain, Size: 1512 bytes --]

On Wed, Dec 17, 2025 at 11:04:43AM -0500, Steven Rostedt wrote:
> On Wed, 17 Dec 2025 15:33:42 +0100
> Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> 
> > > > OK, what about the following?
> > > >
> > > >       pr_warn_once("printk: The kernel.printk sysctl is deprecated and will be removed in 2036.\n");
> > > >       pr_warn_once("printk: Use kernel.console_loglevel or kernel.default_message_loglevel instead.\n");  
> > > I meant it more as a long line in the code. Not a long line in the
> > > log. Like this:
> > >
> > >   pr_warn_once("printk: The kernel.printk sysctl is deprecated. Instead, use "
> > >                "kernel.console_loglevel or kernel.default_message_loglevel.\n");
> > >
> > > Its still long, but more manageable.  
> > 
> > Please do not split long messages, as it makes it harder to find them
> > in the source tree.
> 
> Right. Linus has stated that strings should not be split just because they
> go over the column limit.

Oops, my bad. In that case, just leave it in one line.

   pr_warn_once("printk: The kernel.printk sysctl is deprecated. Instead, use kernel.console_loglevel or kernel.default_message_loglevel.\n");

I would even try to make it shorter. Do you actually need the "kernel"
string? If it still make sense without explicitly stating the "kernel"
dir, then I would shorten it to this:

   pr_warn_once("printk sysctl is deprecated. Use console_loglevel or default_message_loglevel insetad.\n");

Best
-- 

Joel Granados

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2025-12-17 20:23 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-27 19:43 [PATCH v8 00/21] printk: console: Per-console loglevels Chris Down
2025-11-27 19:43 ` [PATCH v8 01/21] printk: Fully resolve loglevel before deciding printk delay suppression Chris Down
2025-12-09 16:40   ` Petr Mladek
2025-12-11 14:49     ` Petr Mladek
2025-12-11 15:28       ` Petr Mladek
2025-11-27 19:43 ` [PATCH v8 02/21] printk: Avoid spuriously delaying messages not solicited by any console Chris Down
2025-11-27 19:43 ` [PATCH v8 03/21] printk: Prioritise user-specified configuration over SPCR/DT Chris Down
2025-12-10 14:38   ` Petr Mladek
2025-11-27 19:43 ` [PATCH v8 04/21] printk: Use effective loglevel for suppression and extended console state Chris Down
2025-11-27 19:43 ` [PATCH v8 05/21] printk: console: Add per-console loglevel support to struct console Chris Down
2025-11-27 19:43 ` [PATCH v8 06/21] printk: nbcon: Synchronise console unregistration against atomic flushers Chris Down
2025-12-10 15:12   ` Petr Mladek
2025-11-27 19:43 ` [PATCH v8 07/21] printk: Introduce per-console loglevel support Chris Down
2025-11-27 19:43 ` [PATCH v8 08/21] printk: Iterate registered consoles for delay suppression decisions Chris Down
2025-11-27 19:43 ` [PATCH v8 09/21] printk: Optimise printk_delay() to avoid walking consoles under SRCU Chris Down
2025-12-11 14:37   ` Petr Mladek
2025-11-27 19:43 ` [PATCH v8 10/21] printk: Add synchronisation for concurrent console state changes Chris Down
2025-11-27 19:43 ` [PATCH v8 11/21] printk: Add ignore_per_console_loglevel module parameter Chris Down
2025-11-27 19:43 ` [PATCH v8 12/21] printk: Ensure sysrq output bypasses per-console filtering Chris Down
2025-11-27 19:44 ` [PATCH v8 13/21] printk: Toggle ignore_per_console_loglevel via syslog Chris Down
2025-11-27 19:44 ` [PATCH v8 14/21] printk: console: Introduce sysfs interface for per-console loglevels Chris Down
2025-12-12 14:04   ` Petr Mladek
2025-11-27 19:44 ` [PATCH v8 15/21] printk: sysrq: Clamp console loglevel to valid range Chris Down
2025-12-12 14:10   ` Petr Mladek
2025-11-27 19:44 ` [PATCH v8 16/21] printk: Constrain hardware-addressed console checks to name position Chris Down
2025-11-27 19:44 ` [PATCH v8 17/21] printk: Support setting initial console loglevel via console= on cmdline Chris Down
2025-11-27 19:44 ` [PATCH v8 18/21] printk: Deconstruct kernel.printk into discrete sysctl controls Chris Down
2025-12-12 15:24   ` Petr Mladek
2025-12-15 10:08     ` Joel Granados
2025-12-15 16:09       ` Petr Mladek
2025-11-27 19:44 ` [PATCH v8 19/21] printk: docs: Add comprehensive guidance for per-console loglevels Chris Down
2025-12-12 15:32   ` Petr Mladek
2025-11-27 19:44 ` [PATCH v8 20/21] printk: Deprecate the kernel.printk sysctl interface Chris Down
2025-12-12 15:51   ` Petr Mladek
2025-12-15  9:52     ` Joel Granados
2025-12-15 16:06       ` Petr Mladek
2025-12-17 11:47         ` Joel Granados
2025-12-17 14:33           ` Geert Uytterhoeven
2025-12-17 16:04             ` Steven Rostedt
2025-12-17 20:23               ` Joel Granados
2025-11-27 19:44 ` [PATCH v8 21/21] printk: Purge default_console_loglevel Chris Down
2025-12-12 16:11 ` [PATCH v8 00/21] printk: console: Per-console loglevels Petr Mladek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).