Skip to content

Commit cf55438

Browse files
committed
printk: Allow to use the printk kthread immediately even for 1st nbcon
The kthreads for nbcon consoles are created by nbcon_alloc() at the beginning of the console registration. But it currently works only for the 2nd or later nbcon console because the code checks @printk_kthreads_running. The kthread for the 1st registered nbcon console is created at the very end of register_console() by printk_kthreads_check_locked(). As a result, the entire log is replayed synchronously when the "enabled" message gets printed. It might block the boot for a long time with a slow serial console. Prevent the synchronous flush by creating the kthread even for the 1st nbcon console when it is safe (kthreads ready and no boot consoles). Also inform printk() to use the kthread by setting @printk_kthreads_running. Note that the kthreads already must be running when it is safe and this is not the 1st nbcon console. Symmetrically, clear @printk_kthreads_running when the last nbcon console was unregistered by nbcon_free(). This requires updating @have_nbcon_console before nbcon_free() gets called. Note that there is _no_ problem when the 1st nbcon console replaces boot consoles. In this case, the kthread will be started at the end of registration after the boot consoles are removed. But the console does not reply the entire log buffer in this case. Note that the flag CON_PRINTBUFFER is always cleared when the boot consoles are removed and vice versa. Closes: https://lore.kernel.org/r/[email protected] Tested-by: Michael Cobb <[email protected]> Reviewed-by: John Ogness <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Petr Mladek <[email protected]>
1 parent af54a3a commit cf55438

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

kernel/printk/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct dev_printk_info;
6464

6565
extern struct printk_ringbuffer *prb;
6666
extern bool printk_kthreads_running;
67+
extern bool printk_kthreads_ready;
6768
extern bool debug_non_panic_cpus;
6869

6970
__printf(4, 0)
@@ -180,6 +181,7 @@ static inline void nbcon_kthread_wake(struct console *con)
180181
#define PRINTKRB_RECORD_MAX 0
181182

182183
#define printk_kthreads_running (false)
184+
#define printk_kthreads_ready (false)
183185

184186
/*
185187
* In !PRINTK builds we still export console_sem

kernel/printk/nbcon.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
17201730
void 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. */

kernel/printk/printk.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3574,7 +3574,7 @@ EXPORT_SYMBOL(console_resume);
35743574
static int unregister_console_locked(struct console *console);
35753575

35763576
/* True when system boot is far enough to create printer threads. */
3577-
static bool printk_kthreads_ready __ro_after_init;
3577+
bool printk_kthreads_ready __ro_after_init;
35783578

35793579
static struct task_struct *printk_legacy_kthread;
35803580

@@ -3713,6 +3713,7 @@ static void printk_kthreads_check_locked(void)
37133713
if (!printk_kthreads_ready)
37143714
return;
37153715

3716+
/* Start or stop the legacy kthread when needed. */
37163717
if (have_legacy_console || have_boot_console) {
37173718
if (!printk_legacy_kthread &&
37183719
force_legacy_kthread() &&
@@ -4204,14 +4205,6 @@ static int unregister_console_locked(struct console *console)
42044205
*/
42054206
synchronize_srcu(&console_srcu);
42064207

4207-
if (console->flags & CON_NBCON)
4208-
nbcon_free(console);
4209-
4210-
console_sysfs_notify();
4211-
4212-
if (console->exit)
4213-
res = console->exit(console);
4214-
42154208
/*
42164209
* With this console gone, the global flags tracking registered
42174210
* console types may have changed. Update them.
@@ -4232,6 +4225,15 @@ static int unregister_console_locked(struct console *console)
42324225
if (!found_nbcon_con)
42334226
have_nbcon_console = found_nbcon_con;
42344227

4228+
/* @have_nbcon_console must be updated before calling nbcon_free(). */
4229+
if (console->flags & CON_NBCON)
4230+
nbcon_free(console);
4231+
4232+
console_sysfs_notify();
4233+
4234+
if (console->exit)
4235+
res = console->exit(console);
4236+
42354237
/* Changed console list, may require printer threads to start/stop. */
42364238
printk_kthreads_check_locked();
42374239

0 commit comments

Comments
 (0)