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
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 | 87 ++++++++++++++++++-
5 files changed, 140 insertions(+), 15 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 1518343bbe22..d883a851fffc 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -799,13 +799,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.
@@ -3167,8 +3172,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 a3dfc2c66e01..240f7a36379d 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 0 (LOGLEVEL_EMERG) 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:
@@ -143,3 +173,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>, 23-October-2024
diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst
index 34419e6fe106..a7c7519fe2d0 100644
--- a/Documentation/networking/netconsole.rst
+++ b/Documentation/networking/netconsole.rst
@@ -72,7 +72,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 bbd037b84a0d..c47dda23a7d6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2597,12 +2597,84 @@ static void set_user_specified(struct console_cmdline *c, bool user_specified)
console_set_on_cmdline = 1;
}
+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;
+
+ 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';
+ }
+
+ 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;
+}
+
+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;
+ }
+
+ if (clamp_loglevel(loglevel) != loglevel) {
+ pr_warn("Per-console loglevel out of range, ignoring: %d\n", loglevel);
+ return -ERANGE;
+ }
+
+ return loglevel;
+}
+
static int __add_preferred_console(const char *name, const short idx,
const char *devname, char *options,
char *brl_options, bool user_specified)
{
struct console_cmdline *c;
- int i;
+ int i, ret;
if (!name && !devname)
return -EINVAL;
@@ -2639,6 +2711,13 @@ static int __add_preferred_console(const char *name, const short idx,
strscpy(c->name, name);
if (devname)
strscpy(c->devname, devname);
+
+ ret = find_and_remove_loglevel_option(options);
+ if (ret >= 0)
+ c->level = ret;
+ else
+ c->level = -1;
+
c->options = options;
set_user_specified(c, user_specified);
braille_set_options(c, brl_options);
@@ -3903,8 +3982,10 @@ 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 = -1;
+ if (c->level > 0)
+ newcon->level = c->level;
+ else
+ newcon->level = -1;
newcon->classdev = NULL;
--
2.46.0
On Mon 2024-10-28 16:45:52, Chris Down wrote: > 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 > > --- 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 0 (LOGLEVEL_EMERG) to 8 The real lower limit, enforced by clamp_loglevel(), is 1. > + (LOGLEVEL_DEBUG + 1), and messages below that will be > + emitted onto the console as they become available. > + > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -3903,8 +3982,10 @@ 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 = -1; > + if (c->level > 0) > + newcon->level = c->level; > + else > + newcon->level = -1; It seems that c->level is already set to -1 when it is not defined on the command line. I think that that we could simply do: newcon->level = c->level; Just for record. We need to explicitely set newcon->level to -1 in try_enable_default_console(). > newcon->classdev = NULL; > Otherwise, it looks good. Best Regards, Petr
© 2016 - 2024 Red Hat, Inc.