[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230919230856.661435-10-john.ogness@linutronix.de>
Date: Wed, 20 Sep 2023 01:14:54 +0206
From: John Ogness <john.ogness@...utronix.de>
To: Petr Mladek <pmladek@...e.com>
Cc: Sergey Senozhatsky <senozhatsky@...omium.org>,
Steven Rostedt <rostedt@...dmis.org>,
Thomas Gleixner <tglx@...utronix.de>,
linux-kernel@...r.kernel.org, Kees Cook <keescook@...omium.org>,
Luis Chamberlain <mcgrof@...nel.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Peter Zijlstra <peterz@...radead.org>,
Josh Poimboeuf <jpoimboe@...nel.org>,
Arnd Bergmann <arnd@...db.de>,
"Guilherme G. Piccoli" <gpiccoli@...lia.com>,
Andy Shevchenko <andriy.shevchenko@...ux.intel.com>
Subject: [PATCH printk v2 09/11] panic: Add atomic write enforcement to oops
Invoke the atomic write enforcement functions for oops to
ensure that the information gets out to the consoles.
Since there is no single general function that calls both
oops_enter() and oops_exit(), the nesting feature of atomic
write sections is taken advantage of in order to guarantee
full coverage between the first oops_enter() and the last
oops_exit().
It is important to note that if there are any legacy consoles
registered, they will be attempting to directly print from the
printk-caller context, which may jeopardize the reliability of
the atomic consoles. Optimally there should be no legacy
consoles registered.
Signed-off-by: John Ogness <john.ogness@...utronix.de>
---
kernel/panic.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/kernel/panic.c b/kernel/panic.c
index 86ed71ba8c4d..e2879098645d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -614,6 +614,10 @@ bool oops_may_print(void)
return pause_on_oops_flag == 0;
}
+static atomic_t oops_cpu = ATOMIC_INIT(-1);
+static int oops_nesting;
+static enum nbcon_prio oops_prev_prio;
+
/*
* Called when the architecture enters its oops handler, before it prints
* anything. If this is the first CPU to oops, and it's oopsing the first
@@ -630,6 +634,36 @@ bool oops_may_print(void)
*/
void oops_enter(void)
{
+ enum nbcon_prio prev_prio;
+ int cpu = -1;
+
+ /*
+ * If this turns out to be the first CPU in oops, this is the
+ * beginning of the outermost atomic section. Otherwise it is
+ * the beginning of an inner atomic section.
+ */
+ prev_prio = nbcon_atomic_enter(NBCON_PRIO_EMERGENCY);
+
+ if (atomic_try_cmpxchg_relaxed(&oops_cpu, &cpu, smp_processor_id())) {
+ /*
+ * This is the first CPU in oops. Save the outermost
+ * @prev_prio in order to restore it on the outermost
+ * matching oops_exit(), when @oops_nesting == 0.
+ */
+ oops_prev_prio = prev_prio;
+
+ /*
+ * Enter an inner atomic section that ends at the end of this
+ * function. In this case, the nbcon_atomic_enter() above
+ * began the outermost atomic section.
+ */
+ prev_prio = nbcon_atomic_enter(NBCON_PRIO_EMERGENCY);
+ }
+
+ /* Track nesting when this CPU is the owner. */
+ if (cpu == -1 || cpu == smp_processor_id())
+ oops_nesting++;
+
tracing_off();
/* can't trust the integrity of the kernel anymore: */
debug_locks_off();
@@ -637,6 +671,9 @@ void oops_enter(void)
if (sysctl_oops_all_cpu_backtrace)
trigger_all_cpu_backtrace();
+
+ /* Exit inner atomic section. */
+ nbcon_atomic_exit(NBCON_PRIO_EMERGENCY, prev_prio);
}
static void print_oops_end_marker(void)
@@ -652,6 +689,18 @@ void oops_exit(void)
{
do_oops_enter_exit();
print_oops_end_marker();
+
+ if (atomic_read(&oops_cpu) == smp_processor_id()) {
+ oops_nesting--;
+ if (oops_nesting == 0) {
+ atomic_set(&oops_cpu, -1);
+
+ /* Exit outmost atomic section. */
+ nbcon_atomic_exit(NBCON_PRIO_EMERGENCY, oops_prev_prio);
+ }
+ }
+ put_cpu();
+
kmsg_dump(KMSG_DUMP_OOPS);
}
--
2.39.2
Powered by blists - more mailing lists