Skip to content

Commit 9e70a5e

Browse files
jognesspmladek
authored andcommitted
printk: Add per-console suspended state
Currently the global @console_suspended is used to determine if consoles are in a suspended state. Its primary purpose is to allow usage of the console_lock when suspended without causing console printing. It is synchronized by the console_lock. Rather than relying on the console_lock to determine suspended state, make it an official per-console state that is set within console->flags. This allows the state to be queried via SRCU. Remove @console_suspended. Console printing will still be avoided when suspended because console_is_usable() returns false when the new suspended flag is set for that console. Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20230717194607.145135-7-john.ogness@linutronix.de
1 parent 696ffaf commit 9e70a5e

File tree

2 files changed

+47
-30
lines changed

2 files changed

+47
-30
lines changed

include/linux/console.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ static inline int con_debug_leave(void)
154154
* receiving the printk spam for obvious reasons.
155155
* @CON_EXTENDED: The console supports the extended output format of
156156
* /dev/kmesg which requires a larger output buffer.
157+
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the
158+
* printing callbacks must not be called.
157159
*/
158160
enum cons_flags {
159161
CON_PRINTBUFFER = BIT(0),
@@ -163,6 +165,7 @@ enum cons_flags {
163165
CON_ANYTIME = BIT(4),
164166
CON_BRL = BIT(5),
165167
CON_EXTENDED = BIT(6),
168+
CON_SUSPENDED = BIT(7),
166169
};
167170

168171
/**

kernel/printk/printk.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ EXPORT_SYMBOL(oops_in_progress);
8686
static DEFINE_MUTEX(console_mutex);
8787

8888
/*
89-
* console_sem protects updates to console->seq and console_suspended,
89+
* console_sem protects updates to console->seq
9090
* and also provides serialization for console printing.
9191
*/
9292
static DEFINE_SEMAPHORE(console_sem);
@@ -359,7 +359,7 @@ static bool panic_in_progress(void)
359359
* paths in the console code where we end up in places I want
360360
* locked without the console semaphore held).
361361
*/
362-
static int console_locked, console_suspended;
362+
static int console_locked;
363363

364364
/*
365365
* Array of consoles built from command line options (console=)
@@ -2549,22 +2549,46 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig
25492549
*/
25502550
void suspend_console(void)
25512551
{
2552+
struct console *con;
2553+
25522554
if (!console_suspend_enabled)
25532555
return;
25542556
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
25552557
pr_flush(1000, true);
2556-
console_lock();
2557-
console_suspended = 1;
2558-
up_console_sem();
2558+
2559+
console_list_lock();
2560+
for_each_console(con)
2561+
console_srcu_write_flags(con, con->flags | CON_SUSPENDED);
2562+
console_list_unlock();
2563+
2564+
/*
2565+
* Ensure that all SRCU list walks have completed. All printing
2566+
* contexts must be able to see that they are suspended so that it
2567+
* is guaranteed that all printing has stopped when this function
2568+
* completes.
2569+
*/
2570+
synchronize_srcu(&console_srcu);
25592571
}
25602572

25612573
void resume_console(void)
25622574
{
2575+
struct console *con;
2576+
25632577
if (!console_suspend_enabled)
25642578
return;
2565-
down_console_sem();
2566-
console_suspended = 0;
2567-
console_unlock();
2579+
2580+
console_list_lock();
2581+
for_each_console(con)
2582+
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
2583+
console_list_unlock();
2584+
2585+
/*
2586+
* Ensure that all SRCU list walks have completed. All printing
2587+
* contexts must be able to see they are no longer suspended so
2588+
* that they are guaranteed to wake up and resume printing.
2589+
*/
2590+
synchronize_srcu(&console_srcu);
2591+
25682592
pr_flush(1000, true);
25692593
}
25702594

@@ -2623,8 +2647,6 @@ void console_lock(void)
26232647
msleep(1000);
26242648

26252649
down_console_sem();
2626-
if (console_suspended)
2627-
return;
26282650
console_locked = 1;
26292651
console_may_schedule = 1;
26302652
}
@@ -2645,10 +2667,6 @@ int console_trylock(void)
26452667
return 0;
26462668
if (down_trylock_console_sem())
26472669
return 0;
2648-
if (console_suspended) {
2649-
up_console_sem();
2650-
return 0;
2651-
}
26522670
console_locked = 1;
26532671
console_may_schedule = 0;
26542672
return 1;
@@ -2674,6 +2692,9 @@ static inline bool console_is_usable(struct console *con)
26742692
if (!(flags & CON_ENABLED))
26752693
return false;
26762694

2695+
if ((flags & CON_SUSPENDED))
2696+
return false;
2697+
26772698
if (!con->write)
26782699
return false;
26792700

@@ -2992,11 +3013,6 @@ void console_unlock(void)
29923013
bool flushed;
29933014
u64 next_seq;
29943015

2995-
if (console_suspended) {
2996-
up_console_sem();
2997-
return;
2998-
}
2999-
30003016
/*
30013017
* Console drivers are called with interrupts disabled, so
30023018
* @console_may_schedule should be cleared before; however, we may
@@ -3726,15 +3742,19 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
37263742

37273743
/*
37283744
* Hold the console_lock to guarantee safe access to
3729-
* console->seq and to prevent changes to @console_suspended
3730-
* until all consoles have been processed.
3745+
* console->seq.
37313746
*/
37323747
console_lock();
37333748

37343749
cookie = console_srcu_read_lock();
37353750
for_each_console_srcu(c) {
37363751
if (con && con != c)
37373752
continue;
3753+
/*
3754+
* If consoles are not usable, it cannot be expected
3755+
* that they make forward progress, so only increment
3756+
* @diff for usable consoles.
3757+
*/
37383758
if (!console_is_usable(c))
37393759
continue;
37403760
printk_seq = c->seq;
@@ -3743,18 +3763,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
37433763
}
37443764
console_srcu_read_unlock(cookie);
37453765

3746-
/*
3747-
* If consoles are suspended, it cannot be expected that they
3748-
* make forward progress, so timeout immediately. @diff is
3749-
* still used to return a valid flush status.
3750-
*/
3751-
if (console_suspended)
3752-
remaining = 0;
3753-
else if (diff != last_diff && reset_on_progress)
3766+
if (diff != last_diff && reset_on_progress)
37543767
remaining = timeout_ms;
37553768

37563769
console_unlock();
37573770

3771+
/* Note: @diff is 0 if there are no usable consoles. */
37583772
if (diff == 0 || remaining == 0)
37593773
break;
37603774

@@ -3788,7 +3802,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
37883802
* printer has been seen to make some forward progress.
37893803
*
37903804
* Context: Process context. May sleep while acquiring console lock.
3791-
* Return: true if all enabled printers are caught up.
3805+
* Return: true if all usable printers are caught up.
37923806
*/
37933807
static bool pr_flush(int timeout_ms, bool reset_on_progress)
37943808
{

0 commit comments

Comments
 (0)