@@ -1671,6 +1671,9 @@ bool nbcon_alloc(struct console *con)
1671
1671
{
1672
1672
struct nbcon_state state = { };
1673
1673
1674
+ /* Synchronize the kthread start. */
1675
+ lockdep_assert_console_list_lock_held ();
1676
+
1674
1677
/* The write_thread() callback is mandatory. */
1675
1678
if (WARN_ON (!con -> write_thread ))
1676
1679
return false;
@@ -1701,12 +1704,15 @@ bool nbcon_alloc(struct console *con)
1701
1704
return false;
1702
1705
}
1703
1706
1704
- if (printk_kthreads_running ) {
1707
+ if (printk_kthreads_ready && ! have_boot_console ) {
1705
1708
if (!nbcon_kthread_create (con )) {
1706
1709
kfree (con -> pbufs );
1707
1710
con -> pbufs = NULL ;
1708
1711
return false;
1709
1712
}
1713
+
1714
+ /* Might be the first kthread. */
1715
+ printk_kthreads_running = true;
1710
1716
}
1711
1717
}
1712
1718
@@ -1716,14 +1722,30 @@ bool nbcon_alloc(struct console *con)
1716
1722
/**
1717
1723
* nbcon_free - Free and cleanup the nbcon console specific data
1718
1724
* @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.
1719
1729
*/
1720
1730
void nbcon_free (struct console * con )
1721
1731
{
1722
1732
struct nbcon_state state = { };
1723
1733
1724
- if (printk_kthreads_running )
1734
+ /* Synchronize the kthread stop. */
1735
+ lockdep_assert_console_list_lock_held ();
1736
+
1737
+ if (printk_kthreads_running ) {
1725
1738
nbcon_kthread_stop (con );
1726
1739
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
+
1727
1749
nbcon_state_set (con , & state );
1728
1750
1729
1751
/* Boot consoles share global printk buffers. */
0 commit comments