From 311b7c599bcaf54d96644cf669acc7e71b34d445 Mon Sep 17 00:00:00 2001 From: meganz009 Date: Fri, 9 Jun 2023 15:15:59 +0800 Subject: [PATCH 1/4] printk: Make rt aware commit ddfc55c94d550664260bd755c4f0ec09f13cfed2 upstream. Drop the lock before calling the console driver and do not disable interrupts while printing to a serial console. Signed-off-by: Thomas Gleixner --- kernel/printk/printk.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 57b61801f2d1..de6edd61879d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1635,6 +1635,7 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) return do_syslog(type, buf, len, SYSLOG_FROM_READER); } +#ifndef CONFIG_PREEMPT_RT_FULL /* * Special console_lock variants that help to reduce the risk of soft-lockups. * They allow to pass console_lock to another printk() call using a busy wait. @@ -1785,6 +1786,15 @@ static int console_trylock_spinning(void) return 1; } +#else + +static int console_trylock_spinning(void) +{ + return console_trylock(); +} + +#endif + /* * Call the console drivers, asking them to write out * log_buf[start] to log_buf[end - 1]. @@ -1800,6 +1810,7 @@ static void call_console_drivers(const char *ext_text, size_t ext_len, if (!console_drivers) return; + migrate_disable(); for_each_console(con) { if (exclusive_console && con != exclusive_console) continue; @@ -1815,6 +1826,7 @@ static void call_console_drivers(const char *ext_text, size_t ext_len, else con->write(con, text, len); } + migrate_enable(); } int printk_delay_msec __read_mostly; @@ -2013,20 +2025,30 @@ asmlinkage int vprintk_emit(int facility, int level, /* If called from the scheduler, we can not call up(). */ if (!in_sched && pending_output) { + int may_trylock = 1; + +#ifdef CONFIG_PREEMPT_RT_FULL + /* + * we can't take a sleeping lock with IRQs or preeption disabled + * so we can't print in these contexts + */ + if (!(preempt_count() == 0 && !irqs_disabled())) + may_trylock = 0; +#endif /* * Disable preemption to avoid being preempted while holding * console_sem which would prevent anyone from printing to * console */ - preempt_disable(); + migrate_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()) + if (may_trylock && console_trylock_spinning()) console_unlock(); - preempt_enable(); + migrate_enable(); } if (pending_output) @@ -2512,6 +2534,10 @@ void console_unlock(void) console_seq++; raw_spin_unlock(&logbuf_lock); +#ifdef CONFIG_PREEMPT_RT_FULL + printk_safe_exit_irqrestore(flags); + call_console_drivers(ext_text, ext_len, text, len); +#else /* * While actively printing out messages, if another printk() * were to occur on another CPU, it may wait for this one to @@ -2530,6 +2556,7 @@ void console_unlock(void) } printk_safe_exit_irqrestore(flags); +#endif /* Allow panic_cpu to take over the consoles safely */ if (abandon_console_lock_in_panic()) -- Gitee From e5e7cdd3a58e1ea6ac25dc633cb063526bbfa754 Mon Sep 17 00:00:00 2001 From: meganz009 Date: Fri, 9 Jun 2023 15:16:09 +0800 Subject: [PATCH 2/4] kernel/printk: Don't try to print from IRQ/NMI region commit ddc0ed9a091fdcda9dba71990fb9300de72e70bf upstream. On -RT we try to acquire sleeping locks which might lead to warnings from lockdep or a warn_on() from spin_try_lock() (which is a rtmutex on RT). We don't print in general from a IRQ off region so we should not try this via console_unblank() / bust_spinlocks() as well. Signed-off-by: Sebastian Andrzej Siewior --- kernel/printk/printk.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index de6edd61879d..a0f57351b22a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1810,6 +1810,11 @@ static void call_console_drivers(const char *ext_text, size_t ext_len, if (!console_drivers) return; + if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { + if (in_irq() || in_nmi()) + return; + } + migrate_disable(); for_each_console(con) { if (exclusive_console && con != exclusive_console) @@ -2608,6 +2613,11 @@ void console_unblank(void) { struct console *c; + if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { + if (in_irq() || in_nmi()) + return; + } + /* * console_unblank can no longer be called in interrupt context unless * oops_in_progress is set to 1.. -- Gitee From a53d6753324a4f8c495d3ef1d009a66001c4c6a2 Mon Sep 17 00:00:00 2001 From: meganz009 Date: Fri, 9 Jun 2023 15:16:22 +0800 Subject: [PATCH 3/4] printk: Drop the logbuf_lock more often commit 369d276b8c46a573a55da8fdf568f3cb6522d075 upstream. The lock is hold with irgs off. The latency drops 500us+ on my arm bugs with a "full" buffer after executing "dmesg" on the shell. Signed-off-by: Sebastian Andrzej Siewior --- kernel/printk/printk.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index a0f57351b22a..1a61989c4721 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1438,12 +1438,23 @@ static int syslog_print_all(char __user *buf, int size, bool clear) u64 next_seq; u64 seq; u32 idx; + int attempts = 0; + int num_msg; text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); if (!text) return -ENOMEM; logbuf_lock_irq(); + +try_again: + attempts++; + if (attempts > 10) { + len = -EBUSY; + goto out; + } + num_msg = 0; + /* * Find first record that fits, including all following records, * into the user-provided buffer for this dump. @@ -1456,6 +1467,14 @@ static int syslog_print_all(char __user *buf, int size, bool clear) len += msg_print_text(msg, true, NULL, 0); idx = log_next(idx); seq++; + num_msg++; + if (num_msg > 5) { + num_msg = 0; + logbuf_unlock_irq(); + logbuf_lock_irq(); + if (clear_seq < log_first_seq) + goto try_again; + } } /* move first record forward until length fits into the buffer */ @@ -1467,6 +1486,14 @@ static int syslog_print_all(char __user *buf, int size, bool clear) len -= msg_print_text(msg, true, NULL, 0); idx = log_next(idx); seq++; + num_msg++; + if (num_msg > 5) { + num_msg = 0; + logbuf_unlock_irq(); + logbuf_lock_irq(); + if (clear_seq < log_first_seq) + goto try_again; + } } /* last message fitting into this dump */ @@ -1504,6 +1531,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) clear_seq = log_next_seq; clear_idx = log_next_idx; } +out: logbuf_unlock_irq(); kfree(text); -- Gitee From b6021f6db51a205ceb1d8a56288675dfc1bd50f4 Mon Sep 17 00:00:00 2001 From: meganz009 Date: Fri, 9 Jun 2023 15:18:04 +0800 Subject: [PATCH 4/4] kgdb/serial: Short term workaround commit d1c62c912763a6d7d729f43e63605bb17d7814fe upstream. On 07/27/2011 04:37 PM, Thomas Gleixner wrote: > - KGDB (not yet disabled) is reportedly unusable on -rt right now due > to missing hacks in the console locking which I dropped on purpose. > To work around this in the short term you can use this patch, in addition to the clocksource watchdog patch that Thomas brewed up. Comments are welcome of course. Ultimately the right solution is to change separation between the console and the HW to have a polled mode + work queue so as not to introduce any kind of latency. Thanks, Jason. --- drivers/tty/serial/8250/8250_port.c | 3 +++ include/linux/kdb.h | 2 ++ kernel/debug/kdb/kdb_io.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index af1fdb01e458..ca3955b92a24 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -3244,6 +3245,8 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, if (port->sysrq || oops_in_progress) locked = 0; + else if (in_kdb_printk()) + locked = spin_trylock_irqsave(&port->lock, flags); else spin_lock_irqsave(&port->lock, flags); diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 68bd88223417..e033b25b0b72 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -167,6 +167,7 @@ extern __printf(2, 0) int vkdb_printf(enum kdb_msgsrc src, const char *fmt, extern __printf(1, 2) int kdb_printf(const char *, ...); typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...); +#define in_kdb_printk() (kdb_trap_printk) extern void kdb_init(int level); /* Access to kdb specific polling devices */ @@ -201,6 +202,7 @@ extern int kdb_register_flags(char *, kdb_func_t, char *, char *, extern int kdb_unregister(char *); #else /* ! CONFIG_KGDB_KDB */ static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; } +#define in_kdb_printk() (0) static inline void kdb_init(int level) {} static inline int kdb_register(char *cmd, kdb_func_t func, char *usage, char *help, short minlen) { return 0; } diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 6a4b41484afe..197cb422f6e1 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -857,9 +857,11 @@ int kdb_printf(const char *fmt, ...) va_list ap; int r; + kdb_trap_printk++; va_start(ap, fmt); r = vkdb_printf(KDB_MSGSRC_INTERNAL, fmt, ap); va_end(ap); + kdb_trap_printk--; return r; } -- Gitee