Skip to content

Commit 6690d6b

Browse files
jognesspmladek
authored andcommitted
printk: Add helper for flush type logic
There are many call sites where console flushing occur. Depending on the system state and types of consoles, the flush methods to use are different. A flush call site generally must consider: @have_boot_console @have_nbcon_console @have_legacy_console @legacy_allow_panic_sync is_printk_preferred() and take into account the current CPU state: NBCON_PRIO_NORMAL NBCON_PRIO_EMERGENCY NBCON_PRIO_PANIC in order to decide if it should: flush nbcon directly via atomic_write() callback flush legacy directly via console_unlock flush legacy via offload to irq_work All of these call sites use their own logic to make this decision, which is complicated and error prone. Especially later when two more flush methods will be introduced: flush nbcon via offload to kthread flush legacy via offload to kthread Introduce a new internal struct console_flush_type that specifies which console flushing methods should be used in the context of the caller. Introduce a helper function to fill out console_flush_type to be used for flushing call sites. Replace the logic of all flushing call sites to use the new helper. This change standardizes behavior, leading to both fixes and optimizations across various call sites. For instance, in console_cpu_notify(), the new logic ensures that nbcon consoles are flushed when they aren’t managed by the legacy loop. Similarly, in console_flush_on_panic(), the system no longer needs to flush nbcon consoles if none are present. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected] [[email protected]: Updated the commit message.] Signed-off-by: Petr Mladek <[email protected]>
1 parent e35a888 commit 6690d6b

File tree

3 files changed

+112
-41
lines changed

3 files changed

+112
-41
lines changed

kernel/printk/internal.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,81 @@ static inline bool console_is_usable(struct console *con, short flags) { return
154154
#endif /* CONFIG_PRINTK */
155155

156156
extern bool have_boot_console;
157+
extern bool have_nbcon_console;
158+
extern bool have_legacy_console;
157159
extern bool legacy_allow_panic_sync;
158160

161+
/**
162+
* struct console_flush_type - Define available console flush methods
163+
* @nbcon_atomic: Flush directly using nbcon_atomic() callback
164+
* @legacy_direct: Call the legacy loop in this context
165+
* @legacy_offload: Offload the legacy loop into IRQ
166+
*
167+
* Note that the legacy loop also flushes the nbcon consoles.
168+
*/
169+
struct console_flush_type {
170+
bool nbcon_atomic;
171+
bool legacy_direct;
172+
bool legacy_offload;
173+
};
174+
175+
/*
176+
* Identify which console flushing methods should be used in the context of
177+
* the caller.
178+
*/
179+
static inline void printk_get_console_flush_type(struct console_flush_type *ft)
180+
{
181+
memset(ft, 0, sizeof(*ft));
182+
183+
switch (nbcon_get_default_prio()) {
184+
case NBCON_PRIO_NORMAL:
185+
if (have_nbcon_console && !have_boot_console)
186+
ft->nbcon_atomic = true;
187+
188+
/* Legacy consoles are flushed directly when possible. */
189+
if (have_legacy_console || have_boot_console) {
190+
if (!is_printk_legacy_deferred())
191+
ft->legacy_direct = true;
192+
else
193+
ft->legacy_offload = true;
194+
}
195+
break;
196+
197+
case NBCON_PRIO_PANIC:
198+
/*
199+
* In panic, the nbcon consoles will directly print. But
200+
* only allowed if there are no boot consoles.
201+
*/
202+
if (have_nbcon_console && !have_boot_console)
203+
ft->nbcon_atomic = true;
204+
205+
if (have_legacy_console || have_boot_console) {
206+
/*
207+
* This is the same decision as NBCON_PRIO_NORMAL
208+
* except that offloading never occurs in panic.
209+
*
210+
* Note that console_flush_on_panic() will flush
211+
* legacy consoles anyway, even if unsafe.
212+
*/
213+
if (!is_printk_legacy_deferred())
214+
ft->legacy_direct = true;
215+
216+
/*
217+
* In panic, if nbcon atomic printing occurs,
218+
* the legacy consoles must remain silent until
219+
* explicitly allowed.
220+
*/
221+
if (ft->nbcon_atomic && !legacy_allow_panic_sync)
222+
ft->legacy_direct = false;
223+
}
224+
break;
225+
226+
default:
227+
WARN_ON_ONCE(1);
228+
break;
229+
}
230+
}
231+
159232
extern struct printk_buffers printk_shared_pbufs;
160233

161234
/**

kernel/printk/nbcon.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,7 @@ EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
13441344
void nbcon_device_release(struct console *con)
13451345
{
13461346
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
1347+
struct console_flush_type ft;
13471348
int cookie;
13481349

13491350
if (!nbcon_context_exit_unsafe(ctxt))
@@ -1359,12 +1360,17 @@ void nbcon_device_release(struct console *con)
13591360
cookie = console_srcu_read_lock();
13601361
if (console_is_usable(con, console_srcu_read_flags(con)) &&
13611362
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
1362-
if (!have_boot_console) {
1363+
/*
1364+
* If nbcon_atomic flushing is not available, fallback to
1365+
* using the legacy loop.
1366+
*/
1367+
printk_get_console_flush_type(&ft);
1368+
if (ft.nbcon_atomic) {
13631369
__nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
1364-
} else if (!is_printk_legacy_deferred()) {
1370+
} else if (ft.legacy_direct) {
13651371
if (console_trylock())
13661372
console_unlock();
1367-
} else {
1373+
} else if (ft.legacy_offload) {
13681374
printk_trigger_flush();
13691375
}
13701376
}

