diff options
Diffstat (limited to 'debian/patches-rt/0025-printk-nbcon-Implement-emergency-sections.patch')
-rw-r--r-- | debian/patches-rt/0025-printk-nbcon-Implement-emergency-sections.patch | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/debian/patches-rt/0025-printk-nbcon-Implement-emergency-sections.patch b/debian/patches-rt/0025-printk-nbcon-Implement-emergency-sections.patch new file mode 100644 index 0000000000..44327c280a --- /dev/null +++ b/debian/patches-rt/0025-printk-nbcon-Implement-emergency-sections.patch @@ -0,0 +1,283 @@ +From: Thomas Gleixner <tglx@linutronix.de> +Date: Mon, 11 Sep 2023 15:21:57 +0000 +Subject: [PATCH 25/46] printk: nbcon: Implement emergency sections +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.9/older/patches-6.9-rt5.tar.xz + +In emergency situations (something has gone wrong but the +system continues to operate), usually important information +(such as a backtrace) is generated via printk(). Each +individual printk record has little meaning. It is the +collection of printk messages that is most often needed by +developers and users. + +In order to help ensure that the collection of printk messages +in an emergency situation are all stored to the ringbuffer as +quickly as possible, disable console output for that CPU while +it is in the emergency situation. The consoles need to be +flushed when exiting the emergency situation. + +Add per-CPU emergency nesting tracking because an emergency +can arise while in an emergency situation. + +Add functions to mark the beginning and end of emergency +sections where the urgent messages are generated. + +Do not print if the current CPU is in an emergency state. + +When exiting all emergency nesting, flush nbcon consoles +directly using their atomic callback. Legacy consoles are +triggered for flushing via irq_work because it is not known +if the context was safe for a trylock on the console lock. + +Note that the emergency state is not system-wide. While one CPU +is in an emergency state, another CPU may continue to print +console messages. + +Co-developed-by: John Ogness <john.ogness@linutronix.de> +Signed-off-by: John Ogness <john.ogness@linutronix.de> +Signed-off-by: Thomas Gleixner (Intel) <tglx@linutronix.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + include/linux/console.h | 6 ++ + kernel/printk/internal.h | 11 ++++ + kernel/printk/nbcon.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++ + kernel/printk/printk.c | 25 +++++----- + 4 files changed, 146 insertions(+), 12 deletions(-) + +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -553,10 +553,16 @@ static inline bool console_is_registered + hlist_for_each_entry(con, &console_list, node) + + #ifdef CONFIG_PRINTK ++extern void nbcon_cpu_emergency_enter(void); ++extern void nbcon_cpu_emergency_exit(void); ++extern void nbcon_cpu_emergency_flush(void); + extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt); + extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt); + extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt); + #else ++static inline void nbcon_cpu_emergency_enter(void) { } ++static inline void nbcon_cpu_emergency_exit(void) { } ++static inline void nbcon_cpu_emergency_flush(void) { } + static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; } + static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; } +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -153,6 +153,17 @@ static inline bool console_is_usable(str + + #endif /* CONFIG_PRINTK */ + ++extern bool have_boot_console; ++extern bool have_legacy_console; ++ ++/* ++ * 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) ++ + extern struct printk_buffers printk_shared_pbufs; + + /** +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -936,6 +936,29 @@ static bool nbcon_emit_next_record(struc + return nbcon_context_exit_unsafe(ctxt); + } + ++/* Track the nbcon emergency nesting per CPU. */ ++static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting); ++static unsigned int early_nbcon_pcpu_emergency_nesting __initdata; ++ ++/** ++ * nbcon_get_cpu_emergency_nesting - Get the per CPU emergency nesting pointer ++ * ++ * Return: Either a pointer to the per CPU emergency nesting counter of ++ * the current CPU or to the init data during early boot. ++ */ ++static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void) ++{ ++ /* ++ * The value of __printk_percpu_data_ready gets set in normal ++ * context and before SMP initialization. As a result it could ++ * never change while inside an nbcon emergency section. ++ */ ++ if (!printk_percpu_data_ready()) ++ return &early_nbcon_pcpu_emergency_nesting; ++ ++ return this_cpu_ptr(&nbcon_pcpu_emergency_nesting); ++} ++ + /** + * nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon + * printing on the current CPU +@@ -946,9 +969,15 @@ static bool nbcon_emit_next_record(struc + */ + enum nbcon_prio nbcon_get_default_prio(void) + { ++ unsigned int *cpu_emergency_nesting; ++ + if (this_cpu_in_panic()) + return NBCON_PRIO_PANIC; + ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ if (*cpu_emergency_nesting) ++ return NBCON_PRIO_EMERGENCY; ++ + return NBCON_PRIO_NORMAL; + } + +@@ -1200,6 +1229,93 @@ void nbcon_atomic_flush_unsafe(void) + } + + /** ++ * nbcon_cpu_emergency_enter - Enter an emergency section where printk() ++ * messages for that CPU are only stored ++ * ++ * Upon exiting the emergency section, all stored messages are flushed. ++ * ++ * Context: Any context. Disables preemption. ++ * ++ * When within an emergency section, no printing occurs on that CPU. This ++ * is to allow all emergency messages to be dumped into the ringbuffer before ++ * flushing the ringbuffer. The actual printing occurs when exiting the ++ * outermost emergency section. ++ */ ++void nbcon_cpu_emergency_enter(void) ++{ ++ unsigned int *cpu_emergency_nesting; ++ ++ preempt_disable(); ++ ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ (*cpu_emergency_nesting)++; ++} ++ ++/** ++ * nbcon_cpu_emergency_exit - Exit an emergency section and flush the ++ * stored messages ++ * ++ * Flushing only occurs when exiting all nesting for the CPU. ++ * ++ * Context: Any context. Enables preemption. ++ */ ++void nbcon_cpu_emergency_exit(void) ++{ ++ unsigned int *cpu_emergency_nesting; ++ bool do_trigger_flush = false; ++ ++ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting(); ++ ++ /* ++ * Flush the messages before enabling preemtion to see them ASAP. ++ * ++ * Reduce the risk of potential softlockup by using the ++ * flush_pending() variant which ignores messages added later. It is ++ * called before decrementing the counter so that the printing context ++ * for the emergency messages is NBCON_PRIO_EMERGENCY. ++ */ ++ if (*cpu_emergency_nesting == 1) { ++ nbcon_atomic_flush_pending(); ++ do_trigger_flush = true; ++ } ++ ++ (*cpu_emergency_nesting)--; ++ ++ if (WARN_ON_ONCE(*cpu_emergency_nesting < 0)) ++ *cpu_emergency_nesting = 0; ++ ++ preempt_enable(); ++ ++ if (do_trigger_flush) ++ printk_trigger_flush(); ++} ++ ++/** ++ * nbcon_cpu_emergency_flush - Explicitly flush consoles while ++ * within emergency context ++ * ++ * Both nbcon and legacy consoles are flushed. ++ * ++ * It should be used only when there are too many messages printed ++ * in emergency context, for example, printing backtraces of all ++ * CPUs or processes. It is typically needed when the watchdogs ++ * need to be touched as well. ++ */ ++void nbcon_cpu_emergency_flush(void) ++{ ++ /* The explicit flush is needed only in the emergency context. */ ++ if (*(nbcon_get_cpu_emergency_nesting()) == 0) ++ return; ++ ++ nbcon_atomic_flush_pending(); ++ ++ if (printing_via_unlock && !in_nmi()) { ++ if (console_trylock()) ++ console_unlock(); ++ } ++} ++ ++/** + * nbcon_alloc - Allocate buffers needed by the nbcon console + * @con: Console to allocate buffers for + * +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -468,7 +468,7 @@ 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, +@@ -483,15 +483,7 @@ static bool have_nbcon_console; + * the console lock. This is because boot consoles and nbcon consoles may + * have mapped the same hardware. + */ +-static bool have_boot_console; +- +-/* +- * 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) ++bool have_boot_console; + + #ifdef CONFIG_PRINTK + DECLARE_WAIT_QUEUE_HEAD(log_wait); +@@ -2412,16 +2404,25 @@ asmlinkage int vprintk_emit(int facility + * printing of all remaining records to all consoles so that + * this context can return as soon as possible. Hopefully + * another printk() caller will take over the printing. ++ * ++ * Also, nbcon_get_default_prio() requires migration disabled. + */ + preempt_disable(); ++ + /* + * Try to acquire and then immediately release the console + * semaphore. The release will print out buffers. With the + * spinning variant, this context tries to take over the + * printing from another printing context. ++ * ++ * Skip it in EMERGENCY priority. The console will be ++ * explicitly flushed when exiting the emergency section. + */ +- if (console_trylock_spinning()) +- console_unlock(); ++ if (nbcon_get_default_prio() != NBCON_PRIO_EMERGENCY) { ++ if (console_trylock_spinning()) ++ console_unlock(); ++ } ++ + preempt_enable(); + } + |