Skip to content

Commit 3a9a3f5

Browse files
committed
Merge branch 'rework/suspend-fixes' into for-linus
2 parents b1e6c41 + 66e7c1e commit 3a9a3f5

3 files changed

Lines changed: 79 additions & 21 deletions

File tree

kernel/printk/internal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ struct console_flush_type {
185185
bool legacy_offload;
186186
};
187187

188+
extern bool console_irqwork_blocked;
189+
188190
/*
189191
* Identify which console flushing methods should be used in the context of
190192
* the caller.
@@ -196,7 +198,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
196198
switch (nbcon_get_default_prio()) {
197199
case NBCON_PRIO_NORMAL:
198200
if (have_nbcon_console && !have_boot_console) {
199-
if (printk_kthreads_running)
201+
if (printk_kthreads_running && !console_irqwork_blocked)
200202
ft->nbcon_offload = true;
201203
else
202204
ft->nbcon_atomic = true;
@@ -206,7 +208,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
206208
if (have_legacy_console || have_boot_console) {
207209
if (!is_printk_legacy_deferred())
208210
ft->legacy_direct = true;
209-
else
211+
else if (!console_irqwork_blocked)
210212
ft->legacy_offload = true;
211213
}
212214
break;
@@ -219,7 +221,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
219221
if (have_legacy_console || have_boot_console) {
220222
if (!is_printk_legacy_deferred())
221223
ft->legacy_direct = true;
222-
else
224+
else if (!console_irqwork_blocked)
223225
ft->legacy_offload = true;
224226
}
225227
break;

kernel/printk/nbcon.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,13 @@ void nbcon_kthreads_wake(void)
13021302
if (!printk_kthreads_running)
13031303
return;
13041304

1305+
/*
1306+
* It is not allowed to call this function when console irq_work
1307+
* is blocked.
1308+
*/
1309+
if (WARN_ON_ONCE(console_irqwork_blocked))
1310+
return;
1311+
13051312
cookie = console_srcu_read_lock();
13061313
for_each_console_srcu(con) {
13071314
if (!(console_srcu_read_flags(con) & CON_NBCON))
@@ -1892,7 +1899,7 @@ void nbcon_device_release(struct console *con)
18921899
if (console_trylock())
18931900
console_unlock();
18941901
} else if (ft.legacy_offload) {
1895-
printk_trigger_flush();
1902+
defer_console_output();
18961903
}
18971904
}
18981905
console_srcu_read_unlock(cookie);

kernel/printk/printk.c

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ bool have_boot_console;
462462
/* See printk_legacy_allow_panic_sync() for details. */
463463
bool legacy_allow_panic_sync;
464464