kernel/printk/printk.c

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -468,14 +468,14 @@ static DEFINE_MUTEX(syslog_lock);
468468
* present, it is necessary to perform the console lock/unlock dance
469469
* whenever console flushing should occur.
470470
*/
471-
static bool have_legacy_console;
471+
bool have_legacy_console;
472472

473473
/*
474474
* Specifies if an nbcon console is registered. If nbcon consoles are present,
475475
* synchronous printing of legacy consoles will not occur during panic until
476476
* the backtrace has been stored to the ringbuffer.
477477
*/
478-
static bool have_nbcon_console;
478+
bool have_nbcon_console;
479479

480480
/*
481481
* Specifies if a boot console is registered. If boot consoles are present,
@@ -488,14 +488,6 @@ bool have_boot_console;
488488
/* See printk_legacy_allow_panic_sync() for details. */
489489
bool legacy_allow_panic_sync;
490490

491-
/*
492-
* Specifies if the console lock/unlock dance is needed for console
493-
* printing. If @have_boot_console is true, the nbcon consoles will
494-
* be printed serially along with the legacy consoles because nbcon
495-
* consoles cannot print simultaneously with boot consoles.
496-
*/
497-
#define printing_via_unlock (have_legacy_console || have_boot_console)
498-
499491
#ifdef CONFIG_PRINTK
500492
DECLARE_WAIT_QUEUE_HEAD(log_wait);
501493
/* All 3 protected by @syslog_lock. */
@@ -2342,9 +2334,12 @@ int vprintk_store(int facility, int level,
23422334
*/
23432335
void printk_legacy_allow_panic_sync(void)
23442336
{
2337+
struct console_flush_type ft;
2338+
23452339
legacy_allow_panic_sync = true;
23462340

2347-
if (printing_via_unlock && !is_printk_legacy_deferred()) {
2341+
printk_get_console_flush_type(&ft);
2342+
if (ft.legacy_direct) {
23482343
if (console_trylock())
23492344
console_unlock();
23502345
}
@@ -2354,8 +2349,7 @@ asmlinkage int vprintk_emit(int facility, int level,
23542349
const struct dev_printk_info *dev_info,
23552350
const char *fmt, va_list args)
23562351
{
2357-
bool do_trylock_unlock = printing_via_unlock;
2358-
bool defer_legacy = false;
2352+
struct console_flush_type ft;
23592353
int printed_len;
23602354

23612355
/* Suppress unimportant messages after panic happens */
@@ -2370,35 +2364,23 @@ asmlinkage int vprintk_emit(int facility, int level,
23702364
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
23712365
return 0;
23722366

2367+
printk_get_console_flush_type(&ft);
2368+
23732369
/* If called from the scheduler, we can not call up(). */
23742370
if (level == LOGLEVEL_SCHED) {
23752371
level = LOGLEVEL_DEFAULT;
2376-
defer_legacy = do_trylock_unlock;
2377-
do_trylock_unlock = false;
2372+
ft.legacy_offload |= ft.legacy_direct;
2373+
ft.legacy_direct = false;
23782374
}
23792375

23802376
printk_delay(level);
23812377

23822378
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
23832379

2384-
if (have_nbcon_console && !have_boot_console) {
2380+
if (ft.nbcon_atomic)
23852381
nbcon_atomic_flush_pending();
23862382

2387-
/*
2388-
* In panic, the legacy consoles are not allowed to print from
2389-
* the printk calling context unless explicitly allowed. This
2390-
* gives the safe nbcon consoles a chance to print out all the
2391-
* panic messages first. This restriction only applies if
2392-
* there are nbcon consoles registered and they are allowed to
2393-
* flush.
2394-
*/
2395-
if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
2396-
do_trylock_unlock = false;
2397-
defer_legacy = false;
2398-
}
2399-
}
2400-
2401-
if (do_trylock_unlock) {
2383+
if (ft.legacy_direct) {
24022384
/*
24032385
* The caller may be holding system-critical or
24042386
* timing-sensitive locks. Disable preemption during
@@ -2418,7 +2400,7 @@ asmlinkage int vprintk_emit(int facility, int level,
24182400
preempt_enable();
24192401
}
24202402

2421-
if (defer_legacy)
2403+
if (ft.legacy_offload)
24222404
defer_console_output();
24232405
else
24242406
wake_up_klogd();
@@ -2777,10 +2759,16 @@ void resume_console(void)
27772759
*/
27782760
static int console_cpu_notify(unsigned int cpu)
27792761
{
2780-
if (!cpuhp_tasks_frozen && printing_via_unlock) {
2781-
/* If trylock fails, someone else is doing the printing */
2782-
if (console_trylock())
2783-
console_unlock();
2762+
struct console_flush_type ft;
2763+
2764+
if (!cpuhp_tasks_frozen) {
2765+
printk_get_console_flush_type(&ft);
2766+
if (ft.nbcon_atomic)
2767+
nbcon_atomic_flush_pending();
2768+
if (ft.legacy_direct) {
2769+
if (console_trylock())
2770+
console_unlock();
2771+
}
27842772
}
27852773
return 0;
27862774
}
@@ -3305,6 +3293,7 @@ static void __console_rewind_all(void)
33053293
*/
33063294
void console_flush_on_panic(enum con_flush_mode mode)
33073295
{
3296+
struct console_flush_type ft;
33083297
bool handover;
33093298
u64 next_seq;
33103299

@@ -3328,7 +3317,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
33283317
if (mode == CONSOLE_REPLAY_ALL)
33293318
__console_rewind_all();
33303319

3331-
if (!have_boot_console)
3320+
printk_get_console_flush_type(&ft);
3321+
if (ft.nbcon_atomic)
33323322
nbcon_atomic_flush_pending();
33333323

33343324
/* Flush legacy consoles once allowed, even when dangerous. */
@@ -3992,6 +3982,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
39923982
{
39933983
unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
39943984
unsigned long remaining_jiffies = timeout_jiffies;
3985+
struct console_flush_type ft;
39953986
struct console *c;
39963987
u64 last_diff = 0;
39973988
u64 printk_seq;
@@ -4005,7 +3996,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
40053996
seq = prb_next_reserve_seq(prb);
40063997

40073998
/* Flush the consoles so that records up to @seq are printed. */
4008-
if (printing_via_unlock) {
3999+
printk_get_console_flush_type(&ft);
4000+
if (ft.legacy_direct) {
40094001
console_lock();
40104002
console_unlock();
40114003
}

0 commit comments

Comments
 (0)