summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0078-printk-nbcon-Add-buffer-management.patch
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/patches-rt/0078-printk-nbcon-Add-buffer-management.patch311
1 files changed, 311 insertions, 0 deletions
diff --git a/debian/patches-rt/0078-printk-nbcon-Add-buffer-management.patch b/debian/patches-rt/0078-printk-nbcon-Add-buffer-management.patch
new file mode 100644
index 0000000000..ea96abd7ed
--- /dev/null
+++ b/debian/patches-rt/0078-printk-nbcon-Add-buffer-management.patch
@@ -0,0 +1,311 @@
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Sat, 16 Sep 2023 21:26:03 +0206
+Subject: [PATCH 078/134] printk: nbcon: Add buffer management
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patches-6.6.7-rt18.tar.xz
+
+In case of hostile takeovers it must be ensured that the previous
+owner cannot scribble over the output buffer of the emergency/panic
+context. This is achieved by:
+
+ - Adding a global output buffer instance for the panic context.
+ This is the only situation where hostile takeovers can occur and
+ there is always at most 1 panic context.
+
+ - Allocating an output buffer per non-boot console upon console
+ registration. This buffer is used by the console owner when not
+ in panic context. (For boot consoles, the existing shared global
+ legacy output buffer is used instead. Boot console printing will
+ be synchronized with legacy console printing.)
+
+ - Choosing the appropriate buffer is handled in the acquire/release
+ functions.
+
+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>
+Reviewed-by: Petr Mladek <pmladek@suse.com>
+Signed-off-by: Petr Mladek <pmladek@suse.com>
+Link: https://lore.kernel.org/r/20230916192007.608398-5-john.ogness@linutronix.de
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/console.h | 7 ++++
+ kernel/printk/internal.h | 12 ++++++-
+ kernel/printk/nbcon.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
+ kernel/printk/printk.c | 22 +++++++++-----
+ 4 files changed, 99 insertions(+), 15 deletions(-)
+
+--- a/include/linux/console.h
++++ b/include/linux/console.h
+@@ -231,6 +231,7 @@ enum nbcon_prio {
+ };
+
+ struct console;
++struct printk_buffers;
+
+ /**
+ * struct nbcon_context - Context for console acquire/release
+@@ -241,6 +242,7 @@ struct console;
+ * be used only with NBCON_PRIO_PANIC @prio. It
+ * might cause a system freeze when the console
+ * is used later.
++ * @pbufs: Pointer to the text buffer for this context
+ */
+ struct nbcon_context {
+ /* members set by caller */
+@@ -248,6 +250,9 @@ struct nbcon_context {
+ unsigned int spinwait_max_us;
+ enum nbcon_prio prio;
+ unsigned int allow_unsafe_takeover : 1;
++
++ /* members set by acquire */
++ struct printk_buffers *pbufs;
+ };
+
+ /**
+@@ -271,6 +276,7 @@ struct nbcon_context {
+ * @node: hlist node for the console list
+ *
+ * @nbcon_state: State for nbcon consoles
++ * @pbufs: Pointer to nbcon private buffer
+ */
+ struct console {
+ char name[16];
+@@ -293,6 +299,7 @@ struct console {
+
+ /* nbcon console specific members */
+ atomic_t __private nbcon_state;
++ struct printk_buffers *pbufs;
+ };
+
+ #ifdef CONFIG_LOCKDEP
+--- a/kernel/printk/internal.h
++++ b/kernel/printk/internal.h
+@@ -13,6 +13,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl
+ #define printk_sysctl_init() do { } while (0)
+ #endif
+
++#define con_printk(lvl, con, fmt, ...) \
++ printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \
++ (con->flags & CON_NBCON) ? "" : "legacy ", \
++ (con->flags & CON_BOOT) ? "boot" : "", \
++ con->name, con->index, ##__VA_ARGS__)
++
+ #ifdef CONFIG_PRINTK
+
+ #ifdef CONFIG_PRINTK_CALLER
+@@ -63,8 +69,9 @@ void defer_console_output(void);
+ u16 printk_parse_prefix(const char *text, int *level,
+ enum printk_info_flags *flags);
+
++bool nbcon_alloc(struct console *con);
+ void nbcon_init(struct console *con);
+-void nbcon_cleanup(struct console *con);
++void nbcon_free(struct console *con);
+
+ #else
+
+@@ -81,8 +88,9 @@ void nbcon_cleanup(struct console *con);
+ #define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
+
+ static inline bool printk_percpu_data_ready(void) { return false; }
++static inline bool nbcon_alloc(struct console *con) { return false; }
+ static inline void nbcon_init(struct console *con) { }
+-static inline void nbcon_cleanup(struct console *con) { }
++static inline void nbcon_free(struct console *con) { }
+
+ #endif /* CONFIG_PRINTK */
+
+--- a/kernel/printk/nbcon.c
++++ b/kernel/printk/nbcon.c
+@@ -5,6 +5,7 @@
+ #include <linux/kernel.h>
+ #include <linux/console.h>
+ #include <linux/delay.h>
++#include <linux/slab.h>
+ #include "internal.h"
+ /*
+ * Printk console printing implementation for consoles which does not depend
+@@ -70,6 +71,10 @@
+ * console is an unsafe state. It is used only in panic() by the final
+ * attempt to flush consoles in a try and hope mode.
+ *
++ * Note that separate record buffers are used in panic(). As a result,
++ * the messages can be read and formatted without any risk even after
++ * using the hostile takeover in unsafe state.
++ *
+ * The release function simply clears the 'prio' field.
+ *
+ * All operations on @console::nbcon_state are atomic cmpxchg based to
+@@ -459,6 +464,8 @@ static int nbcon_context_try_acquire_hos
+ return 0;
+ }
+
++static struct printk_buffers panic_nbcon_pbufs;
++
+ /**
+ * nbcon_context_try_acquire - Try to acquire nbcon console
+ * @ctxt: The context of the caller
+@@ -473,6 +480,7 @@ static int nbcon_context_try_acquire_hos
+ __maybe_unused
+ static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
+ {
++ unsigned int cpu = smp_processor_id();
+ struct console *con = ctxt->console;
+ struct nbcon_state cur;
+ int err;
+@@ -491,7 +499,18 @@ static bool nbcon_context_try_acquire(st
+
+ err = nbcon_context_try_acquire_hostile(ctxt, &cur);
+ out:
+- return !err;
++ if (err)
++ return false;
++
++ /* Acquire succeeded. */
++
++ /* Assign the appropriate buffer for this context. */
++ if (atomic_read(&panic_cpu) == cpu)
++ ctxt->pbufs = &panic_nbcon_pbufs;
++ else
++ ctxt->pbufs = con->pbufs;
++
++ return true;
+ }
+
+ static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu,
+@@ -530,7 +549,7 @@ static void nbcon_context_release(struct
+
+ do {
+ if (!nbcon_owner_matches(&cur, cpu, ctxt->prio))
+- return;
++ break;
+
+ new.atom = cur.atom;
+ new.prio = NBCON_PRIO_NONE;
+@@ -542,26 +561,70 @@ static void nbcon_context_release(struct
+ new.unsafe |= cur.unsafe_takeover;
+
+ } while (!nbcon_state_try_cmpxchg(con, &cur, &new));
++
++ ctxt->pbufs = NULL;
++}
++
++/**
++ * nbcon_alloc - Allocate buffers needed by the nbcon console
++ * @con: Console to allocate buffers for
++ *
++ * Return: True on success. False otherwise and the console cannot
++ * be used.
++ *
++ * This is not part of nbcon_init() because buffer allocation must
++ * be performed earlier in the console registration process.
++ */
++bool nbcon_alloc(struct console *con)
++{
++ if (con->flags & CON_BOOT) {
++ /*
++ * Boot console printing is synchronized with legacy console
++ * printing, so boot consoles can share the same global printk
++ * buffers.
++ */
++ con->pbufs = &printk_shared_pbufs;
++ } else {
++ con->pbufs = kmalloc(sizeof(*con->pbufs), GFP_KERNEL);
++ if (!con->pbufs) {
++ con_printk(KERN_ERR, con, "failed to allocate printing buffer\n");
++ return false;
++ }
++ }
++
++ return true;
+ }
+
+ /**
+ * nbcon_init - Initialize the nbcon console specific data
+ * @con: Console to initialize
++ *
++ * nbcon_alloc() *must* be called and succeed before this function
++ * is called.
+ */
+ void nbcon_init(struct console *con)
+ {
+ struct nbcon_state state = { };
+
++ /* nbcon_alloc() must have been called and successful! */
++ BUG_ON(!con->pbufs);
++
+ nbcon_state_set(con, &state);
+ }
+
+ /**
+- * nbcon_cleanup - Cleanup the nbcon console specific data
+- * @con: Console to cleanup
++ * nbcon_free - Free and cleanup the nbcon console specific data
++ * @con: Console to free/cleanup nbcon data
+ */
+-void nbcon_cleanup(struct console *con)
++void nbcon_free(struct console *con)
+ {
+ struct nbcon_state state = { };
+
+ nbcon_state_set(con, &state);
++
++ /* Boot consoles share global printk buffers. */
++ if (!(con->flags & CON_BOOT))
++ kfree(con->pbufs);
++
++ con->pbufs = NULL;
+ }
+--- a/kernel/printk/printk.c
++++ b/kernel/printk/printk.c
+@@ -3331,12 +3331,6 @@ static void try_enable_default_console(s
+ newcon->flags |= CON_CONSDEV;
+ }
+
+-#define con_printk(lvl, con, fmt, ...) \
+- printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \
+- (con->flags & CON_NBCON) ? "" : "legacy ", \
+- (con->flags & CON_BOOT) ? "boot" : "", \
+- con->name, con->index, ##__VA_ARGS__)
+-
+ static void console_init_seq(struct console *newcon, bool bootcon_registered)
+ {
+ struct console *con;
+@@ -3450,6 +3444,15 @@ void register_console(struct console *ne
+ goto unlock;
+ }
+
++ if (newcon->flags & CON_NBCON) {
++ /*
++ * Ensure the nbcon console buffers can be allocated
++ * before modifying any global data.
++ */
++ if (!nbcon_alloc(newcon))
++ goto unlock;
++ }
++
+ /*
+ * See if we want to enable this console driver by default.
+ *
+@@ -3477,8 +3480,11 @@ void register_console(struct console *ne
+ err = try_enable_preferred_console(newcon, false);
+
+ /* printk() messages are not printed to the Braille console. */
+- if (err || newcon->flags & CON_BRL)
++ if (err || newcon->flags & CON_BRL) {
++ if (newcon->flags & CON_NBCON)
++ nbcon_free(newcon);
+ goto unlock;
++ }
+
+ /*
+ * If we have a bootconsole, and are switching to a real console,
+@@ -3589,7 +3595,7 @@ static int unregister_console_locked(str
+ synchronize_srcu(&console_srcu);
+
+ if (console->flags & CON_NBCON)
+- nbcon_cleanup(console);
++ nbcon_free(console);
+
+ console_sysfs_notify();
+