Commit 98d0052d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull printk updates from Petr Mladek:

 - Add NMI-safe SRCU reader API. It uses atomic_inc() instead of
   this_cpu_inc() on strong load-store architectures.

 - Introduce new console_list_lock to synchronize a manipulation of the
   list of registered consoles and their flags.

   This is a first step in removing the big-kernel-lock-like behavior of
   console_lock(). This semaphore still serializes console->write()
   calbacks against:

      - each other. It primary prevents potential races between early
        and proper console drivers using the same device.

      - suspend()/resume() callbacks and init() operations in some
        drivers.

      - various other operations in the tty/vt and framebufer
        susbsystems. It is likely that console_lock() serializes even
        operations that are not directly conflicting with the
        console->write() callbacks here. This is the most complicated
        big-kernel-lock aspect of the console_lock() that will be hard
        to untangle.

 - Introduce new console_srcu lock that is used to safely iterate and
   access the registered console drivers under SRCU read lock.

   This is a prerequisite for introducing atomic console drivers and
   console kthreads. It will reduce the complexity of serialization
   against normal consoles and console_lock(). Also it should remove the
   risk of deadlock during critical situations, like Oops or panic, when
   only atomic consoles are registered.

 - Check whether the console is registered instead of enabled on many
   locations. It was a historical leftover.

 - Cleanly force a preferred console in xenfb code instead of a dirty
   hack.

 - A lot of code and comment clean ups and improvements.

* tag 'printk-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: (47 commits)
  printk: htmldocs: add missing description
  tty: serial: sh-sci: use setup() callback for early console
  printk: relieve console_lock of list synchronization duties
  tty: serial: kgdboc: use console_list_lock to trap exit
  tty: serial: kgdboc: synchronize tty_find_polling_driver() and register_console()
  tty: serial: kgdboc: use console_list_lock for list traversal
  tty: serial: kgdboc: use srcu console list iterator
  proc: consoles: use console_list_lock for list iteration
  tty: tty_io: use console_list_lock for list synchronization
  printk, xen: fbfront: create/use safe function for forcing preferred
  netconsole: avoid CON_ENABLED misuse to track registration
  usb: early: xhci-dbc: use console_is_registered()
  tty: serial: xilinx_uartps: use console_is_registered()
  tty: serial: samsung_tty: use console_is_registered()
  tty: serial: pic32_uart: use console_is_registered()
  tty: serial: earlycon: use console_is_registered()
  tty: hvc: use console_is_registered()
  efi: earlycon: use console_is_registered()
  tty: nfcon: use console_is_registered()
  serial_core: replace uart_console_enabled() with uart_console_registered()
  ...
parents 73fa58dc 6b2b0d83
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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'
+7 −2
Original line number Diff line number Diff line
@@ -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;
+15 −9
Original line number Diff line number Diff line
@@ -16,20 +16,26 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
	struct console *con;
	unsigned long flags;
	size_t len = 0;
	int cookie;

	/* only dump kmsg when no console is available */
	if (!console_trylock())
		return;
	/*
	 * If no consoles are available to output crash information, dump
	 * the kmsg buffer to stdout.
	 */

	for_each_console(con) {
		if(strcmp(con->name, "tty") == 0 &&
		   (con->flags & (CON_ENABLED | CON_CONSDEV)) != 0) {
	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 &&
		    (console_srcu_read_flags(con) & CON_ENABLED)) {
			break;
		}
	}

	console_unlock();

	console_srcu_read_unlock(cookie);
	if (con)
		return;

+4 −4
Original line number Diff line number Diff line
@@ -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;
}
+11 −10
Original line number Diff line number Diff line
@@ -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,6 +945,7 @@ static void __exit cleanup_netconsole(void)
{
	struct netconsole_target *nt, *tmp;

	if (console_is_registered(&netconsole_ext))
		unregister_console(&netconsole_ext);
	unregister_console(&netconsole);
	dynamic_netconsole_exit();
Loading