public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH printk v4 00/39] reduce console_lock scope
@ 2022-11-14 16:28 John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 01/39] serial: kgdboc: Lock console list in probe function John Ogness
                   ` (38 more replies)
  0 siblings, 39 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial,
	linux-fsdevel, Miguel Ojeda, Richard Weinberger, Anton Ivanov,
	Johannes Berg, linux-um, Luis Chamberlain, Aaron Tomlin,
	Ilpo Järvinen, Andy Shevchenko, Lukas Wunner,
	Geert Uytterhoeven, Geert Uytterhoeven, linux-m68k,
	Ard Biesheuvel, linux-efi, linuxppc-dev, Krzysztof Kozlowski,
	Alim Akhtar, linux-arm-kernel, linux-samsung-soc, Michal Simek,
	Peter Zijlstra, Mathias Nyman, linux-usb, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, Helge Deller,
	Javier Martinez Canillas, Thomas Zimmermann, Juergen Gross,
	Boris Ostrovsky, Tom Rix, linux-fbdev, dri-devel

This is v4 of a series to prepare for threaded/atomic
printing. v3 is here [0]. This series focuses on reducing the
scope of the BKL console_lock. It achieves this by switching to
SRCU and a dedicated mutex for console list iteration and
modification, respectively. The console_lock will no longer
offer this protection.

Also, during the review of v2 it came to our attention that
many console drivers are checking CON_ENABLED to see if they
are registered. Because this flag can change without
unregistering and because this flag does not represent an
atomic point when an (un)registration process is complete,
a new console_is_registered() function is introduced. This
function uses the console_list_lock to synchronize with the
(un)registration process to provide a reliable status.

All users of the console_lock for list iteration have been
modified. For the call sites where the console_lock is still
needed (for other reasons), comments are added to explain
exactly why the console_lock was needed.

All users of CON_ENABLED for registration status have been
modified to use console_is_registered(). Note that there are
still users of CON_ENABLED, but this is for legitimate purposes
about a registered console being able to print.

The base commit for this series is from Paul McKenney's RCU tree
and provides an NMI-safe SRCU implementation [1]. Without the
NMI-safe SRCU implementation, this series is not less safe than
mainline. But we will need the NMI-safe SRCU implementation for
atomic consoles anyway, so we might as well get it in
now. Especially since it _does_ increase the reliability for
mainline in the panic path.

Changes since v3:

general:

- Implement console_srcu_read_flags() and console_srcu_write_flags()
  to be used for console->flags access under the srcu_read_lock or
  console_list_lock, respectively. The functions document their
  relationship to one another and use data_race(), READ_ONCE(), and
  WRITE_ONCE() macros to annotate their relationship. They also make
  use of lockdep to warn if used in improper contexts.

- Replace all console_is_enabled() usage with
  console_srcu_read_flags() (all were under the srcu_read_lock).

serial_core:

- For uart_console_registered(), check uart_console() before taking
  the console_list_lock to avoid unnecessary lock contention for
  non-console ports.

m68k/emu/nfcon:

- Only explicitly enable the console if registering via debug=nfcon.

tty/serial/sh-sci:

- Add comments about why @options will always be NULL for the
  earlyprintk console.

kdb:

- Add comments explaining the expectations for console drivers to
  work correctly.

printk:

- Some code sites under SRCU were checking flags directly. Use
  console_srcu_read_flags() instead.

- In register_console() rename bootcon_enabled/realcon_enabled to
  bootcon_registered/realcon_registered to avoid confusion.

- In register_console() only check for boot console sequences if a
  boot console is registered and !keep_bootcon. In this case, also
  take the console_lock to guarantee safe access to console->seq.

- In console_force_preferred_locked() use hlist_del_rcu() instead of
  hlist_del_init_rcu() so that there is never a window where the
  console can be viewed as unregistered.

John Ogness

[0] https://lore.kernel.org/lkml/20221107141638.3790965-1-john.ogness@linutronix.de
[1] https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git/log/?h=srcunmisafe.2022.11.09a

John Ogness (37):
  printk: Prepare for SRCU console list protection
  printk: register_console: use "registered" for variable names
  printk: fix setting first seq for consoles
  um: kmsg_dump: only dump when no output console available
  tty: serial: kgdboc: document console_lock usage
  tty: tty_io: document console_lock usage
  proc: consoles: document console_lock usage
  printk: introduce console_list_lock
  console: introduce wrappers to read/write console flags
  um: kmsg_dumper: use srcu console list iterator
  kdb: use srcu console list iterator
  printk: console_flush_all: use srcu console list iterator
  printk: __pr_flush: use srcu console list iterator
  printk: console_is_usable: use console_srcu_read_flags
  printk: console_unblank: use srcu console list iterator
  printk: console_flush_on_panic: use srcu console list iterator
  printk: console_device: use srcu console list iterator
  console: introduce console_is_registered()
  serial_core: replace uart_console_enabled() with
    uart_console_registered()
  tty: nfcon: use console_is_registered()
  efi: earlycon: use console_is_registered()
  tty: hvc: use console_is_registered()
  tty: serial: earlycon: use console_is_registered()
  tty: serial: pic32_uart: use console_is_registered()
  tty: serial: samsung_tty: use console_is_registered()
  tty: serial: xilinx_uartps: use console_is_registered()
  usb: early: xhci-dbc: use console_is_registered()
  netconsole: avoid CON_ENABLED misuse to track registration
  printk, xen: fbfront: create/use safe function for forcing preferred
  tty: tty_io: use console_list_lock for list synchronization
  proc: consoles: use console_list_lock for list iteration
  tty: serial: kgdboc: use srcu console list iterator
  tty: serial: kgdboc: use console_list_lock for list traversal
  tty: serial: kgdboc: synchronize tty_find_polling_driver() and
    register_console()
  tty: serial: kgdboc: use console_list_lock to trap exit
  printk: relieve console_lock of list synchronization duties
  tty: serial: sh-sci: use setup() callback for early console

Thomas Gleixner (2):
  serial: kgdboc: Lock console list in probe function
  printk: Convert console_drivers list to hlist

 .clang-format                       |   1 +
 arch/m68k/emu/nfcon.c               |   9 +-
 arch/um/kernel/kmsg_dump.c          |  24 +-
 drivers/firmware/efi/earlycon.c     |   8 +-
 drivers/net/netconsole.c            |  21 +-
 drivers/tty/hvc/hvc_console.c       |   4 +-
 drivers/tty/serial/8250/8250_core.c |   2 +-
 drivers/tty/serial/earlycon.c       |   4 +-
 drivers/tty/serial/kgdboc.c         |  46 ++-
 drivers/tty/serial/pic32_uart.c     |   4 +-
 drivers/tty/serial/samsung_tty.c    |   2 +-
 drivers/tty/serial/serial_core.c    |  14 +-
 drivers/tty/serial/sh-sci.c         |  20 +-
 drivers/tty/serial/xilinx_uartps.c  |   2 +-
 drivers/tty/tty_io.c                |  18 +-
 drivers/usb/early/xhci-dbc.c        |   2 +-
 drivers/video/fbdev/xen-fbfront.c   |  12 +-
 fs/proc/consoles.c                  |  21 +-
 include/linux/console.h             | 129 +++++++-
 include/linux/serial_core.h         |  10 +-
 kernel/debug/kdb/kdb_io.c           |  18 +-
 kernel/printk/printk.c              | 459 +++++++++++++++++++++-------
 22 files changed, 648 insertions(+), 182 deletions(-)


base-commit: f733615e39aa2d6ddeef33b7b2c9aa6a5a2c2785
-- 
2.30.2


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

* [PATCH printk v4 01/39] serial: kgdboc: Lock console list in probe function
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 02/39] printk: Convert console_drivers list to hlist John Ogness
                   ` (37 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

From: Thomas Gleixner <tglx@linutronix.de>

Unprotected list walks are not necessarily safe.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 drivers/tty/serial/kgdboc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 7aa37be3216a..e76f0186c335 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -193,6 +193,7 @@ static int configure_kgdboc(void)
 	if (!p)
 		goto noconfig;
 
+	console_lock();
 	for_each_console(cons) {
 		int idx;
 		if (cons->device && cons->device(cons, &idx) == p &&
@@ -201,6 +202,7 @@ static int configure_kgdboc(void)
 			break;
 		}
 	}
+	console_unlock();
 
 	kgdb_tty_driver = p;
 	kgdb_tty_line = tty_line;
-- 
2.30.2


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

* [PATCH printk v4 02/39] printk: Convert console_drivers list to hlist
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 01/39] serial: kgdboc: Lock console list in probe function John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection John Ogness
                   ` (36 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, linux-fsdevel

From: Thomas Gleixner <tglx@linutronix.de>

Replace the open coded single linked list with a hlist so a conversion
to SRCU protected list walks can reuse the existing primitives.

Co-developed-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 fs/proc/consoles.c      |   3 +-
 include/linux/console.h |   8 ++--
 kernel/printk/printk.c  | 101 ++++++++++++++++++++++------------------
 3 files changed, 62 insertions(+), 50 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index dfe6ce3505ce..cf2e0788f9c7 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -74,8 +74,9 @@ static void *c_start(struct seq_file *m, loff_t *pos)
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
 	struct console *con = v;
+
 	++*pos;
-	return con->next;
+	return hlist_entry_safe(con->node.next, struct console, node);
 }
 
 static void c_stop(struct seq_file *m, void *v)
diff --git a/include/linux/console.h b/include/linux/console.h
index 8c1686e2c233..7b5f21f9e469 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -15,6 +15,7 @@
 #define _LINUX_CONSOLE_H_ 1
 
 #include <linux/atomic.h>
+#include <linux/list.h>
 #include <linux/types.h>
 
 struct vc_data;
@@ -154,14 +155,16 @@ struct console {
 	u64	seq;
 	unsigned long dropped;
 	void	*data;
-	struct	 console *next;
+	struct hlist_node node;
 };
 
+extern struct hlist_head console_list;
+
 /*
  * for_each_console() allows you to iterate on each console
  */
 #define for_each_console(con) \
-	for (con = console_drivers; con != NULL; con = con->next)
+	hlist_for_each_entry(con, &console_list, node)
 
 extern int console_set_on_cmdline;
 extern struct console *early_console;
@@ -174,7 +177,6 @@ enum con_flush_mode {
 extern int add_preferred_console(char *name, int idx, char *options);
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
-extern struct console *console_drivers;
 extern void console_lock(void);
 extern int console_trylock(void);
 extern void console_unlock(void);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e4f1e7478b52..e6f0832e71f0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -79,13 +79,12 @@ int oops_in_progress;
 EXPORT_SYMBOL(oops_in_progress);
 
 /*
- * console_sem protects the console_drivers list, and also
- * provides serialisation for access to the entire console
- * driver system.
+ * console_sem protects console_list and console->flags updates, and also
+ * provides serialization for access to the entire console driver system.
  */
 static DEFINE_SEMAPHORE(console_sem);
-struct console *console_drivers;
-EXPORT_SYMBOL_GPL(console_drivers);
+HLIST_HEAD(console_list);
+EXPORT_SYMBOL_GPL(console_list);
 
 /*
  * System may need to suppress printk message under certain
@@ -2556,7 +2555,7 @@ static int console_cpu_notify(unsigned int cpu)
  * console_lock - lock the console system for exclusive use.
  *
  * Acquires a lock which guarantees that the caller has
- * exclusive access to the console system and the console_drivers list.
+ * exclusive access to the console system and console_list.
  *
  * Can sleep, returns nothing.
  */
@@ -2576,7 +2575,7 @@ EXPORT_SYMBOL(console_lock);
  * console_trylock - try to lock the console system for exclusive use.
  *
  * Try to acquire a lock which guarantees that the caller has exclusive
- * access to the console system and the console_drivers list.
+ * access to the console system and console_list.
  *
  * returns 1 on success, and 0 on failure to acquire the lock.
  */
@@ -2940,11 +2939,20 @@ void console_flush_on_panic(enum con_flush_mode mode)
 	console_may_schedule = 0;
 
 	if (mode == CONSOLE_REPLAY_ALL) {
+		struct hlist_node *tmp;
 		struct console *c;
 		u64 seq;
 
 		seq = prb_first_valid_seq(prb);
-		for_each_console(c)
+		/*
+		 * This cannot use for_each_console() because it's not established
+		 * that the current context has console locked and neither there is
+		 * a guarantee that there is no concurrency in that case.
+		 *
+		 * Open code it for documentation purposes and pretend that
+		 * it works.
+		 */
+		hlist_for_each_entry_safe(c, tmp, &console_list, node)
 			c->seq = seq;
 	}
 	console_unlock();
@@ -3081,6 +3089,9 @@ static void try_enable_default_console(struct console *newcon)
 	       (con->flags & CON_BOOT) ? "boot" : "",	\
 	       con->name, con->index, ##__VA_ARGS__)
 
+#define console_first()				\
+	hlist_entry(console_list.first, struct console, node)
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to
@@ -3140,8 +3151,8 @@ void register_console(struct console *newcon)
 	 * flag set and will be first in the list.
 	 */
 	if (preferred_console < 0) {
-		if (!console_drivers || !console_drivers->device ||
-		    console_drivers->flags & CON_BOOT) {
+		if (hlist_empty(&console_list) || !console_first()->device ||
+		    console_first()->flags & CON_BOOT) {
 			try_enable_default_console(newcon);
 		}
 	}
@@ -3169,20 +3180,22 @@ void register_console(struct console *newcon)
 	}
 
 	/*
-	 *	Put this console in the list - keep the
-	 *	preferred driver at the head of the list.
+	 * Put this console in the list - keep the
+	 * preferred driver at the head of the list.
 	 */
 	console_lock();
-	if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
-		newcon->next = console_drivers;
-		console_drivers = newcon;
-		if (newcon->next)
-			newcon->next->flags &= ~CON_CONSDEV;
-		/* Ensure this flag is always set for the head of the list */
+	if (hlist_empty(&console_list)) {
+		/* Ensure CON_CONSDEV is always set for the head. */
 		newcon->flags |= CON_CONSDEV;
+		hlist_add_head(&newcon->node, &console_list);
+
+	} else if (newcon->flags & CON_CONSDEV) {
+		/* Only the new head can have CON_CONSDEV set. */
+		console_first()->flags &= ~CON_CONSDEV;
+		hlist_add_head(&newcon->node, &console_list);
+
 	} else {
-		newcon->next = console_drivers->next;
-		console_drivers->next = newcon;
+		hlist_add_behind(&newcon->node, console_list.first);
 	}
 
 	newcon->dropped = 0;
@@ -3209,16 +3222,18 @@ void register_console(struct console *newcon)
 	if (bootcon_enabled &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
 	    !keep_bootcon) {
-		for_each_console(con)
+		struct hlist_node *tmp;
+
+		hlist_for_each_entry_safe(con, tmp, &console_list, node) {
 			if (con->flags & CON_BOOT)
 				unregister_console(con);
+		}
 	}
 }
 EXPORT_SYMBOL(register_console);
 
 int unregister_console(struct console *console)
 {
-	struct console *con;
 	int res;
 
 	con_printk(KERN_INFO, console, "disabled\n");
@@ -3229,32 +3244,30 @@ int unregister_console(struct console *console)
 	if (res > 0)
 		return 0;
 
-	res = -ENODEV;
 	console_lock();
-	if (console_drivers == console) {
-		console_drivers=console->next;
-		res = 0;
-	} else {
-		for_each_console(con) {
-			if (con->next == console) {
-				con->next = console->next;
-				res = 0;
-				break;
-			}
-		}
+
+	/* Disable it unconditionally */
+	console->flags &= ~CON_ENABLED;
+
+	if (hlist_unhashed(&console->node)) {
+		console_unlock();
+		return -ENODEV;
 	}
 
-	if (res)
-		goto out_disable_unlock;
+	hlist_del_init(&console->node);
 
 	/*
+	 * <HISTORICAL>
 	 * If this isn't the last console and it has CON_CONSDEV set, we
 	 * need to set it on the next preferred console.
+	 * </HISTORICAL>
+	 *
+	 * The above makes no sense as there is no guarantee that the next
+	 * console has any device attached. Oh well....
 	 */
-	if (console_drivers != NULL && console->flags & CON_CONSDEV)
-		console_drivers->flags |= CON_CONSDEV;
+	if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV)
+		console_first()->flags |= CON_CONSDEV;
 
-	console->flags &= ~CON_ENABLED;
 	console_unlock();
 	console_sysfs_notify();
 
@@ -3262,12 +3275,6 @@ int unregister_console(struct console *console)
 		res = console->exit(console);
 
 	return res;
-
-out_disable_unlock:
-	console->flags &= ~CON_ENABLED;
-	console_unlock();
-
-	return res;
 }
 EXPORT_SYMBOL(unregister_console);
 
@@ -3317,10 +3324,11 @@ void __init console_init(void)
  */
 static int __init printk_late_init(void)
 {
+	struct hlist_node *tmp;
 	struct console *con;
 	int ret;
 
-	for_each_console(con) {
+	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
 		if (!(con->flags & CON_BOOT))
 			continue;
 
@@ -3340,6 +3348,7 @@ static int __init printk_late_init(void)
 			unregister_console(con);
 		}
 	}
+
 	ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL,
 					console_cpu_notify);
 	WARN_ON(ret < 0);
-- 
2.30.2


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

* [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 01/39] serial: kgdboc: Lock console list in probe function John Ogness
  2022-11-14 16:28 ` [PATCH printk v4 02/39] printk: Convert console_drivers list to hlist John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-15 10:50   ` Petr Mladek
  2022-11-14 16:28 ` [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names John Ogness
                   ` (35 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Miguel Ojeda, Greg Kroah-Hartman, Paul E . McKenney

Provide an NMI-safe SRCU protected variant to walk the console list.

Note that all console fields are now set before adding the console
to the list to avoid the console becoming visible by SCRU readers
before being fully initialized.

This is a preparatory change for a new console infrastructure which
operates independent of the console BKL.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Acked-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 .clang-format           |  1 +
 include/linux/console.h | 28 ++++++++++++-
 kernel/printk/printk.c  | 87 ++++++++++++++++++++++++++++++++++-------
 3 files changed, 100 insertions(+), 16 deletions(-)

diff --git a/.clang-format b/.clang-format
index 1247d54f9e49..04a675b56b57 100644
--- a/.clang-format
+++ b/.clang-format
@@ -222,6 +222,7 @@ ForEachMacros:
   - 'for_each_component_dais'
   - 'for_each_component_dais_safe'
   - 'for_each_console'
+  - 'for_each_console_srcu'
   - 'for_each_cpu'
   - 'for_each_cpu_and'
   - 'for_each_cpu_not'
diff --git a/include/linux/console.h b/include/linux/console.h
index 7b5f21f9e469..f4f0c9523835 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -15,7 +15,7 @@
 #define _LINUX_CONSOLE_H_ 1
 
 #include <linux/atomic.h>
-#include <linux/list.h>
+#include <linux/rculist.h>
 #include <linux/types.h>
 
 struct vc_data;
@@ -158,8 +158,34 @@ struct console {
 	struct hlist_node node;
 };
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern bool console_srcu_read_lock_is_held(void);
+#else
+static inline bool console_srcu_read_lock_is_held(void)
+{
+	return 1;
+}
+#endif
+
+extern int console_srcu_read_lock(void);
+extern void console_srcu_read_unlock(int cookie);
+
 extern struct hlist_head console_list;
 
+/**
+ * for_each_console_srcu() - Iterator over registered consoles
+ * @con:	struct console pointer used as loop cursor
+ *
+ * Although SRCU guarantees the console list will be consistent, the
+ * struct console fields may be updated by other CPUs while iterating.
+ *
+ * Requires console_srcu_read_lock to be held. Can be invoked from
+ * any context.
+ */
+#define for_each_console_srcu(con)					\
+	hlist_for_each_entry_srcu(con, &console_list, node,		\
+				  console_srcu_read_lock_is_held())
+
 /*
  * for_each_console() allows you to iterate on each console
  */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e6f0832e71f0..173f46a29252 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -85,6 +85,7 @@ EXPORT_SYMBOL(oops_in_progress);
 static DEFINE_SEMAPHORE(console_sem);
 HLIST_HEAD(console_list);
 EXPORT_SYMBOL_GPL(console_list);
+DEFINE_STATIC_SRCU(console_srcu);
 
 /*
  * System may need to suppress printk message under certain
@@ -104,6 +105,13 @@ static struct lockdep_map console_lock_dep_map = {
 };
 #endif
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+bool console_srcu_read_lock_is_held(void)
+{
+	return srcu_read_lock_held(&console_srcu);
+}
+#endif
+
 enum devkmsg_log_bits {
 	__DEVKMSG_LOG_BIT_ON = 0,
 	__DEVKMSG_LOG_BIT_OFF,
@@ -219,6 +227,32 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
 }
 #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */
 
+/**
+ * console_srcu_read_lock - Register a new reader for the
+ *	SRCU-protected console list
+ *
+ * Use for_each_console_srcu() to iterate the console list
+ *
+ * Context: Any context.
+ */
+int console_srcu_read_lock(void)
+{
+	return srcu_read_lock_nmisafe(&console_srcu);
+}
+EXPORT_SYMBOL(console_srcu_read_lock);
+
+/**
+ * console_srcu_read_unlock - Unregister an old reader from
+ *	the SRCU-protected console list
+ *
+ * Counterpart to console_srcu_read_lock()
+ */
+void console_srcu_read_unlock(int cookie)
+{
+	srcu_read_unlock_nmisafe(&console_srcu, cookie);
+}
+EXPORT_SYMBOL(console_srcu_read_unlock);
+
 /*
  * Helper macros to handle lockdep when locking/unlocking console_sem. We use
  * macros instead of functions so that _RET_IP_ contains useful information.
@@ -2989,6 +3023,14 @@ void console_stop(struct console *console)
 	console_lock();
 	console->flags &= ~CON_ENABLED;
 	console_unlock();
+
+	/*
+	 * Ensure that all SRCU list walks have completed. All contexts must
+	 * be able to see that this console is disabled so that (for example)
+	 * the caller can suspend the port without risk of another context
+	 * using the port.
+	 */
+	synchronize_srcu(&console_srcu);
 }
 EXPORT_SYMBOL(console_stop);
 
@@ -3179,6 +3221,17 @@ void register_console(struct console *newcon)
 		newcon->flags &= ~CON_PRINTBUFFER;
 	}
 
+	newcon->dropped = 0;
+	if (newcon->flags & CON_PRINTBUFFER) {
+		/* Get a consistent copy of @syslog_seq. */
+		mutex_lock(&syslog_lock);
+		newcon->seq = syslog_seq;
+		mutex_unlock(&syslog_lock);
+	} else {
+		/* Begin with next message. */
+		newcon->seq = prb_next_seq(prb);
+	}
+
 	/*
 	 * Put this console in the list - keep the
 	 * preferred driver at the head of the list.
@@ -3187,28 +3240,24 @@ void register_console(struct console *newcon)
 	if (hlist_empty(&console_list)) {
 		/* Ensure CON_CONSDEV is always set for the head. */
 		newcon->flags |= CON_CONSDEV;
-		hlist_add_head(&newcon->node, &console_list);
+		hlist_add_head_rcu(&newcon->node, &console_list);
 
 	} else if (newcon->flags & CON_CONSDEV) {
 		/* Only the new head can have CON_CONSDEV set. */
 		console_first()->flags &= ~CON_CONSDEV;
-		hlist_add_head(&newcon->node, &console_list);
+		hlist_add_head_rcu(&newcon->node, &console_list);
 
 	} else {
-		hlist_add_behind(&newcon->node, console_list.first);
-	}
-
-	newcon->dropped = 0;
-	if (newcon->flags & CON_PRINTBUFFER) {
-		/* Get a consistent copy of @syslog_seq. */
-		mutex_lock(&syslog_lock);
-		newcon->seq = syslog_seq;
-		mutex_unlock(&syslog_lock);
-	} else {
-		/* Begin with next message. */
-		newcon->seq = prb_next_seq(prb);
+		hlist_add_behind_rcu(&newcon->node, console_list.first);
 	}
 	console_unlock();
+
+	/*
+	 * No need to synchronize SRCU here! The caller does not rely
+	 * on all contexts being able to see the new console before
+	 * register_console() completes.
+	 */
+
 	console_sysfs_notify();
 
 	/*
@@ -3254,7 +3303,7 @@ int unregister_console(struct console *console)
 		return -ENODEV;
 	}
 
-	hlist_del_init(&console->node);
+	hlist_del_init_rcu(&console->node);
 
 	/*
 	 * <HISTORICAL>
@@ -3269,6 +3318,14 @@ int unregister_console(struct console *console)
 		console_first()->flags |= CON_CONSDEV;
 
 	console_unlock();
+
+	/*
+	 * Ensure that all SRCU list walks have completed. All contexts
+	 * must not be able to see this console in the list so that any
+	 * exit/cleanup routines can be performed safely.
+	 */
+	synchronize_srcu(&console_srcu);
+
 	console_sysfs_notify();
 
 	if (console->exit)
-- 
2.30.2


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

* [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (2 preceding siblings ...)
  2022-11-14 16:28 ` [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-15 11:01   ` Petr Mladek
  2022-11-14 16:28 ` [PATCH printk v4 05/39] printk: fix setting first seq for consoles John Ogness
                   ` (34 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

The @bootcon_enabled and @realcon_enabled local variables actually
represent if such console types are registered. In general there
has been a confusion about enabled vs. registered. Incorrectly
naming such variables promotes such confusion.

Rename the variables to _registered.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 kernel/printk/printk.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 173f46a29252..3d449dfb1ed6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3156,8 +3156,8 @@ static void try_enable_default_console(struct console *newcon)
 void register_console(struct console *newcon)
 {
 	struct console *con;
-	bool bootcon_enabled = false;
-	bool realcon_enabled = false;
+	bool bootcon_registered = false;
+	bool realcon_registered = false;
 	int err;
 
 	for_each_console(con) {
@@ -3168,13 +3168,13 @@ void register_console(struct console *newcon)
 
 	for_each_console(con) {
 		if (con->flags & CON_BOOT)
-			bootcon_enabled = true;
+			bootcon_registered = true;
 		else
-			realcon_enabled = true;
+			realcon_registered = true;
 	}
 
 	/* Do not register boot consoles when there already is a real one. */
-	if (newcon->flags & CON_BOOT && realcon_enabled) {
+	if ((newcon->flags & CON_BOOT) && realcon_registered) {
 		pr_info("Too late to register bootconsole %s%d\n",
 			newcon->name, newcon->index);
 		return;
@@ -3216,7 +3216,7 @@ void register_console(struct console *newcon)
 	 * the real console are the same physical device, it's annoying to
 	 * see the beginning boot messages twice
 	 */
-	if (bootcon_enabled &&
+	if (bootcon_registered &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
 		newcon->flags &= ~CON_PRINTBUFFER;
 	}
@@ -3268,7 +3268,7 @@ void register_console(struct console *newcon)
 	 * went to the bootconsole (that they do not see on the real console)
 	 */
 	con_printk(KERN_INFO, newcon, "enabled\n");
-	if (bootcon_enabled &&
+	if (bootcon_registered &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
 	    !keep_bootcon) {
 		struct hlist_node *tmp;
-- 
2.30.2


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

* [PATCH printk v4 05/39] printk: fix setting first seq for consoles
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (3 preceding siblings ...)
  2022-11-14 16:28 ` [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-15 12:04   ` Petr Mladek
  2022-11-14 16:28 ` [PATCH printk v4 06/39] um: kmsg_dump: only dump when no output console available John Ogness
                   ` (33 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

It used to be that all consoles were synchronized with respect to
which message they were printing. After commit a699449bb13b ("printk:
refactor and rework printing logic"), all consoles have their own
@seq for tracking which message they are on. That commit also changed
how the initial sequence number was chosen. Instead of choosing the
next non-printed message, it chose the sequence number of the next
message that will be added to the ringbuffer.

That change created a possibility that a non-boot console taking over
for a boot console might skip messages if the boot console was behind
and did not have a chance to catch up before being unregistered.

Since it is not possible to know which boot console a console is
taking over, use the lowest @seq of all the enabled boot consoles. If
no boot consoles are available/enabled, begin with the next message
that will be added to the ringbuffer.

Also, since boot consoles are meant to be used at boot time, handle
them the same as CON_PRINTBUFFER to ensure that no initial messages
are skipped.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 kernel/printk/printk.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 3d449dfb1ed6..8dbf3461cba0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3222,14 +3222,31 @@ void register_console(struct console *newcon)
 	}
 
 	newcon->dropped = 0;
-	if (newcon->flags & CON_PRINTBUFFER) {
+	if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
 		/* Get a consistent copy of @syslog_seq. */
 		mutex_lock(&syslog_lock);
 		newcon->seq = syslog_seq;
 		mutex_unlock(&syslog_lock);
 	} else {
-		/* Begin with next message. */
+		/* Begin with next message added to ringbuffer. */
 		newcon->seq = prb_next_seq(prb);
+
+		/*
+		 * If any enabled boot consoles are due to be unregistered
+		 * shortly, some may not be caught up and may be the same
+		 * device as @newcon. Since it is not known which boot console
+		 * is the same device, start with the message of the enabled
+		 * boot console that is the furthest behind.
+		 */
+		if (bootcon_registered && !keep_bootcon) {
+			for_each_console(con) {
+				if ((con->flags & CON_BOOT) &&
+				    (con->flags & CON_ENABLED) &&
+				    con->seq < newcon->seq) {
+					newcon->seq = con->seq;
+				}
+			}
+		}
 	}
 
 	/*
-- 
2.30.2


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

* [PATCH printk v4 06/39] um: kmsg_dump: only dump when no output console available
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (4 preceding siblings ...)
  2022-11-14 16:28 ` [PATCH printk v4 05/39] printk: fix setting first seq for consoles John Ogness
@ 2022-11-14 16:28 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 07/39] tty: serial: kgdboc: document console_lock usage John Ogness
                   ` (32 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:28 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Richard Weinberger, Anton Ivanov, Johannes Berg, linux-um

The initial intention of the UML kmsg_dumper is to dump the kernel
buffers to stdout if there is no console available to perform the
regular crash output.

However, if ttynull was registered as a console, no crash output was
seen. Commit e23fe90dec28 ("um: kmsg_dumper: always dump when not tty
console") tried to fix this by performing the kmsg_dump unless the
stdio console was behind /dev/console or enabled. But this allowed
kmsg dumping to occur even if other non-stdio consoles will output
the crash output. Also, a console being the driver behind
/dev/console has nothing to do with a crash scenario.

Restore the initial intention by dumping the kernel buffers to stdout
only if a non-ttynull console is registered and enabled. Also add
detailed comments so that it is clear why these rules are applied.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 arch/um/kernel/kmsg_dump.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c
index 0224fcb36e22..40abf1e9ccb1 100644
--- a/arch/um/kernel/kmsg_dump.c
+++ b/arch/um/kernel/kmsg_dump.c
@@ -17,13 +17,22 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
 	unsigned long flags;
 	size_t len = 0;
 
-	/* only dump kmsg when no console is available */
+	/*
+	 * If no consoles are available to output crash information, dump
+	 * the kmsg buffer to stdout.
+	 */
+
 	if (!console_trylock())
 		return;
 
 	for_each_console(con) {
-		if(strcmp(con->name, "tty") == 0 &&
-		   (con->flags & (CON_ENABLED | CON_CONSDEV)) != 0) {
+		/*
+		 * The ttynull console and disabled consoles are ignored
+		 * since they cannot output. All other consoles are
+		 * expected to output the crash information.
+		 */
+		if (strcmp(con->name, "ttynull") != 0 &&
+		    (con->flags & CON_ENABLED)) {
 			break;
 		}
 	}
-- 
2.30.2


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

* [PATCH printk v4 07/39] tty: serial: kgdboc: document console_lock usage
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (5 preceding siblings ...)
  2022-11-14 16:28 ` [PATCH printk v4 06/39] um: kmsg_dump: only dump when no output console available John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 08/39] tty: tty_io: " John Ogness
                   ` (31 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

kgdboc_earlycon_init() uses the console_lock to ensure that no consoles
are unregistered until the kgdboc_earlycon is setup. This is necessary
because the trapping of the exit() callback assumes that the exit()
callback is not called before the trap is setup.

Explicitly document this non-typical console_lock usage.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/kgdboc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index e76f0186c335..5be381003e58 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -530,6 +530,14 @@ static int __init kgdboc_earlycon_init(char *opt)
 	 * Look for a matching console, or if the name was left blank just
 	 * pick the first one we find.
 	 */
+
+	/*
+	 * Hold the console_lock to guarantee that no consoles are
+	 * unregistered until the kgdboc_earlycon setup is complete.
+	 * Trapping the exit() callback relies on exit() not being
+	 * called until the trap is setup. This also allows safe
+	 * traversal of the console list and race-free reading of @flags.
+	 */
 	console_lock();
 	for_each_console(con) {
 		if (con->write && con->read &&
-- 
2.30.2


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

* [PATCH printk v4 08/39] tty: tty_io: document console_lock usage
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (6 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 07/39] tty: serial: kgdboc: document console_lock usage John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 09/39] proc: consoles: " John Ogness
                   ` (30 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby

show_cons_active() uses the console_lock to gather information
on registered consoles. Since the console_lock is being used for
multiple reasons, explicitly document these reasons. This will
be useful when the console_lock is split into fine-grained
locking.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/tty_io.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index de06c3c2ff70..ee4da2fec328 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3526,6 +3526,16 @@ static ssize_t show_cons_active(struct device *dev,
 	struct console *c;
 	ssize_t count = 0;
 
+	/*
+	 * Hold the console_lock to guarantee that no consoles are
+	 * unregistered until all console processing is complete.
+	 * This also allows safe traversal of the console list and
+	 * race-free reading of @flags.
+	 *
+	 * Take console_lock to serialize device() callback with
+	 * other console operations. For example, fg_console is
+	 * modified under console_lock when switching vt.
+	 */
 	console_lock();
 	for_each_console(c) {
 		if (!c->device)
-- 
2.30.2


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

* [PATCH printk v4 09/39] proc: consoles: document console_lock usage
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (7 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 08/39] tty: tty_io: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 10/39] printk: introduce console_list_lock John Ogness
                   ` (29 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, linux-fsdevel

The console_lock is held throughout the start/show/stop procedure
to print out device/driver information about all registered
consoles. Since the console_lock is being used for multiple reasons,
explicitly document these reasons. This will be useful when the
console_lock is split into fine-grained locking.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 fs/proc/consoles.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index cf2e0788f9c7..46b305fa04ed 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -63,6 +63,15 @@ static void *c_start(struct seq_file *m, loff_t *pos)
 	struct console *con;
 	loff_t off = 0;
 
+	/*
+	 * Take console_lock to serialize device() callback with
+	 * other console operations. For example, fg_console is
+	 * modified under console_lock when switching vt.
+	 *
+	 * Hold the console_lock to guarantee safe traversal of the
+	 * console list. SRCU cannot be used because there is no
+	 * place to store the SRCU cookie.
+	 */
 	console_lock();
 	for_each_console(con)
 		if (off++ == *pos)
-- 
2.30.2


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

* [PATCH printk v4 10/39] printk: introduce console_list_lock
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (8 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 09/39] proc: consoles: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags John Ogness
                   ` (28 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman

Currently there exist races in register_console(), where the types
of registered consoles are checked (without holding the console_lock)
and then after acquiring the console_lock, it is assumed that the list
has not changed. Also, some code that performs console_unregister()
make similar assumptions.

It might be possible to fix these races using the console_lock. But
it would require a complex analysis of all console drivers to make
sure that the console_lock is not taken in match() and setup()
callbacks. And we really prefer to split up and reduce the
responsibilities of console_lock rather than expand its complexity.
Therefore, introduce a new console_list_lock to provide full
synchronization for any console list changes.

In addition, also use console_list_lock for synchronization of
console->flags updates. All flags are either static or modified only
during the console registration. There are only two exceptions.

The first exception is CON_ENABLED, which is also modified by
console_start()/console_stop(). Therefore, these functions must
also take the console_list_lock.

The second exception is when the flags are modified by the console
driver init code before the console is registered. These will be
ignored because they are not visible to the rest of the system
via the console_drivers list.

Note that one of the various responsibilities of the console_lock is
also intended to provide console list and console->flags
synchronization. Later changes will update call sites relying on the
console_lock for these purposes. Once all call sites have been
updated, the console_lock will be relieved of synchronizing
console_list and console->flags updates.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 include/linux/console.h | 23 +++++++++--
 kernel/printk/printk.c  | 88 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 99 insertions(+), 12 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index f4f0c9523835..24d83e24840b 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -158,6 +158,14 @@ struct console {
 	struct hlist_node node;
 };
 
+#ifdef CONFIG_LOCKDEP
+extern void lockdep_assert_console_list_lock_held(void);
+#else
+static inline void lockdep_assert_console_list_lock_held(void)
+{
+}
+#endif
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern bool console_srcu_read_lock_is_held(void);
 #else
@@ -170,6 +178,9 @@ static inline bool console_srcu_read_lock_is_held(void)
 extern int console_srcu_read_lock(void);
 extern void console_srcu_read_unlock(int cookie);
 
+extern void console_list_lock(void) __acquires(console_mutex);
+extern void console_list_unlock(void) __releases(console_mutex);
+
 extern struct hlist_head console_list;
 
 /**
@@ -186,10 +197,16 @@ extern struct hlist_head console_list;
 	hlist_for_each_entry_srcu(con, &console_list, node,		\
 				  console_srcu_read_lock_is_held())
 
-/*
- * for_each_console() allows you to iterate on each console
+/**
+ * for_each_console() - Iterator over registered consoles
+ * @con:	struct console pointer used as loop cursor
+ *
+ * The console list and the console->flags are immutable while iterating.
+ *
+ * Requires console_list_lock to be held.
  */
-#define for_each_console(con) \
+#define for_each_console(con)						\
+	lockdep_assert_console_list_lock_held();			\
 	hlist_for_each_entry(con, &console_list, node)
 
 extern int console_set_on_cmdline;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8dbf3461cba0..e3f81dda5b09 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -78,6 +78,13 @@ EXPORT_SYMBOL(ignore_console_lock_warning);
 int oops_in_progress;
 EXPORT_SYMBOL(oops_in_progress);
 
+/*
+ * console_mutex protects console_list updates and console->flags updates.
+ * The flags are synchronized only for consoles that are registered, i.e.
+ * accessible via the console list.
+ */
+static DEFINE_MUTEX(console_mutex);
+
 /*
  * console_sem protects console_list and console->flags updates, and also
  * provides serialization for access to the entire console driver system.
@@ -103,6 +110,11 @@ static int __read_mostly suppress_panic_printk;
 static struct lockdep_map console_lock_dep_map = {
 	.name = "console_lock"
 };
+
+void lockdep_assert_console_list_lock_held(void)
+{
+	lockdep_assert_held(&console_mutex);
+}
 #endif
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -227,6 +239,40 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
 }
 #endif /* CONFIG_PRINTK && CONFIG_SYSCTL */
 
+/**
+ * console_list_lock - Lock the console list
+ *
+ * For console list or console->flags updates
+ */
+void console_list_lock(void)
+{
+	/*
+	 * In unregister_console(), synchronize_srcu() is called with the
+	 * console_list_lock held. Therefore it is not allowed that the
+	 * console_list_lock is taken with the srcu_lock held.
+	 *
+	 * Detecting if this context is really in the read-side critical
+	 * section is only possible if the appropriate debug options are
+	 * enabled.
+	 */
+	WARN_ON_ONCE(debug_lockdep_rcu_enabled() &&
+		     srcu_read_lock_held(&console_srcu));
+
+	mutex_lock(&console_mutex);
+}
+EXPORT_SYMBOL(console_list_lock);
+
+/**
+ * console_list_unlock - Unlock the console list
+ *
+ * Counterpart to console_list_lock()
+ */
+void console_list_unlock(void)
+{
+	mutex_unlock(&console_mutex);
+}
+EXPORT_SYMBOL(console_list_unlock);
+
 /**
  * console_srcu_read_lock - Register a new reader for the
  *	SRCU-protected console list
@@ -3020,9 +3066,11 @@ struct tty_driver *console_device(int *index)
 void console_stop(struct console *console)
 {
 	__pr_flush(console, 1000, true);
+	console_list_lock();
 	console_lock();
 	console->flags &= ~CON_ENABLED;
 	console_unlock();
+	console_list_unlock();
 
 	/*
 	 * Ensure that all SRCU list walks have completed. All contexts must
@@ -3036,9 +3084,11 @@ EXPORT_SYMBOL(console_stop);
 
 void console_start(struct console *console)
 {
+	console_list_lock();
 	console_lock();
 	console->flags |= CON_ENABLED;
 	console_unlock();
+	console_list_unlock();
 	__pr_flush(console, 1000, true);
 }
 EXPORT_SYMBOL(console_start);
@@ -3134,6 +3184,8 @@ static void try_enable_default_console(struct console *newcon)
 #define console_first()				\
 	hlist_entry(console_list.first, struct console, node)
 
+static int unregister_console_locked(struct console *console);
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to
@@ -3160,13 +3212,14 @@ void register_console(struct console *newcon)
 	bool realcon_registered = false;
 	int err;
 
+	console_list_lock();
+
 	for_each_console(con) {
 		if (WARN(con == newcon, "console '%s%d' already registered\n",
-					 con->name, con->index))
-			return;
-	}
+					 con->name, con->index)) {
+			goto unlock;
+		}
 
-	for_each_console(con) {
 		if (con->flags & CON_BOOT)
 			bootcon_registered = true;
 		else
@@ -3177,7 +3230,7 @@ void register_console(struct console *newcon)
 	if ((newcon->flags & CON_BOOT) && realcon_registered) {
 		pr_info("Too late to register bootconsole %s%d\n",
 			newcon->name, newcon->index);
-		return;
+		goto unlock;
 	}
 
 	/*
@@ -3208,7 +3261,7 @@ void register_console(struct console *newcon)
 
 	/* printk() messages are not printed to the Braille console. */
 	if (err || newcon->flags & CON_BRL)
-		return;
+		goto unlock;
 
 	/*
 	 * If we have a bootconsole, and are switching to a real console,
@@ -3292,16 +3345,21 @@ void register_console(struct console *newcon)
 
 		hlist_for_each_entry_safe(con, tmp, &console_list, node) {
 			if (con->flags & CON_BOOT)
-				unregister_console(con);
+				unregister_console_locked(con);
 		}
 	}
+unlock:
+	console_list_unlock();
 }
 EXPORT_SYMBOL(register_console);
 
-int unregister_console(struct console *console)
+/* Must be called under console_list_lock(). */
+static int unregister_console_locked(struct console *console)
 {
 	int res;
 
+	lockdep_assert_console_list_lock_held();
+
 	con_printk(KERN_INFO, console, "disabled\n");
 
 	res = _braille_unregister_console(console);
@@ -3350,6 +3408,16 @@ int unregister_console(struct console *console)
 
 	return res;
 }
+
+int unregister_console(struct console *console)
+{
+	int res;
+
+	console_list_lock();
+	res = unregister_console_locked(console);
+	console_list_unlock();
+	return res;
+}
 EXPORT_SYMBOL(unregister_console);
 
 /*
@@ -3402,6 +3470,7 @@ static int __init printk_late_init(void)
 	struct console *con;
 	int ret;
 
+	console_list_lock();
 	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
 		if (!(con->flags & CON_BOOT))
 			continue;
@@ -3419,9 +3488,10 @@ static int __init printk_late_init(void)
 			 */
 			pr_warn("bootconsole [%s%d] uses init memory and must be disabled even before the real one is ready\n",
 				con->name, con->index);
-			unregister_console(con);
+			unregister_console_locked(con);
 		}
 	}
+	console_list_unlock();
 
 	ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL,
 					console_cpu_notify);
-- 
2.30.2


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

* [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (9 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 10/39] printk: introduce console_list_lock John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 12:26   ` Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 12/39] um: kmsg_dumper: use srcu console list iterator John Ogness
                   ` (27 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman

After switching to SRCU for console list iteration, some readers
will begin readings console->flags as a data race. Locklessly
reading console->flags provides a consistent value because there
is at most one CPU modifying console->flags and that CPU is
using only read-modify-write operations.

Introduce a wrapper for SRCU iterators to read console flags.
Introduce a matching wrapper to write to flags of registered
consoles. Writing to flags of registered consoles is synchronized
by the console_list_lock.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 include/linux/console.h | 45 +++++++++++++++++++++++++++++++++++++++++
 kernel/printk/printk.c  | 10 ++++-----
 2 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index 24d83e24840b..c1ca461d088a 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -183,6 +183,51 @@ extern void console_list_unlock(void) __releases(console_mutex);
 
 extern struct hlist_head console_list;
 
+/**
+ * console_srcu_read_flags - Locklessly read the console flags
+ * @con:	struct console pointer of console to read flags from
+ *
+ * This function provides the necessary READ_ONCE() and data_race()
+ * notation for locklessly reading the console flags. The READ_ONCE()
+ * in this function matches the WRITE_ONCE() when @flags are modified
+ * for registered consoles with console_srcu_write_flags().
+ *
+ * Only use this function to read console flags when locklessly
+ * iterating the console list via srcu.
+ *
+ * Context: Any context.
+ */
+static inline short console_srcu_read_flags(const struct console *con)
+{
+	WARN_ON_ONCE(!console_srcu_read_lock_is_held());
+
+	/*
+	 * Locklessly reading console->flags provides a consistent
+	 * read value because there is at most one CPU modifying
+	 * console->flags and that CPU is using only read-modify-write
+	 * operations to do so.
+	 */
+	return data_race(READ_ONCE(con->flags));
+}
+
+/**
+ * console_srcu_write_flags - Write flags for a registered console
+ * @con:	struct console pointer of console to write flags to
+ * @flags:	new flags value to write
+ *
+ * Only use this function to write flags for registered consoles. It
+ * requires holding the console_list_lock.
+ *
+ * Context: Any context.
+ */
+static inline void console_srcu_write_flags(struct console *con, short flags)
+{
+	lockdep_assert_console_list_lock_held();
+
+	/* This matches the READ_ONCE() in console_srcu_read_flags(). */
+	WRITE_ONCE(con->flags, flags);
+}
+
 /**
  * for_each_console_srcu() - Iterator over registered consoles
  * @con:	struct console pointer used as loop cursor
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e3f81dda5b09..41c90b768c1c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3068,7 +3068,7 @@ void console_stop(struct console *console)
 	__pr_flush(console, 1000, true);
 	console_list_lock();
 	console_lock();
-	console->flags &= ~CON_ENABLED;
+	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
 	console_unlock();
 	console_list_unlock();
 
@@ -3086,7 +3086,7 @@ void console_start(struct console *console)
 {
 	console_list_lock();
 	console_lock();
-	console->flags |= CON_ENABLED;
+	console_srcu_write_flags(console, console->flags | CON_ENABLED);
 	console_unlock();
 	console_list_unlock();
 	__pr_flush(console, 1000, true);
@@ -3314,7 +3314,7 @@ void register_console(struct console *newcon)
 
 	} else if (newcon->flags & CON_CONSDEV) {
 		/* Only the new head can have CON_CONSDEV set. */
-		console_first()->flags &= ~CON_CONSDEV;
+		console_srcu_write_flags(console_first(), console_first()->flags & ~CON_CONSDEV);
 		hlist_add_head_rcu(&newcon->node, &console_list);
 
 	} else {
@@ -3371,7 +3371,7 @@ static int unregister_console_locked(struct console *console)
 	console_lock();
 
 	/* Disable it unconditionally */
-	console->flags &= ~CON_ENABLED;
+	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
 
 	if (hlist_unhashed(&console->node)) {
 		console_unlock();
@@ -3390,7 +3390,7 @@ static int unregister_console_locked(struct console *console)
 	 * console has any device attached. Oh well....
 	 */
 	if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV)
-		console_first()->flags |= CON_CONSDEV;
+		console_srcu_write_flags(console_first(), console_first()->flags | CON_CONSDEV);
 
 	console_unlock();
 
-- 
2.30.2


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

* [PATCH printk v4 12/39] um: kmsg_dumper: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (10 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 13/39] kdb: " John Ogness
                   ` (26 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Richard Weinberger, Anton Ivanov, Johannes Berg, linux-um

Rather than using the console_lock to guarantee safe console list
traversal, use srcu console list iteration.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 arch/um/kernel/kmsg_dump.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/arch/um/kernel/kmsg_dump.c b/arch/um/kernel/kmsg_dump.c
index 40abf1e9ccb1..427dd5a61a38 100644
--- a/arch/um/kernel/kmsg_dump.c
+++ b/arch/um/kernel/kmsg_dump.c
@@ -16,29 +16,26 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
 	struct console *con;
 	unsigned long flags;
 	size_t len = 0;
+	int cookie;
 
 	/*
 	 * If no consoles are available to output crash information, dump
 	 * the kmsg buffer to stdout.
 	 */
 
-	if (!console_trylock())
-		return;
-
-	for_each_console(con) {
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(con) {
 		/*
 		 * The ttynull console and disabled consoles are ignored
 		 * since they cannot output. All other consoles are
 		 * expected to output the crash information.
 		 */
 		if (strcmp(con->name, "ttynull") != 0 &&
-		    (con->flags & CON_ENABLED)) {
+		    (console_srcu_read_flags(con) & CON_ENABLED)) {
 			break;
 		}
 	}
-
-	console_unlock();
-
+	console_srcu_read_unlock(cookie);
 	if (con)
 		return;
 
-- 
2.30.2


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

* [PATCH printk v4 13/39] kdb: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (11 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 12/39] um: kmsg_dumper: use srcu console list iterator John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 21:16   ` Aaron Tomlin
  2022-11-14 16:29 ` [PATCH printk v4 14/39] printk: console_flush_all: " John Ogness
                   ` (25 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson, Luis Chamberlain,
	Aaron Tomlin, kgdb-bugreport

Guarantee safe iteration of the console list by using SRCU.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/debug/kdb/kdb_io.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
index 67d3c48a1522..5c7e9ba7cd6b 100644
--- a/kernel/debug/kdb/kdb_io.c
+++ b/kernel/debug/kdb/kdb_io.c
@@ -545,6 +545,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
 {
 	struct console *c;
 	const char *cp;
+	int cookie;
 	int len;
 
 	if (msg_len == 0)
@@ -558,8 +559,20 @@ static void kdb_msg_write(const char *msg, int msg_len)
 		cp++;
 	}
 
-	for_each_console(c) {
-		if (!(c->flags & CON_ENABLED))
+	/*
+	 * The console_srcu_read_lock() only provides safe console list
+	 * traversal. The use of the ->write() callback relies on all other
+	 * CPUs being stopped at the moment and console drivers being able to
+	 * handle reentrance when @oops_in_progress is set.
+	 *
+	 * There is no guarantee that every console driver can handle
+	 * reentrance in this way; the developer deploying the debugger
+	 * is responsible for ensuring that the console drivers they
+	 * have selected handle reentrance appropriately.
+	 */
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(c) {
+		if (!(console_srcu_read_flags(c) & CON_ENABLED))
 			continue;
 		if (c == dbg_io_ops->cons)
 			continue;
@@ -577,6 +590,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
 		--oops_in_progress;
 		touch_nmi_watchdog();
 	}
+	console_srcu_read_unlock(cookie);
 }
 
 int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
-- 
2.30.2


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

* [PATCH printk v4 14/39] printk: console_flush_all: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (12 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 13/39] kdb: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 15/39] printk: __pr_flush: " John Ogness
                   ` (24 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Guarantee safe iteration of the console list by using SRCU.

Note that in the case of a handover, the SRCU read lock is also
released. This is documented in the function description and as
comments in the code. It is a bit tricky, but this preserves the
lockdep lock ordering for the context handing over the
console_lock:

  console_lock()
  | mutex_acquire(&console_lock_dep_map)       <-- console lock
  |
  console_unlock()
  | console_flush_all()
  | | srcu_read_lock(&console_srcu)            <-- srcu lock
  | | console_emit_next_record()
  | | | console_lock_spinning_disable_and_check()
  | | | | srcu_read_unlock(&console_srcu)      <-- srcu unlock
  | | | | mutex_release(&console_lock_dep_map) <-- console unlock

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 50 +++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 41c90b768c1c..b37ca16abbd0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1893,13 +1893,13 @@ static void console_lock_spinning_enable(void)
  * safe to start busy waiting for the lock. Second, it checks if
  * there is a busy waiter and passes the lock rights to her.
  *
- * Important: Callers lose the lock if there was a busy waiter.
- *	They must not touch items synchronized by console_lock
- *	in this case.
+ * Important: Callers lose both the console_lock and the SRCU read lock if
+ *	there was a busy waiter. They must not touch items synchronized by
+ *	console_lock or SRCU read lock in this case.
  *
  * Return: 1 if the lock rights were passed, 0 otherwise.
  */
-static int console_lock_spinning_disable_and_check(void)
+static int console_lock_spinning_disable_and_check(int cookie)
 {
 	int waiter;
 
@@ -1918,6 +1918,12 @@ static int console_lock_spinning_disable_and_check(void)
 
 	spin_release(&console_owner_dep_map, _THIS_IP_);
 
+	/*
+	 * Preserve lockdep lock ordering. Release the SRCU read lock before
+	 * releasing the console_lock.
+	 */
+	console_srcu_read_unlock(cookie);
+
 	/*
 	 * Hand off console_lock to waiter. The waiter will perform
 	 * the up(). After this, the waiter is the console_lock owner.
@@ -2401,7 +2407,7 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
 				  char *text, size_t text_len,
 				  struct dev_printk_info *dev_info) { return 0; }
 static void console_lock_spinning_enable(void) { }
-static int console_lock_spinning_disable_and_check(void) { return 0; }
+static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
 static void call_console_driver(struct console *con, const char *text, size_t len,
 				char *dropped_text)
 {
@@ -2743,16 +2749,18 @@ static void __console_unlock(void)
  * DROPPED_TEXT_MAX. Otherwise @dropped_text must be NULL.
  *
  * @handover will be set to true if a printk waiter has taken over the
- * console_lock, in which case the caller is no longer holding the
- * console_lock. Otherwise it is set to false.
+ * console_lock, in which case the caller is no longer holding both the
+ * console_lock and the SRCU read lock. Otherwise it is set to false.
+ *
+ * @cookie is the cookie from the SRCU read lock.
  *
  * Returns false if the given console has no next record to print, otherwise
  * true.
  *
- * Requires the console_lock.
+ * Requires the console_lock and the SRCU read lock.
  */
 static bool console_emit_next_record(struct console *con, char *text, char *ext_text,
-				     char *dropped_text, bool *handover)
+				     char *dropped_text, bool *handover, int cookie)
 {
 	static int panic_console_dropped;
 	struct printk_info info;
@@ -2812,7 +2820,7 @@ static bool console_emit_next_record(struct console *con, char *text, char *ext_
 
 	con->seq++;
 
-	*handover = console_lock_spinning_disable_and_check();
+	*handover = console_lock_spinning_disable_and_check(cookie);
 	printk_safe_exit_irqrestore(flags);
 skip:
 	return true;
@@ -2849,6 +2857,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
 	bool any_usable = false;
 	struct console *con;
 	bool any_progress;
+	int cookie;
 
 	*next_seq = 0;
 	*handover = false;
@@ -2856,23 +2865,29 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
 	do {
 		any_progress = false;
 
-		for_each_console(con) {
+		cookie = console_srcu_read_lock();
+		for_each_console_srcu(con) {
 			bool progress;
 
 			if (!console_is_usable(con))
 				continue;
 			any_usable = true;
 
-			if (con->flags & CON_EXTENDED) {
+			if (console_srcu_read_flags(con) & CON_EXTENDED) {
 				/* Extended consoles do not print "dropped messages". */
 				progress = console_emit_next_record(con, &text[0],
 								    &ext_text[0], NULL,
-								    handover);
+								    handover, cookie);
 			} else {
 				progress = console_emit_next_record(con, &text[0],
 								    NULL, &dropped_text[0],
-								    handover);
+								    handover, cookie);
 			}
+
+			/*
+			 * If a handover has occurred, the SRCU read lock
+			 * is already released.
+			 */
 			if (*handover)
 				return false;
 
@@ -2886,14 +2901,19 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
 
 			/* Allow panic_cpu to take over the consoles safely. */
 			if (abandon_console_lock_in_panic())
-				return false;
+				goto abandon;
 
 			if (do_cond_resched)
 				cond_resched();
 		}
+		console_srcu_read_unlock(cookie);
 	} while (any_progress);
 
 	return any_usable;
+
+abandon:
+	console_srcu_read_unlock(cookie);
+	return false;
 }
 
 /**
-- 
2.30.2


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

* [PATCH printk v4 15/39] printk: __pr_flush: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (13 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 14/39] printk: console_flush_all: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags John Ogness
                   ` (23 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Use srcu console list iteration for console list traversal.

Document why the console_lock is still necessary. Note that this
is a preparatory change for when console_lock no longer provides
synchronization for the console list.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b37ca16abbd0..3d9e5bb1a50b 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3532,6 +3532,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 	struct console *c;
 	u64 last_diff = 0;
 	u64 printk_seq;
+	int cookie;
 	u64 diff;
 	u64 seq;
 
@@ -3542,9 +3543,15 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 	for (;;) {
 		diff = 0;
 
+		/*
+		 * Hold the console_lock to guarantee safe access to
+		 * console->seq and to prevent changes to @console_suspended
+		 * until all consoles have been processed.
+		 */
 		console_lock();
 
-		for_each_console(c) {
+		cookie = console_srcu_read_lock();
+		for_each_console_srcu(c) {
 			if (con && con != c)
 				continue;
 			if (!console_is_usable(c))
@@ -3553,6 +3560,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
 			if (printk_seq < seq)
 				diff += seq - printk_seq;
 		}
+		console_srcu_read_unlock(cookie);
 
 		/*
 		 * If consoles are suspended, it cannot be expected that they
-- 
2.30.2


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

* [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (14 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 15/39] printk: __pr_flush: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 12:47   ` Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 17/39] printk: console_unblank: use srcu console list iterator John Ogness
                   ` (22 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

All users of console_is_usable() are SRCU iterators. Use the
appropriate wrapper function to locklessly read the flags.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 kernel/printk/printk.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 3d9e5bb1a50b..bc563972e468 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2708,11 +2708,13 @@ static bool abandon_console_lock_in_panic(void)
  * Check if the given console is currently capable and allowed to print
  * records.
  *
- * Requires the console_lock.
+ * Requires the console_srcu_read_lock.
  */
 static inline bool console_is_usable(struct console *con)
 {
-	if (!(con->flags & CON_ENABLED))
+	short flags = console_srcu_read_flags(con);
+
+	if (!(flags & CON_ENABLED))
 		return false;
 
 	if (!con->write)
@@ -2723,8 +2725,7 @@ static inline bool console_is_usable(struct console *con)
 	 * allocated. So unless they're explicitly marked as being able to
 	 * cope (CON_ANYTIME) don't call them until this CPU is officially up.
 	 */
-	if (!cpu_online(raw_smp_processor_id()) &&
-	    !(con->flags & CON_ANYTIME))
+	if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
 		return false;
 
 	return true;
-- 
2.30.2


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

* [PATCH printk v4 17/39] printk: console_unblank: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (15 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 18/39] printk: console_flush_on_panic: " John Ogness
                   ` (21 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Use srcu console list iteration for console list traversal.

Document why the console_lock is still necessary. Note that this
is a preparatory change for when console_lock no longer provides
synchronization for the console list.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index bc563972e468..7304cbcd6dd4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2999,10 +2999,14 @@ EXPORT_SYMBOL(console_conditional_schedule);
 void console_unblank(void)
 {
 	struct console *c;
+	int cookie;
 
 	/*
-	 * console_unblank can no longer be called in interrupt context unless
-	 * oops_in_progress is set to 1..
+	 * Stop console printing because the unblank() callback may
+	 * assume the console is not within its write() callback.
+	 *
+	 * If @oops_in_progress is set, this may be an atomic context.
+	 * In that case, attempt a trylock as best-effort.
 	 */
 	if (oops_in_progress) {
 		if (down_trylock_console_sem() != 0)
@@ -3012,9 +3016,14 @@ void console_unblank(void)
 
 	console_locked = 1;
 	console_may_schedule = 0;
-	for_each_console(c)
-		if ((c->flags & CON_ENABLED) && c->unblank)
+
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(c) {
+		if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank)
 			c->unblank();
+	}
+	console_srcu_read_unlock(cookie);
+
 	console_unlock();
 
 	if (!oops_in_progress)
-- 
2.30.2


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

* [PATCH printk v4 18/39] printk: console_flush_on_panic: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (16 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 17/39] printk: console_unblank: use srcu console list iterator John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 19/39] printk: console_device: " John Ogness
                   ` (20 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

With SRCU it is now safe to traverse the console list, even if
the console_trylock() failed. However, overwriting console->seq
when console_trylock() failed is still an issue.

Switch to SRCU iteration and document remaining issue with
console->seq.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7304cbcd6dd4..f536233d8234 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3049,21 +3049,22 @@ void console_flush_on_panic(enum con_flush_mode mode)
 	console_may_schedule = 0;
 
 	if (mode == CONSOLE_REPLAY_ALL) {
-		struct hlist_node *tmp;
 		struct console *c;
+		int cookie;
 		u64 seq;
 
 		seq = prb_first_valid_seq(prb);
-		/*
-		 * This cannot use for_each_console() because it's not established
-		 * that the current context has console locked and neither there is
-		 * a guarantee that there is no concurrency in that case.
-		 *
-		 * Open code it for documentation purposes and pretend that
-		 * it works.
-		 */
-		hlist_for_each_entry_safe(c, tmp, &console_list, node)
+
+		cookie = console_srcu_read_lock();
+		for_each_console_srcu(c) {
+			/*
+			 * If the above console_trylock() failed, this is an
+			 * unsynchronized assignment. But in that case, the
+			 * kernel is in "hope and pray" mode anyway.
+			 */
 			c->seq = seq;
+		}
+		console_srcu_read_unlock(cookie);
 	}
 	console_unlock();
 }
-- 
2.30.2


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

* [PATCH printk v4 19/39] printk: console_device: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (17 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 18/39] printk: console_flush_on_panic: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 20/39] console: introduce console_is_registered() John Ogness
                   ` (19 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Use srcu console list iteration for console list traversal. It is
acceptable because the consoles might come and go at any time.
Strict synchronizing with console registration code would not bring
any advantage over srcu.

Document why the console_lock is still necessary. Note that this
is a preparatory change for when console_lock no longer provides
synchronization for the console list.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 kernel/printk/printk.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index f536233d8234..fb609a19f797 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3076,15 +3076,25 @@ struct tty_driver *console_device(int *index)
 {
 	struct console *c;
 	struct tty_driver *driver = NULL;
+	int cookie;
 
+	/*
+	 * Take console_lock to serialize device() callback with
+	 * other console operations. For example, fg_console is
+	 * modified under console_lock when switching vt.
+	 */
 	console_lock();
-	for_each_console(c) {
+
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(c) {
 		if (!c->device)
 			continue;
 		driver = c->device(c, index);
 		if (driver)
 			break;
 	}
+	console_srcu_read_unlock(cookie);
+
 	console_unlock();
 	return driver;
 }
-- 
2.30.2


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

* [PATCH printk v4 20/39] console: introduce console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (18 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 19/39] printk: console_device: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 21/39] serial_core: replace uart_console_enabled() with uart_console_registered() John Ogness
                   ` (18 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman

Currently it is not possible for drivers to detect if they have
already successfully registered their console. Several drivers
have multiple paths that lead to console registration. To avoid
attempting a 2nd registration (which leads to a WARN), drivers
are implementing their own solution.

Introduce console_is_registered() so drivers can easily identify
if their console is currently registered. A _locked() variant
is also provided if the caller is already holding the
console_list_lock.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 include/linux/console.h | 28 ++++++++++++++++++++++++++++
 kernel/printk/printk.c  |  2 +-
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index c1ca461d088a..f716e1dd9eaf 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -228,6 +228,34 @@ static inline void console_srcu_write_flags(struct console *con, short flags)
 	WRITE_ONCE(con->flags, flags);
 }
 
+/* Variant of console_is_registered() when the console_list_lock is held. */
+static inline bool console_is_registered_locked(const struct console *con)
+{
+	lockdep_assert_console_list_lock_held();
+	return !hlist_unhashed(&con->node);
+}
+
+/*
+ * console_is_registered - Check if the console is registered
+ * @con:	struct console pointer of console to check
+ *
+ * Context: Process context. May sleep while acquiring console list lock.
+ * Return: true if the console is in the console list, otherwise false.
+ *
+ * If false is returned for a console that was previously registered, it
+ * can be assumed that the console's unregistration is fully completed,
+ * including the exit() callback after console list removal.
+ */
+static inline bool console_is_registered(const struct console *con)
+{
+	bool ret;
+
+	console_list_lock();
+	ret = console_is_registered_locked(con);
+	console_list_unlock();
+	return ret;
+}
+
 /**
  * for_each_console_srcu() - Iterator over registered consoles
  * @con:	struct console pointer used as loop cursor
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index fb609a19f797..e770b1ede6c9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3414,7 +3414,7 @@ static int unregister_console_locked(struct console *console)
 	/* Disable it unconditionally */
 	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
 
-	if (hlist_unhashed(&console->node)) {
+	if (!console_is_registered_locked(console)) {
 		console_unlock();
 		return -ENODEV;
 	}
-- 
2.30.2


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

* [PATCH printk v4 21/39] serial_core: replace uart_console_enabled() with uart_console_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (19 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 20/39] console: introduce console_is_registered() John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 22/39] tty: nfcon: use console_is_registered() John Ogness
                   ` (17 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, Ilpo Järvinen,
	Andy Shevchenko, Lukas Wunner, Geert Uytterhoeven, linux-serial

All users of uart_console_enabled() really want to know if a console
is registered. It is not reliable to check for CON_ENABLED in order
to identify if a console is registered. Use console_is_registered()
instead.

A _locked() variant is provided because uart_set_options() is always
called with the console_list_lock held and must check if a console
is registered in order to synchronize with kgdboc.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/8250/8250_core.c |  2 +-
 drivers/tty/serial/pic32_uart.c     |  2 +-
 drivers/tty/serial/serial_core.c    | 14 +++++++-------
 include/linux/serial_core.h         | 10 ++++++++--
 4 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 94fbf0add2ce..74568292186f 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -565,7 +565,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
 		up->port.dev = dev;
 
-		if (uart_console_enabled(&up->port))
+		if (uart_console_registered(&up->port))
 			pm_runtime_get_sync(up->port.dev);
 
 		serial8250_apply_quirks(up);
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index 2beada66c824..1183b2a26539 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -919,7 +919,7 @@ static int pic32_uart_probe(struct platform_device *pdev)
 	}
 
 #ifdef CONFIG_SERIAL_PIC32_CONSOLE
-	if (uart_console_enabled(port)) {
+	if (uart_console_registered(port)) {
 		/* The peripheral clock has been enabled by console_setup,
 		 * so disable it till the port is used.
 		 */
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 179ee199df34..b9fbbee598b8 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2223,11 +2223,11 @@ uart_set_options(struct uart_port *port, struct console *co,
 	/*
 	 * Ensure that the serial-console lock is initialised early.
 	 *
-	 * Note that the console-enabled check is needed because of kgdboc,
-	 * which can end up calling uart_set_options() for an already enabled
+	 * Note that the console-registered check is needed because
+	 * kgdboc can call uart_set_options() for an already registered
 	 * console via tty_find_polling_driver() and uart_poll_init().
 	 */
-	if (!uart_console_enabled(port) && !port->console_reinit)
+	if (!uart_console_registered_locked(port) && !port->console_reinit)
 		uart_port_spin_lock_init(port);
 
 	memset(&termios, 0, sizeof(struct ktermios));
@@ -2573,7 +2573,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 		 * successfully registered yet, try to re-register it.
 		 * It may be that the port was not available.
 		 */
-		if (port->cons && !(port->cons->flags & CON_ENABLED))
+		if (port->cons && !console_is_registered(port->cons))
 			register_console(port->cons);
 
 		/*
@@ -2956,7 +2956,7 @@ static ssize_t console_show(struct device *dev,
 	mutex_lock(&port->mutex);
 	uport = uart_port_check(state);
 	if (uport)
-		console = uart_console_enabled(uport);
+		console = uart_console_registered(uport);
 	mutex_unlock(&port->mutex);
 
 	return sprintf(buf, "%c\n", console ? 'Y' : 'N');
@@ -2978,7 +2978,7 @@ static ssize_t console_store(struct device *dev,
 	mutex_lock(&port->mutex);
 	uport = uart_port_check(state);
 	if (uport) {
-		oldconsole = uart_console_enabled(uport);
+		oldconsole = uart_console_registered(uport);
 		if (oldconsole && !newconsole) {
 			ret = unregister_console(uport->cons);
 		} else if (!oldconsole && newconsole) {
@@ -3086,7 +3086,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
 	 * If this port is in use as a console then the spinlock is already
 	 * initialised.
 	 */
-	if (!uart_console_enabled(uport))
+	if (!uart_console_registered(uport))
 		uart_port_spin_lock_init(uport);
 
 	if (uport->cons && uport->dev)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index d657f2a42a7b..91871464b99d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -743,9 +743,15 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
 static inline int setup_earlycon(char *buf) { return 0; }
 #endif
 
-static inline bool uart_console_enabled(struct uart_port *port)
+/* Variant of uart_console_registered() when the console_list_lock is held. */
+static inline bool uart_console_registered_locked(struct uart_port *port)
 {
-	return uart_console(port) && (port->cons->flags & CON_ENABLED);
+	return uart_console(port) && console_is_registered_locked(port->cons);
+}
+
+static inline bool uart_console_registered(struct uart_port *port)
+{
+	return uart_console(port) && console_is_registered(port->cons);
 }
 
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
-- 
2.30.2


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

* [PATCH printk v4 22/39] tty: nfcon: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (20 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 21/39] serial_core: replace uart_console_enabled() with uart_console_registered() John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 13:08   ` Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 23/39] efi: earlycon: " John Ogness
                   ` (16 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Geert Uytterhoeven, linux-m68k

Currently CON_ENABLED is being (mis)used to identify if the console
has been registered. This is not reliable because it can be set even
though registration failed or it can be unset, even though the console
is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 arch/m68k/emu/nfcon.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 557d60867f98..6fdc13610565 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -49,7 +49,7 @@ static void nfcon_write(struct console *con, const char *str,
 static struct tty_driver *nfcon_device(struct console *con, int *index)
 {
 	*index = 0;
-	return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL;
+	return console_is_registered(con) ? nfcon_tty_driver : NULL;
 }
 
 static struct console nf_console = {
@@ -107,6 +107,11 @@ static int __init nf_debug_setup(char *arg)
 
 	stderr_id = nf_get_id("NF_STDERR");
 	if (stderr_id) {
+		/*
+		 * The console will be enabled when debug=nfcon is specified
+		 * as a kernel parameter. Since this is a non-standard way
+		 * of enabling consoles, it must be explicitly enabled.
+		 */
 		nf_console.flags |= CON_ENABLED;
 		register_console(&nf_console);
 	}
@@ -151,7 +156,7 @@ static int __init nfcon_init(void)
 
 	nfcon_tty_driver = driver;
 
-	if (!(nf_console.flags & CON_ENABLED))
+	if (!console_is_registered(&nf_console))
 		register_console(&nf_console);
 
 	return 0;
-- 
2.30.2


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

* [PATCH printk v4 23/39] efi: earlycon: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (21 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 22/39] tty: nfcon: use console_is_registered() John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 24/39] tty: hvc: " John Ogness
                   ` (15 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Ard Biesheuvel, linux-efi

The CON_ENABLED status of a console is a runtime setting that does not
involve the console driver. Drivers must not assume that if the console
is disabled then proper hardware management is not needed. For the EFI
earlycon case, it is about remapping/unmapping memory for the
framebuffer.

Use console_is_registered() instead of checking CON_ENABLED.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/firmware/efi/earlycon.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index a52236e11e5f..4d6c5327471a 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -29,8 +29,8 @@ static void *efi_fb;
  */
 static int __init efi_earlycon_remap_fb(void)
 {
-	/* bail if there is no bootconsole or it has been disabled already */
-	if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
+	/* bail if there is no bootconsole or it was unregistered already */
+	if (!earlycon_console || !console_is_registered(earlycon_console))
 		return 0;
 
 	efi_fb = memremap(fb_base, screen_info.lfb_size,
@@ -42,8 +42,8 @@ early_initcall(efi_earlycon_remap_fb);
 
 static int __init efi_earlycon_unmap_fb(void)
 {
-	/* unmap the bootconsole fb unless keep_bootcon has left it enabled */
-	if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
+	/* unmap the bootconsole fb unless keep_bootcon left it registered */
+	if (efi_fb && !console_is_registered(earlycon_console))
 		memunmap(efi_fb);
 	return 0;
 }
-- 
2.30.2


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

* [PATCH printk v4 24/39] tty: hvc: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (22 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 23/39] efi: earlycon: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 25/39] tty: serial: earlycon: " John Ogness
                   ` (14 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, linuxppc-dev

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/hvc/hvc_console.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 4802cfaa107f..a683e21df19c 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -264,8 +264,8 @@ static void hvc_port_destruct(struct tty_port *port)
 
 static void hvc_check_console(int index)
 {
-	/* Already enabled, bail out */
-	if (hvc_console.flags & CON_ENABLED)
+	/* Already registered, bail out */
+	if (console_is_registered(&hvc_console))
 		return;
 
  	/* If this index is what the user requested, then register
-- 
2.30.2


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

* [PATCH printk v4 25/39] tty: serial: earlycon: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (23 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 24/39] tty: hvc: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 26/39] tty: serial: pic32_uart: " John Ogness
                   ` (13 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/earlycon.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index a5f380584cda..4f6e9bf57169 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -181,7 +181,7 @@ int __init setup_earlycon(char *buf)
 	if (!buf || !buf[0])
 		return -EINVAL;
 
-	if (early_con.flags & CON_ENABLED)
+	if (console_is_registered(&early_con))
 		return -EALREADY;
 
 again:
@@ -253,7 +253,7 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
 	bool big_endian;
 	u64 addr;
 
-	if (early_con.flags & CON_ENABLED)
+	if (console_is_registered(&early_con))
 		return -EALREADY;
 
 	spin_lock_init(&port->lock);
-- 
2.30.2


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

* [PATCH printk v4 26/39] tty: serial: pic32_uart: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (24 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 25/39] tty: serial: earlycon: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 27/39] tty: serial: samsung_tty: " John Ogness
                   ` (12 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/pic32_uart.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index 1183b2a26539..c38754d593ca 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -843,7 +843,7 @@ console_initcall(pic32_console_init);
  */
 static int __init pic32_late_console_init(void)
 {
-	if (!(pic32_console.flags & CON_ENABLED))
+	if (!console_is_registered(&pic32_console))
 		register_console(&pic32_console);
 
 	return 0;
-- 
2.30.2


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

* [PATCH printk v4 27/39] tty: serial: samsung_tty: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (25 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 26/39] tty: serial: pic32_uart: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 28/39] tty: serial: xilinx_uartps: " John Ogness
                   ` (11 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Krzysztof Kozlowski, Alim Akhtar, Greg Kroah-Hartman, Jiri Slaby,
	linux-arm-kernel, linux-samsung-soc, linux-serial

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/samsung_tty.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 77d1363029f5..9c252c9ca95a 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -1732,7 +1732,7 @@ static void __init s3c24xx_serial_register_console(void)
 
 static void s3c24xx_serial_unregister_console(void)
 {
-	if (s3c24xx_serial_console.flags & CON_ENABLED)
+	if (console_is_registered(&s3c24xx_serial_console))
 		unregister_console(&s3c24xx_serial_console);
 }
 
-- 
2.30.2


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

* [PATCH printk v4 28/39] tty: serial: xilinx_uartps: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (26 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 27/39] tty: serial: samsung_tty: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 29/39] usb: early: xhci-dbc: " John Ogness
                   ` (10 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, Michal Simek, linux-serial,
	linux-arm-kernel

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/xilinx_uartps.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 2eff7cff57c4..0cbd1892c53b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1631,7 +1631,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
 #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
 	/* This is not port which is used for console that's why clean it up */
 	if (console_port == port &&
-	    !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
+	    !console_is_registered(cdns_uart_uart_driver.cons)) {
 		console_port = NULL;
 		cdns_uart_console.index = -1;
 	}
-- 
2.30.2


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

* [PATCH printk v4 29/39] usb: early: xhci-dbc: use console_is_registered()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (27 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 28/39] tty: serial: xilinx_uartps: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 30/39] netconsole: avoid CON_ENABLED misuse to track registration John Ogness
                   ` (9 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Peter Zijlstra, Mathias Nyman, linux-usb

It is not reliable to check for CON_ENABLED in order to identify if a
console is registered. Use console_is_registered() instead.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 drivers/usb/early/xhci-dbc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index bfb7e2b85299..797047154820 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -927,7 +927,7 @@ void __init early_xdbc_register_console(void)
 
 static void xdbc_unregister_console(void)
 {
-	if (early_xdbc_console.flags & CON_ENABLED)
+	if (console_is_registered(&early_xdbc_console))
 		unregister_console(&early_xdbc_console);
 }
 
-- 
2.30.2


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

* [PATCH printk v4 30/39] netconsole: avoid CON_ENABLED misuse to track registration
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (28 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 29/39] usb: early: xhci-dbc: " John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred John Ogness
                   ` (8 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	netdev

The CON_ENABLED flag is being misused to track whether or not the
extended console should be or has been registered. Instead use
a local variable to decide if the extended console should be
registered and console_is_registered() to determine if it has
been registered.

Also add a check in cleanup_netconsole() to only unregister the
extended console if it has been registered.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/net/netconsole.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index bdff9ac5056d..4f4f79532c6c 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -332,10 +332,8 @@ static ssize_t enabled_store(struct config_item *item,
 	}
 
 	if (enabled) {	/* true */
-		if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
-			netconsole_ext.flags |= CON_ENABLED;
+		if (nt->extended && !console_is_registered(&netconsole_ext))
 			register_console(&netconsole_ext);
-		}
 
 		/*
 		 * Skip netpoll_parse_options() -- all the attributes are
@@ -869,7 +867,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 
 static struct console netconsole_ext = {
 	.name	= "netcon_ext",
-	.flags	= CON_EXTENDED,	/* starts disabled, registered on first use */
+	.flags	= CON_ENABLED | CON_EXTENDED,
 	.write	= write_ext_msg,
 };
 
@@ -883,6 +881,7 @@ static int __init init_netconsole(void)
 {
 	int err;
 	struct netconsole_target *nt, *tmp;
+	bool extended = false;
 	unsigned long flags;
 	char *target_config;
 	char *input = config;
@@ -895,11 +894,12 @@ static int __init init_netconsole(void)
 				goto fail;
 			}
 			/* Dump existing printks when we register */
-			if (nt->extended)
-				netconsole_ext.flags |= CON_PRINTBUFFER |
-							CON_ENABLED;
-			else
+			if (nt->extended) {
+				extended = true;
+				netconsole_ext.flags |= CON_PRINTBUFFER;
+			} else {
 				netconsole.flags |= CON_PRINTBUFFER;
+			}
 
 			spin_lock_irqsave(&target_list_lock, flags);
 			list_add(&nt->list, &target_list);
@@ -915,7 +915,7 @@ static int __init init_netconsole(void)
 	if (err)
 		goto undonotifier;
 
-	if (netconsole_ext.flags & CON_ENABLED)
+	if (extended)
 		register_console(&netconsole_ext);
 	register_console(&netconsole);
 	pr_info("network logging started\n");
@@ -945,7 +945,8 @@ static void __exit cleanup_netconsole(void)
 {
 	struct netconsole_target *nt, *tmp;
 
-	unregister_console(&netconsole_ext);
+	if (console_is_registered(&netconsole_ext))
+		unregister_console(&netconsole_ext);
 	unregister_console(&netconsole);
 	dynamic_netconsole_exit();
 	unregister_netdevice_notifier(&netconsole_netdev_notifier);
-- 
2.30.2


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

* [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (29 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 30/39] netconsole: avoid CON_ENABLED misuse to track registration John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 19:51   ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 32/39] tty: tty_io: use console_list_lock for list synchronization John Ogness
                   ` (7 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Helge Deller, Greg Kroah-Hartman, Javier Martinez Canillas,
	Thomas Zimmermann, Juergen Gross, Boris Ostrovsky, Tom Rix,
	linux-fbdev, dri-devel

With commit 9e124fe16ff2("xen: Enable console tty by default in domU
if it's not a dummy") a hack was implemented to make sure that the
tty console remains the console behind the /dev/console device. The
main problem with the hack is that, after getting the console pointer
to the tty console, it is assumed the pointer is still valid after
releasing the console_sem. This assumption is incorrect and unsafe.

Make the hack safe by introducing a new function
console_force_preferred_locked() and perform the full operation
under the console_list_lock.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 drivers/video/fbdev/xen-fbfront.c | 12 +++-----
 include/linux/console.h           |  1 +
 kernel/printk/printk.c            | 49 +++++++++++++++++++++++++++++--
 3 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c
index 4d2694d904aa..8752d389e382 100644
--- a/drivers/video/fbdev/xen-fbfront.c
+++ b/drivers/video/fbdev/xen-fbfront.c
@@ -504,18 +504,14 @@ static void xenfb_make_preferred_console(void)
 	if (console_set_on_cmdline)
 		return;
 
-	console_lock();
+	console_list_lock();
 	for_each_console(c) {
 		if (!strcmp(c->name, "tty") && c->index == 0)
 			break;
 	}
-	console_unlock();
-	if (c) {
-		unregister_console(c);
-		c->flags |= CON_CONSDEV;
-		c->flags &= ~CON_PRINTBUFFER; /* don't print again */
-		register_console(c);
-	}
+	if (c)
+		console_force_preferred_locked(c);
+	console_list_unlock();
 }
 
 static int xenfb_resume(struct xenbus_device *dev)
diff --git a/include/linux/console.h b/include/linux/console.h
index f716e1dd9eaf..9cea254b34b8 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -291,6 +291,7 @@ enum con_flush_mode {
 };
 
 extern int add_preferred_console(char *name, int idx, char *options);
+extern void console_force_preferred_locked(struct console *con);
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
 extern void console_lock(void);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e770b1ede6c9..dff76c1cef80 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -247,9 +247,10 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
 void console_list_lock(void)
 {
 	/*
-	 * In unregister_console(), synchronize_srcu() is called with the
-	 * console_list_lock held. Therefore it is not allowed that the
-	 * console_list_lock is taken with the srcu_lock held.
+	 * In unregister_console() and console_force_preferred_locked(),
+	 * synchronize_srcu() is called with the console_list_lock held.
+	 * Therefore it is not allowed that the console_list_lock is taken
+	 * with the srcu_lock held.
 	 *
 	 * Detecting if this context is really in the read-side critical
 	 * section is only possible if the appropriate debug options are
@@ -3461,6 +3462,48 @@ int unregister_console(struct console *console)
 }
 EXPORT_SYMBOL(unregister_console);
 
+/**
+ * console_force_preferred_locked - force a registered console preferred
+ * @con: The registered console to force preferred.
+ *
+ * Must be called under console_list_lock().
+ */
+void console_force_preferred_locked(struct console *con)
+{
+	struct console *cur_pref_con;
+
+	if (!console_is_registered_locked(con))
+		return;
+
+	cur_pref_con = console_first();
+
+	/* Already preferred? */
+	if (cur_pref_con == con)
+		return;
+
+	/*
+	 * Delete, but do not re-initialize the entry. This allows the console
+	 * to continue to appear registered (via any hlist_unhashed_lockless()
+	 * checks), even though it was briefly removed from the console list.
+	 */
+	hlist_del_rcu(&con->node);
+
+	/*
+	 * Ensure that all SRCU list walks have completed so that the console
+	 * can be added to the beginning of the console list and its forward
+	 * list pointer can be re-initialized.
+	 */
+	synchronize_srcu(&console_srcu);
+
+	con->flags |= CON_CONSDEV;
+	WARN_ON(!con->device);
+
+	/* Only the new head can have CON_CONSDEV set. */
+	console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
+	hlist_add_behind_rcu(&con->node, console_list.first);
+}
+EXPORT_SYMBOL(console_force_preferred_locked);
+
 /*
  * Initialize the console device. This is called *early*, so
  * we can't necessarily depend on lots of kernel help here.
-- 
2.30.2


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

* [PATCH printk v4 32/39] tty: tty_io: use console_list_lock for list synchronization
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (30 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 33/39] proc: consoles: use console_list_lock for list iteration John Ogness
                   ` (6 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby

show_cons_active() uses the console_lock to gather information
on registered consoles. It requires that no consoles are unregistered
until it is finished. The console_list_lock should be used because
list synchronization responsibility will be removed from the
console_lock in a later change.

Note, the console_lock is still needed to serialize the device()
callback with other console operations.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/tty_io.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index ee4da2fec328..cafdff575716 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3527,16 +3527,13 @@ static ssize_t show_cons_active(struct device *dev,
 	ssize_t count = 0;
 
 	/*
-	 * Hold the console_lock to guarantee that no consoles are
+	 * Hold the console_list_lock to guarantee that no consoles are
 	 * unregistered until all console processing is complete.
 	 * This also allows safe traversal of the console list and
 	 * race-free reading of @flags.
-	 *
-	 * Take console_lock to serialize device() callback with
-	 * other console operations. For example, fg_console is
-	 * modified under console_lock when switching vt.
 	 */
-	console_lock();
+	console_list_lock();
+
 	for_each_console(c) {
 		if (!c->device)
 			continue;
@@ -3548,6 +3545,13 @@ static ssize_t show_cons_active(struct device *dev,
 		if (i >= ARRAY_SIZE(cs))
 			break;
 	}
+
+	/*
+	 * Take console_lock to serialize device() callback with
+	 * other console operations. For example, fg_console is
+	 * modified under console_lock when switching vt.
+	 */
+	console_lock();
 	while (i--) {
 		int index = cs[i]->index;
 		struct tty_driver *drv = cs[i]->device(cs[i], &index);
@@ -3563,6 +3567,8 @@ static ssize_t show_cons_active(struct device *dev,
 	}
 	console_unlock();
 
+	console_list_unlock();
+
 	return count;
 }
 static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
-- 
2.30.2


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

* [PATCH printk v4 33/39] proc: consoles: use console_list_lock for list iteration
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (31 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 32/39] tty: tty_io: use console_list_lock for list synchronization John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator John Ogness
                   ` (5 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, linux-fsdevel

The console_lock is used in part to guarantee safe list iteration.
The console_list_lock should be used because list synchronization
responsibility will be removed from the console_lock in a later
change.

Note, the console_lock is still needed to serialize the device()
callback with other console operations.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 fs/proc/consoles.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index 46b305fa04ed..e0758fe7936d 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -33,7 +33,16 @@ static int show_console_dev(struct seq_file *m, void *v)
 	if (con->device) {
 		const struct tty_driver *driver;
 		int index;
+
+		/*
+		 * Take console_lock to serialize device() callback with
+		 * other console operations. For example, fg_console is
+		 * modified under console_lock when switching vt.
+		 */
+		console_lock();
 		driver = con->device(con, &index);
+		console_unlock();
+
 		if (driver) {
 			dev = MKDEV(driver->major, driver->minor_start);
 			dev += index;
@@ -64,15 +73,11 @@ static void *c_start(struct seq_file *m, loff_t *pos)
 	loff_t off = 0;
 
 	/*
-	 * Take console_lock to serialize device() callback with
-	 * other console operations. For example, fg_console is
-	 * modified under console_lock when switching vt.
-	 *
-	 * Hold the console_lock to guarantee safe traversal of the
+	 * Hold the console_list_lock to guarantee safe traversal of the
 	 * console list. SRCU cannot be used because there is no
 	 * place to store the SRCU cookie.
 	 */
-	console_lock();
+	console_list_lock();
 	for_each_console(con)
 		if (off++ == *pos)
 			break;
@@ -90,7 +95,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void c_stop(struct seq_file *m, void *v)
 {
-	console_unlock();
+	console_list_unlock();
 }
 
 static const struct seq_operations consoles_op = {
-- 
2.30.2


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

* [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (32 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 33/39] proc: consoles: use console_list_lock for list iteration John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 15:17   ` Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal John Ogness
                   ` (4 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

Use srcu console list iteration for safe console list traversal.
Note that this is a preparatory change for when console_lock no
longer provides synchronization for the console list.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 drivers/tty/serial/kgdboc.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 5be381003e58..c6df9ef34099 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -451,6 +451,7 @@ static void kgdboc_earlycon_pre_exp_handler(void)
 {
 	struct console *con;
 	static bool already_warned;
+	int cookie;
 
 	if (already_warned)
 		return;
@@ -463,9 +464,14 @@ static void kgdboc_earlycon_pre_exp_handler(void)
 	 * serial drivers might be OK with this, print a warning once per
 	 * boot if we detect this case.
 	 */
-	for_each_console(con)
+	cookie = console_srcu_read_lock();
+	for_each_console_srcu(con) {
 		if (con == kgdboc_earlycon_io_ops.cons)
-			return;
+			break;
+	}
+	console_srcu_read_unlock(cookie);
+	if (con)
+		return;
 
 	already_warned = true;
 	pr_warn("kgdboc_earlycon is still using bootconsole\n");
-- 
2.30.2


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

* [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (33 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 15:18   ` Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 36/39] tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console() John Ogness
                   ` (3 subsequent siblings)
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

configure_kgdboc() uses the console_lock for console list iteration. Use
the console_list_lock instead because list synchronization responsibility
will be removed from the console_lock in a later change.

The SRCU iterator could have been used here, but a later change will
relocate the locking of the console_list_lock to also provide
synchronization against register_console().

Note, the console_lock is still needed to serialize the device()
callback with other console operations.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 drivers/tty/serial/kgdboc.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index c6df9ef34099..82b4b4d67823 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -193,7 +193,16 @@ static int configure_kgdboc(void)
 	if (!p)
 		goto noconfig;
 
+	/* For safe traversal of the console list. */
+	console_list_lock();
+
+	/*
+	 * Take console_lock to serialize device() callback with
+	 * other console operations. For example, fg_console is
+	 * modified under console_lock when switching vt.
+	 */
 	console_lock();
+
 	for_each_console(cons) {
 		int idx;
 		if (cons->device && cons->device(cons, &idx) == p &&
@@ -202,8 +211,11 @@ static int configure_kgdboc(void)
 			break;
 		}
 	}
+
 	console_unlock();
 
+	console_list_unlock();
+
 	kgdb_tty_driver = p;
 	kgdb_tty_line = tty_line;
 
-- 
2.30.2


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

* [PATCH printk v4 36/39] tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console()
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (34 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 37/39] tty: serial: kgdboc: use console_list_lock to trap exit John Ogness
                   ` (2 subsequent siblings)
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

Calling tty_find_polling_driver() can lead to uart_set_options() being
called (via the poll_init() callback of tty_operations) to configure the
uart. But uart_set_options() can also be called by register_console()
(via the setup() callback of console).

Take the console_list_lock to synchronize against register_console() and
also use it for console list traversal. This also ensures the console list
cannot change until the polling console has been chosen.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/kgdboc.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 82b4b4d67823..8c2b7ccdfebf 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -189,12 +189,20 @@ static int configure_kgdboc(void)
 	if (kgdboc_register_kbd(&cptr))
 		goto do_register;
 
+	/*
+	 * tty_find_polling_driver() can call uart_set_options()
+	 * (via poll_init) to configure the uart. Take the console_list_lock
+	 * in order to synchronize against register_console(), which can also
+	 * configure the uart via uart_set_options(). This also allows safe
+	 * traversal of the console list.
+	 */
+	console_list_lock();
+
 	p = tty_find_polling_driver(cptr, &tty_line);
-	if (!p)
+	if (!p) {
+		console_list_unlock();
 		goto noconfig;
-
-	/* For safe traversal of the console list. */
-	console_list_lock();
+	}
 
 	/*
 	 * Take console_lock to serialize device() callback with
-- 
2.30.2


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

* [PATCH printk v4 37/39] tty: serial: kgdboc: use console_list_lock to trap exit
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (35 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 36/39] tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console() John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties John Ogness
  2022-11-14 16:29 ` [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console John Ogness
  38 siblings, 0 replies; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

kgdboc_earlycon_init() uses the console_lock to ensure that no consoles
are unregistered until the kgdboc_earlycon is setup. The console_list_lock
should be used instead because list synchronization responsibility will
be removed from the console_lock in a later change.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
 drivers/tty/serial/kgdboc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 8c2b7ccdfebf..a3ed9b34e2ab 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -558,13 +558,13 @@ static int __init kgdboc_earlycon_init(char *opt)
 	 */
 
 	/*
-	 * Hold the console_lock to guarantee that no consoles are
+	 * Hold the console_list_lock to guarantee that no consoles are
 	 * unregistered until the kgdboc_earlycon setup is complete.
 	 * Trapping the exit() callback relies on exit() not being
 	 * called until the trap is setup. This also allows safe
 	 * traversal of the console list and race-free reading of @flags.
 	 */
-	console_lock();
+	console_list_lock();
 	for_each_console(con) {
 		if (con->write && con->read &&
 		    (con->flags & (CON_BOOT | CON_ENABLED)) &&
@@ -606,7 +606,7 @@ static int __init kgdboc_earlycon_init(char *opt)
 	}
 
 unlock:
-	console_unlock();
+	console_list_unlock();
 
 	/* Non-zero means malformed option so we always return zero */
 	return 0;
-- 
2.30.2


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

* [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (36 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 37/39] tty: serial: kgdboc: use console_list_lock to trap exit John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 15:34   ` replay log: " Petr Mladek
  2022-11-14 16:29 ` [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console John Ogness
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

The console_list_lock provides synchronization for console list and
console->flags updates. All call sites that were using the console_lock
for this synchronization have either switched to use the
console_list_lock or the SRCU list iterator.

Remove console_lock usage for console list updates and console->flags
updates.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
 kernel/printk/printk.c | 42 ++++++++++++++++++------------------------
 1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index dff76c1cef80..8d635467882f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -86,8 +86,8 @@ EXPORT_SYMBOL(oops_in_progress);
 static DEFINE_MUTEX(console_mutex);
 
 /*
- * console_sem protects console_list and console->flags updates, and also
- * provides serialization for access to the entire console driver system.
+ * console_sem protects updates to console->seq and console_suspended,
+ * and also provides serialization for console printing.
  */
 static DEFINE_SEMAPHORE(console_sem);
 HLIST_HEAD(console_list);
@@ -2639,10 +2639,10 @@ static int console_cpu_notify(unsigned int cpu)
 }
 
 /**
- * console_lock - lock the console system for exclusive use.
+ * console_lock - block the console subsystem from printing
  *
- * Acquires a lock which guarantees that the caller has
- * exclusive access to the console system and console_list.
+ * Acquires a lock which guarantees that no consoles will
+ * be in or enter their write() callback.
  *
  * Can sleep, returns nothing.
  */
@@ -2659,10 +2659,10 @@ void console_lock(void)
 EXPORT_SYMBOL(console_lock);
 
 /**
- * console_trylock - try to lock the console system for exclusive use.
+ * console_trylock - try to block the console subsystem from printing
  *
- * Try to acquire a lock which guarantees that the caller has exclusive
- * access to the console system and console_list.
+ * Try to acquire a lock which guarantees that no consoles will
+ * be in or enter their write() callback.
  *
  * returns 1 on success, and 0 on failure to acquire the lock.
  */
@@ -2919,10 +2919,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
 }
 
 /**
- * console_unlock - unlock the console system
+ * console_unlock - unblock the console subsystem from printing
  *
- * Releases the console_lock which the caller holds on the console system
- * and the console driver list.
+ * Releases the console_lock which the caller holds to block printing of
+ * the console subsystem.
  *
  * While the console_lock was held, console output may have been buffered
  * by printk().  If this is the case, console_unlock(); emits
@@ -3109,9 +3109,7 @@ void console_stop(struct console *console)
 {
 	__pr_flush(console, 1000, true);
 	console_list_lock();
-	console_lock();
 	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
-	console_unlock();
 	console_list_unlock();
 
 	/*
@@ -3127,9 +3125,7 @@ EXPORT_SYMBOL(console_stop);
 void console_start(struct console *console)
 {
 	console_list_lock();
-	console_lock();
 	console_srcu_write_flags(console, console->flags | CON_ENABLED);
-	console_unlock();
 	console_list_unlock();
 	__pr_flush(console, 1000, true);
 }
@@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
 		 * boot console that is the furthest behind.
 		 */
 		if (bootcon_registered && !keep_bootcon) {
+			/*
+			 * Hold the console_lock to guarantee safe access to
+			 * console->seq.
+			 */
+			console_lock();
 			for_each_console(con) {
 				if ((con->flags & CON_BOOT) &&
 				    (con->flags & CON_ENABLED) &&
@@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
 					newcon->seq = con->seq;
 				}
 			}
+			console_unlock();
 		}
 	}
 
@@ -3348,7 +3350,6 @@ void register_console(struct console *newcon)
 	 * Put this console in the list - keep the
 	 * preferred driver at the head of the list.
 	 */
-	console_lock();
 	if (hlist_empty(&console_list)) {
 		/* Ensure CON_CONSDEV is always set for the head. */
 		newcon->flags |= CON_CONSDEV;
@@ -3362,7 +3363,6 @@ void register_console(struct console *newcon)
 	} else {
 		hlist_add_behind_rcu(&newcon->node, console_list.first);
 	}
-	console_unlock();
 
 	/*
 	 * No need to synchronize SRCU here! The caller does not rely
@@ -3410,15 +3410,11 @@ static int unregister_console_locked(struct console *console)
 	if (res > 0)
 		return 0;
 
-	console_lock();
-
 	/* Disable it unconditionally */
 	console_srcu_write_flags(console, console->flags & ~CON_ENABLED);
 
-	if (!console_is_registered_locked(console)) {
-		console_unlock();
+	if (!console_is_registered_locked(console))
 		return -ENODEV;
-	}
 
 	hlist_del_init_rcu(&console->node);
 
@@ -3434,8 +3430,6 @@ static int unregister_console_locked(struct console *console)
 	if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV)
 		console_srcu_write_flags(console_first(), console_first()->flags | CON_CONSDEV);
 
-	console_unlock();
-
 	/*
 	 * Ensure that all SRCU list walks have completed. All contexts
 	 * must not be able to see this console in the list so that any
-- 
2.30.2


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

* [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console
  2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
                   ` (37 preceding siblings ...)
  2022-11-14 16:29 ` [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties John Ogness
@ 2022-11-14 16:29 ` John Ogness
  2022-11-15 16:43   ` Petr Mladek
  38 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 16:29 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial, Linux-sh list,
	Linux-Renesas, Geert Uytterhoeven

When setting up the early console, the setup() callback of the
regular console is used. It is called manually before registering
the early console instead of providing a setup() callback for the
early console. This is probably because the early setup needs a
different @options during the early stage.

The issue here is that the setup() callback is called without the
console_list_lock held and functions such as uart_set_options()
expect that.

Rather than manually calling the setup() function before registering,
provide an early console setup() callback that will use the different
early options. This ensures that the error checking, ordering, and
locking context when setting up the early console are correct.

Since this early console can only be registered via the earlyprintk=
parameter, the @options argument of the setup() callback will always
be NULL. Rather than simply ignoring the argument, add a WARN_ON()
to get our attention in case the setup() callback semantics should
change in the future.

Note that technically the current implementation works because it is
only used in early boot. And since the early console setup is
performed before registering, it cannot race with anything and thus
does not need any locking. However, longterm maintenance is easier
when drivers rely on the subsystem API rather than manually
implementing steps that could cause breakage in the future.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/tty/serial/sh-sci.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 62f773286d44..76452fe2af86 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -3054,15 +3054,29 @@ static struct console serial_console = {
 };
 
 #ifdef CONFIG_SUPERH
+static char early_serial_buf[32];
+
+static int early_serial_console_setup(struct console *co, char *options)
+{
+	/*
+	 * This early console is always registered using the earlyprintk=
+	 * parameter, which does not call add_preferred_console(). Thus
+	 * @options is always NULL and the options for this early console
+	 * are passed using a custom buffer.
+	 */
+	WARN_ON(options);
+
+	return serial_console_setup(co, early_serial_buf);
+}
+
 static struct console early_serial_console = {
 	.name           = "early_ttySC",
 	.write          = serial_console_write,
+	.setup		= early_serial_console_setup,
 	.flags          = CON_PRINTBUFFER,
 	.index		= -1,
 };
 
-static char early_serial_buf[32];
-
 static int sci_probe_earlyprintk(struct platform_device *pdev)
 {
 	const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
@@ -3074,8 +3088,6 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
 
 	sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
 
-	serial_console_setup(&early_serial_console, early_serial_buf);
-
 	if (!strstr(early_serial_buf, "keep"))
 		early_serial_console.flags |= CON_BOOT;
 
-- 
2.30.2


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

* Re: [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred
  2022-11-14 16:29 ` [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred John Ogness
@ 2022-11-14 19:51   ` John Ogness
  2022-11-15 13:22     ` Petr Mladek
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-14 19:51 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Helge Deller, Greg Kroah-Hartman, Javier Martinez Canillas,
	Thomas Zimmermann, Juergen Gross, Boris Ostrovsky, Tom Rix,
	linux-fbdev, dri-devel

Hi,

After more detailed runtime testing I discovered that I didn't re-insert
the console to the correct place in the list. More below...

On 2022-11-14, John Ogness <john.ogness@linutronix.de> wrote:
> diff --git a/include/linux/console.h b/include/linux/console.h
> index f716e1dd9eaf..9cea254b34b8 100644
> --- a/include/linux/console.h
> +++ b/include/linux/console.h
> @@ -291,6 +291,7 @@ enum con_flush_mode {
>  };
>  
>  extern int add_preferred_console(char *name, int idx, char *options);
> +extern void console_force_preferred_locked(struct console *con);
>  extern void register_console(struct console *);
>  extern int unregister_console(struct console *);
>  extern void console_lock(void);
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index e770b1ede6c9..dff76c1cef80 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -3461,6 +3462,48 @@ int unregister_console(struct console *console)
>  }
>  EXPORT_SYMBOL(unregister_console);
>  
> +/**
> + * console_force_preferred_locked - force a registered console preferred
> + * @con: The registered console to force preferred.
> + *
> + * Must be called under console_list_lock().
> + */
> +void console_force_preferred_locked(struct console *con)
> +{
> +	struct console *cur_pref_con;
> +
> +	if (!console_is_registered_locked(con))
> +		return;
> +
> +	cur_pref_con = console_first();
> +
> +	/* Already preferred? */
> +	if (cur_pref_con == con)
> +		return;
> +
> +	/*
> +	 * Delete, but do not re-initialize the entry. This allows the console
> +	 * to continue to appear registered (via any hlist_unhashed_lockless()
> +	 * checks), even though it was briefly removed from the console list.
> +	 */
> +	hlist_del_rcu(&con->node);
> +
> +	/*
> +	 * Ensure that all SRCU list walks have completed so that the console
> +	 * can be added to the beginning of the console list and its forward
> +	 * list pointer can be re-initialized.
> +	 */
> +	synchronize_srcu(&console_srcu);
> +
> +	con->flags |= CON_CONSDEV;
> +	WARN_ON(!con->device);
> +
> +	/* Only the new head can have CON_CONSDEV set. */
> +	console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
> +	hlist_add_behind_rcu(&con->node, console_list.first);

This is adding the console as the 2nd item. It should be the new
head. The patch below fixes it.

I have done careful runtime testing with this fixup. After the
force_preferred, the console is the new head and sending data to
/dev/console redirects to that console.

It would be nice if we could fold this in. Sorry.

John Ogness

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8d635467882f..4b77586cf4cb 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3494,7 +3494,7 @@ void console_force_preferred_locked(struct console *con)
 
 	/* Only the new head can have CON_CONSDEV set. */
 	console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
-	hlist_add_behind_rcu(&con->node, console_list.first);
+	hlist_add_head_rcu(&con->node, &console_list);
 }
 EXPORT_SYMBOL(console_force_preferred_locked);
 

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

* Re: [PATCH printk v4 13/39] kdb: use srcu console list iterator
  2022-11-14 16:29 ` [PATCH printk v4 13/39] kdb: " John Ogness
@ 2022-11-14 21:16   ` Aaron Tomlin
  0 siblings, 0 replies; 64+ messages in thread
From: Aaron Tomlin @ 2022-11-14 21:16 UTC (permalink / raw)
  To: John Ogness
  Cc: Petr Mladek, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
	linux-kernel, Jason Wessel, Daniel Thompson, Douglas Anderson,
	Luis Chamberlain, kgdb-bugreport

On Mon 2022-11-14 17:35 +0106, John Ogness wrote:
> Guarantee safe iteration of the console list by using SRCU.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> ---
>  kernel/debug/kdb/kdb_io.c | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c
> index 67d3c48a1522..5c7e9ba7cd6b 100644
> --- a/kernel/debug/kdb/kdb_io.c
> +++ b/kernel/debug/kdb/kdb_io.c
> @@ -545,6 +545,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
>  {
>  	struct console *c;
>  	const char *cp;
> +	int cookie;
>  	int len;
>  
>  	if (msg_len == 0)
> @@ -558,8 +559,20 @@ static void kdb_msg_write(const char *msg, int msg_len)
>  		cp++;
>  	}
>  
> -	for_each_console(c) {
> -		if (!(c->flags & CON_ENABLED))
> +	/*
> +	 * The console_srcu_read_lock() only provides safe console list
> +	 * traversal. The use of the ->write() callback relies on all other
> +	 * CPUs being stopped at the moment and console drivers being able to
> +	 * handle reentrance when @oops_in_progress is set.
> +	 *
> +	 * There is no guarantee that every console driver can handle
> +	 * reentrance in this way; the developer deploying the debugger
> +	 * is responsible for ensuring that the console drivers they
> +	 * have selected handle reentrance appropriately.
> +	 */
> +	cookie = console_srcu_read_lock();
> +	for_each_console_srcu(c) {
> +		if (!(console_srcu_read_flags(c) & CON_ENABLED))
>  			continue;
>  		if (c == dbg_io_ops->cons)
>  			continue;
> @@ -577,6 +590,7 @@ static void kdb_msg_write(const char *msg, int msg_len)
>  		--oops_in_progress;
>  		touch_nmi_watchdog();
>  	}
> +	console_srcu_read_unlock(cookie);
>  }
>  
>  int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
> -- 
> 2.30.2
> 

Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>

-- 
Aaron Tomlin


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

* Re: [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection
  2022-11-14 16:28 ` [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection John Ogness
@ 2022-11-15 10:50   ` Petr Mladek
  2022-11-15 11:33     ` John Ogness
  0 siblings, 1 reply; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 10:50 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Miguel Ojeda, Greg Kroah-Hartman, Paul E . McKenney

On Mon 2022-11-14 17:34:56, John Ogness wrote:
> Provide an NMI-safe SRCU protected variant to walk the console list.
> 
> Note that all console fields are now set before adding the console
> to the list to avoid the console becoming visible by SCRU readers
> before being fully initialized.
> 
> This is a preparatory change for a new console infrastructure which
> operates independent of the console BKL.
> 
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -3254,7 +3303,7 @@ int unregister_console(struct console *console)
>  		return -ENODEV;
>  	}
>  
> -	hlist_del_init(&console->node);
> +	hlist_del_init_rcu(&console->node);

This should be hlist_del_rcu() here so that a list walker that it just
processing this console could see the rest of the list.

It seems that hlist_unhashed() checks only node.pprev pointer
so that we even do not need to initialize it.

We discussed this in v3 in the patch implementing
console_force_preferred_locked(), see
https://lore.kernel.org/r/Y20aBwNWT19YDeib@alley.
I forgot that unregister_console() might have the same problem.

Best Regards,
Petr

>  
>  	/*
>  	 * <HISTORICAL>
> @@ -3269,6 +3318,14 @@ int unregister_console(struct console *console)
>  		console_first()->flags |= CON_CONSDEV;
>  
>  	console_unlock();
> +
> +	/*
> +	 * Ensure that all SRCU list walks have completed. All contexts
> +	 * must not be able to see this console in the list so that any
> +	 * exit/cleanup routines can be performed safely.
> +	 */
> +	synchronize_srcu(&console_srcu);
> +
>  	console_sysfs_notify();
>  
>  	if (console->exit)
> -- 
> 2.30.2

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

* Re: [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names
  2022-11-14 16:28 ` [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names John Ogness
@ 2022-11-15 11:01   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 11:01 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Mon 2022-11-14 17:34:57, John Ogness wrote:
> The @bootcon_enabled and @realcon_enabled local variables actually
> represent if such console types are registered. In general there
> has been a confusion about enabled vs. registered. Incorrectly
> naming such variables promotes such confusion.
> 
> Rename the variables to _registered.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

I like this:

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection
  2022-11-15 10:50   ` Petr Mladek
@ 2022-11-15 11:33     ` John Ogness
  2022-11-15 12:03       ` Petr Mladek
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-15 11:33 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Miguel Ojeda, Greg Kroah-Hartman, Paul E . McKenney

On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> On Mon 2022-11-14 17:34:56, John Ogness wrote:
>> Provide an NMI-safe SRCU protected variant to walk the console list.
>> 
>> Note that all console fields are now set before adding the console
>> to the list to avoid the console becoming visible by SCRU readers
>> before being fully initialized.
>> 
>> This is a preparatory change for a new console infrastructure which
>> operates independent of the console BKL.
>> 
>> --- a/kernel/printk/printk.c
>> +++ b/kernel/printk/printk.c
>> @@ -3254,7 +3303,7 @@ int unregister_console(struct console *console)
>>  		return -ENODEV;
>>  	}
>>  
>> -	hlist_del_init(&console->node);
>> +	hlist_del_init_rcu(&console->node);
>
> This should be hlist_del_rcu() here so that a list walker that it just
> processing this console could see the rest of the list.

hlist_del_init_rcu() does not prevent the rest of the list from being
seen. It only unlinks @pprev for future iterators.

> It seems that hlist_unhashed() checks only node.pprev pointer
> so that we even do not need to initialize it.
>
> We discussed this in v3 in the patch implementing
> console_force_preferred_locked(), see
> https://lore.kernel.org/r/Y20aBwNWT19YDeib@alley.
> I forgot that unregister_console() might have the same problem.

For console_force_preferred_locked() it was about making sure that the
console always appears registered, even though it is temporarily removed
from the console list.

For unregister_console() we want it to be seen as removed from the
console list.

John

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

* Re: [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection
  2022-11-15 11:33     ` John Ogness
@ 2022-11-15 12:03       ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 12:03 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Miguel Ojeda, Greg Kroah-Hartman, Paul E . McKenney

On Tue 2022-11-15 12:39:18, John Ogness wrote:
> On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> > On Mon 2022-11-14 17:34:56, John Ogness wrote:
> >> Provide an NMI-safe SRCU protected variant to walk the console list.
> >> 
> >> Note that all console fields are now set before adding the console
> >> to the list to avoid the console becoming visible by SCRU readers
> >> before being fully initialized.
> >> 
> >> This is a preparatory change for a new console infrastructure which
> >> operates independent of the console BKL.
> >> 
> >> --- a/kernel/printk/printk.c
> >> +++ b/kernel/printk/printk.c
> >> @@ -3254,7 +3303,7 @@ int unregister_console(struct console *console)
> >>  		return -ENODEV;
> >>  	}
> >>  
> >> -	hlist_del_init(&console->node);
> >> +	hlist_del_init_rcu(&console->node);
> >
> > This should be hlist_del_rcu() here so that a list walker that it just
> > processing this console could see the rest of the list.
> 
> hlist_del_init_rcu() does not prevent the rest of the list from being
> seen. It only unlinks @pprev for future iterators.

I see. I looked at hlist_del_init() instead of on the _rcu() variant.
hlist_del_init_rcu() is correct here.


> > It seems that hlist_unhashed() checks only node.pprev pointer
> > so that we even do not need to initialize it.
> >
> > We discussed this in v3 in the patch implementing
> > console_force_preferred_locked(), see
> > https://lore.kernel.org/r/Y20aBwNWT19YDeib@alley.
> > I forgot that unregister_console() might have the same problem.
> 
> For console_force_preferred_locked() it was about making sure that the
> console always appears registered, even though it is temporarily removed
> from the console list.
> 
> For unregister_console() we want it to be seen as removed from the
> console list.

Makes sense.

Best Regards,
Petr

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

* Re: [PATCH printk v4 05/39] printk: fix setting first seq for consoles
  2022-11-14 16:28 ` [PATCH printk v4 05/39] printk: fix setting first seq for consoles John Ogness
@ 2022-11-15 12:04   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 12:04 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Mon 2022-11-14 17:34:58, John Ogness wrote:
> It used to be that all consoles were synchronized with respect to
> which message they were printing. After commit a699449bb13b ("printk:
> refactor and rework printing logic"), all consoles have their own
> @seq for tracking which message they are on. That commit also changed
> how the initial sequence number was chosen. Instead of choosing the
> next non-printed message, it chose the sequence number of the next
> message that will be added to the ringbuffer.
> 
> That change created a possibility that a non-boot console taking over
> for a boot console might skip messages if the boot console was behind
> and did not have a chance to catch up before being unregistered.
> 
> Since it is not possible to know which boot console a console is
> taking over, use the lowest @seq of all the enabled boot consoles. If
> no boot consoles are available/enabled, begin with the next message
> that will be added to the ringbuffer.
> 
> Also, since boot consoles are meant to be used at boot time, handle
> them the same as CON_PRINTBUFFER to ensure that no initial messages
> are skipped.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags
  2022-11-14 16:29 ` [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags John Ogness
@ 2022-11-15 12:26   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 12:26 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman

On Mon 2022-11-14 17:35:04, John Ogness wrote:
> After switching to SRCU for console list iteration, some readers
> will begin readings console->flags as a data race. Locklessly
> reading console->flags provides a consistent value because there
> is at most one CPU modifying console->flags and that CPU is
> using only read-modify-write operations.
> 
> Introduce a wrapper for SRCU iterators to read console flags.
> Introduce a matching wrapper to write to flags of registered
> consoles. Writing to flags of registered consoles is synchronized
> by the console_list_lock.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags
  2022-11-14 16:29 ` [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags John Ogness
@ 2022-11-15 12:47   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 12:47 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Mon 2022-11-14 17:35:09, John Ogness wrote:
> All users of console_is_usable() are SRCU iterators. Use the
> appropriate wrapper function to locklessly read the flags.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 22/39] tty: nfcon: use console_is_registered()
  2022-11-14 16:29 ` [PATCH printk v4 22/39] tty: nfcon: use console_is_registered() John Ogness
@ 2022-11-15 13:08   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 13:08 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Geert Uytterhoeven, linux-m68k

On Mon 2022-11-14 17:35:15, John Ogness wrote:
> Currently CON_ENABLED is being (mis)used to identify if the console
> has been registered. This is not reliable because it can be set even
> though registration failed or it can be unset, even though the console
> is registered. Use console_is_registered() instead.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred
  2022-11-14 19:51   ` John Ogness
@ 2022-11-15 13:22     ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 13:22 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Helge Deller, Greg Kroah-Hartman, Javier Martinez Canillas,
	Thomas Zimmermann, Juergen Gross, Boris Ostrovsky, Tom Rix,
	linux-fbdev, dri-devel

On Mon 2022-11-14 20:57:18, John Ogness wrote:
> Hi,
> 
> After more detailed runtime testing I discovered that I didn't re-insert
> the console to the correct place in the list. More below...
> 
> > --- a/kernel/printk/printk.c
> > +++ b/kernel/printk/printk.c
> > @@ -3461,6 +3462,48 @@ int unregister_console(struct console *console)
> >  }
> >  EXPORT_SYMBOL(unregister_console);
> >  
> > +/**
> > + * console_force_preferred_locked - force a registered console preferred
> > + * @con: The registered console to force preferred.
> > + *
> > + * Must be called under console_list_lock().
> > + */
> > +void console_force_preferred_locked(struct console *con)
> > +{
> > +	struct console *cur_pref_con;
> > +
> > +	if (!console_is_registered_locked(con))
> > +		return;
> > +
> > +	cur_pref_con = console_first();
> > +
> > +	/* Already preferred? */
> > +	if (cur_pref_con == con)
> > +		return;
> > +
> > +	/*
> > +	 * Delete, but do not re-initialize the entry. This allows the console
> > +	 * to continue to appear registered (via any hlist_unhashed_lockless()
> > +	 * checks), even though it was briefly removed from the console list.
> > +	 */
> > +	hlist_del_rcu(&con->node);
> > +
> > +	/*
> > +	 * Ensure that all SRCU list walks have completed so that the console
> > +	 * can be added to the beginning of the console list and its forward
> > +	 * list pointer can be re-initialized.
> > +	 */
> > +	synchronize_srcu(&console_srcu);
> > +
> > +	con->flags |= CON_CONSDEV;
> > +	WARN_ON(!con->device);
> > +
> > +	/* Only the new head can have CON_CONSDEV set. */
> > +	console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
> > +	hlist_add_behind_rcu(&con->node, console_list.first);
> 
> This is adding the console as the 2nd item. It should be the new
> head. The patch below fixes it.
> 
> I have done careful runtime testing with this fixup. After the
> force_preferred, the console is the new head and sending data to
> /dev/console redirects to that console.

Great catch!

> It would be nice if we could fold this in. Sorry.

I have missed it as well :-/

> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 8d635467882f..4b77586cf4cb 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -3494,7 +3494,7 @@ void console_force_preferred_locked(struct console *con)
>  
>  	/* Only the new head can have CON_CONSDEV set. */
>  	console_srcu_write_flags(cur_pref_con, cur_pref_con->flags & ~CON_CONSDEV);
> -	hlist_add_behind_rcu(&con->node, console_list.first);
> +	hlist_add_head_rcu(&con->node, &console_list);
>  }
>  EXPORT_SYMBOL(console_force_preferred_locked);

With this change:

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator
  2022-11-14 16:29 ` [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator John Ogness
@ 2022-11-15 15:17   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 15:17 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

On Mon 2022-11-14 17:35:27, John Ogness wrote:
> Use srcu console list iteration for safe console list traversal.
> Note that this is a preparatory change for when console_lock no
> longer provides synchronization for the console list.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal
  2022-11-14 16:29 ` [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal John Ogness
@ 2022-11-15 15:18   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 15:18 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Jason Wessel, Daniel Thompson, Douglas Anderson,
	Greg Kroah-Hartman, Jiri Slaby, kgdb-bugreport, linux-serial

On Mon 2022-11-14 17:35:28, John Ogness wrote:
> configure_kgdboc() uses the console_lock for console list iteration. Use
> the console_list_lock instead because list synchronization responsibility
> will be removed from the console_lock in a later change.
> 
> The SRCU iterator could have been used here, but a later change will
> relocate the locking of the console_list_lock to also provide
> synchronization against register_console().
> 
> Note, the console_lock is still needed to serialize the device()
> callback with other console operations.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

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

Best Regards,
Petr

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

* replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-14 16:29 ` [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties John Ogness
@ 2022-11-15 15:34   ` Petr Mladek
  2022-11-15 16:41     ` John Ogness
  2022-11-15 16:41     ` Petr Mladek
  0 siblings, 2 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 15:34 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Mon 2022-11-14 17:35:31, John Ogness wrote:
> The console_list_lock provides synchronization for console list and
> console->flags updates. All call sites that were using the console_lock
> for this synchronization have either switched to use the
> console_list_lock or the SRCU list iterator.
> 
> Remove console_lock usage for console list updates and console->flags
> updates.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>

> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
>  		 * boot console that is the furthest behind.
>  		 */
>  		if (bootcon_registered && !keep_bootcon) {
> +			/*
> +			 * Hold the console_lock to guarantee safe access to
> +			 * console->seq.
> +			 */
> +			console_lock();
>  			for_each_console(con) {
>  				if ((con->flags & CON_BOOT) &&
>  				    (con->flags & CON_ENABLED) &&
> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
>  					newcon->seq = con->seq;
>  				}
>  			}
> +			console_unlock();

Thinking more about it. This console_unlock() will actually cause
flushing the boot consoles. A solution would be to call
console_flush_all() here.

And we could/should solve this in a separate patch. This code was not locked
before. It is a corner case. It could be solved later.

>  		}
>  	}
>  

Best Regards,
Petr

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 15:34   ` replay log: " Petr Mladek
@ 2022-11-15 16:41     ` John Ogness
  2022-11-15 18:23       ` Petr Mladek
  2022-11-15 16:41     ` Petr Mladek
  1 sibling, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-15 16:41 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> On Mon 2022-11-14 17:35:31, John Ogness wrote:
>> --- a/kernel/printk/printk.c
>> +++ b/kernel/printk/printk.c
>> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
>>  		 * boot console that is the furthest behind.
>>  		 */
>>  		if (bootcon_registered && !keep_bootcon) {
>> +			/*
>> +			 * Hold the console_lock to guarantee safe access to
>> +			 * console->seq.
>> +			 */
>> +			console_lock();
>>  			for_each_console(con) {
>>  				if ((con->flags & CON_BOOT) &&
>>  				    (con->flags & CON_ENABLED) &&
>> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
>>  					newcon->seq = con->seq;
>>  				}
>>  			}
>> +			console_unlock();
>
> Thinking more about it. This console_unlock() will actually cause
> flushing the boot consoles. A solution would be to call
> console_flush_all() here.

console_flush_all() requires the console_lock, so I don't think it would
be different.

The correct solution would be to recognize if nextcon is taking over a
bootcon. If yes, that bootcon could be unregistered right here with
unregister_console_locked() and then seq for nextcon set appropriately
to perfectly take over.

But we will need to think about how we could recognize the same
device. I was thinking about if consoles hat some attribute showing
their io-membase or something so that it could be clear that the two are
the same hardware.

> And we could/should solve this in a separate patch. This code was not
> locked before. It is a corner case. It could be solved later.

Agreed.

John

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 15:34   ` replay log: " Petr Mladek
  2022-11-15 16:41     ` John Ogness
@ 2022-11-15 16:41     ` Petr Mladek
  2022-11-15 17:15       ` John Ogness
  1 sibling, 1 reply; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 16:41 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Tue 2022-11-15 16:34:10, Petr Mladek wrote:
> On Mon 2022-11-14 17:35:31, John Ogness wrote:
> > The console_list_lock provides synchronization for console list and
> > console->flags updates. All call sites that were using the console_lock
> > for this synchronization have either switched to use the
> > console_list_lock or the SRCU list iterator.
> > 
> > Remove console_lock usage for console list updates and console->flags
> > updates.
> > 
> > Signed-off-by: John Ogness <john.ogness@linutronix.de>
> 
> > --- a/kernel/printk/printk.c
> > +++ b/kernel/printk/printk.c
> > @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
> >  		 * boot console that is the furthest behind.
> >  		 */
> >  		if (bootcon_registered && !keep_bootcon) {
> > +			/*
> > +			 * Hold the console_lock to guarantee safe access to
> > +			 * console->seq.
> > +			 */
> > +			console_lock();
> >  			for_each_console(con) {
> >  				if ((con->flags & CON_BOOT) &&
> >  				    (con->flags & CON_ENABLED) &&
> > @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
> >  					newcon->seq = con->seq;
> >  				}
> >  			}
> > +			console_unlock();
> 
> Thinking more about it. This console_unlock() will actually cause
> flushing the boot consoles. A solution would be to call
> console_flush_all() here.
> 
> And we could/should solve this in a separate patch. This code was not locked
> before. It is a corner case. It could be solved later.
> 
> >  		}
> >  	}
> >  

The rest of the patch looks fine. I checked hopefully console_list walks
and console flags manipulations and everything looks good.

So, without the above two hunks:

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

Best Regards,
Petr

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

* Re: [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console
  2022-11-14 16:29 ` [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console John Ogness
@ 2022-11-15 16:43   ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 16:43 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial, Linux-sh list,
	Linux-Renesas, Geert Uytterhoeven

On Mon 2022-11-14 17:35:32, John Ogness wrote:
> When setting up the early console, the setup() callback of the
> regular console is used. It is called manually before registering
> the early console instead of providing a setup() callback for the
> early console. This is probably because the early setup needs a
> different @options during the early stage.
> 
> The issue here is that the setup() callback is called without the
> console_list_lock held and functions such as uart_set_options()
> expect that.
> 
> Rather than manually calling the setup() function before registering,
> provide an early console setup() callback that will use the different
> early options. This ensures that the error checking, ordering, and
> locking context when setting up the early console are correct.
> 
> Since this early console can only be registered via the earlyprintk=
> parameter, the @options argument of the setup() callback will always
> be NULL. Rather than simply ignoring the argument, add a WARN_ON()
> to get our attention in case the setup() callback semantics should
> change in the future.
> 
> Note that technically the current implementation works because it is
> only used in early boot. And since the early console setup is
> performed before registering, it cannot race with anything and thus
> does not need any locking. However, longterm maintenance is easier
> when drivers rely on the subsystem API rather than manually
> implementing steps that could cause breakage in the future.
> 
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

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

Best Regards,
Petr

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 16:41     ` Petr Mladek
@ 2022-11-15 17:15       ` John Ogness
  2022-11-15 18:36         ` Petr Mladek
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-15 17:15 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
>>> --- a/kernel/printk/printk.c
>>> +++ b/kernel/printk/printk.c
>>> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
>>>  		 * boot console that is the furthest behind.
>>>  		 */
>>>  		if (bootcon_registered && !keep_bootcon) {
>>> +			/*
>>> +			 * Hold the console_lock to guarantee safe access to
>>> +			 * console->seq.
>>> +			 */
>>> +			console_lock();
>>>  			for_each_console(con) {
>>>  				if ((con->flags & CON_BOOT) &&
>>>  				    (con->flags & CON_ENABLED) &&
>>> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
>>>  					newcon->seq = con->seq;
>>>  				}
>>>  			}
>>> +			console_unlock();
>
> So, without the above two hunks:
>
> Reviewed-by: Petr Mladek <pmladek@suse.com>

Note that we actually need those hunks to guarantee a consistent @seq
value. The console_lock is the only synchronization mechanism available
to read console->seq.

John

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 16:41     ` John Ogness
@ 2022-11-15 18:23       ` Petr Mladek
  2022-11-16  8:52         ` John Ogness
  0 siblings, 1 reply; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 18:23 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Tue 2022-11-15 17:47:12, John Ogness wrote:
> On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> > On Mon 2022-11-14 17:35:31, John Ogness wrote:
> >> --- a/kernel/printk/printk.c
> >> +++ b/kernel/printk/printk.c
> >> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
> >>  		 * boot console that is the furthest behind.
> >>  		 */
> >>  		if (bootcon_registered && !keep_bootcon) {
> >> +			/*
> >> +			 * Hold the console_lock to guarantee safe access to
> >> +			 * console->seq.
> >> +			 */
> >> +			console_lock();
> >>  			for_each_console(con) {
> >>  				if ((con->flags & CON_BOOT) &&
> >>  				    (con->flags & CON_ENABLED) &&
> >> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
> >>  					newcon->seq = con->seq;
> >>  				}
> >>  			}
> >> +			console_unlock();
> >
> > Thinking more about it. This console_unlock() will actually cause
> > flushing the boot consoles. A solution would be to call
> > console_flush_all() here.
> 
> console_flush_all() requires the console_lock, so I don't think it would
> be different.

I meant to keep the console_lock(), something like:

		if (bootcon_registered && !keep_bootcon) {
			/*
			 * Hold the console_lock to guarantee safe access to
			 * console->seq.
			 */
			console_lock();
			/* Try to sync all consoles. */
			console_flush_all();
			/* Check if some boot console is still behind. */
			for_each_console(con) {
				if ((con->flags & CON_BOOT) &&
				    (con->flags & CON_ENABLED) &&
				    con->seq < newcon->seq) {
					newcon->seq = con->seq;
				}
			}
			console_unlock();
		}

It is not that easy because console_flush_all() might handover the
console_lock(). Also some new messages might appear so that we
should re-read prb_next_seq().

Maybe, the best solution would be to call pr_flush():

		if (bootcon_registered && !keep_bootcon) {
			/*
			 * Try to sync all consoles because we do not
			 * know which one is going to be replaced
			 */
			pr_flush();
			/*
			 * Hold the console_lock to guarantee safe access to
			 * console->seq.
			 */
			console_lock();
			/* Check if some boot console is still behind. */
			for_each_console(con) {
				if ((con->flags & CON_BOOT) &&
				    (con->flags & CON_ENABLED) &&
				    con->seq < newcon->seq) {
					newcon->seq = con->seq;
				}
			}
			console_unlock();
		}

It was always just the best effort. It does not need to be perfect.
On the other hand, we should not make it much worse because people
report duplicated messages from time to time.

> The correct solution would be to recognize if nextcon is taking over a
> bootcon. If yes, that bootcon could be unregistered right here with
> unregister_console_locked() and then seq for nextcon set appropriately
> to perfectly take over.
> 
> But we will need to think about how we could recognize the same
> device. I was thinking about if consoles hat some attribute showing
> their io-membase or something so that it could be clear that the two are
> the same hardware.

Interesting idea. Well, it is out of scope of this patchset.

Best Regards,
Petr

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 17:15       ` John Ogness
@ 2022-11-15 18:36         ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-15 18:36 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Tue 2022-11-15 18:21:34, John Ogness wrote:
> On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> >>> --- a/kernel/printk/printk.c
> >>> +++ b/kernel/printk/printk.c
> >>> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon)
> >>>  		 * boot console that is the furthest behind.
> >>>  		 */
> >>>  		if (bootcon_registered && !keep_bootcon) {
> >>> +			/*
> >>> +			 * Hold the console_lock to guarantee safe access to
> >>> +			 * console->seq.
> >>> +			 */
> >>> +			console_lock();
> >>>  			for_each_console(con) {
> >>>  				if ((con->flags & CON_BOOT) &&
> >>>  				    (con->flags & CON_ENABLED) &&
> >>> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon)
> >>>  					newcon->seq = con->seq;
> >>>  				}
> >>>  			}
> >>> +			console_unlock();
> >
> > So, without the above two hunks:
> >
> > Reviewed-by: Petr Mladek <pmladek@suse.com>
> 
> Note that we actually need those hunks to guarantee a consistent @seq
> value. The console_lock is the only synchronization mechanism available
> to read console->seq.

Yes, we need a solution. But it does not need to be in this patch.

This patch removes console_lock() on some locations. But this
particular code was called without console_lock() even before
this patch.

Note that the regression was added in the 3rd patch that moved
this code outside console_lock().

Maybe, the easiest solution would be to do in the 3rd patch [*]:

	} else {
		/* Begin with next message. */
		newcon->seq = prb_next_seq(prb);
		/*
		 * Try hard to show the pending messages on boot consoles.
		 * so that the new console does not start too late.
		 */
		pr_flush();
	}

It should behave as good and as bad as the original code.

[*] Or move the code and add this change before the 3rd patch
    to keep this questionable solution separated and avoid
    the regression.

Best Regards,
Petr

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-15 18:23       ` Petr Mladek
@ 2022-11-16  8:52         ` John Ogness
  2022-11-16  8:56           ` John Ogness
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-16  8:52 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote:
> It is not that easy because console_flush_all() might handover the
> console_lock(). Also some new messages might appear so that we
> should re-read prb_next_seq().

OK. Taking all this into account, how about:

	if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
		/* Get a consistent copy of @syslog_seq. */
		mutex_lock(&syslog_lock);
		newcon->seq = syslog_seq;
		mutex_unlock(&syslog_lock);
	} else {
		/* Begin with next message added to ringbuffer. */
		newcon->seq = prb_next_seq(prb);

		/*
		 * If any enabled boot consoles are due to be unregistered
		 * shortly, some may not be caught up and may be the same
		 * device as @newcon. Since it is not known which boot console
		 * is the same device, flush all consoles and, if necessary,
		 * start with the message of the enabled boot console that is
		 * the furthest behind.
		 */
		if (bootcon_registered && !keep_bootcon) {
			bool handover;

			/*
			 * Hold the console_lock to guarantee safe access to
			 * console->seq.
			 */
			console_lock();

			/*
			 * Flush all consoles and set the console to start at
			 * the next unprinted sequence number.
			 */
			if (!console_flush_all(true, &newcon->seq, &handover)) {
				/*
				 * Flushing failed. Just choose the lowest
				 * sequence of the enabled boot consoles.
				 */
				newcon->seq = prb_next_seq(prb);
				for_each_console(con) {
					if ((con->flags & CON_BOOT) &&
					    (con->flags & CON_ENABLED) &&
					    con->seq < newcon->seq) {
						newcon->seq = con->seq;
					}
				}
			}

			console_unlock();
		}
	}

John Ogness

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-16  8:52         ` John Ogness
@ 2022-11-16  8:56           ` John Ogness
  2022-11-16  9:08             ` John Ogness
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-16  8:56 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Hi,

I forgot to re-lock the console... See below.

On 2022-11-16, John Ogness <john.ogness@linutronix.de> wrote:
> 	if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
> 		/* Get a consistent copy of @syslog_seq. */
> 		mutex_lock(&syslog_lock);
> 		newcon->seq = syslog_seq;
> 		mutex_unlock(&syslog_lock);
> 	} else {
> 		/* Begin with next message added to ringbuffer. */
> 		newcon->seq = prb_next_seq(prb);
>
> 		/*
> 		 * If any enabled boot consoles are due to be unregistered
> 		 * shortly, some may not be caught up and may be the same
> 		 * device as @newcon. Since it is not known which boot console
> 		 * is the same device, flush all consoles and, if necessary,
> 		 * start with the message of the enabled boot console that is
> 		 * the furthest behind.
> 		 */
> 		if (bootcon_registered && !keep_bootcon) {
> 			bool handover;
>
> 			/*
> 			 * Hold the console_lock to guarantee safe access to
> 			 * console->seq.
> 			 */
> 			console_lock();
>
> 			/*
> 			 * Flush all consoles and set the console to start at
> 			 * the next unprinted sequence number.
> 			 */
> 			if (!console_flush_all(true, &newcon->seq, &handover)) {
> 				/*
> 				 * Flushing failed. Just choose the lowest
> 				 * sequence of the enabled boot consoles.
> 				 */

Sorry. Here we lost the console_lock. Another acquire is needed here.

				console_lock();

> 				newcon->seq = prb_next_seq(prb);
> 				for_each_console(con) {
> 					if ((con->flags & CON_BOOT) &&
> 					    (con->flags & CON_ENABLED) &&
> 					    con->seq < newcon->seq) {
> 						newcon->seq = con->seq;
> 					}
> 				}
> 			}
>
> 			console_unlock();
> 		}
> 	}

John Ogness

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-16  8:56           ` John Ogness
@ 2022-11-16  9:08             ` John Ogness
  2022-11-16  9:48               ` Petr Mladek
  0 siblings, 1 reply; 64+ messages in thread
From: John Ogness @ 2022-11-16  9:08 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

Hi Petr,

Sorry, console_flush_all() only loses the console_lock if there was a
handover. Here is a new complete suggestion from me.

	if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
		/* Get a consistent copy of @syslog_seq. */
		mutex_lock(&syslog_lock);
		newcon->seq = syslog_seq;
		mutex_unlock(&syslog_lock);
	} else {
		/* Begin with next message added to ringbuffer. */
		newcon->seq = prb_next_seq(prb);

		/*
		 * If any enabled boot consoles are due to be unregistered
		 * shortly, some may not be caught up and may be the same
		 * device as @newcon. Since it is not known which boot console
		 * is the same device, flush all consoles and, if necessary,
		 * start with the message of the enabled boot console that is
		 * the furthest behind.
		 */
		if (bootcon_registered && !keep_bootcon) {
			bool handover;

			/*
			 * Hold the console_lock to guarantee safe access to
			 * console->seq.
			 */
			console_lock();

			/*
			 * Flush all consoles and set the console to start at
			 * the next unprinted sequence number.
			 */
			if (!console_flush_all(true, &newcon->seq, &handover)) {
				/*
				 * Flushing failed. Just choose the lowest
				 * sequence of the enabled boot consoles.
				 */

				/*
				 * If there was a handover, this context no
				 * longer holds the console_lock.
				 */
				if (handover)
					console_lock();

				newcon->seq = prb_next_seq(prb);
				for_each_console(con) {
					if ((con->flags & CON_BOOT) &&
					    (con->flags & CON_ENABLED) &&
					    con->seq < newcon->seq) {
						newcon->seq = con->seq;
					}
				}
			}

			console_unlock();
		}

John Ogness

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

* Re: replay log: Re: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties
  2022-11-16  9:08             ` John Ogness
@ 2022-11-16  9:48               ` Petr Mladek
  0 siblings, 0 replies; 64+ messages in thread
From: Petr Mladek @ 2022-11-16  9:48 UTC (permalink / raw)
  To: John Ogness
  Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel

On Wed 2022-11-16 10:14:35, John Ogness wrote:
> Hi Petr,
> 
> Sorry, console_flush_all() only loses the console_lock if there was a
> handover. Here is a new complete suggestion from me.
> 
> 	if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
> 		/* Get a consistent copy of @syslog_seq. */
> 		mutex_lock(&syslog_lock);
> 		newcon->seq = syslog_seq;
> 		mutex_unlock(&syslog_lock);
> 	} else {
> 		/* Begin with next message added to ringbuffer. */
> 		newcon->seq = prb_next_seq(prb);
> 
> 		/*
> 		 * If any enabled boot consoles are due to be unregistered
> 		 * shortly, some may not be caught up and may be the same
> 		 * device as @newcon. Since it is not known which boot console
> 		 * is the same device, flush all consoles and, if necessary,
> 		 * start with the message of the enabled boot console that is
> 		 * the furthest behind.
> 		 */
> 		if (bootcon_registered && !keep_bootcon) {
> 			bool handover;
> 
> 			/*
> 			 * Hold the console_lock to guarantee safe access to
> 			 * console->seq.
> 			 */
> 			console_lock();
> 
> 			/*
> 			 * Flush all consoles and set the console to start at
> 			 * the next unprinted sequence number.
> 			 */
> 			if (!console_flush_all(true, &newcon->seq, &handover)) {
> 				/*
> 				 * Flushing failed. Just choose the lowest
> 				 * sequence of the enabled boot consoles.
> 				 */
> 
> 				/*
> 				 * If there was a handover, this context no
> 				 * longer holds the console_lock.
> 				 */
> 				if (handover)
> 					console_lock();
> 
> 				newcon->seq = prb_next_seq(prb);
> 				for_each_console(con) {
> 					if ((con->flags & CON_BOOT) &&
> 					    (con->flags & CON_ENABLED) &&
> 					    con->seq < newcon->seq) {
> 						newcon->seq = con->seq;
> 					}
> 				}
> 			}
> 
> 			console_unlock();
> 		}

It looks good to me.

Now, we just need to agree how to add this into the patchset.
My proposal is to:

1. patch: hide the original code into a function, .e.g. console_init_seq()
2. patch: move console_init_seq() and add the above trickery

Do both before the 3rd patch in this patchset. It moved the code
outside console_lock() guarded section.

Best Regards,
Petr

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

end of thread, other threads:[~2022-11-16  9:49 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-14 16:28 [PATCH printk v4 00/39] reduce console_lock scope John Ogness
2022-11-14 16:28 ` [PATCH printk v4 01/39] serial: kgdboc: Lock console list in probe function John Ogness
2022-11-14 16:28 ` [PATCH printk v4 02/39] printk: Convert console_drivers list to hlist John Ogness
2022-11-14 16:28 ` [PATCH printk v4 03/39] printk: Prepare for SRCU console list protection John Ogness
2022-11-15 10:50   ` Petr Mladek
2022-11-15 11:33     ` John Ogness
2022-11-15 12:03       ` Petr Mladek
2022-11-14 16:28 ` [PATCH printk v4 04/39] printk: register_console: use "registered" for variable names John Ogness
2022-11-15 11:01   ` Petr Mladek
2022-11-14 16:28 ` [PATCH printk v4 05/39] printk: fix setting first seq for consoles John Ogness
2022-11-15 12:04   ` Petr Mladek
2022-11-14 16:28 ` [PATCH printk v4 06/39] um: kmsg_dump: only dump when no output console available John Ogness
2022-11-14 16:29 ` [PATCH printk v4 07/39] tty: serial: kgdboc: document console_lock usage John Ogness
2022-11-14 16:29 ` [PATCH printk v4 08/39] tty: tty_io: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 09/39] proc: consoles: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 10/39] printk: introduce console_list_lock John Ogness
2022-11-14 16:29 ` [PATCH printk v4 11/39] console: introduce wrappers to read/write console flags John Ogness
2022-11-15 12:26   ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 12/39] um: kmsg_dumper: use srcu console list iterator John Ogness
2022-11-14 16:29 ` [PATCH printk v4 13/39] kdb: " John Ogness
2022-11-14 21:16   ` Aaron Tomlin
2022-11-14 16:29 ` [PATCH printk v4 14/39] printk: console_flush_all: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 15/39] printk: __pr_flush: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 16/39] printk: console_is_usable: use console_srcu_read_flags John Ogness
2022-11-15 12:47   ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 17/39] printk: console_unblank: use srcu console list iterator John Ogness
2022-11-14 16:29 ` [PATCH printk v4 18/39] printk: console_flush_on_panic: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 19/39] printk: console_device: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 20/39] console: introduce console_is_registered() John Ogness
2022-11-14 16:29 ` [PATCH printk v4 21/39] serial_core: replace uart_console_enabled() with uart_console_registered() John Ogness
2022-11-14 16:29 ` [PATCH printk v4 22/39] tty: nfcon: use console_is_registered() John Ogness
2022-11-15 13:08   ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 23/39] efi: earlycon: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 24/39] tty: hvc: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 25/39] tty: serial: earlycon: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 26/39] tty: serial: pic32_uart: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 27/39] tty: serial: samsung_tty: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 28/39] tty: serial: xilinx_uartps: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 29/39] usb: early: xhci-dbc: " John Ogness
2022-11-14 16:29 ` [PATCH printk v4 30/39] netconsole: avoid CON_ENABLED misuse to track registration John Ogness
2022-11-14 16:29 ` [PATCH printk v4 31/39] printk, xen: fbfront: create/use safe function for forcing preferred John Ogness
2022-11-14 19:51   ` John Ogness
2022-11-15 13:22     ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 32/39] tty: tty_io: use console_list_lock for list synchronization John Ogness
2022-11-14 16:29 ` [PATCH printk v4 33/39] proc: consoles: use console_list_lock for list iteration John Ogness
2022-11-14 16:29 ` [PATCH printk v4 34/39] tty: serial: kgdboc: use srcu console list iterator John Ogness
2022-11-15 15:17   ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 35/39] tty: serial: kgdboc: use console_list_lock for list traversal John Ogness
2022-11-15 15:18   ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 36/39] tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console() John Ogness
2022-11-14 16:29 ` [PATCH printk v4 37/39] tty: serial: kgdboc: use console_list_lock to trap exit John Ogness
2022-11-14 16:29 ` [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties John Ogness
2022-11-15 15:34   ` replay log: " Petr Mladek
2022-11-15 16:41     ` John Ogness
2022-11-15 18:23       ` Petr Mladek
2022-11-16  8:52         ` John Ogness
2022-11-16  8:56           ` John Ogness
2022-11-16  9:08             ` John Ogness
2022-11-16  9:48               ` Petr Mladek
2022-11-15 16:41     ` Petr Mladek
2022-11-15 17:15       ` John Ogness
2022-11-15 18:36         ` Petr Mladek
2022-11-14 16:29 ` [PATCH printk v4 39/39] tty: serial: sh-sci: use setup() callback for early console John Ogness
2022-11-15 16:43   ` Petr Mladek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox