@@ -1671,6 +1671,9 @@ bool nbcon_alloc(struct console *con)
16711671{
16721672 struct nbcon_state state = { };
16731673
1674+ /* Synchronize the kthread start. */
1675+ lockdep_assert_console_list_lock_held ();
1676+
16741677 /* The write_thread() callback is mandatory. */
16751678 if (WARN_ON (!con -> write_thread ))
16761679 return false;
@@ -1701,12 +1704,15 @@ bool nbcon_alloc(struct console *con)
17011704 return false;
17021705 }
17031706
1704- if (printk_kthreads_running ) {
1707+ if (printk_kthreads_ready && ! have_boot_console ) {
17051708 if (!nbcon_kthread_create (con )) {
17061709 kfree (con -> pbufs );
17071710 con -> pbufs = NULL ;
17081711 return false;
17091712 }
1713+
1714+ /* Might be the first kthread. */
1715+ printk_kthreads_running = true;
17101716 }
17111717 }
17121718
@@ -1716,14 +1722,30 @@ bool nbcon_alloc(struct console *con)
17161722/**
17171723 * nbcon_free - Free and cleanup the nbcon console specific data
17181724 * @con: Console to free/cleanup nbcon data
1725+ *
1726+ * Important: @have_nbcon_console must be updated before calling
1727+ * this function. In particular, it can be set only when there
1728+ * is still another nbcon console registered.
17191729 */
17201730void nbcon_free (struct console * con )
17211731{
17221732 struct nbcon_state state = { };
17231733
1724- if (printk_kthreads_running )
1734+ /* Synchronize the kthread stop. */
1735+ lockdep_assert_console_list_lock_held ();
1736+
1737+ if (printk_kthreads_running ) {
17251738 nbcon_kthread_stop (con );
17261739
1740+ /* Might be the last nbcon console.
1741+ *
1742+ * Do not rely on printk_kthreads_check_locked(). It is not
1743+ * called in some code paths, see nbcon_free() callers.
1744+ */
1745+ if (!have_nbcon_console )
1746+ printk_kthreads_running = false;
1747+ }
1748+
17271749 nbcon_state_set (con , & state );
17281750
17291751 /* Boot consoles share global printk buffers. */
0 commit comments