[PATCH 1/2] printk: Track command line console positions to fix console order

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Recent changes to allow using DEVNAME:0.0 style console names caused a
regression to the kernel command line handling for the console options.

The last preferred console added gets used for init. This is documented
in the comments for add_preferred_console(). Now the kernel command line
options for console=ttyS0,115200 console=tty0 are wrongly handled and
cause the /dev/console to be associated with ttyS0 instead of tty0.

This happens because we are calling __add_preferred_console() later on
from serial8250_isa_init_ports() after console_setup() and the console
gets treated as the last added preferred console. As the DEVNAME:0.0 style
console device is not known at console_setup() time, and we need to call
__add_preferred_console() later.

Let's fix the issue by reserving a position in console_cmdline for a
deferred console, and then populate the reserved entry before calling
__add_preferred_console().

Note that we now need to check for valid preferred console too in
__add_preferred_console().

Reported-by: Petr Mladek <pmladek@xxxxxxxx>
Link: https://lore.kernel.org/linux-serial/ZlC6_Um4P4b-_WQE@xxxxxxxxxxxxxxx/
Fixes: f03e8c1060f8 ("printk: Save console options for add_preferred_console_match()")
Signed-off-by: Tony Lindgren <tony.lindgren@xxxxxxxxxxxxxxx>
---
 kernel/printk/conopt.c          |  2 +-
 kernel/printk/console_cmdline.h |  6 ++-
 kernel/printk/printk.c          | 68 ++++++++++++++++++++++++++++++---
 3 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/kernel/printk/conopt.c b/kernel/printk/conopt.c
index 9d507bac3657..08dded8fbb3b 100644
--- a/kernel/printk/conopt.c
+++ b/kernel/printk/conopt.c
@@ -140,7 +140,7 @@ int add_preferred_console_match(const char *match, const char *name,
 	if (con->has_brl_opt)
 		brl_opt = con->brl_opt;
 
-	console_opt_add_preferred_console(name, idx, con->opt, brl_opt);
+	console_opt_add_preferred_console(match, name, idx, con->opt, brl_opt);
 
 	return 0;
 }
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
index a125e0235589..e22021e3e28b 100644
--- a/kernel/printk/console_cmdline.h
+++ b/kernel/printk/console_cmdline.h
@@ -5,13 +5,15 @@
 #define MAX_CMDLINECONSOLES 8
 
 int console_opt_save(const char *str, const char *brl_opt);
-int console_opt_add_preferred_console(const char *name, const short idx,
-				      char *options, char *brl_options);
+int console_opt_add_preferred_console(const char *devname, const char *name,
+				      const short idx, char *options,
+				      char *brl_options);
 
 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 */
 	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 420fd310129d..52bdd7dcdb6f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2426,6 +2426,24 @@ static void set_user_specified(struct console_cmdline *c, bool user_specified)
 	console_set_on_cmdline = 1;
 }
 
+/* Checks if a console is the last user specified preferred console */
+static bool is_last_user_prefcon(int position)
+{
+	struct console_cmdline *c = console_cmdline;
+	int last_user_specified = -1;
+	int i;
+
+	for (i = 0; i < MAX_CMDLINECONSOLES; i++, c++) {
+		if (!c->name[0] && !c->devname[0])
+			break;
+
+		if (c->user_specified || c->devname[0])
+			last_user_specified = i;
+	}
+
+	return position == last_user_specified;
+}
+
 static int __add_preferred_console(const char *name, const short idx, char *options,
 				   char *brl_options, bool user_specified)
 {
@@ -2445,10 +2463,10 @@ static int __add_preferred_console(const char *name, const short idx, char *opti
 	 *	if we have a slot free.
 	 */
 	for (i = 0, c = console_cmdline;
-	     i < MAX_CMDLINECONSOLES && c->name[0];
+	     i < MAX_CMDLINECONSOLES && (c->name[0] || c->devname[0]);
 	     i++, c++) {
 		if (strcmp(c->name, name) == 0 && c->index == idx) {
-			if (!brl_options)
+			if (!brl_options && (!user_specified || is_last_user_prefcon(i)))
 				preferred_console = i;
 			set_user_specified(c, user_specified);
 			return 0;
@@ -2467,6 +2485,25 @@ static int __add_preferred_console(const char *name, const short idx, char *opti
 	return 0;
 }
 
+/* Reserves a console_cmdline position for a deferred devname console */
+static void reserve_deferred_console(const char *str)
+{
+	struct console_cmdline *c = console_cmdline;
+	size_t namelen;
+	int i;
+
+	namelen = strcspn(str, ",");
+	if (namelen == 0 || namelen >= sizeof(c->devname))
+		return;
+
+	for (i = 0; i < MAX_CMDLINECONSOLES; i++, c++) {
+		if (c->name[0] || c->devname[0])
+			continue;
+		strscpy(c->devname, str, namelen + 1);
+		return;
+	}
+}
+
 static int __init console_msg_format_setup(char *str)
 {
 	if (!strcmp(str, "syslog"))
@@ -2508,8 +2545,10 @@ static int __init console_setup(char *str)
 	console_set_on_cmdline = 1;
 
 	/* Don't attempt to parse a DEVNAME:0.0 style console */
-	if (strchr(str, ':'))
+	if (strchr(str, ':')) {
+		reserve_deferred_console(str);
 		return 1;
+	}
 
 	/*
 	 * Decode str into name, index, options.
@@ -2542,9 +2581,26 @@ static int __init console_setup(char *str)
 __setup("console=", console_setup);
 
 /* Only called from add_preferred_console_match() */
-int console_opt_add_preferred_console(const char *name, const short idx,
-				      char *options, char *brl_options)
+int console_opt_add_preferred_console(const char *devname, const char *name,
+				      const short idx, char *options,
+				      char *brl_options)
 {
+	struct console_cmdline *c = console_cmdline;
+	int i;
+
+	/* Populate a reserved console based on devname */
+	for (i = 0; i < MAX_CMDLINECONSOLES; i++, c++) {
+		if (!c->name[0] && !strcmp(c->devname, devname)) {
+			strscpy(c->name, name);
+			c->index = idx;
+			c->options = options;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+			c->brl_options = brl_options;
+#endif
+			break;
+		}
+	}
+
 	return __add_preferred_console(name, idx, options, brl_options, true);
 }
 
@@ -3333,7 +3389,7 @@ static int try_enable_preferred_console(struct console *newcon,
 	int i, err;
 
 	for (i = 0, c = console_cmdline;
-	     i < MAX_CMDLINECONSOLES && c->name[0];
+	     i < MAX_CMDLINECONSOLES && (c->name[0] || c->devname[0]);
 	     i++, c++) {
 		if (c->user_specified != user_specified)
 			continue;
-- 
2.45.2





[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux