summaryrefslogtreecommitdiff
path: root/kernel/printk/printk.c
diff options
context:
space:
mode:
authorJohn Ogness <john.ogness@linutronix.de>2024-08-20 08:35:56 +0206
committerPetr Mladek <pmladek@suse.com>2024-08-21 14:56:49 +0200
commit6690d6b52726bcb2b743466a1833e0b9f049b9d7 (patch)
treef1c08a6c2c0939af185060bf6b4a4d80f9a57d3c /kernel/printk/printk.c
parente35a8884270bae11196eedf3b0a5bf22619f11f2 (diff)
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 <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20240820063001.36405-31-john.ogness@linutronix.de [pmladek@suse.com: Updated the commit message.] Signed-off-by: Petr Mladek <pmladek@suse.com>
Diffstat (limited to 'kernel/printk/printk.c')
-rw-r--r--kernel/printk/printk.c68
1 files changed, 30 insertions, 38 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index fc3f8970eea2..6accd1704e73 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -468,14 +468,14 @@ static DEFINE_MUTEX(syslog_lock);
* present, it is necessary to perform the console lock/unlock dance
* whenever console flushing should occur.
*/
-static bool have_legacy_console;
+bool have_legacy_console;
/*
* Specifies if an nbcon console is registered. If nbcon consoles are present,
* synchronous printing of legacy consoles will not occur during panic until
* the backtrace has been stored to the ringbuffer.
*/
-static bool have_nbcon_console;
+bool have_nbcon_console;
/*
* Specifies if a boot console is registered. If boot consoles are present,
@@ -488,14 +488,6 @@ bool have_boot_console;
/* See printk_legacy_allow_panic_sync() for details. */
bool legacy_allow_panic_sync;
-/*
- * Specifies if the console lock/unlock dance is needed for console
- * printing. If @have_boot_console is true, the nbcon consoles will
- * be printed serially along with the legacy consoles because nbcon
- * consoles cannot print simultaneously with boot consoles.
- */
-#define printing_via_unlock (have_legacy_console || have_boot_console)
-
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -2342,9 +2334,12 @@ out:
*/
void printk_legacy_allow_panic_sync(void)
{
+ struct console_flush_type ft;
+
legacy_allow_panic_sync = true;
- if (printing_via_unlock && !is_printk_legacy_deferred()) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
@@ -2354,8 +2349,7 @@ asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
- bool do_trylock_unlock = printing_via_unlock;
- bool defer_legacy = false;
+ struct console_flush_type ft;
int printed_len;
/* Suppress unimportant messages after panic happens */
@@ -2370,35 +2364,23 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
return 0;
+ printk_get_console_flush_type(&ft);
+
/* If called from the scheduler, we can not call up(). */
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
- defer_legacy = do_trylock_unlock;
- do_trylock_unlock = false;
+ ft.legacy_offload |= ft.legacy_direct;
+ ft.legacy_direct = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
- if (have_nbcon_console && !have_boot_console) {
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
- /*
- * In panic, the legacy consoles are not allowed to print from
- * the printk calling context unless explicitly allowed. This
- * gives the safe nbcon consoles a chance to print out all the
- * panic messages first. This restriction only applies if
- * there are nbcon consoles registered and they are allowed to
- * flush.
- */
- if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
- do_trylock_unlock = false;
- defer_legacy = false;
- }
- }
-
- if (do_trylock_unlock) {
+ if (ft.legacy_direct) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2418,7 +2400,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (defer_legacy)
+ if (ft.legacy_offload)
defer_console_output();
else
wake_up_klogd();
@@ -2777,10 +2759,16 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
- if (!cpuhp_tasks_frozen && printing_via_unlock) {
- /* If trylock fails, someone else is doing the printing */
- if (console_trylock())
- console_unlock();
+ struct console_flush_type ft;
+
+ if (!cpuhp_tasks_frozen) {
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
+ nbcon_atomic_flush_pending();
+ if (ft.legacy_direct) {
+ if (console_trylock())
+ console_unlock();
+ }
}
return 0;
}
@@ -3305,6 +3293,7 @@ static void __console_rewind_all(void)
*/
void console_flush_on_panic(enum con_flush_mode mode)
{
+ struct console_flush_type ft;
bool handover;
u64 next_seq;
@@ -3328,7 +3317,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL)
__console_rewind_all();
- if (!have_boot_console)
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
/* 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
{
unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
unsigned long remaining_jiffies = timeout_jiffies;
+ struct console_flush_type ft;
struct console *c;
u64 last_diff = 0;
u64 printk_seq;
@@ -4005,7 +3996,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
seq = prb_next_reserve_seq(prb);
/* Flush the consoles so that records up to @seq are printed. */
- if (printing_via_unlock) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
console_lock();
console_unlock();
}