linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] printk: add per console loglevel
@ 2014-12-20 22:49 dwalker
  2014-12-21 18:47 ` Bruno Prémont
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: dwalker @ 2014-12-20 22:49 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel


This adds to to the console= command line options allowing the
addition of a per console log level setting.

examples,

	console=ttyS0,ll4
	console=tty0,ll6

This can be used on systems which have multiple serial consoles, but
it's desired for logging to be light on one and heavy on another.

Signed-off-by: Daniel Walker <dwalker@fifo99.com>
---
 Documentation/kernel-parameters.txt | 24 ++++++++++++++++++------
 include/linux/console.h             |  1 +
 kernel/printk/console_cmdline.h     |  9 +++++----
 kernel/printk/printk.c              | 37 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 60 insertions(+), 11 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4df73da..7e65d5b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -696,30 +696,42 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
 	console=	[KNL] Output console device and options.
 
-		tty<n>	Use the virtual console device <n>.
+		tty<n>[,llX]	Use the virtual console device <n>.
 
-		ttyS<n>[,options]
-		ttyUSB0[,options]
+		ttyS<n>[,options][,llX]
+		ttyUSB0[,options][,llX]
 			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".
 
+			"llX" explained below,
+
 			See Documentation/serial-console.txt for more
 			information.  See
 			Documentation/networking/netconsole.txt for an
 			alternative.
 
-		uart[8250],io,<addr>[,options]
-		uart[8250],mmio,<addr>[,options]
+		uart[8250],io,<addr>[,options][,llX]
+		uart[8250],mmio,<addr>[,options][,llX]
 			Start an early, polled-mode console on the 8250/16550
 			UART at the specified I/O port or MMIO address,
 			switching to the matching ttyS device later.  The
 			options are the same as for ttyS, above.
-		hvc<n>	Use the hypervisor console device <n>. This is for
+
+			"llX" explained below,
+
+		hvc<n>[,llX]
+			Use the hypervisor console device <n>. This is for
 			both Xen and PowerPC hypervisors.
 
+			"llX" is used to define the loglevel per console. The "X"
+			defines the loglevel number for this console. The usage
+			is similar to the "loglevel=" option, and the effect is
+			the same only per console. The "loglevel=" option takes
+			precedence of this option.
+
                 If the device connected to the port is not a TTY but a braille
                 device, prepend "brl," before the device type, for instance
 			console=brl,ttyS0
diff --git a/include/linux/console.h b/include/linux/console.h
index 7571a16..99020d5 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -118,6 +118,7 @@ static inline int con_debug_leave(void)
 
 struct console {
 	char	name[16];
+	int	loglevel;
 	void	(*write)(struct console *, const char *, unsigned);
 	int	(*read)(struct console *, char *, unsigned);
 	struct tty_driver *(*device)(struct console *, int *);
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
index cbd69d8..6f6f98f 100644
--- a/kernel/printk/console_cmdline.h
+++ b/kernel/printk/console_cmdline.h
@@ -3,11 +3,12 @@
 
 struct console_cmdline
 {
-	char	name[8];			/* Name of the driver	    */
-	int	index;				/* Minor dev. to use	    */
-	char	*options;			/* Options for the driver   */
+	char	name[8];		/* Name of the driver		*/
+	int	index;			/* Minor dev. to use		*/
+	int	loglevel;		/* Log level for this console	*/
+	char	*options;		/* Options for the driver	*/
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-	char	*brl_options;			/* Options for braille driver */
+	char	*brl_options;		/* Options for braille driver	*/
 #endif
 };
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 02d6b6d..218d94d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1414,6 +1414,9 @@ static void call_console_drivers(int level, const char *text, size_t len)
 		if (!cpu_online(smp_processor_id()) &&
 		    !(con->flags & CON_ANYTIME))
 			continue;
+		if (con->loglevel && !ignore_loglevel &&
+		    level >= con->loglevel)
+			continue;
 		con->write(con, text, len);
 	}
 }
@@ -1925,6 +1928,33 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 }
 #endif
 
+
+char *setup_per_console_loglevel(struct console_cmdline *con, char *options)
+{
+	int size = options ? strlen(options) : 0;
+
+	if (size >= 3 &&
+	    options[size - 3] == 'l' &&
+	    options[size - 2] == 'l' &&
+	    options[size - 1] >=  '1' && options[size - 1] <= '9') {
+		con->loglevel = options[size - 1] - '0';
+
+		/* Catch if the user added a comma after some serial console
+		 * options,
+		 * i.e. console=ttyS0,9600n8,ll3
+		 * the first comma is gone at this point, but we need to delete
+		 * the second one.
+		 */
+		if (size > 3 && options[size - 4] == ',')
+			options[size - 4] = 0;
+		else
+			options[size - 3] = 0;
+	} else
+		con->loglevel = 0;
+
+	return options;
+}
+
 static int __add_preferred_console(char *name, int idx, char *options,
 				   char *brl_options)
 {
@@ -1949,12 +1979,15 @@ static int __add_preferred_console(char *name, int idx, char *options,
 	if (!brl_options)
 		selected_console = i;
 	strlcpy(c->name, name, sizeof(c->name));
-	c->options = options;
+
+	c->options = setup_per_console_loglevel(c, options);
+
 	braille_set_options(c, brl_options);
 
 	c->index = idx;
 	return 0;
 }
+
 /*
  * Set up a console.  Called via do_early_param() in init/main.c
  * for each "console=" parameter in the boot command line.
@@ -2478,6 +2511,8 @@ void register_console(struct console *newcon)
 		if (newcon->setup &&
 		    newcon->setup(newcon, console_cmdline[i].options) != 0)
 			break;
+
+		newcon->loglevel = c->loglevel;
 		newcon->flags |= CON_ENABLED;
 		newcon->index = c->index;
 		if (i == selected_console) {
-- 
1.9.1


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

* Re: [PATCH] printk: add per console loglevel
  2014-12-20 22:49 [PATCH] printk: add per console loglevel dwalker
@ 2014-12-21 18:47 ` Bruno Prémont
  2014-12-21 19:03   ` Joe Perches
  2014-12-23 16:20   ` dwalker
  2014-12-23 21:22 ` [PATCH 1/3] printk: Use a flag to indicate console-private loglevel Bruno Prémont
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 11+ messages in thread
From: Bruno Prémont @ 2014-12-21 18:47 UTC (permalink / raw)
  To: dwalker; +Cc: Andrew Morton, linux-kernel

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

On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> This adds to to the console= command line options allowing the
> addition of a per console log level setting.
> 
> examples,
> 
> 	console=ttyS0,ll4
> 	console=tty0,ll6
> 
> This can be used on systems which have multiple serial consoles, but
> it's desired for logging to be light on one and heavy on another.

Looks useful to me.
What would be the best way to make these per-console loglevels
configurable at runtime? `dmesg -n $LEVEL` only affects the global
limit.

One drawback to letting global loglevel have precedence is that
all consoles that should not get detailed log messages need to have
their loglevel explicitly lowered and it's not possible to have
one console forced to show more than the global loglevel.


An approach I would prefer is to have all consoles follow global
loglevel except when something different had been explicitly requested
for them.
This way a single console can be added later on (e.g. netconsole)
and set to pass through debug messages without affecting anyone else.

Bruno

> Signed-off-by: Daniel Walker <dwalker@fifo99.com>
> ---
>  Documentation/kernel-parameters.txt | 24 ++++++++++++++++++------
>  include/linux/console.h             |  1 +
>  kernel/printk/console_cmdline.h     |  9 +++++----
>  kernel/printk/printk.c              | 37 ++++++++++++++++++++++++++++++++++++-
>  4 files changed, 60 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index 4df73da..7e65d5b 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -696,30 +696,42 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>  
>  	console=	[KNL] Output console device and options.
>  
> -		tty<n>	Use the virtual console device <n>.
> +		tty<n>[,llX]	Use the virtual console device <n>.
>  
> -		ttyS<n>[,options]
> -		ttyUSB0[,options]
> +		ttyS<n>[,options][,llX]
> +		ttyUSB0[,options][,llX]
>  			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".
>  
> +			"llX" explained below,
> +
>  			See Documentation/serial-console.txt for more
>  			information.  See
>  			Documentation/networking/netconsole.txt for an
>  			alternative.
>  
> -		uart[8250],io,<addr>[,options]
> -		uart[8250],mmio,<addr>[,options]
> +		uart[8250],io,<addr>[,options][,llX]
> +		uart[8250],mmio,<addr>[,options][,llX]
>  			Start an early, polled-mode console on the 8250/16550
>  			UART at the specified I/O port or MMIO address,
>  			switching to the matching ttyS device later.  The
>  			options are the same as for ttyS, above.
> -		hvc<n>	Use the hypervisor console device <n>. This is for
> +
> +			"llX" explained below,
> +
> +		hvc<n>[,llX]
> +			Use the hypervisor console device <n>. This is for
>  			both Xen and PowerPC hypervisors.
>  
> +			"llX" is used to define the loglevel per console. The "X"
> +			defines the loglevel number for this console. The usage
> +			is similar to the "loglevel=" option, and the effect is
> +			the same only per console. The "loglevel=" option takes
> +			precedence of this option.
> +
>                  If the device connected to the port is not a TTY but a braille
>                  device, prepend "brl," before the device type, for instance
>  			console=brl,ttyS0
> diff --git a/include/linux/console.h b/include/linux/console.h
> index 7571a16..99020d5 100644
> --- a/include/linux/console.h
> +++ b/include/linux/console.h
> @@ -118,6 +118,7 @@ static inline int con_debug_leave(void)
>  
>  struct console {
>  	char	name[16];
> +	int	loglevel;
>  	void	(*write)(struct console *, const char *, unsigned);
>  	int	(*read)(struct console *, char *, unsigned);
>  	struct tty_driver *(*device)(struct console *, int *);
> diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
> index cbd69d8..6f6f98f 100644
> --- a/kernel/printk/console_cmdline.h
> +++ b/kernel/printk/console_cmdline.h
> @@ -3,11 +3,12 @@
>  
>  struct console_cmdline
>  {
> -	char	name[8];			/* Name of the driver	    */
> -	int	index;				/* Minor dev. to use	    */
> -	char	*options;			/* Options for the driver   */
> +	char	name[8];		/* Name of the driver		*/
> +	int	index;			/* Minor dev. to use		*/
> +	int	loglevel;		/* Log level for this console	*/
> +	char	*options;		/* Options for the driver	*/
>  #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
> -	char	*brl_options;			/* Options for braille driver */
> +	char	*brl_options;		/* Options for braille driver	*/
>  #endif
>  };
>  
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 02d6b6d..218d94d 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -1414,6 +1414,9 @@ static void call_console_drivers(int level, const char *text, size_t len)
>  		if (!cpu_online(smp_processor_id()) &&
>  		    !(con->flags & CON_ANYTIME))
>  			continue;
> +		if (con->loglevel && !ignore_loglevel &&
> +		    level >= con->loglevel)
> +			continue;
>  		con->write(con, text, len);
>  	}
>  }
> @@ -1925,6 +1928,33 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
>  }
>  #endif
>  
> +
> +char *setup_per_console_loglevel(struct console_cmdline *con, char *options)
> +{
> +	int size = options ? strlen(options) : 0;
> +
> +	if (size >= 3 &&
> +	    options[size - 3] == 'l' &&
> +	    options[size - 2] == 'l' &&
> +	    options[size - 1] >=  '1' && options[size - 1] <= '9') {
> +		con->loglevel = options[size - 1] - '0';
> +
> +		/* Catch if the user added a comma after some serial console
> +		 * options,
> +		 * i.e. console=ttyS0,9600n8,ll3
> +		 * the first comma is gone at this point, but we need to delete
> +		 * the second one.
> +		 */
> +		if (size > 3 && options[size - 4] == ',')
> +			options[size - 4] = 0;
> +		else
> +			options[size - 3] = 0;
> +	} else
> +		con->loglevel = 0;
> +
> +	return options;
> +}
> +
>  static int __add_preferred_console(char *name, int idx, char *options,
>  				   char *brl_options)
>  {
> @@ -1949,12 +1979,15 @@ static int __add_preferred_console(char *name, int idx, char *options,
>  	if (!brl_options)
>  		selected_console = i;
>  	strlcpy(c->name, name, sizeof(c->name));
> -	c->options = options;
> +
> +	c->options = setup_per_console_loglevel(c, options);
> +
>  	braille_set_options(c, brl_options);
>  
>  	c->index = idx;
>  	return 0;
>  }
> +
>  /*
>   * Set up a console.  Called via do_early_param() in init/main.c
>   * for each "console=" parameter in the boot command line.
> @@ -2478,6 +2511,8 @@ void register_console(struct console *newcon)
>  		if (newcon->setup &&
>  		    newcon->setup(newcon, console_cmdline[i].options) != 0)
>  			break;
> +
> +		newcon->loglevel = c->loglevel;
>  		newcon->flags |= CON_ENABLED;
>  		newcon->index = c->index;
>  		if (i == selected_console) {

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 648 bytes --]

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

* Re: [PATCH] printk: add per console loglevel
  2014-12-21 18:47 ` Bruno Prémont
