181 lines
5.7 KiB
Diff
181 lines
5.7 KiB
Diff
|
From: John Ogness <john.ogness@linutronix.de>
|
||
|
Date: Tue, 20 Aug 2024 08:35:39 +0206
|
||
|
Subject: [PATCH 13/54] nbcon: Add API to acquire context for non-printing
|
||
|
operations
|
||
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.11/older/patches-6.11-rt7.tar.xz
|
||
|
|
||
|
Provide functions nbcon_device_try_acquire() and
|
||
|
nbcon_device_release() which will try to acquire the nbcon
|
||
|
console ownership with NBCON_PRIO_NORMAL and mark it unsafe for
|
||
|
handover/takeover.
|
||
|
|
||
|
These functions are to be used together with the device-specific
|
||
|
locking when performing non-printing activities on the console
|
||
|
device. They will allow synchronization against the
|
||
|
atomic_write() callback which will be serialized, for higher
|
||
|
priority contexts, only by acquiring the console context
|
||
|
ownership.
|
||
|
|
||
|
Pitfalls:
|
||
|
|
||
|
The API requires to be called in a context with migration
|
||
|
disabled because it uses per-CPU variables internally.
|
||
|
|
||
|
The context is set unsafe for a takeover all the time. It
|
||
|
guarantees full serialization against any atomic_write() caller
|
||
|
except for the final flush in panic() which might try an unsafe
|
||
|
takeover.
|
||
|
|
||
|
Signed-off-by: John Ogness <john.ogness@linutronix.de>
|
||
|
Reviewed-by: Petr Mladek <pmladek@suse.com>
|
||
|
Link: https://lore.kernel.org/r/20240820063001.36405-14-john.ogness@linutronix.de
|
||
|
Signed-off-by: Petr Mladek <pmladek@suse.com>
|
||
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||
|
---
|
||
|
include/linux/console.h | 2 +
|
||
|
include/linux/printk.h | 14 +++++++++++
|
||
|
kernel/printk/nbcon.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||
|
3 files changed, 73 insertions(+), 1 deletion(-)
|
||
|
|
||
|
--- a/include/linux/console.h
|
||
|
+++ b/include/linux/console.h
|
||
|
@@ -322,6 +322,7 @@ struct nbcon_write_context {
|
||
|
*
|
||
|
* @nbcon_state: State for nbcon consoles
|
||
|
* @nbcon_seq: Sequence number of the next record for nbcon to print
|
||
|
+ * @nbcon_device_ctxt: Context available for non-printing operations
|
||
|
* @pbufs: Pointer to nbcon private buffer
|
||
|
*/
|
||
|
struct console {
|
||
|
@@ -417,6 +418,7 @@ struct console {
|
||
|
|
||
|
atomic_t __private nbcon_state;
|
||
|
atomic_long_t __private nbcon_seq;
|
||
|
+ struct nbcon_context __private nbcon_device_ctxt;
|
||
|
struct printk_buffers *pbufs;
|
||
|
};
|
||
|
|
||
|
--- a/include/linux/printk.h
|
||
|
+++ b/include/linux/printk.h
|
||
|
@@ -9,6 +9,8 @@
|
||
|
#include <linux/ratelimit_types.h>
|
||
|
#include <linux/once_lite.h>
|
||
|
|
||
|
+struct console;
|
||
|
+
|
||
|
extern const char linux_banner[];
|
||
|
extern const char linux_proc_banner[];
|
||
|
|
||
|
@@ -198,6 +200,8 @@ extern asmlinkage void dump_stack_lvl(co
|
||
|
extern asmlinkage void dump_stack(void) __cold;
|
||
|
void printk_trigger_flush(void);
|
||
|
void console_try_replay_all(void);
|
||
|
+extern bool nbcon_device_try_acquire(struct console *con);
|
||
|
+extern void nbcon_device_release(struct console *con);
|
||
|
#else
|
||
|
static inline __printf(1, 0)
|
||
|
int vprintk(const char *s, va_list args)
|
||
|
@@ -280,6 +284,16 @@ static inline void printk_trigger_flush(
|
||
|
static inline void console_try_replay_all(void)
|
||
|
{
|
||
|
}
|
||
|
+
|
||
|
+static inline bool nbcon_device_try_acquire(struct console *con)
|
||
|
+{
|
||
|
+ return false;
|
||
|
+}
|
||
|
+
|
||
|
+static inline void nbcon_device_release(struct console *con)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
#endif
|
||
|
|
||
|
bool this_cpu_in_panic(void);
|
||
|
--- a/kernel/printk/nbcon.c
|
||
|
+++ b/kernel/printk/nbcon.c
|
||
|
@@ -5,7 +5,9 @@
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/console.h>
|
||
|
#include <linux/delay.h>
|
||
|
+#include <linux/export.h>
|
||
|
#include <linux/slab.h>
|
||
|
+#include <linux/string.h>
|
||
|
#include "internal.h"
|
||
|
/*
|
||
|
* Printk console printing implementation for consoles which does not depend
|
||
|
@@ -546,6 +548,7 @@ static struct printk_buffers panic_nbcon
|
||
|
* nbcon_context_try_acquire - Try to acquire nbcon console
|
||
|
* @ctxt: The context of the caller
|
||
|
*
|
||
|
+ * Context: Under @ctxt->con->device_lock() or local_irq_save().
|
||
|
* Return: True if the console was acquired. False otherwise.
|
||
|
*
|
||
|
* If the caller allowed an unsafe hostile takeover, on success the
|
||
|
@@ -553,7 +556,6 @@ static struct printk_buffers panic_nbcon
|
||
|
* in an unsafe state. Otherwise, on success the caller may assume
|
||
|
* the console is not in an unsafe state.
|
||
|
*/
|
||
|
-__maybe_unused
|
||
|
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
|
||
|
{
|
||
|
unsigned int cpu = smp_processor_id();
|
||
|
@@ -1011,3 +1013,57 @@ void nbcon_free(struct console *con)
|
||
|
|
||
|
con->pbufs = NULL;
|
||
|
}
|
||
|
+
|
||
|
+/**
|
||
|
+ * nbcon_device_try_acquire - Try to acquire nbcon console and enter unsafe
|
||
|
+ * section
|
||
|
+ * @con: The nbcon console to acquire
|
||
|
+ *
|
||
|
+ * Context: Under the locking mechanism implemented in
|
||
|
+ * @con->device_lock() including disabling migration.
|
||
|
+ * Return: True if the console was acquired. False otherwise.
|
||
|
+ *
|
||
|
+ * Console drivers will usually use their own internal synchronization
|
||
|
+ * mechasism to synchronize between console printing and non-printing
|
||
|
+ * activities (such as setting baud rates). However, nbcon console drivers
|
||
|
+ * supporting atomic consoles may also want to mark unsafe sections when
|
||
|
+ * performing non-printing activities in order to synchronize against their
|
||
|
+ * atomic_write() callback.
|
||
|
+ *
|
||
|
+ * This function acquires the nbcon console using priority NBCON_PRIO_NORMAL
|
||
|
+ * and marks it unsafe for handover/takeover.
|
||
|
+ */
|
||
|
+bool nbcon_device_try_acquire(struct console *con)
|
||
|
+{
|
||
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
|
||
|
+
|
||
|
+ cant_migrate();
|
||
|
+
|
||
|
+ memset(ctxt, 0, sizeof(*ctxt));
|
||
|
+ ctxt->console = con;
|
||
|
+ ctxt->prio = NBCON_PRIO_NORMAL;
|
||
|
+
|
||
|
+ if (!nbcon_context_try_acquire(ctxt))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ if (!nbcon_context_enter_unsafe(ctxt))
|
||
|
+ return false;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
|
||
|
+
|
||
|
+/**
|
||
|
+ * nbcon_device_release - Exit unsafe section and release the nbcon console
|
||
|
+ * @con: The nbcon console acquired in nbcon_device_try_acquire()
|
||
|
+ */
|
||
|
+void nbcon_device_release(struct console *con)
|
||
|
+{
|
||
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
|
||
|
+
|
||
|
+ if (!nbcon_context_exit_unsafe(ctxt))
|
||
|
+ return;
|
||
|
+
|
||
|
+ nbcon_context_release(ctxt);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(nbcon_device_release);
|