From 0e8d22ad8010838573d07b529c15a944af641785 Mon Sep 17 00:00:00 2001
From: John Ogness <john.ogness@linutronix.de>
Date: Fri, 4 Feb 2022 16:01:17 +0106
Subject: [PATCH] printk: avoid preempt_disable() for PREEMPT_RT
References: SLE Realtime Extension
Patch-mainline: Queued in subsystem maintainer repository
Git-commit: e408f85eb6864195d43a870cee74fb5d730a5858
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git
During non-normal operation, printk() calls will attempt to
write the messages directly to the consoles. This involves
using console_trylock() to acquire @console_sem.
Preemption is disabled while directly printing to the consoles
in order to ensure that the printing task is not scheduled away
while holding @console_sem, thus blocking all other printers
and causing delays in printing.
Commit fd5f7cde1b85 ("printk: Never set console_may_schedule in
console_trylock()") specifically reverted a previous attempt at
allowing preemption while printing.
However, on PREEMPT_RT systems, disabling preemption while
printing is not allowed because console drivers typically
acquire a spin lock (which under PREEMPT_RT is an rtmutex).
Since direct printing is only used during early boot and
non-panic dumps, the risks of delayed print output for these
scenarios will be accepted under PREEMPT_RT.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
kernel/printk/printk.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -277,10 +277,12 @@ static void __up_console_sem(unsigned lo
}
#define up_console_sem() __up_console_sem(_RET_IP_)
+#ifndef CONFIG_PREEMPT_RT
static bool panic_in_progress(void)
{
return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
}
+#endif
/*
* Tracks whether kthread printers are all paused. A value of true implies
@@ -1919,6 +1921,7 @@ static int console_lock_spinning_disable
return 1;
}
+#if !IS_ENABLED(CONFIG_PREEMPT_RT)
/**
* console_trylock_spinning - try to get console_lock by busy waiting
*
@@ -1992,6 +1995,7 @@ static int console_trylock_spinning(void
return 1;
}
+#endif /* CONFIG_PREEMPT_RT */
/*
* Call the specified console driver, asking it to write out the specified
@@ -2325,19 +2329,31 @@ asmlinkage int vprintk_emit(int facility
/* If called from the scheduler, we can not call up(). */
if (!in_sched && allow_direct_printing()) {
/*
+ * Try to acquire and then immediately release the console
+ * semaphore. The release will print out buffers.
+ */
+#if IS_ENABLED(CONFIG_PREEMPT_RT)
+ /*
+ * Use the non-spinning trylock since PREEMPT_RT does not
+ * support console lock handovers.
+ *
+ * Direct printing will most likely involve taking spinlocks.
+ * For PREEMPT_RT, this is only allowed if in a preemptible
+ * context.
+ */
+ if (preemptible() && console_trylock())
+ console_unlock();
+#else
+ /*
* Disable preemption to avoid being preempted while holding
* console_sem which would prevent anyone from printing to
* console
*/
preempt_disable();
- /*
- * Try to acquire and then immediately release the console
- * semaphore. The release will print out buffers and wake up
- * /dev/kmsg and syslog() users.
- */
if (console_trylock_spinning())
console_unlock();
preempt_enable();
+#endif
}
wake_up_klogd();
@@ -2965,8 +2981,13 @@ static bool console_emit_next_record(str
len = record_print_text(&r, console_msg_format & MSG_FORMAT_SYSLOG, printk_time);
}
+#if IS_ENABLED(CONFIG_PREEMPT_RT)
+ /* PREEMPT_RT does not support console lock handovers. */
+ allow_handover = false;
+#else
/* Handovers may only happen between trylock contexts. */
allow_handover = (handover && atomic_read(&console_lock_count) == -1);
+#endif
if (allow_handover) {
/*