@ 2014-12-21 19:03   ` Joe Perches
  2014-12-22  1:49     ` Lennart Sorensen
  2014-12-23 16:11     ` dwalker
  2014-12-23 16:20   ` dwalker
  1 sibling, 2 replies; 11+ messages in thread
From: Joe Perches @ 2014-12-21 19:03 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: dwalker, Andrew Morton, linux-kernel

On Sun, 2014-12-21 at 19:47 +0100, Bruno Prémont wrote:
> On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > This adds to to the console= command line options allowing the
> > addition of a per console log level setting.
> > 
> > examples,
> > 
> > 	console=ttyS0,ll4
> > 	console=tty0,ll6
> > 
> > This can be used on systems which have multiple serial consoles, but
> > it's desired for logging to be light on one and heavy on another.
> 
> Looks useful to me.

I think this is reasonable to, but for consistency
with other loglevel uses, I suggest using
loglevel=<level> instead of ll<d>



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

* Re: [PATCH] printk: add per console loglevel
  2014-12-21 19:03   ` Joe Perches
@ 2014-12-22  1:49     ` Lennart Sorensen
  2014-12-23 16:11     ` dwalker
  1 sibling, 0 replies; 11+ messages in thread
From: Lennart Sorensen @ 2014-12-22  1:49 UTC (permalink / raw)
  To: Joe Perches; +Cc: Bruno Prémont, dwalker, Andrew Morton, linux-kernel

On Sun, Dec 21, 2014 at 11:03:24AM -0800, Joe Perches wrote:
> On Sun, 2014-12-21 at 19:47 +0100, Bruno Prémont wrote:
> > On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > > This adds to to the console= command line options allowing the
> > > addition of a per console log level setting.
> > > 
> > > examples,
> > > 
> > > 	console=ttyS0,ll4
> > > 	console=tty0,ll6
> > > 
> > > This can be used on systems which have multiple serial consoles, but
> > > it's desired for logging to be light on one and heavy on another.
> > 
> > Looks useful to me.
> 
> I think this is reasonable to, but for consistency
> with other loglevel uses, I suggest using
> loglevel=<level> instead of ll<d>

Oh those are l not 1.  I read that as ,114 and ,116 and was wondering
what that meant.

-- 
Len Sorensen

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

* Re: [PATCH] printk: add per console loglevel
  2014-12-21 19:03   ` Joe Perches
  2014-12-22  1:49     ` Lennart Sorensen
@ 2014-12-23 16:11     ` dwalker
  1 sibling, 0 replies; 11+ messages in thread
From: dwalker @ 2014-12-23 16:11 UTC (permalink / raw)
  To: Joe Perches; +Cc: Bruno Prémont, Andrew Morton, linux-kernel

On Sun, Dec 21, 2014 at 11:03:24AM -0800, Joe Perches wrote:
> On Sun, 2014-12-21 at 19:47 +0100, Bruno Prémont wrote:
> > On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > > This adds to to the console= command line options allowing the
> > > addition of a per console log level setting.
> > > 
> > > examples,
> > > 
> > > 	console=ttyS0,ll4
> > > 	console=tty0,ll6
> > > 
> > > This can be used on systems which have multiple serial consoles, but
> > > it's desired for logging to be light on one and heavy on another.
> > 
> > Looks useful to me.
> 
> I think this is reasonable to, but for consistency
> with other loglevel uses, I suggest using
> loglevel=<level> instead of ll<d>
> 

I can try it, I didn't do it initially because I didn't want to confuse the parsing of the other
parameters ..

Daniel

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

* Re: [PATCH] printk: add per console loglevel
  2014-12-21 18:47 ` Bruno Prémont
  2014-12-21 19:03   ` Joe Perches
@ 2014-12-23 16:20   ` dwalker
  2014-12-23 21:13     ` Bruno Prémont
  1 sibling, 1 reply; 11+ messages in thread
From: dwalker @ 2014-12-23 16:20 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: Andrew Morton, linux-kernel

On Sun, Dec 21, 2014 at 07:47:53PM +0100, Bruno Prémont wrote:
> On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > This adds to to the console= command line options allowing the
> > addition of a per console log level setting.
> > 
> > examples,
> > 
> > 	console=ttyS0,ll4
> > 	console=tty0,ll6
> > 
> > This can be used on systems which have multiple serial consoles, but
> > it's desired for logging to be light on one and heavy on another.
> 
> Looks useful to me.
> What would be the best way to make these per-console loglevels
> configurable at runtime? `dmesg -n $LEVEL` only affects the global
> limit.
> 
> One drawback to letting global loglevel have precedence is that
> all consoles that should not get detailed log messages need to have
> their loglevel explicitly lowered and it's not possible to have
> one console forced to show more than the global loglevel.

Right, reason for the patch.
 
> 
> An approach I would prefer is to have all consoles follow global
> loglevel except when something different had been explicitly requested
> for them.

This patch is mostly like this. It breaks down when you set the "llX"
parameter to something above KERN_NOTICE, and the global one is also
set above that.

> This way a single console can be added later on (e.g. netconsole)
> and set to pass through debug messages without affecting anyone else.

Not following the "added later" part.

Daniel

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

* Re: [PATCH] printk: add per console loglevel
  2014-12-23 16:20   ` dwalker
@ 2014-12-23 21:13     ` Bruno Prémont
  2015-01-04 20:19       ` dwalker
  0 siblings, 1 reply; 11+ messages in thread
From: Bruno Prémont @ 2014-12-23 21:13 UTC (permalink / raw)
  To: dwalker; +Cc: Andrew Morton, linux-kernel

On Tue, 23 December 2014 dwalker@fifo99.com wrote:
> On Sun, Dec 21, 2014 at 07:47:53PM +0100, Bruno Prémont wrote:
> > On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > > This adds to to the console= command line options allowing the
> > > addition of a per console log level setting.
> > > 
> > > examples,
> > > 
> > > 	console=ttyS0,ll4
> > > 	console=tty0,ll6
> > > 
> > > This can be used on systems which have multiple serial consoles, but
> > > it's desired for logging to be light on one and heavy on another.
> > 
> > Looks useful to me.
> > What would be the best way to make these per-console loglevels
> > configurable at runtime? `dmesg -n $LEVEL` only affects the global
> > limit.
> > 
> > One drawback to letting global loglevel have precedence is that
> > all consoles that should not get detailed log messages need to have
> > their loglevel explicitly lowered and it's not possible to have
> > one console forced to show more than the global loglevel.
> 
> Right, reason for the patch.
>  
> > 
> > An approach I would prefer is to have all consoles follow global
> > loglevel except when something different had been explicitly requested
> > for them.
> 
> This patch is mostly like this. It breaks down when you set the "llX"
> parameter to something above KERN_NOTICE, and the global one is also
> set above that.

In your patch global filter applies first, then what passes global filter
gets filtered with the per-console filter.

So I can't have `dmesg -n 3` and "console=ttyS0,ll8 console=tty0"
to get my debugging output over serial console.

> > This way a single console can be added later on (e.g. netconsole)
> > and set to pass through debug messages without affecting anyone else.

Netconsole console can be added at any time when system is running
either through loading of its module or using dynamic configuration
via configfs.

See also my patches.

Thanks,
Bruno

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

* [PATCH 1/3] printk: Use a flag to indicate console-private loglevel
  2014-12-20 22:49 [PATCH] printk: add per console loglevel dwalker
  2014-12-21 18:47 ` Bruno Prémont
@ 2014-12-23 21:22 ` Bruno Prémont
  2014-12-23 21:27 ` [PATCH 2/3] netconsole: make loglevel configurable per target Bruno Prémont
  2014-12-23 21:37 ` [PATCH 3/3] netconsole: New console flag to dump full log buffer Bruno Prémont
  3 siblings, 0 replies; 11+ messages in thread
From: Bruno Prémont @ 2014-12-23 21:22 UTC (permalink / raw)
  To: dwalker; +Cc: linux-kernel, Andrew Morton, Joe Perches

In order to set loglevel for a given console that is not affected by
global loglevel as adjusted via syslog(2), add a flag to the console and
choose the level to match against msg level depending on this flag.

Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
---
This depends on Daniel's patch "printk: add per console loglevel"
and modifies the way its filtering is applied.


 include/linux/console.h |  1 +
 kernel/printk/printk.c  | 12 ++++++------
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index 99020d5..f3a8996 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -115,6 +115,7 @@ static inline int con_debug_leave(void)
 #define CON_BOOT	(8)
 #define CON_ANYTIME	(16) /* Safe to call when cpu is offline */
 #define CON_BRL		(32) /* Used for a braille device */
+#define CON_LOGLEVEL	(64) /* Per-console log-level filtering */
 
 struct console {
 	char	name[16];
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 218d94d..8f09f30 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1399,12 +1399,12 @@ static void call_console_drivers(int level, const char *text, size_t len)
 
 	trace_console(text, len);
 
-	if (level >= console_loglevel && !ignore_loglevel)
-		return;
 	if (!console_drivers)
 		return;
 
 	for_each_console(con) {
+		if (!ignore_loglevel && level >= (con->flags & CON_LOGLEVEL ? con->loglevel : console_loglevel))
+			continue;
 		if (exclusive_console && con != exclusive_console)
 			continue;
 		if (!(con->flags & CON_ENABLED))
@@ -1414,9 +1414,6 @@ static void call_console_drivers(int level, const char *text, size_t len)
 		if (!cpu_online(smp_processor_id()) &&
 		    !(con->flags & CON_ANYTIME))
 			continue;
-		if (con->loglevel && !ignore_loglevel &&
-		    level >= con->loglevel)
-			continue;
 		con->write(con, text, len);
 	}
 }
@@ -2512,7 +2509,10 @@ void register_console(struct console *newcon)
 		    newcon->setup(newcon, console_cmdline[i].options) != 0)
 			break;
 
-		newcon->loglevel = c->loglevel;
+		if (c->loglevel) {
+			newcon->loglevel = c->loglevel;
+			newcon->flags |= CON_LOGLEVEL;
+		}
 		newcon->flags |= CON_ENABLED;
 		newcon->index = c->index;
 		if (i == selected_console) {
-- 
2.0.4


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

* [PATCH 2/3] netconsole: make loglevel configurable per target
  2014-12-20 22:49 [PATCH] printk: add per console loglevel dwalker
  2014-12-21 18:47 ` Bruno Prémont
  2014-12-23 21:22 ` [PATCH 1/3] printk: Use a flag to indicate console-private loglevel Bruno Prémont
@ 2014-12-23 21:27 ` Bruno Prémont
  2014-12-23 21:37 ` [PATCH 3/3] netconsole: New console flag to dump full log buffer Bruno Prémont
  3 siblings, 0 replies; 11+ messages in thread
From: Bruno Prémont @ 2014-12-23 21:27 UTC (permalink / raw)
  To: dwalker, Matt Mackall, Satyam Sharma, Cong Wang
  Cc: linux-kernel, Andrew Morton, Joe Perches

Switch to registering a new console for each target so that loglevel
based message filtering can be set individually for each target.

This adds a new loglevel= option to netconsole module parameter and also
add a configfs file to configure the loglevel.

The loglevel conf be adjusted at any time for synamic netconsole
consoles.

Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
---
Note: only configuration via configfs has been runtime-tested.

 Documentation/networking/netconsole.txt |  11 ++-
 drivers/net/netconsole.c                | 114 +++++++++++++++++++++++---------
 2 files changed, 94 insertions(+), 31 deletions(-)

diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index a5d574a..c1df516 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -24,7 +24,7 @@ Sender and receiver configuration:
 It takes a string configuration parameter "netconsole" in the
 following format:
 
- netconsole=[src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]
+ netconsole=[src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr][,loglevel=level]
 
    where
         src-port      source for UDP packets (defaults to 6665)
@@ -33,6 +33,9 @@ following format:
         tgt-port      port for logging agent (6666)
         tgt-ip        IP address for logging agent
         tgt-macaddr   ethernet MAC address for logging agent (broadcast)
+        level         limit messages printed to those whose loglevel is
+                      smaller that value, range is 1 to 8
+                      If missing, loglevel limit as set via syslog(1) applies
 
 Examples:
 
@@ -114,11 +117,16 @@ The interface exposes these parameters of a netconsole target to userspace:
 	remote_ip	Remote agent's IP address		(read-write)
 	local_mac	Local interface's MAC address		(read-only)
 	remote_mac	Remote agent's MAC address		(read-write)
+	loglevel        Console loglevel filter                 (read-write)
 
 The "enabled" attribute is also used to control whether the parameters of
 a target can be updated or not -- you can modify the parameters of only
 disabled targets (i.e. if "enabled" is 0).
 
+The "loglevel" parameter can be set at any time. When set to "0" it will
+read back as empty string and global loglevel filter applies. Otherwise
+specified loglevel filter applies.
+
 To update a target's parameters:
 
  cat enabled				# check if enabled is 1
@@ -164,6 +172,7 @@ priority messages to the console. You can change this at runtime using:
 
  dmesg -n 8
 
+or by specifying netconsole loglevel parameter
 or by specifying "debug" on the kernel command line at boot, to send
 all kernel messages to the console. A specific value for this parameter
 can also be set using the "loglevel" kernel boot option. See the
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index ba2f5e7..a96cd8e 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -103,10 +103,12 @@ struct netconsole_target {
 #ifdef	CONFIG_NETCONSOLE_DYNAMIC
 	struct config_item	item;
 #endif
+	struct console		console;
 	int			enabled;
 	struct mutex		mutex;
 	struct netpoll		np;
 };
+static void write_msg(struct console *con, const char *msg, unsigned int len);
 
 #ifdef	CONFIG_NETCONSOLE_DYNAMIC
 
@@ -171,6 +173,7 @@ static struct netconsole_target *alloc_param_target(char *target_config)
 {
 	int err = -ENOMEM;
 	struct netconsole_target *nt;
+	char *loglevel;
 
 	/*
 	 * Allocate and initialize with defaults.
@@ -186,8 +189,26 @@ static struct netconsole_target *alloc_param_target(char *target_config)
 	nt->np.remote_port = 6666;
 	mutex_init(&nt->mutex);
 	memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+	snprintf(nt->console.name, sizeof(nt->console.name), "netcon");
+	/* Dump existing printks when we register */
+	nt->console.flags = CON_ENABLED | CON_PRINTBUFFER;
+	nt->console.write = write_msg;
 
 	/* Parse parameters and setup netpoll */
+	loglevel = strstr(target_config, ",loglevel=");
+	if (loglevel) {
+		int level;
+		err = kstrtoint(loglevel+10, 10, &level);
+		if (err < 0)
+			goto fail;
+		if (level < 1 || level > 8) {
+			err = -EINVAL;
+			goto fail;
+		}
+		nt->console.loglevel = level;
+		nt->console.flags |= CON_LOGLEVEL;
+		*loglevel = '\0';
+	}
 	err = netpoll_parse_options(&nt->np, target_config);
 	if (err)
 		goto fail;
@@ -228,6 +249,7 @@ static void free_param_target(struct netconsole_target *nt)
  *				|	remote_ip
  *				|	local_mac
  *				|	remote_mac
+ *				|	loglevel
  *				|
  *				<target>/...
  */
@@ -301,6 +323,14 @@ static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
 	return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac);
 }
 
+static ssize_t show_loglevel(struct netconsole_target *nt, char *buf)
+{
+	if (nt->console.flags & CON_LOGLEVEL)
+		return snprintf(buf, PAGE_SIZE, "%u\n", nt->console.loglevel);
+	else
+		return snprintf(buf, PAGE_SIZE, "\n");
+}
+
 /*
  * This one is special -- targets created through the configfs interface
  * are not enabled (and the corresponding netpoll activated) by default.
@@ -338,6 +368,8 @@ static ssize_t store_enabled(struct netconsole_target *nt,
 		if (err)
 			return err;
 
+		nt->enabled = 1;
+		register_console(&nt->console);
 		pr_info("netconsole: network logging started\n");
 	} else {	/* 0 */
 		/* We need to disable the netconsole before cleaning it up
@@ -347,11 +379,11 @@ static ssize_t store_enabled(struct netconsole_target *nt,
 		spin_lock_irqsave(&target_list_lock, flags);
 		nt->enabled = 0;
 		spin_unlock_irqrestore(&target_list_lock, flags);
+		unregister_console(&nt->console);
 		netpoll_cleanup(&nt->np);
+		nt->console.flags = nt->console.flags & ~CON_PRINTBUFFER;
 	}
 
-	nt->enabled = enabled;
-
 	return strnlen(buf, count);
 }
 
@@ -494,6 +526,27 @@ static ssize_t store_remote_mac(struct netconsole_target *nt,
 	return strnlen(buf, count);
 }
 
+static ssize_t store_loglevel(struct netconsole_target *nt,
+				 const char *buf,
+				 size_t count)
+{
+	int rv, level;
+
+	rv = kstrtoint(buf, 10, &level);
+	if (rv < 0)
+		return rv;
+	if (level < 0 || level > 8)
+		return -EINVAL;
+
+	if (level > 0) {
+		nt->console.loglevel = level;
+		nt->console.flags |= CON_LOGLEVEL;
+	} else
+		nt->console.flags &= ~CON_LOGLEVEL;
+
+	return strnlen(buf, count);
+}
+
 /*
  * Attribute definitions for netconsole_target.
  */
@@ -514,6 +567,7 @@ NETCONSOLE_TARGET_ATTR_RW(local_ip);
 NETCONSOLE_TARGET_ATTR_RW(remote_ip);
 NETCONSOLE_TARGET_ATTR_RO(local_mac);
 NETCONSOLE_TARGET_ATTR_RW(remote_mac);
+NETCONSOLE_TARGET_ATTR_RW(loglevel);
 
 static struct configfs_attribute *netconsole_target_attrs[] = {
 	&netconsole_target_enabled.attr,
@@ -524,6 +578,7 @@ static struct configfs_attribute *netconsole_target_attrs[] = {
 	&netconsole_target_remote_ip.attr,
 	&netconsole_target_local_mac.attr,
 	&netconsole_target_remote_mac.attr,
+	&netconsole_target_loglevel.attr,
 	NULL,
 };
 
@@ -605,6 +660,10 @@ static struct config_item *make_netconsole_target(struct config_group *group,
 	nt->np.remote_port = 6666;
 	mutex_init(&nt->mutex);
 	memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+	snprintf(nt->console.name, sizeof(nt->console.name), "netcon-%s", name);
+	nt->console.flags = CON_ENABLED;
+	nt->console.write = write_msg;
+	nt->console.loglevel = 0;
 
 	/* Initialize the config_item member */
 	config_item_init_type_name(&nt->item, name, &netconsole_target_type);
@@ -626,6 +685,7 @@ static void drop_netconsole_target(struct config_group *group,
 	spin_lock_irqsave(&target_list_lock, flags);
 	list_del(&nt->list);
 	spin_unlock_irqrestore(&target_list_lock, flags);
+	unregister_console(&nt->console);
 
 	/*
 	 * The target may have never been enabled, or was manually disabled
@@ -732,7 +792,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 {
 	int frag, left;
 	unsigned long flags;
-	struct netconsole_target *nt;
+	struct netconsole_target *nt = container_of(con, struct netconsole_target, console);
 	const char *tmp;
 
 	if (oops_only && !oops_in_progress)
@@ -742,34 +802,26 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 		return;
 
 	spin_lock_irqsave(&target_list_lock, flags);
-	list_for_each_entry(nt, &target_list, list) {
-		netconsole_target_get(nt);
-		if (nt->enabled && netif_running(nt->np.dev)) {
-			/*
-			 * We nest this inside the for-each-target loop above
-			 * so that we're able to get as much logging out to
-			 * at least one target if we die inside here, instead
-			 * of unnecessarily keeping all targets in lock-step.
-			 */
-			tmp = msg;
-			for (left = len; left;) {
-				frag = min(left, MAX_PRINT_CHUNK);
-				netpoll_send_udp(&nt->np, tmp, frag);
-				tmp += frag;
-				left -= frag;
-			}
+	netconsole_target_get(nt);
+	if (nt->enabled && netif_running(nt->np.dev)) {
+		/*
+		 * We nest this inside the for-each-target loop above
+		 * so that we're able to get as much logging out to
+		 * at least one target if we die inside here, instead
+		 * of unnecessarily keeping all targets in lock-step.
+		 */
+		tmp = msg;
+		for (left = len; left;) {
+			frag = min(left, MAX_PRINT_CHUNK);
+			netpoll_send_udp(&nt->np, tmp, frag);
+			tmp += frag;
+			left -= frag;
 		}
-		netconsole_target_put(nt);
 	}
+	netconsole_target_put(nt);
 	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
-static struct console netconsole = {
-	.name	= "netcon",
-	.flags	= CON_ENABLED,
-	.write	= write_msg,
-};
-
 static int __init init_netconsole(void)
 {
 	int err;
@@ -785,8 +837,6 @@ static int __init init_netconsole(void)
 				err = PTR_ERR(nt);
 				goto fail;
 			}
-			/* Dump existing printks when we register */
-			netconsole.flags |= CON_PRINTBUFFER;
 
 			spin_lock_irqsave(&target_list_lock, flags);
 			list_add(&nt->list, &target_list);
@@ -802,7 +852,9 @@ static int __init init_netconsole(void)
 	if (err)
 		goto undonotifier;
 
-	register_console(&netconsole);
+	list_for_each_entry_safe(nt, tmp, &target_list, list) {
+		register_console(&nt->console);
+	}
 	pr_info("network logging started\n");
 
 	return err;
@@ -830,7 +882,9 @@ static void __exit cleanup_netconsole(void)
 {
 	struct netconsole_target *nt, *tmp;
 
-	unregister_console(&netconsole);
+	list_for_each_entry_safe(nt, tmp, &target_list, list) {
+		unregister_console(&nt->console);
+	}
 	dynamic_netconsole_exit();
 	unregister_netdevice_notifier(&netconsole_netdev_notifier);
 
-- 
2.0.4


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

* [PATCH 3/3] netconsole: New console flag to dump full log buffer
  2014-12-20 22:49 [PATCH] printk: add per console loglevel dwalker
                   ` (2 preceding siblings ...)
  2014-12-23 21:27 ` [PATCH 2/3] netconsole: make loglevel configurable per target Bruno Prémont
@ 2014-12-23 21:37 ` Bruno Prémont
  3 siblings, 0 replies; 11+ messages in thread
