Commit adf6f37d authored by John Ogness's avatar John Ogness Committed by Petr Mladek

nbcon: Add API to acquire context for non-printing operations

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: default avatarJohn Ogness <john.ogness@linutronix.de>
Reviewed-by: default avatarPetr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-14-john.ogness@linutronix.deSigned-off-by: default avatarPetr Mladek <pmladek@suse.com>
parent dc219d8d
...@@ -322,6 +322,7 @@ struct nbcon_write_context { ...@@ -322,6 +322,7 @@ struct nbcon_write_context {
* *
* @nbcon_state: State for nbcon consoles * @nbcon_state: State for nbcon consoles
* @nbcon_seq: Sequence number of the next record for nbcon to print * @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 * @pbufs: Pointer to nbcon private buffer
*/ */
struct console { struct console {
...@@ -417,6 +418,7 @@ struct console { ...@@ -417,6 +418,7 @@ struct console {
atomic_t __private nbcon_state; atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq; atomic_long_t __private nbcon_seq;
struct nbcon_context __private nbcon_device_ctxt;
struct printk_buffers *pbufs; struct printk_buffers *pbufs;
}; };
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <linux/ratelimit_types.h> #include <linux/ratelimit_types.h>
#include <linux/once_lite.h> #include <linux/once_lite.h>
struct console;
extern const char linux_banner[]; extern const char linux_banner[];
extern const char linux_proc_banner[]; extern const char linux_proc_banner[];
...@@ -198,6 +200,8 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold; ...@@ -198,6 +200,8 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
extern asmlinkage void dump_stack(void) __cold; extern asmlinkage void dump_stack(void) __cold;
void printk_trigger_flush(void); void printk_trigger_flush(void);
void console_try_replay_all(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 #else
static inline __printf(1, 0) static inline __printf(1, 0)
int vprintk(const char *s, va_list args) int vprintk(const char *s, va_list args)
...@@ -280,6 +284,16 @@ static inline void printk_trigger_flush(void) ...@@ -280,6 +284,16 @@ static inline void printk_trigger_flush(void)
static inline void console_try_replay_all(void) 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 #endif
bool this_cpu_in_panic(void); bool this_cpu_in_panic(void);
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h>
#include "internal.h" #include "internal.h"
/* /*
* Printk console printing implementation for consoles which does not depend * Printk console printing implementation for consoles which does not depend
...@@ -546,6 +548,7 @@ static struct printk_buffers panic_nbcon_pbufs; ...@@ -546,6 +548,7 @@ static struct printk_buffers panic_nbcon_pbufs;
* nbcon_context_try_acquire - Try to acquire nbcon console * nbcon_context_try_acquire - Try to acquire nbcon console
* @ctxt: The context of the caller * @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. * Return: True if the console was acquired. False otherwise.
* *
* If the caller allowed an unsafe hostile takeover, on success the * If the caller allowed an unsafe hostile takeover, on success the
...@@ -553,7 +556,6 @@ static struct printk_buffers panic_nbcon_pbufs; ...@@ -553,7 +556,6 @@ static struct printk_buffers panic_nbcon_pbufs;
* in an unsafe state. Otherwise, on success the caller may assume * in an unsafe state. Otherwise, on success the caller may assume
* the console is not in an unsafe state. * the console is not in an unsafe state.
*/ */
__maybe_unused
static bool nbcon_context_try_acquire(struct nbcon_context *ctxt) static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
...@@ -1011,3 +1013,57 @@ void nbcon_free(struct console *con) ...@@ -1011,3 +1013,57 @@ void nbcon_free(struct console *con)
con->pbufs = NULL; 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment