linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
@ 2020-02-06  4:02 Benjamin Herrenschmidt
  2020-02-11 14:41 ` Petr Mladek
  2020-02-13  5:52 ` Sergey Senozhatsky
  0 siblings, 2 replies; 6+ messages in thread
From: Benjamin Herrenschmidt @ 2020-02-06  4:02 UTC (permalink / raw)
  To: Petr Mladek; +Cc: Sergey Senozhatsky, linux-kernel

In the following circumstances, the rule of selecting the console
corresponding to the last "console=" entry on the command line as
the preferred console (CON_CONSDEV, ie, /dev/console) fails. This
is a specific example, but it could happen with different consoles
that have a similar name aliasing mechanism.

  - The kernel command line has both console=tty0 and console=ttyS0
    in that order (the latter with speed etc... arguments).
    This is common with some cloud setups such as Amazon Linux.

  - add_preferred_console is called early to register "uart0". In
    our case that happens from acpi_parse_spcr() on arm64 since the
    "enable_console" argument is true on that architecture. This causes
    "uart0" to become entry 0 of the console_cmdline array.

Now, because of the above, what happens is:

  - add_preferred_console is called by the cmdline parsing for tty0
    and ttyS0 respectively, thus occupying entries 1 and 2 of the
    console_cmdline array (since this happens after ACPI SPCR parsing).
    At that point preferred_console is set to 2 as expected.

  - When the tty layer kicks in, it will call register_console for tty0.
    This will match entry 1 in console_cmdline array. It isn't our preferred
    console but because it's our only console at this point, it will end up
    "first" in the consoles list.

  - When 8250 probes the actual serial port later on, it calls
    register_console for ttyS0. At that point the loop in register_console
    tries to match it with the entries in the console_cmdline array. Ideally
    this should match ttyS0 in entry 2, which is preferred, causing it to
    be inserted first and to replace tty0 as CONSDEV. However, 8250 provides
    a "match" hook in its struct console, and that hook will match "uart"
    as an alias to "ttyS". So we match uart0 at entry 0 in the array which
    is not the preferred console and will not match entry 2 which is since
    we break out of the loop on the first match. As a result, we don't set
    CONSDEV and don't insert it first, but second in the console list.

    As a result, we end up with tty0 remaining first in the array, and thus
    /dev/console going there instead of the last user specified one which
    is ttyS0.

This tentative fix register_console() to scan first for consoles
specified on the command line, and only if none is found, to then
scan for consoles specified by the architecture.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

v3. Refactor based on Petr suggestion
v2. Use a different logic to avoid calling match/setup multiple
    times as discussed with Petr.
---
 kernel/printk/console_cmdline.h |  1 +
 kernel/printk/printk.c          | 31 +++++++++++++++++++++----------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
index 11f19c466af5..3ca74ad391d6 100644
--- a/kernel/printk/console_cmdline.h
+++ b/kernel/printk/console_cmdline.h
@@ -6,6 +6,7 @@ struct console_cmdline
 {
 	char	name[16];			/* Name of the driver	    */
 	int	index;				/* Minor dev. to use	    */
+	bool	user_specified;			/* Specified by command line vs. platform */
 	char	*options;			/* Options for the driver   */
 #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
 	char	*brl_options;			/* Options for braille driver */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 17602d7b7ffc..5cf47a7b880c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2116,7 +2116,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
 #endif
 
 static int __add_preferred_console(char *name, int idx, char *options,
-				   char *brl_options)
+				   char *brl_options, bool user_specified)
 {
 	struct console_cmdline *c;
 	int i;
@@ -2131,6 +2131,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
 		if (strcmp(c->name, name) == 0 && c->index == idx) {
 			if (!brl_options)
 				preferred_console = i;
+                       if (user_specified)
+                               c->user_specified = true;
 			return 0;
 		}
 	}
@@ -2140,6 +2142,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
 		preferred_console = i;
 	strlcpy(c->name, name, sizeof(c->name));
 	c->options = options;
+	c->user_specified = user_specified;
 	braille_set_options(c, brl_options);
 
 	c->index = idx;
@@ -2194,7 +2197,7 @@ static int __init console_setup(char *str)
 	idx = simple_strtoul(s, NULL, 10);
 	*s = 0;
 