465+
/* Avoid using irq_work when suspending. */
466+
bool console_irqwork_blocked;
467+
465468
#ifdef CONFIG_PRINTK
466469
DECLARE_WAIT_QUEUE_HEAD(log_wait);
467470
static DECLARE_WAIT_QUEUE_HEAD(legacy_wait);
@@ -2390,7 +2393,7 @@ asmlinkage int vprintk_emit(int facility, int level,
23902393
/* If called from the scheduler, we can not call up(). */
23912394
if (level == LOGLEVEL_SCHED) {
23922395
level = LOGLEVEL_DEFAULT;
2393-
ft.legacy_offload |= ft.legacy_direct;
2396+
ft.legacy_offload |= ft.legacy_direct && !console_irqwork_blocked;
23942397
ft.legacy_direct = false;
23952398
}
23962399

@@ -2426,7 +2429,7 @@ asmlinkage int vprintk_emit(int facility, int level,
24262429

24272430
if (ft.legacy_offload)
24282431
defer_console_output();
2429-
else
2432+
else if (!console_irqwork_blocked)
24302433
wake_up_klogd();
24312434

24322435
return printed_len;
@@ -2730,10 +2733,20 @@ void console_suspend_all(void)
27302733
{
27312734
struct console *con;
27322735

2736+
if (console_suspend_enabled)
2737+
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
2738+
2739+
/*
2740+
* Flush any console backlog and then avoid queueing irq_work until
2741+
* console_resume_all(). Until then deferred printing is no longer
2742+
* triggered, NBCON consoles transition to atomic flushing, and
2743+
* any klogd waiters are not triggered.
2744+
*/
2745+
pr_flush(1000, true);
2746+
console_irqwork_blocked = true;
2747+
27332748
if (!console_suspend_enabled)
27342749
return;
2735-
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
2736-
pr_flush(1000, true);
27372750

27382751
console_list_lock();
27392752
for_each_console(con)
@@ -2754,26 +2767,34 @@ void console_resume_all(void)
27542767
struct console_flush_type ft;
27552768
struct console *con;
27562769

2757-
if (!console_suspend_enabled)
2758-
return;
2759-
2760-
console_list_lock();
2761-
for_each_console(con)
2762-
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
2763-
console_list_unlock();
2764-
27652770
/*
2766-
* Ensure that all SRCU list walks have completed. All printing
2767-
* contexts must be able to see they are no longer suspended so
2768-
* that they are guaranteed to wake up and resume printing.
2771+
* Allow queueing irq_work. After restoring console state, deferred
2772+
* printing and any klogd waiters need to be triggered in case there
2773+
* is now a console backlog.
27692774
*/
2770-
synchronize_srcu(&console_srcu);
2775+
console_irqwork_blocked = false;
2776+
2777+
if (console_suspend_enabled) {
2778+
console_list_lock();
2779+
for_each_console(con)
2780+
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
2781+
console_list_unlock();
2782+
2783+
/*
2784+
* Ensure that all SRCU list walks have completed. All printing
2785+
* contexts must be able to see they are no longer suspended so
2786+
* that they are guaranteed to wake up and resume printing.
2787+
*/
2788+
synchronize_srcu(&console_srcu);
2789+
}
27712790

27722791
printk_get_console_flush_type(&ft);
27732792
if (ft.nbcon_offload)
27742793
nbcon_kthreads_wake();
27752794
if (ft.legacy_offload)
27762795
defer_console_output();
2796+
else
2797+
wake_up_klogd();
27772798

27782799
pr_flush(1000, true);
27792800
}
@@ -4559,6 +4580,13 @@ static void __wake_up_klogd(int val)
45594580
if (!printk_percpu_data_ready())
45604581
return;
45614582

4583+
/*
4584+
* It is not allowed to call this function when console irq_work
4585+
* is blocked.
4586+
*/
4587+
if (WARN_ON_ONCE(console_irqwork_blocked))
4588+
return;
4589+
45624590
preempt_disable();
45634591
/*
45644592
* Guarantee any new records can be seen by tasks preparing to wait
@@ -4615,9 +4643,30 @@ void defer_console_output(void)
46154643
__wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
46164644
}
46174645

4646+
/**
4647+
* printk_trigger_flush - Attempt to flush printk buffer to consoles.
4648+
*
4649+
* If possible, flush the printk buffer to all consoles in the caller's
4650+
* context. If offloading is available, trigger deferred printing.
4651+
*
4652+
* This is best effort. Depending on the system state, console states,
4653+
* and caller context, no actual flushing may result from this call.
4654+
*/
46184655
void printk_trigger_flush(void)
46194656
{
4620-
defer_console_output();
4657+
struct console_flush_type ft;
4658+
4659+
printk_get_console_flush_type(&ft);
4660+
if (ft.nbcon_atomic)
4661+
nbcon_atomic_flush_pending();
4662+
if (ft.nbcon_offload)
4663+
nbcon_kthreads_wake();
4664+
if (ft.legacy_direct) {
4665+
if (console_trylock())
4666+
console_unlock();
4667+
}
4668+
if (ft.legacy_offload)
4669+
defer_console_output();
46214670
}
46224671

46234672
int vprintk_deferred(const char *fmt, va_list args)

0 commit comments

Comments
 (0)