mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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
This commit is contained in:
parent
696ffaf50e
commit
9e70a5e109
@ -154,6 +154,8 @@ static inline int con_debug_leave(void)
|
|||||||
* receiving the printk spam for obvious reasons.
|
* receiving the printk spam for obvious reasons.
|
||||||
* @CON_EXTENDED: The console supports the extended output format of
|
* @CON_EXTENDED: The console supports the extended output format of
|
||||||
* /dev/kmesg which requires a larger output buffer.
|
* /dev/kmesg which requires a larger output buffer.
|
||||||
|
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the
|
||||||
|
* printing callbacks must not be called.
|
||||||
*/
|
*/
|
||||||
enum cons_flags {
|
enum cons_flags {
|
||||||
CON_PRINTBUFFER = BIT(0),
|
CON_PRINTBUFFER = BIT(0),
|
||||||
@ -163,6 +165,7 @@ enum cons_flags {
|
|||||||
CON_ANYTIME = BIT(4),
|
CON_ANYTIME = BIT(4),
|
||||||
CON_BRL = BIT(5),
|
CON_BRL = BIT(5),
|
||||||
CON_EXTENDED = BIT(6),
|
CON_EXTENDED = BIT(6),
|
||||||
|
CON_SUSPENDED = BIT(7),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +86,7 @@ EXPORT_SYMBOL(oops_in_progress);
|
|||||||
static DEFINE_MUTEX(console_mutex);
|
static DEFINE_MUTEX(console_mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* console_sem protects updates to console->seq and console_suspended,
|
* console_sem protects updates to console->seq
|
||||||
* and also provides serialization for console printing.
|
* and also provides serialization for console printing.
|
||||||
*/
|
*/
|
||||||
static DEFINE_SEMAPHORE(console_sem);
|
static DEFINE_SEMAPHORE(console_sem);
|
||||||
@ -359,7 +359,7 @@ static bool panic_in_progress(void)
|
|||||||
* paths in the console code where we end up in places I want
|
* paths in the console code where we end up in places I want
|
||||||
* locked without the console semaphore held).
|
* locked without the console semaphore held).
|
||||||
*/
|
*/
|
||||||
static int console_locked, console_suspended;
|
static int console_locked;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Array of consoles built from command line options (console=)
|
* 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
|
|||||||
*/
|
*/
|
||||||
void suspend_console(void)
|
void suspend_console(void)
|
||||||
{
|
{
|
||||||
|
struct console *con;
|
||||||
|
|
||||||
if (!console_suspend_enabled)
|
if (!console_suspend_enabled)
|
||||||
return;
|
return;
|
||||||
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
|
pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
|
||||||
pr_flush(1000, true);
|
pr_flush(1000, true);
|
||||||
console_lock();
|
|
||||||
console_suspended = 1;
|
console_list_lock();
|
||||||
up_console_sem();
|
for_each_console(con)
|
||||||
|
console_srcu_write_flags(con, con->flags | CON_SUSPENDED);
|
||||||
|
console_list_unlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that all SRCU list walks have completed. All printing
|
||||||
|
* contexts must be able to see that they are suspended so that it
|
||||||
|
* is guaranteed that all printing has stopped when this function
|
||||||
|
* completes.
|
||||||
|
*/
|
||||||
|
synchronize_srcu(&console_srcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resume_console(void)
|
void resume_console(void)
|
||||||
{
|
{
|
||||||
|
struct console *con;
|
||||||
|
|
||||||
if (!console_suspend_enabled)
|
if (!console_suspend_enabled)
|
||||||
return;
|
return;
|
||||||
down_console_sem();
|
|
||||||
console_suspended = 0;
|
console_list_lock();
|
||||||
console_unlock();
|
for_each_console(con)
|
||||||
|
console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED);
|
||||||
|
console_list_unlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that all SRCU list walks have completed. All printing
|
||||||
|
* contexts must be able to see they are no longer suspended so
|
||||||
|
* that they are guaranteed to wake up and resume printing.
|
||||||
|
*/
|
||||||
|
synchronize_srcu(&console_srcu);
|
||||||
|
|
||||||
pr_flush(1000, true);
|
pr_flush(1000, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2623,8 +2647,6 @@ void console_lock(void)
|
|||||||
msleep(1000);
|
msleep(1000);
|
||||||
|
|
||||||
down_console_sem();
|
down_console_sem();
|
||||||
if (console_suspended)
|
|
||||||
return;
|
|
||||||
console_locked = 1;
|
console_locked = 1;
|
||||||
console_may_schedule = 1;
|
console_may_schedule = 1;
|
||||||
}
|
}
|
||||||
@ -2645,10 +2667,6 @@ int console_trylock(void)
|
|||||||
return 0;
|
return 0;
|
||||||
if (down_trylock_console_sem())
|
if (down_trylock_console_sem())
|
||||||
return 0;
|
return 0;
|
||||||
if (console_suspended) {
|
|
||||||
up_console_sem();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
console_locked = 1;
|
console_locked = 1;
|
||||||
console_may_schedule = 0;
|
console_may_schedule = 0;
|
||||||
return 1;
|
return 1;
|
||||||
@ -2674,6 +2692,9 @@ static inline bool console_is_usable(struct console *con)
|
|||||||
if (!(flags & CON_ENABLED))
|
if (!(flags & CON_ENABLED))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if ((flags & CON_SUSPENDED))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!con->write)
|
if (!con->write)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2992,11 +3013,6 @@ void console_unlock(void)
|
|||||||
bool flushed;
|
bool flushed;
|
||||||
u64 next_seq;
|
u64 next_seq;
|
||||||
|
|
||||||
if (console_suspended) {
|
|
||||||
up_console_sem();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Console drivers are called with interrupts disabled, so
|
* Console drivers are called with interrupts disabled, so
|
||||||
* @console_may_schedule should be cleared before; however, we may
|
* @console_may_schedule should be cleared before; however, we may
|
||||||
@ -3726,8 +3742,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Hold the console_lock to guarantee safe access to
|
* Hold the console_lock to guarantee safe access to
|
||||||
* console->seq and to prevent changes to @console_suspended
|
* console->seq.
|
||||||
* until all consoles have been processed.
|
|
||||||
*/
|
*/
|
||||||
console_lock();
|
console_lock();
|
||||||
|
|
||||||
@ -3735,6 +3750,11 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
|||||||
for_each_console_srcu(c) {
|
for_each_console_srcu(c) {
|
||||||
if (con && con != c)
|
if (con && con != c)
|
||||||
continue;
|
continue;
|
||||||
|
/*
|
||||||
|
* If consoles are not usable, it cannot be expected
|
||||||
|
* that they make forward progress, so only increment
|
||||||
|
* @diff for usable consoles.
|
||||||
|
*/
|
||||||
if (!console_is_usable(c))
|
if (!console_is_usable(c))
|
||||||
continue;
|
continue;
|
||||||
printk_seq = c->seq;
|
printk_seq = c->seq;
|
||||||
@ -3743,18 +3763,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
|||||||
}
|
}
|
||||||
console_srcu_read_unlock(cookie);
|
console_srcu_read_unlock(cookie);
|
||||||
|
|
||||||
/*
|
if (diff != last_diff && reset_on_progress)
|
||||||
* If consoles are suspended, it cannot be expected that they
|
|
||||||
* make forward progress, so timeout immediately. @diff is
|
|
||||||
* still used to return a valid flush status.
|
|
||||||
*/
|
|
||||||
if (console_suspended)
|
|
||||||
remaining = 0;
|
|
||||||
else if (diff != last_diff && reset_on_progress)
|
|
||||||
remaining = timeout_ms;
|
remaining = timeout_ms;
|
||||||
|
|
||||||
console_unlock();
|
console_unlock();
|
||||||
|
|
||||||
|
/* Note: @diff is 0 if there are no usable consoles. */
|
||||||
if (diff == 0 || remaining == 0)
|
if (diff == 0 || remaining == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3788,7 +3802,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
|||||||
* printer has been seen to make some forward progress.
|
* printer has been seen to make some forward progress.
|
||||||
*
|
*
|
||||||
* Context: Process context. May sleep while acquiring console lock.
|
* Context: Process context. May sleep while acquiring console lock.
|
||||||
* Return: true if all enabled printers are caught up.
|
* Return: true if all usable printers are caught up.
|
||||||
*/
|
*/
|
||||||
static bool pr_flush(int timeout_ms, bool reset_on_progress)
|
static bool pr_flush(int timeout_ms, bool reset_on_progress)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user