-	__add_preferred_console(buf, idx, options, brl_options);
+	__add_preferred_console(buf, idx, options, brl_options, true);
 	console_set_on_cmdline = 1;
 	return 1;
 }
@@ -2215,7 +2218,7 @@ __setup("console=", console_setup);
  */
 int add_preferred_console(char *name, int idx, char *options)
 {
-	return __add_preferred_console(name, idx, options, NULL);
+	return __add_preferred_console(name, idx, options, NULL, false);
 }
 
 bool console_suspend_enabled = true;
@@ -2636,7 +2639,7 @@ early_param("keep_bootcon", keep_bootcon_setup);
  * Care need to be taken with consoles that are statically
  * enabled such as netconsole
  */
-static int try_enable_new_console(struct console *newcon)
+static int try_enable_new_console(struct console *newcon, bool user_specified)
 {
 	struct console_cmdline *c;
 	int i;
@@ -2644,6 +2647,8 @@ static int try_enable_new_console(struct console *newcon)
 	for (i = 0, c = console_cmdline;
 	     i < MAX_CMDLINECONSOLES && c->name[0];
 	     i++, c++) {
+		if (c->user_specified != user_specified)
+			continue;
 		if (!newcon->match ||
 		    newcon->match(newcon, c->name, c->index, c->options) != 0) {
 			/* default matching */
@@ -2674,8 +2679,13 @@ static int try_enable_new_console(struct console *newcon)
 	/*
          * Some consoles, such as pstore and netconsole, can be enabled even
          * without matching.
+	 *
+	 * Note: We only do this test on the !user_specified pass so that such
+	 * a statically enabled console that isn't user specified gets a chance
+	 * to have its match() or setup() function called on our second pass
+	 * through this function.
          */
-        if (newcon->flags & CON_ENABLED)
+        if (newcon->flags & CON_ENABLED && !user_specified)
                 return 0;
 
 	return -ENOENT;
@@ -2752,11 +2762,12 @@ void register_console(struct console *newcon)
 		}
 	}
 
-	/*
-	 * See if this console matches one we selected on
-	 * the command line or if it was statically enabled
-	 */
-        err = try_enable_new_console(newcon);
+	/* See if this console matches one we selected on the command line */
+        err = try_enable_new_console(newcon, true);
+
+	/* If not, try to match against the platform default(s) */
+	if (err == -ENOENT)
+		err = try_enable_new_console(newcon, false);
 
         /* printk() messages are not printed to the Braille console. */
         if (err || newcon->flags & CON_BRL)



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

* Re: [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
  2020-02-06  4:02 [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches Benjamin Herrenschmidt
@ 2020-02-11 14:41 ` Petr Mladek
  2020-02-11 15:33   ` Benjamin Herrenschmidt
  2020-02-13  5:52 ` Sergey Senozhatsky
  1 sibling, 1 reply; 6+ messages in thread
From: Petr Mladek @ 2020-02-11 14:41 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Sergey Senozhatsky, linux-kernel

On Thu 2020-02-06 15:02:25, Benjamin Herrenschmidt wrote:
> In the following circumstances, the rule of selecting the console
> corresponding to the last "console=" entry on the command line as
> the preferred console (CON_CONSDEV, ie, /dev/console) fails. This
> is a specific example, but it could happen with different consoles
> that have a similar name aliasing mechanism.
> 
> This tentative fix register_console() to scan first for consoles
> specified on the command line, and only if none is found, to then
> scan for consoles specified by the architecture.
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 17602d7b7ffc..5cf47a7b880c 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2674,8 +2679,13 @@ static int try_enable_new_console(struct console *newcon)
>  	/*
>           * Some consoles, such as pstore and netconsole, can be enabled even
>           * without matching.
> +	 *
> +	 * Note: We only do this test on the !user_specified pass so that such
> +	 * a statically enabled console that isn't user specified gets a chance
> +	 * to have its match() or setup() function called on our second pass
> +	 * through this function.

I had some troubles to part the comment. I wonder if the following is
more clear:

	* Accept pre-enabled consoles only when match() and setup()
	* was called.

And I would do the same check as in the for cycle:

	if (newcon->flags & CON_ENABLED && c->user_specified ==	user_specified)
		return 0;

With the above change:

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

I could do the change when pushing if you agree and v4 is not needed
for other reasons.

Best Regards,
Petr

PS: JFYI, I am going to look at the 3rd patch tomorrow. I have to go now.

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

* Re: [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
  2020-02-11 14:41 ` Petr Mladek
@ 2020-02-11 15:33   ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 6+ messages in thread
From: Benjamin Herrenschmidt @ 2020-02-11 15:33 UTC (permalink / raw)
  To: Petr Mladek; +Cc: Sergey Senozhatsky, linux-kernel

On Tue, 2020-02-11 at 15:41 +0100, Petr Mladek wrote:
> 
> > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> > index 17602d7b7ffc..5cf47a7b880c 100644
> > --- a/kernel/printk/printk.c
> > +++ b/kernel/printk/printk.c
> > @@ -2674,8 +2679,13 @@ static int try_enable_new_console(struct console *newcon)
> >  	/*
> >           * Some consoles, such as pstore and netconsole, can be enabled even
> >           * without matching.
> > +	 *
> > +	 * Note: We only do this test on the !user_specified pass so that such
> > +	 * a statically enabled console that isn't user specified gets a chance
> > +	 * to have its match() or setup() function called on our second pass
> > +	 * through this function.
> 
> I had some troubles to part the comment. I wonder if the following is
> more clear:
> 
> 	* Accept pre-enabled consoles only when match() and setup()
> 	* was called.

Yeah the sentence is a bit convoluted, I agree. As for the fix, see
below

> And I would do the same check as in the for cycle:
> 
> 	if (newcon->flags & CON_ENABLED && c->user_specified ==	user_specified)
> 		return 0;

Fair enough, this is simpler.

> With the above change:
> 
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> 
> I could do the change when pushing if you agree and v4 is not needed
> for other reasons.

Of course. I'm travelling this week (which is why I somewhat rushed
sending you the patches last week, hence the glitches you noted), so I
won't have a chance to repost until sometime next week.

> 
> PS: JFYI, I am going to look at the 3rd patch tomorrow. I have to go now.

No worries. It's not super important, it's a minor thing I noticed
while testing (when I artifically make my consoles not match to test
the "default" fallback). It's not directly related to the fix in patch
2, but is completely standlaone.

Cheers,
Ben.



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

* Re: [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
  2020-02-06  4:02 [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches Benjamin Herrenschmidt
  2020-02-11 14:41 ` Petr Mladek
@ 2020-02-13  5:52 ` Sergey Senozhatsky
  2020-02-13  8:39   ` Petr Mladek
  1 sibling, 1 reply; 6+ messages in thread
From: Sergey Senozhatsky @ 2020-02-13  5:52 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Petr Mladek, Sergey Senozhatsky, linux-kernel

On (20/02/06 15:02), Benjamin Herrenschmidt wrote:
[..]
>  static int __add_preferred_console(char *name, int idx, char *options,
> -				   char *brl_options)
> +				   char *brl_options, bool user_specified)
>  {
>  	struct console_cmdline *c;
>  	int i;
> @@ -2131,6 +2131,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
>  		if (strcmp(c->name, name) == 0 && c->index == idx) {
>  			if (!brl_options)
>  				preferred_console = i;
> +                       if (user_specified)
> +                               c->user_specified = true;
>  			return 0;
>  		}
>  	}
> @@ -2140,6 +2142,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
>  		preferred_console = i;
>  	strlcpy(c->name, name, sizeof(c->name));
>  	c->options = options;
> +	c->user_specified = user_specified;
>  	braille_set_options(c, brl_options);
>  
>  	c->index = idx;
> @@ -2194,7 +2197,7 @@ static int __init console_setup(char *str)
>  	idx = simple_strtoul(s, NULL, 10);
>  	*s = 0;
>  
> -	__add_preferred_console(buf, idx, options, brl_options);
> +	__add_preferred_console(buf, idx, options, brl_options, true);
>  	console_set_on_cmdline = 1;
>  	return 1;
>  }
> @@ -2215,7 +2218,7 @@ __setup("console=", console_setup);
>   */
>  int add_preferred_console(char *name, int idx, char *options)
>  {
> -	return __add_preferred_console(name, idx, options, NULL);
> +	return __add_preferred_console(name, idx, options, NULL, false);
>  }

A silly question:

Can the same console first be added by
	console_setup()->__add_preferred_console(true)
and then by
	add_preferred_console()->__add_preferred_console(false)

	-ss

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

* Re: [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
  2020-02-13  5:52 ` Sergey Senozhatsky
@ 2020-02-13  8:39   ` Petr Mladek
  2020-02-13  9:09     ` Sergey Senozhatsky
  0 siblings, 1 reply; 6+ messages in thread
From: Petr Mladek @ 2020-02-13  8:39 UTC (permalink / raw)
  To: Sergey Senozhatsky; +Cc: Benjamin Herrenschmidt, linux-kernel

On Thu 2020-02-13 14:52:36, Sergey Senozhatsky wrote:
> On (20/02/06 15:02), Benjamin Herrenschmidt wrote:
> [..]
> >  static int __add_preferred_console(char *name, int idx, char *options,
> > -				   char *brl_options)
> > +				   char *brl_options, bool user_specified)
> >  {
> >  	struct console_cmdline *c;
> >  	int i;
> > @@ -2131,6 +2131,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
> >  		if (strcmp(c->name, name) == 0 && c->index == idx) {
> >  			if (!brl_options)
> >  				preferred_console = i;
> > +                       if (user_specified)
> > +                               c->user_specified = true;
> >  			return 0;
> >  		}
> >  	}
> > @@ -2140,6 +2142,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
> >  		preferred_console = i;
> >  	strlcpy(c->name, name, sizeof(c->name));
> >  	c->options = options;
> > +	c->user_specified = user_specified;
> >  	braille_set_options(c, brl_options);
> >  
> >  	c->index = idx;
> > @@ -2194,7 +2197,7 @@ static int __init console_setup(char *str)
> >  	idx = simple_strtoul(s, NULL, 10);
> >  	*s = 0;
> >  
> > -	__add_preferred_console(buf, idx, options, brl_options);
> > +	__add_preferred_console(buf, idx, options, brl_options, true);
> >  	console_set_on_cmdline = 1;
> >  	return 1;
> >  }
> > @@ -2215,7 +2218,7 @@ __setup("console=", console_setup);
> >   */
> >  int add_preferred_console(char *name, int idx, char *options)
> >  {
> > -	return __add_preferred_console(name, idx, options, NULL);
> > +	return __add_preferred_console(name, idx, options, NULL, false);
> >  }
> 
> A silly question:
> 
> Can the same console first be added by
> 	console_setup()->__add_preferred_console(true)
> and then by
> 	add_preferred_console()->__add_preferred_console(false)

I guess that this might happen. It should be safe because
user_specified flag is set only to true when found again,
see:

                       if (user_specified)
                               c->user_specified = true;

Best Regards,
Petr

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

* Re: [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches
  2020-02-13  8:39   ` Petr Mladek
@ 2020-02-13  9:09     ` Sergey Senozhatsky
  0 siblings, 0 replies; 6+ messages in thread
From: Sergey Senozhatsky @ 2020-02-13  9:09 UTC (permalink / raw)
  To: Petr Mladek; +Cc: Sergey Senozhatsky, Benjamin Herrenschmidt, linux-kernel

On (20/02/13 09:39), Petr Mladek wrote:
> > >  	struct console_cmdline *c;
> > >  	int i;
> > > @@ -2131,6 +2131,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
> > >  		if (strcmp(c->name, name) == 0 && c->index == idx) {
> > >  			if (!brl_options)
> > >  				preferred_console = i;
> > > +                       if (user_specified)
> > > +                               c->user_specified = true;
> > >  			return 0;
> > >  		}
> > >  	}

[..]

> > A silly question:
> > 
> > Can the same console first be added by
> > 	console_setup()->__add_preferred_console(true)
> > and then by
> > 	add_preferred_console()->__add_preferred_console(false)
> 
> I guess that this might happen. It should be safe because
> user_specified flag is set only to true when found again,
> see:
> 
>                        if (user_specified)
>                                c->user_specified = true;

Yikes, I didn't see the if-condition. Yes, you are right.

	-ss

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

end of thread, other threads:[~2020-02-13  9:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06  4:02 [PATCH v3 2/3] printk: Fix preferred console selection with multiple matches Benjamin Herrenschmidt
2020-02-11 14:41 ` Petr Mladek
2020-02-11 15:33   ` Benjamin Herrenschmidt
2020-02-13  5:52 ` Sergey Senozhatsky
2020-02-13  8:39   ` Petr Mladek
2020-02-13  9:09     ` Sergey Senozhatsky

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