From: Bruno Prémont @ 2014-12-23 21:37 UTC (permalink / raw)
  To: dwalker, Matt Mackall, Satyam Sharma, Cong Wang
  Cc: linux-kernel, Andrew Morton, Joe Perches

Be default only log messages not yet seen by userspace are output when
enabling netconsole via module parameter (none when enabling dynamic
targets).

When using netconsole to centrally log kernel messages it's of interest
to have the whole kernel log sent over the same medium, even if netconsole
setup happens rather late during system boot. The big advantage of netconsole
over syslog for this task is that it usually allow catching much more
messages when system crashes/panics.

This causes dynamic netconsoles to request full kernel log when first
enabled.

Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
---
Note, with this kernel is too quick at sending packets for some receiving
machines to catch all of them. Either packets get dropped by the receiving
NIC if can't buffer enough until OS has time to empty the buffers or they
get lost between kernel and userspace socket if backlog is too small.

My test environment was 4core AMD APU with Gbit NIC to Marvell Kirkwood
SheevaPlug with Gbit NIC. About first 100 lines get through, then lines
start getting lost.

 drivers/net/netconsole.c |  3 ++-
 include/linux/console.h  |  1 +
 kernel/printk/printk.c   | 12 +++++++++---
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index a96cd8e..241c70f 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -661,7 +661,8 @@ static struct config_item *make_netconsole_target(struct config_group *group,
 	mutex_init(&nt->mutex);
 	memset(nt->np.remote_mac, 0xff, ETH_ALEN);
 	snprintf(nt->console.name, sizeof(nt->console.name), "netcon-%s", name);
-	nt->console.flags = CON_ENABLED;
+	/* Dump existing printks when we register */
+	nt->console.flags = CON_ENABLED | CON_PRINTBUFFER | CON_PRINTALL;
 	nt->console.write = write_msg;
 	nt->console.loglevel = 0;
 
diff --git a/include/linux/console.h b/include/linux/console.h
index f3a8996..6f53a54 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -116,6 +116,7 @@ static inline int con_debug_leave(void)
 #define CON_ANYTIME	(16) /* Safe to call when cpu is offline */
 #define CON_BRL		(32) /* Used for a braille device */
 #define CON_LOGLEVEL	(64) /* Per-console log-level filtering */
+#define CON_PRINTALL	(128) /* Extends CON_PRINTBUFFER */
 
 struct console {
 	char	name[16];
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8f09f30..193665d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2554,9 +2554,15 @@ void register_console(struct console *newcon)
 		 * for us.
 		 */
 		raw_spin_lock_irqsave(&logbuf_lock, flags);
-		console_seq = syslog_seq;
-		console_idx = syslog_idx;
-		console_prev = syslog_prev;
+		if (newcon->flags & CON_PRINTALL) {
+			console_seq = log_first_seq;
+			console_idx = log_first_idx;
+			console_prev = LOG_NEWLINE;
+		} else {
+			console_seq = syslog_seq;
+			console_idx = syslog_idx;
+			console_prev = syslog_prev;
+		}
 		raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 		/*
 		 * We're about to replay the log buffer.  Only do this to the
-- 
2.0.4


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

* Re: [PATCH] printk: add per console loglevel
  2014-12-23 21:13     ` Bruno Prémont
@ 2015-01-04 20:19       ` dwalker
  0 siblings, 0 replies; 11+ messages in thread
From: dwalker @ 2015-01-04 20:19 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: Andrew Morton, linux-kernel

On Tue, Dec 23, 2014 at 10:13:24PM +0100, Bruno Prémont wrote:
> On Tue, 23 December 2014 dwalker@fifo99.com wrote:
> > On Sun, Dec 21, 2014 at 07:47:53PM +0100, Bruno Prémont wrote:
> > > On Sat, 20 December 2014 dwalker@fifo99.com wrote:
> > > > This adds to to the console= command line options allowing the
> > > > addition of a per console log level setting.
> > > > 
> > > > examples,
> > > > 
> > > > 	console=ttyS0,ll4
> > > > 	console=tty0,ll6
> > > > 
> > > > This can be used on systems which have multiple serial consoles, but
> > > > it's desired for logging to be light on one and heavy on another.
> > > 
> > > Looks useful to me.
> > > What would be the best way to make these per-console loglevels
> > > configurable at runtime? `dmesg -n $LEVEL` only affects the global
> > > limit.
> > > 
> > > One drawback to letting global loglevel have precedence is that
> > > all consoles that should not get detailed log messages need to have
> > > their loglevel explicitly lowered and it's not possible to have
> > > one console forced to show more than the global loglevel.
> > 
> > Right, reason for the patch.
> >  
> > > 
> > > An approach I would prefer is to have all consoles follow global
> > > loglevel except when something different had been explicitly requested
> > > for them.
> > 
> > This patch is mostly like this. It breaks down when you set the "llX"
> > parameter to something above KERN_NOTICE, and the global one is also
> > set above that.
> 
> In your patch global filter applies first, then what passes global filter
> gets filtered with the per-console filter.
> 
> So I can't have `dmesg -n 3` and "console=ttyS0,ll8 console=tty0"
> to get my debugging output over serial console.

Yeah .. This would improve things. I changed it after I sent the first patch, but it
looks like one of your patches changes it also.

I was a little concerned about altering the fast path in call_console_drivers().. With
the changes I made each call into call_console_drivers is forced to go thru the whole list
of consoles, instead of short circuiting prior to the list.
 
I was thinking the max local and global log level could be saved and used for short circuiting
instead of using the global log level.

> > > This way a single console can be added later on (e.g. netconsole)
> > > and set to pass through debug messages without affecting anyone else.
> 
> Netconsole console can be added at any time when system is running
> either through loading of its module or using dynamic configuration
> via configfs.
> 
> See also my patches.

Yeah, I saw them .. Not in too much detail, but it seems worth while for it to
work with netconsole.

Daniel

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

end of thread, other threads:[~2015-01-04 20:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-20 22:49 [PATCH] printk: add per console loglevel dwalker
2014-12-21 18:47 ` Bruno Prémont
2014-12-21 19:03   ` Joe Perches
2014-12-22  1:49     ` Lennart Sorensen
2014-12-23 16:11     ` dwalker
2014-12-23 16:20   ` dwalker
2014-12-23 21:13     ` Bruno Prémont
2015-01-04 20:19       ` dwalker
2014-12-23 21:22 ` [PATCH 1/3] printk: Use a flag to indicate console-private loglevel Bruno Prémont
2014-12-23 21:27 ` [PATCH 2/3] netconsole: make loglevel configurable per target Bruno Prémont
2014-12-23 21:37 ` [PATCH 3/3] netconsole: New console flag to dump full log buffer Bruno Prémont

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).