* [PATCH printk v8 00/35] wire up write_atomic() printing
@ 2024-08-20 6:29 John Ogness
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
` (35 more replies)
0 siblings, 36 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Miguel Ojeda, Paul E. McKenney, Greg Kroah-Hartman, Jiri Slaby,
linux-serial, Russell King, Tony Lindgren, Andy Shevchenko,
Geert Uytterhoeven, Arnd Bergmann, Uwe Kleine-König,
Théo Lebrun, Linus Walleij, Lino Sanfilippo,
Ilpo Järvinen, Konrad Dybcio, Sebastian Andrzej Siewior,
Andrew Morton, Jani Nikula, Ryo Takakura, Uros Bizjak,
Joel Granados, Lukas Wunner, Feng Tang, Baoquan He,
Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Mathieu Desnoyers,
Lai Jiangshan, Zqiang, rcu, Peter Zijlstra, Ingo Molnar,
Will Deacon, Waiman Long
Hi,
This is v8 of a series to wire up the nbcon consoles so that
they actually perform printing using their write_atomic()
callback. v7 is here [0]. For information about the motivation
of the atomic consoles, please read the cover letter of v1 [1].
The main focus of this series:
- For nbcon consoles, always call write_atomic() directly from
printk() caller context for the panic CPU.
- For nbcon consoles, call write_atomic() when unlocking the
console lock.
- Only perform the console lock/unlock dance if legacy or boot
consoles are registered.
- For legacy consoles, if nbcon consoles are registered, do not
attempt to print from printk() caller context for the panic
CPU until nbcon consoles have had a chance to print the most
significant messages.
- Mark emergency sections. In these sections, every printk()
call will attempt to directly flush to the consoles using the
EMERGENCY priority.
This series does _not_ include threaded printing or nbcon
drivers. Those features will be added in separate follow-up
series.
The changes since v7:
- Change printk_get_console_flush_type() to set preferred flush
types.
- Change printk_get_console_flush_type() to also check for
legacy consoles before seting @legacy_direct.
- Change vprintk_emit() to hack the struct console_flush_type
for LOGLEVEL_SCHED rather than using local variables.
- Change console_cpu_notify() to also flush nbcon atomic
consoles.
- Remove unnecessary flush type check in
nbcon_atomic_flush_pending_con(). It is not needed until the
threaded series.
- Fix compiling issues related to @legacy_allow_panic_sync for
!CONFIG_PRINTK.
John Ogness
[0] https://lore.kernel.org/lkml/20240804005138.3722656-1-john.ogness@linutronix.de
[1] https://lore.kernel.org/lkml/20230302195618.156940-1-john.ogness@linutronix.de
John Ogness (30):
printk: Add notation to console_srcu locking
printk: nbcon: Consolidate alloc() and init()
printk: nbcon: Clarify rules of the owner/waiter matching
printk: nbcon: Remove return value for write_atomic()
printk: nbcon: Add detailed doc for write_atomic()
printk: nbcon: Add callbacks to synchronize with driver
printk: nbcon: Use driver synchronization while (un)registering
serial: core: Provide low-level functions to lock port
serial: core: Introduce wrapper to set @uart_port->cons
console: Improve console_srcu_read_flags() comments
nbcon: Add API to acquire context for non-printing operations
serial: core: Acquire nbcon context in port->lock wrapper
printk: nbcon: Do not rely on proxy headers
printk: Make console_is_usable() available to nbcon.c
printk: Let console_is_usable() handle nbcon
printk: Add @flags argument for console_is_usable()
printk: nbcon: Add helper to assign priority based on CPU state
printk: Track registered boot consoles
printk: nbcon: Use nbcon consoles in console_flush_all()
printk: Add is_printk_legacy_deferred()
printk: nbcon: Flush new records on device_release()
printk: Flush nbcon consoles first on panic
printk: nbcon: Add unsafe flushing on panic
printk: Avoid console_lock dance if no legacy or boot consoles
printk: Track nbcon consoles
printk: Coordinate direct printing in panic
printk: Add helper for flush type logic
panic: Mark emergency section in oops
rcu: Mark emergency sections in rcu stalls
lockdep: Mark emergency sections in lockdep splats
Petr Mladek (1):
printk: Properly deal with nbcon consoles on seq init
Sebastian Andrzej Siewior (1):
printk: Check printk_deferred_enter()/_exit() usage
Thomas Gleixner (3):
printk: nbcon: Provide function to flush using write_atomic()
printk: nbcon: Implement emergency sections
panic: Mark emergency section in warn
drivers/tty/serial/8250/8250_core.c | 6 +-
drivers/tty/serial/amba-pl011.c | 2 +-
drivers/tty/serial/serial_core.c | 16 +-
include/linux/console.h | 110 +++++-
include/linux/printk.h | 33 +-
include/linux/serial_core.h | 117 +++++-
kernel/locking/lockdep.c | 83 ++++-
kernel/panic.c | 9 +
kernel/printk/internal.h | 137 ++++++-
kernel/printk/nbcon.c | 556 +++++++++++++++++++++++++---
kernel/printk/printk.c | 251 ++++++++++---
kernel/printk/printk_ringbuffer.h | 2 +
kernel/printk/printk_safe.c | 23 +-
kernel/rcu/tree_exp.h | 7 +
kernel/rcu/tree_stall.h | 9 +
15 files changed, 1210 insertions(+), 151 deletions(-)
base-commit: bcc954c6caba01fca143162d5fbb90e46aa1ad80
--
2.39.2
^ permalink raw reply [flat|nested] 84+ messages in thread
* [PATCH printk v8 01/35] printk: Add notation to console_srcu locking
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-08-20 17:49 ` Paul E. McKenney
2024-09-09 17:28 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 02/35] printk: nbcon: Consolidate alloc() and init() John Ogness
` (34 subsequent siblings)
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Miguel Ojeda, Paul E. McKenney
kernel/printk/printk.c:284:5: sparse: sparse: context imbalance in
'console_srcu_read_lock' - wrong count at exit
include/linux/srcu.h:301:9: sparse: sparse: context imbalance in
'console_srcu_read_unlock' - unexpected unlock
Fixes: 6c4afa79147e ("printk: Prepare for SRCU console list protection")
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c22b07049c38..93c67eb7ca9e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -282,6 +282,7 @@ EXPORT_SYMBOL(console_list_unlock);
* Return: A cookie to pass to console_srcu_read_unlock().
*/
int console_srcu_read_lock(void)
+ __acquires(&console_srcu)
{
return srcu_read_lock_nmisafe(&console_srcu);
}
@@ -295,6 +296,7 @@ EXPORT_SYMBOL(console_srcu_read_lock);
* Counterpart to console_srcu_read_lock()
*/
void console_srcu_read_unlock(int cookie)
+ __releases(&console_srcu)
{
srcu_read_unlock_nmisafe(&console_srcu, cookie);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 02/35] printk: nbcon: Consolidate alloc() and init()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 03/35] printk: Properly deal with nbcon consoles on seq init John Ogness
` (33 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Rather than splitting the nbcon allocation and initialization into
two pieces, perform all initialization in nbcon_alloc(). Later,
the initial sequence is calculated and can be explicitly set using
nbcon_seq_force(). This removes the need for the strong rules of
nbcon_init() that even included a BUG_ON().
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 --
kernel/printk/nbcon.c | 37 +++++++++++--------------------------
kernel/printk/printk.c | 2 +-
3 files changed, 12 insertions(+), 29 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 19dcc5832651..398ecb40d279 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -75,7 +75,6 @@ u16 printk_parse_prefix(const char *text, int *level,
u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
-void nbcon_init(struct console *con);
void nbcon_free(struct console *con);
#else
@@ -96,7 +95,6 @@ static inline bool printk_percpu_data_ready(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
-static inline void nbcon_init(struct console *con) { }
static inline void nbcon_free(struct console *con) { }
#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index c8093bcc01fe..670692dc9b10 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -929,17 +929,22 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
}
/**
- * nbcon_alloc - Allocate buffers needed by the nbcon console
- * @con: Console to allocate buffers for
+ * nbcon_alloc - Allocate and init the nbcon console specific data
+ * @con: Console to initialize
*
- * Return: True on success. False otherwise and the console cannot
- * be used.
+ * Return: True if the console was fully allocated and initialized.
+ * Otherwise @con must not be registered.
*
- * This is not part of nbcon_init() because buffer allocation must
- * be performed earlier in the console registration process.
+ * When allocation and init was successful, the console must be properly
+ * freed using nbcon_free() once it is no longer needed.
*/
bool nbcon_alloc(struct console *con)
{
+ struct nbcon_state state = { };
+
+ nbcon_state_set(con, &state);
+ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), 0);
+
if (con->flags & CON_BOOT) {
/*
* Boot console printing is synchronized with legacy console
@@ -958,26 +963,6 @@ bool nbcon_alloc(struct console *con)
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.
- *
- * This function expects that the legacy @con->seq has been set.
- */
-void nbcon_init(struct console *con)
-{
- struct nbcon_state state = { };
-
- /* nbcon_alloc() must have been called and successful! */
- BUG_ON(!con->pbufs);
-
- nbcon_seq_force(con, con->seq);
- nbcon_state_set(con, &state);
-}
-
/**
* nbcon_free - Free and cleanup the nbcon console specific data
* @con: Console to free/cleanup nbcon data
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 93c67eb7ca9e..a47017c932be 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3618,7 +3618,7 @@ void register_console(struct console *newcon)
console_init_seq(newcon, bootcon_registered);
if (newcon->flags & CON_NBCON)
- nbcon_init(newcon);
+ nbcon_seq_force(newcon, newcon->seq);
/*
* Put this console in the list - keep the
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 03/35] printk: Properly deal with nbcon consoles on seq init
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
2024-08-20 6:29 ` [PATCH printk v8 02/35] printk: nbcon: Consolidate alloc() and init() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Petr Mladek
2024-08-20 6:29 ` [PATCH printk v8 04/35] printk: Check printk_deferred_enter()/_exit() usage John Ogness
` (32 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
From: Petr Mladek <pmladek@suse.com>
If a non-boot console is registering and boot consoles exist,
the consoles are flushed before being unregistered. This allows
the non-boot console to continue where the boot console left
off.
If for whatever reason flushing fails, the lowest seq found from
any of the enabled boot consoles is used. Until now con->seq was
checked. However, if it is an nbcon boot console, the function
nbcon_seq_read() must be used to read seq because con->seq is
not updated for nbcon consoles.
Check if it is an nbcon boot console and if so call
nbcon_seq_read() to read seq.
Also, avoid usage of con->seq as temporary storage of the
starting record. Instead, rename console_init_seq() to
get_init_console_seq() and just return the value. For nbcon
consoles set the sequence via nbcon_seq_force(), for legacy
consoles set con->seq.
The cleaned design should make sure that the value stays and is
set before the console is added to the console list. It also
unifies the sequence number initialization for legacy and nbcon
consoles.
Signed-off-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: John Ogness <john.ogness@linutronix.de>
---
kernel/printk/nbcon.c | 3 ---
kernel/printk/printk.c | 41 +++++++++++++++++++++++++++++------------
2 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 670692dc9b10..776746d20fc0 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -172,9 +172,6 @@ void nbcon_seq_force(struct console *con, u64 seq)
u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb));
atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq));
-
- /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */
- con->seq = 0;
}
/**
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index a47017c932be..20c39505f5aa 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3448,19 +3448,21 @@ static void try_enable_default_console(struct console *newcon)
newcon->flags |= CON_CONSDEV;
}
-static void console_init_seq(struct console *newcon, bool bootcon_registered)
+/* Return the starting sequence number for a newly registered console. */
+static u64 get_init_console_seq(struct console *newcon, bool bootcon_registered)
{
struct console *con;
bool handover;
+ u64 init_seq;
if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
/* Get a consistent copy of @syslog_seq. */
mutex_lock(&syslog_lock);
- newcon->seq = syslog_seq;
+ init_seq = syslog_seq;
mutex_unlock(&syslog_lock);
} else {
/* Begin with next message added to ringbuffer. */
- newcon->seq = prb_next_seq(prb);
+ init_seq = prb_next_seq(prb);
/*
* If any enabled boot consoles are due to be unregistered
@@ -3481,7 +3483,7 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)
* Flush all consoles and set the console to start at
* the next unprinted sequence number.
*/
- if (!console_flush_all(true, &newcon->seq, &handover)) {
+ if (!console_flush_all(true, &init_seq, &handover)) {
/*
* Flushing failed. Just choose the lowest
* sequence of the enabled boot consoles.
@@ -3494,19 +3496,30 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)
if (handover)
console_lock();
- newcon->seq = prb_next_seq(prb);
+ init_seq = prb_next_seq(prb);
for_each_console(con) {
- if ((con->flags & CON_BOOT) &&
- (con->flags & CON_ENABLED) &&
- con->seq < newcon->seq) {
- newcon->seq = con->seq;
+ u64 seq;
+
+ if (!(con->flags & CON_BOOT) ||
+ !(con->flags & CON_ENABLED)) {
+ continue;
}
+
+ if (con->flags & CON_NBCON)
+ seq = nbcon_seq_read(con);
+ else
+ seq = con->seq;
+
+ if (seq < init_seq)
+ init_seq = seq;
}
}
console_unlock();
}
}
+
+ return init_seq;
}
#define console_first() \
@@ -3538,6 +3551,7 @@ void register_console(struct console *newcon)
struct console *con;
bool bootcon_registered = false;
bool realcon_registered = false;
+ u64 init_seq;
int err;
console_list_lock();
@@ -3615,10 +3629,13 @@ void register_console(struct console *newcon)
}
newcon->dropped = 0;
- console_init_seq(newcon, bootcon_registered);
+ init_seq = get_init_console_seq(newcon, bootcon_registered);
- if (newcon->flags & CON_NBCON)
- nbcon_seq_force(newcon, newcon->seq);
+ if (newcon->flags & CON_NBCON) {
+ nbcon_seq_force(newcon, init_seq);
+ } else {
+ newcon->seq = init_seq;
+ }
/*
* Put this console in the list - keep the
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 04/35] printk: Check printk_deferred_enter()/_exit() usage
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (2 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 03/35] printk: Properly deal with nbcon consoles on seq init John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Sebastian Andrzej Siewior
2024-08-20 6:29 ` [PATCH printk v8 05/35] printk: nbcon: Clarify rules of the owner/waiter matching John Ogness
` (31 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Sebastian Andrzej Siewior
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Add validation that printk_deferred_enter()/_exit() are called in
non-migration contexts.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 9 +++++----
kernel/printk/internal.h | 3 +++
kernel/printk/printk_safe.c | 12 ++++++++++++
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index b937cefcb31c..eee8e97da681 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -161,15 +161,16 @@ int _printk(const char *fmt, ...);
*/
__printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
-extern void __printk_safe_enter(void);
-extern void __printk_safe_exit(void);
+extern void __printk_deferred_enter(void);
+extern void __printk_deferred_exit(void);
+
/*
* The printk_deferred_enter/exit macros are available only as a hack for
* some code paths that need to defer all printk console printing. Interrupts
* must be disabled for the deferred duration.
*/
-#define printk_deferred_enter __printk_safe_enter
-#define printk_deferred_exit __printk_safe_exit
+#define printk_deferred_enter() __printk_deferred_enter()
+#define printk_deferred_exit() __printk_deferred_exit()
/*
* Please don't use printk_ratelimit(), because it shares ratelimiting state
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 398ecb40d279..dc8bc0890fd2 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -53,6 +53,9 @@ int vprintk_store(int facility, int level,
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args);
+void __printk_safe_enter(void);
+void __printk_safe_exit(void);
+
bool printk_percpu_data_ready(void);
#define printk_safe_enter_irqsave(flags) \
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 6d10927a07d8..4421ccac3113 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -26,6 +26,18 @@ void __printk_safe_exit(void)
this_cpu_dec(printk_context);
}
+void __printk_deferred_enter(void)
+{
+ cant_migrate();
+ __printk_safe_enter();
+}
+
+void __printk_deferred_exit(void)
+{
+ cant_migrate();
+ __printk_safe_exit();
+}
+
asmlinkage int vprintk(const char *fmt, va_list args)
{
#ifdef CONFIG_KGDB_KDB
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 05/35] printk: nbcon: Clarify rules of the owner/waiter matching
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (3 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 04/35] printk: Check printk_deferred_enter()/_exit() usage John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 06/35] printk: nbcon: Remove return value for write_atomic() John Ogness
` (30 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
The functions nbcon_owner_matches() and nbcon_waiter_matches()
use a minimal set of data to determine if a context matches.
The existing kerneldoc and comments were not clear enough and
caused the printk folks to re-prove that the functions are
indeed reliable in all cases.
Update and expand the explanations so that it is clear that the
implementations are sufficient for all cases.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/nbcon.c | 56 +++++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 776746d20fc0..931b8f086902 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -228,6 +228,13 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
struct nbcon_state new;
do {
+ /*
+ * Panic does not imply that the console is owned. However, it
+ * is critical that non-panic CPUs during panic are unable to
+ * acquire ownership in order to satisfy the assumptions of
+ * nbcon_waiter_matches(). In particular, the assumption that
+ * lower priorities are ignored during panic.
+ */
if (other_cpu_in_panic())
return -EPERM;
@@ -259,18 +266,29 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
/*
* The request context is well defined by the @req_prio because:
*
- * - Only a context with a higher priority can take over the request.
+ * - Only a context with a priority higher than the owner can become
+ * a waiter.
+ * - Only a context with a priority higher than the waiter can
+ * directly take over the request.
* - There are only three priorities.
* - Only one CPU is allowed to request PANIC priority.
* - Lower priorities are ignored during panic() until reboot.
*
* As a result, the following scenario is *not* possible:
*
- * 1. Another context with a higher priority directly takes ownership.
- * 2. The higher priority context releases the ownership.
- * 3. A lower priority context takes the ownership.
- * 4. Another context with the same priority as this context
+ * 1. This context is currently a waiter.
+ * 2. Another context with a higher priority than this context
+ * directly takes ownership.
+ * 3. The higher priority context releases the ownership.
+ * 4. Another lower priority context takes the ownership.
+ * 5. Another context with the same priority as this context
* creates a request and starts waiting.
+ *
+ * Event #1 implies this context is EMERGENCY.
+ * Event #2 implies the new context is PANIC.
+ * Event #3 occurs when panic() has flushed the console.
+ * Events #4 and #5 are not possible due to the other_cpu_in_panic()
+ * check in nbcon_context_try_acquire_direct().
*/
return (cur->req_prio == expected_prio);
@@ -578,11 +596,29 @@ static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu,
int expected_prio)
{
/*
- * Since consoles can only be acquired by higher priorities,
- * owning contexts are uniquely identified by @prio. However,
- * since contexts can unexpectedly lose ownership, it is
- * possible that later another owner appears with the same
- * priority. For this reason @cpu is also needed.
+ * A similar function, nbcon_waiter_matches(), only deals with
+ * EMERGENCY and PANIC priorities. However, this function must also
+ * deal with the NORMAL priority, which requires additional checks
+ * and constraints.
+ *
+ * For the case where preemption and interrupts are disabled, it is
+ * enough to also verify that the owning CPU has not changed.
+ *
+ * For the case where preemption or interrupts are enabled, an
+ * external synchronization method *must* be used. In particular,
+ * the driver-specific locking mechanism used in device_lock()
+ * (including disabling migration) should be used. It prevents
+ * scenarios such as:
+ *
+ * 1. [Task A] owns a context with NBCON_PRIO_NORMAL on [CPU X] and
+ * is scheduled out.
+ * 2. Another context takes over the lock with NBCON_PRIO_EMERGENCY
+ * and releases it.
+ * 3. [Task B] acquires a context with NBCON_PRIO_NORMAL on [CPU X]
+ * and is scheduled out.
+ * 4. [Task A] gets running on [CPU X] and sees that the console is
+ * still owned by a task on [CPU X] with NBON_PRIO_NORMAL. Thus
+ * [Task A] thinks it is the owner when it is not.
*/
if (cur->prio != expected_prio)
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 06/35] printk: nbcon: Remove return value for write_atomic()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (4 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 05/35] printk: nbcon: Clarify rules of the owner/waiter matching John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 07/35] printk: nbcon: Add detailed doc " John Ogness
` (29 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
The return value of write_atomic() does not provide any useful
information. On the contrary, it makes things more complicated
for the caller to appropriately deal with the information.
Change write_atomic() to not have a return value. If the
message did not get printed due to loss of ownership, the
caller will notice this on its own. If ownership was not lost,
it will be assumed that the driver successfully printed the
message and the sequence number for that console will be
incremented.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 2 +-
kernel/printk/nbcon.c | 15 +++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 31a8f5b85f5d..577b157fe4fb 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -345,7 +345,7 @@ struct console {
struct hlist_node node;
/* nbcon console specific members */
- bool (*write_atomic)(struct console *con,
+ void (*write_atomic)(struct console *con,
struct nbcon_write_context *wctxt);
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 931b8f086902..f279f839741a 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -885,7 +885,6 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
unsigned long con_dropped;
struct nbcon_state cur;
unsigned long dropped;
- bool done;
/*
* The printk buffers are filled within an unsafe section. This
@@ -925,16 +924,16 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
wctxt->unsafe_takeover = cur.unsafe_takeover;
if (con->write_atomic) {
- done = con->write_atomic(con, wctxt);
+ con->write_atomic(con, wctxt);
} else {
- nbcon_context_release(ctxt);
+ /*
+ * This function should never be called for legacy consoles.
+ * Handle it as if ownership was lost and try to continue.
+ */
WARN_ON_ONCE(1);
- done = false;
- }
-
- /* If not done, the emit was aborted. */
- if (!done)
+ nbcon_context_release(ctxt);
return false;
+ }
/*
* Since any dropped message was successfully output, reset the
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 07/35] printk: nbcon: Add detailed doc for write_atomic()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (5 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 06/35] printk: nbcon: Remove return value for write_atomic() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 08/35] printk: nbcon: Add callbacks to synchronize with driver John Ogness
` (28 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
The write_atomic() callback has special requirements and is
allowed to use special helper functions. Provide detailed
documentation of the callback so that a developer has a
chance of implementing it correctly.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 577b157fe4fb..35c64ee3827b 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -303,7 +303,7 @@ struct nbcon_write_context {
/**
* struct console - The console descriptor structure
* @name: The name of the console driver
- * @write: Write callback to output messages (Optional)
+ * @write: Legacy write callback to output messages (Optional)
* @read: Read callback for console input (Optional)
* @device: The underlying TTY device driver (Optional)
* @unblank: Callback to unblank the console (Optional)
@@ -320,7 +320,6 @@ struct nbcon_write_context {
* @data: Driver private data
* @node: hlist node for the console list
*
- * @write_atomic: Write callback for atomic context
* @nbcon_state: State for nbcon consoles
* @nbcon_seq: Sequence number of the next record for nbcon to print
* @pbufs: Pointer to nbcon private buffer
@@ -345,8 +344,34 @@ struct console {
struct hlist_node node;
/* nbcon console specific members */
- void (*write_atomic)(struct console *con,
- struct nbcon_write_context *wctxt);
+
+ /**
+ * @write_atomic:
+ *
+ * NBCON callback to write out text in any context. (Optional)
+ *
+ * This callback is called with the console already acquired. However,
+ * a higher priority context is allowed to take it over by default.
+ *
+ * The callback must call nbcon_enter_unsafe() and nbcon_exit_unsafe()
+ * around any code where the takeover is not safe, for example, when
+ * manipulating the serial port registers.
+ *
+ * nbcon_enter_unsafe() will fail if the context has lost the console
+ * ownership in the meantime. In this case, the callback is no longer
+ * allowed to go forward. It must back out immediately and carefully.
+ * The buffer content is also no longer trusted since it no longer
+ * belongs to the context.
+ *
+ * The callback should allow the takeover whenever it is safe. It
+ * increases the chance to see messages when the system is in trouble.
+ *
+ * The callback can be called from any context (including NMI).
+ * Therefore it must avoid usage of any locking and instead rely
+ * on the console ownership for synchronization.
+ */
+ void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
+
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
struct printk_buffers *pbufs;
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 08/35] printk: nbcon: Add callbacks to synchronize with driver
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (6 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 07/35] printk: nbcon: Add detailed doc " John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 09/35] printk: nbcon: Use driver synchronization while (un)registering John Ogness
` (27 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
Console drivers typically must deal with access to the hardware
via user input/output (such as an interactive login shell) and
output of kernel messages via printk() calls. To provide the
necessary synchronization, usually some driver-specific locking
mechanism is used (for example, the port spinlock for uart
serial consoles).
Until now, usage of this driver-specific locking has been hidden
from the printk-subsystem and implemented within the various
console callbacks. However, nbcon consoles would need to use it
even in the generic code.
Add device_lock() and device_unlock() callback which will need
to get implemented by nbcon consoles.
The callbacks will use whatever synchronization mechanism the
driver is using for itself. The minimum requirement is to
prevent CPU migration. It would allow a context friendly
acquiring of nbcon console ownership in non-emergency and
non-panic context.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 43 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/include/linux/console.h b/include/linux/console.h
index 35c64ee3827b..46b3c210b931 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -372,6 +372,49 @@ struct console {
*/
void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
+ /**
+ * @device_lock:
+ *
+ * NBCON callback to begin synchronization with driver code.
+ *
+ * Console drivers typically must deal with access to the hardware
+ * via user input/output (such as an interactive login shell) and
+ * output of kernel messages via printk() calls. This callback is
+ * called by the printk-subsystem whenever it needs to synchronize
+ * with hardware access by the driver. It should be implemented to
+ * use whatever synchronization mechanism the driver is using for
+ * itself (for example, the port lock for uart serial consoles).
+ *
+ * The callback is always called from task context. It may use any
+ * synchronization method required by the driver.
+ *
+ * IMPORTANT: The callback MUST disable migration. The console driver
+ * may be using a synchronization mechanism that already takes
+ * care of this (such as spinlocks). Otherwise this function must
+ * explicitly call migrate_disable().
+ *
+ * The flags argument is provided as a convenience to the driver. It
+ * will be passed again to device_unlock(). It can be ignored if the
+ * driver does not need it.
+ */
+ void (*device_lock)(struct console *con, unsigned long *flags);
+
+ /**
+ * @device_unlock:
+ *
+ * NBCON callback to finish synchronization with driver code.
+ *
+ * It is the counterpart to device_lock().
+ *
+ * This callback is always called from task context. It must
+ * appropriately re-enable migration (depending on how device_lock()
+ * disabled migration).
+ *
+ * The flags argument is the value of the same variable that was
+ * passed to device_lock().
+ */
+ void (*device_unlock)(struct console *con, unsigned long flags);
+
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
struct printk_buffers *pbufs;
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 09/35] printk: nbcon: Use driver synchronization while (un)registering
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (7 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 08/35] printk: nbcon: Add callbacks to synchronize with driver John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 10/35] serial: core: Provide low-level functions to lock port John Ogness
` (26 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Console drivers typically have to deal with access to the
hardware via user input/output (such as an interactive login
shell) and output of kernel messages via printk() calls.
They use some classic driver-specific locking mechanism in most
situations. But console->write_atomic() callbacks, used by nbcon
consoles, are synchronized only by acquiring the console
context.
The synchronization via the console context ownership is possible
only when the console driver is registered. It is when a
particular device driver is connected with a particular console
driver.
The two synchronization mechanisms must be synchronized between
each other. It is tricky because the console context ownership
is quite special. It might be taken over by a higher priority
context. Also CPU migration must be disabled. The most tricky
part is to (dis)connect these two mechanisms during the console
(un)registration.
Use the driver-specific locking callbacks: device_lock(),
device_unlock(). They allow taking the device-specific lock
while the device is being (un)registered by the related console
driver.
For example, these callbacks lock/unlock the port lock for
serial port drivers.
Note that the driver-specific locking is only needed during
(un)register if it is an nbcon console with the write_atomic()
callback implemented. If write_atomic() is not implemented, the
driver should never attempt to access the hardware without
first acquiring its driver-specific lock.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 20c39505f5aa..4cd2c50dd06d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3548,9 +3548,11 @@ static int unregister_console_locked(struct console *console);
*/
void register_console(struct console *newcon)
{
- struct console *con;
+ bool use_device_lock = (newcon->flags & CON_NBCON) && newcon->write_atomic;
bool bootcon_registered = false;
bool realcon_registered = false;
+ struct console *con;
+ unsigned long flags;
u64 init_seq;
int err;
@@ -3637,6 +3639,19 @@ void register_console(struct console *newcon)
newcon->seq = init_seq;
}
+ /*
+ * If another context is actively using the hardware of this new
+ * console, it will not be aware of the nbcon synchronization. This
+ * is a risk that two contexts could access the hardware
+ * simultaneously if this new console is used for atomic printing
+ * and the other context is still using the hardware.
+ *
+ * Use the driver synchronization to ensure that the hardware is not
+ * in use while this new console transitions to being registered.
+ */
+ if (use_device_lock)
+ newcon->device_lock(newcon, &flags);
+
/*
* Put this console in the list - keep the
* preferred driver at the head of the list.
@@ -3661,6 +3676,10 @@ void register_console(struct console *newcon)
* register_console() completes.
*/
+ /* This new console is now registered. */
+ if (use_device_lock)
+ newcon->device_unlock(newcon, flags);
+
console_sysfs_notify();
/*
@@ -3689,6 +3708,8 @@ EXPORT_SYMBOL(register_console);
/* Must be called under console_list_lock(). */
static int unregister_console_locked(struct console *console)
{
+ bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ unsigned long flags;
int res;
lockdep_assert_console_list_lock_held();
@@ -3707,8 +3728,18 @@ static int unregister_console_locked(struct console *console)
if (!console_is_registered_locked(console))
return -ENODEV;
+ /*
+ * Use the driver synchronization to ensure that the hardware is not
+ * in use while this console transitions to being unregistered.
+ */
+ if (use_device_lock)
+ console->device_lock(console, &flags);
+
hlist_del_init_rcu(&console->node);
+ if (use_device_lock)
+ console->device_unlock(console, flags);
+
/*
* <HISTORICAL>
* If this isn't the last console and it has CON_CONSDEV set, we
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 10/35] serial: core: Provide low-level functions to lock port
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (8 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 09/35] printk: nbcon: Use driver synchronization while (un)registering John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons John Ogness
` (25 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman, Jiri Slaby, linux-serial
It will be necessary at times for the uart nbcon console
drivers to acquire the port lock directly (without the
additional nbcon functionality of the port lock wrappers).
These are special cases such as the implementation of the
device_lock()/device_unlock() callbacks or for internal
port lock wrapper synchronization.
Provide low-level variants __uart_port_lock_irqsave() and
__uart_port_unlock_irqrestore() for this purpose.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/serial_core.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index aea25eef9a1a..8872cd21e70a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -590,6 +590,24 @@ struct uart_port {
void *private_data; /* generic platform data pointer */
};
+/*
+ * Only for console->device_lock()/_unlock() callbacks and internal
+ * port lock wrapper synchronization.
+ */
+static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
+{
+ spin_lock_irqsave(&up->lock, *flags);
+}
+
+/*
+ * Only for console->device_lock()/_unlock() callbacks and internal
+ * port lock wrapper synchronization.
+ */
+static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
+{
+ spin_unlock_irqrestore(&up->lock, flags);
+}
+
/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (9 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 10/35] serial: core: Provide low-level functions to lock port John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-08-20 11:12 ` Ilpo Järvinen
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 12/35] console: Improve console_srcu_read_flags() comments John Ogness
` (24 subsequent siblings)
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman, Jiri Slaby, Russell King, Tony Lindgren,
Andy Shevchenko, Geert Uytterhoeven, Arnd Bergmann,
Uwe Kleine-König, Théo Lebrun, Linus Walleij,
Lino Sanfilippo, Ilpo Järvinen, Konrad Dybcio,
Sebastian Andrzej Siewior, linux-serial
Introduce uart_port_set_cons() as a wrapper to set @cons of a
uart_port. The wrapper sets @cons under the port lock in order
to prevent @cons from disappearing while another context is
holding the port lock. This is necessary for a follow-up
commit relating to the port lock wrappers, which rely on @cons
not changing between lock and unlock.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Tested-by: Théo Lebrun <theo.lebrun@bootlin.com> # EyeQ5, AMBA-PL011
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
drivers/tty/serial/8250/8250_core.c | 6 +++---
drivers/tty/serial/amba-pl011.c | 2 +-
drivers/tty/serial/serial_core.c | 16 ++++++++--------
include/linux/serial_core.h | 17 +++++++++++++++++
4 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 29e4b83e0376..5f9f06911795 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -423,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
port = &serial8250_ports[co->index].port;
/* link port to console */
- port->cons = co;
+ uart_port_set_cons(port, co);
retval = serial8250_console_setup(port, options, false);
if (retval != 0)
- port->cons = NULL;
+ uart_port_set_cons(port, NULL);
return retval;
}
@@ -485,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return serial8250_console_setup(port, options, true);
}
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8b1644f5411e..7d0134ecd82f 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2480,7 +2480,7 @@ static int pl011_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return pl011_console_setup(co, options);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9a18d0b95a41..61c7e1268957 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3168,8 +3168,15 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->uart_port = uport;
uport->state = state;
+ /*
+ * If this port is in use as a console then the spinlock is already
+ * initialised.
+ */
+ if (!uart_console_registered(uport))
+ uart_port_spin_lock_init(uport);
+
state->pm_state = UART_PM_STATE_UNDEFINED;
- uport->cons = drv->cons;
+ uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
drv->tty_driver->name_base + uport->line);
@@ -3178,13 +3185,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
goto out;
}
- /*
- * If this port is in use as a console then the spinlock is already
- * initialised.
- */
- if (!uart_console_registered(uport))
- uart_port_spin_lock_init(uport);
-
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 8872cd21e70a..2cf03ff2056a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -608,6 +608,23 @@ static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned
spin_unlock_irqrestore(&up->lock, flags);
}
+/**
+ * uart_port_set_cons - Safely set the @cons field for a uart
+ * @up: The uart port to set
+ * @con: The new console to set to
+ *
+ * This function must be used to set @up->cons. It uses the port lock to
+ * synchronize with the port lock wrappers in order to ensure that the console
+ * cannot change or disappear while another context is holding the port lock.
+ */
+static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
+{
+ unsigned long flags;
+
+ __uart_port_lock_irqsave(up, &flags);
+ up->cons = con;
+ __uart_port_unlock_irqrestore(up, flags);
+}
/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 12/35] console: Improve console_srcu_read_flags() comments
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (10 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 13/35] nbcon: Add API to acquire context for non-printing operations John Ogness
` (23 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
It was not clear when exactly console_srcu_read_flags() must be
used vs. directly reading @console->flags.
Refactor and clarify that console_srcu_read_flags() is only
needed if the console is registered or the caller is in a
context where the registration status of the console may change
(due to another context).
The function requires the caller holds @console_srcu, which will
ensure that the caller sees an appropriate @flags value for the
registered console and that exit/cleanup routines will not run
if the console is in the process of unregistration.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 46b3c210b931..aafe3121b74e 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -446,28 +446,34 @@ extern void console_list_unlock(void) __releases(console_mutex);
extern struct hlist_head console_list;
/**
- * console_srcu_read_flags - Locklessly read the console flags
+ * console_srcu_read_flags - Locklessly read flags of a possibly registered
+ * console
* @con: struct console pointer of console to read flags from
*
- * This function provides the necessary READ_ONCE() and data_race()
- * notation for locklessly reading the console flags. The READ_ONCE()
- * in this function matches the WRITE_ONCE() when @flags are modified
- * for registered consoles with console_srcu_write_flags().
+ * Locklessly reading @con->flags provides a consistent read value because
+ * there is at most one CPU modifying @con->flags and that CPU is using only
+ * read-modify-write operations to do so.
*
- * Only use this function to read console flags when locklessly
- * iterating the console list via srcu.
+ * Requires console_srcu_read_lock to be held, which implies that @con might
+ * be a registered console. The purpose of holding console_srcu_read_lock is
+ * to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
+ * and that no exit/cleanup routines will run if the console is currently
+ * undergoing unregistration.
+ *
+ * If the caller is holding the console_list_lock or it is _certain_ that
+ * @con is not and will not become registered, the caller may read
+ * @con->flags directly instead.
*
* Context: Any context.
+ * Return: The current value of the @con->flags field.
*/
static inline short console_srcu_read_flags(const struct console *con)
{
WARN_ON_ONCE(!console_srcu_read_lock_is_held());
/*
- * Locklessly reading console->flags provides a consistent
- * read value because there is at most one CPU modifying
- * console->flags and that CPU is using only read-modify-write
- * operations to do so.
+ * The READ_ONCE() matches the WRITE_ONCE() when @flags are modified
+ * for registered consoles with console_srcu_write_flags().
*/
return data_race(READ_ONCE(con->flags));
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 13/35] nbcon: Add API to acquire context for non-printing operations
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (11 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 12/35] console: Improve console_srcu_read_flags() comments John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 14/35] serial: core: Acquire nbcon context in port->lock wrapper John Ogness
` (22 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
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>
---
include/linux/console.h | 2 ++
include/linux/printk.h | 14 ++++++++++
kernel/printk/nbcon.c | 58 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index aafe3121b74e..3706f944de46 100644
--- 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;
};
diff --git a/include/linux/printk.h b/include/linux/printk.h
index eee8e97da681..9687089f5ace 100644
--- 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(const char *log_lvl) __cold;
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(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
bool this_cpu_in_panic(void);
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index f279f839741a..61f0ae6a4809 100644
--- 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_pbufs;
* 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_pbufs;
* 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);
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 14/35] serial: core: Acquire nbcon context in port->lock wrapper
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (12 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 13/35] nbcon: Add API to acquire context for non-printing operations John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 15/35] printk: nbcon: Do not rely on proxy headers John Ogness
` (21 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman, Jiri Slaby, linux-serial
Currently the port->lock wrappers uart_port_lock(),
uart_port_unlock() (and their variants) only lock/unlock
the spin_lock.
If the port is an nbcon console that has implemented the
write_atomic() callback, the wrappers must also acquire/release
the console context and mark the region as unsafe. This allows
general port->lock synchronization to be synchronized against
the nbcon write_atomic() callback.
Note that __uart_port_using_nbcon() relies on the port->lock
being held while a console is added and removed from the
console list (i.e. all uart nbcon drivers *must* take the
port->lock in their device_lock() callbacks).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/serial_core.h | 82 ++++++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 2 deletions(-)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 2cf03ff2056a..4ab65874a850 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -11,6 +11,8 @@
#include <linux/compiler.h>
#include <linux/console.h>
#include <linux/interrupt.h>
+#include <linux/lockdep.h>
+#include <linux/printk.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -625,6 +627,60 @@ static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
up->cons = con;
__uart_port_unlock_irqrestore(up, flags);
}
+
+/* Only for internal port lock wrapper usage. */
+static inline bool __uart_port_using_nbcon(struct uart_port *up)
+{
+ lockdep_assert_held_once(&up->lock);
+
+ if (likely(!uart_console(up)))
+ return false;
+
+ /*
+ * @up->cons is only modified under the port lock. Therefore it is
+ * certain that it cannot disappear here.
+ *
+ * @up->cons->node is added/removed from the console list under the
+ * port lock. Therefore it is certain that the registration status
+ * cannot change here, thus @up->cons->flags can be read directly.
+ */
+ if (hlist_unhashed_lockless(&up->cons->node) ||
+ !(up->cons->flags & CON_NBCON) ||
+ !up->cons->write_atomic) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline bool __uart_port_nbcon_try_acquire(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return true;
+
+ return nbcon_device_try_acquire(up->cons);
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline void __uart_port_nbcon_acquire(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return;
+
+ while (!nbcon_device_try_acquire(up->cons))
+ cpu_relax();
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline void __uart_port_nbcon_release(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return;
+
+ nbcon_device_release(up->cons);
+}
+
/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
@@ -632,6 +688,7 @@ static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
static inline void uart_port_lock(struct uart_port *up)
{
spin_lock(&up->lock);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -641,6 +698,7 @@ static inline void uart_port_lock(struct uart_port *up)
static inline void uart_port_lock_irq(struct uart_port *up)
{
spin_lock_irq(&up->lock);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -651,6 +709,7 @@ static inline void uart_port_lock_irq(struct uart_port *up)
static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
{
spin_lock_irqsave(&up->lock, *flags);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -661,7 +720,15 @@ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *f
*/
static inline bool uart_port_trylock(struct uart_port *up)
{
- return spin_trylock(&up->lock);
+ if (!spin_trylock(&up->lock))
+ return false;
+
+ if (!__uart_port_nbcon_try_acquire(up)) {
+ spin_unlock(&up->lock);
+ return false;
+ }
+
+ return true;
}
/**
@@ -673,7 +740,15 @@ static inline bool uart_port_trylock(struct uart_port *up)
*/
static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags)
{
- return spin_trylock_irqsave(&up->lock, *flags);
+ if (!spin_trylock_irqsave(&up->lock, *flags))
+ return false;
+
+ if (!__uart_port_nbcon_try_acquire(up)) {
+ spin_unlock_irqrestore(&up->lock, *flags);
+ return false;
+ }
+
+ return true;
}
/**
@@ -682,6 +757,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
*/
static inline void uart_port_unlock(struct uart_port *up)
{
+ __uart_port_nbcon_release(up);
spin_unlock(&up->lock);
}
@@ -691,6 +767,7 @@ static inline void uart_port_unlock(struct uart_port *up)
*/
static inline void uart_port_unlock_irq(struct uart_port *up)
{
+ __uart_port_nbcon_release(up);
spin_unlock_irq(&up->lock);
}
@@ -701,6 +778,7 @@ static inline void uart_port_unlock_irq(struct uart_port *up)
*/
static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
{
+ __uart_port_nbcon_release(up);
spin_unlock_irqrestore(&up->lock, flags);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 15/35] printk: nbcon: Do not rely on proxy headers
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (13 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 14/35] serial: core: Acquire nbcon context in port->lock wrapper John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 16/35] printk: Make console_is_usable() available to nbcon.c John Ogness
` (20 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andy Shevchenko
The headers kernel.h, serial_core.h, and console.h allow for the
definitions of many types and functions from other headers.
Rather than relying on these as proxy headers, explicitly
include all headers providing needed definitions. Also sort the
list alphabetically to be able to easily detect duplicates.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 8 ++++++--
kernel/printk/nbcon.c | 13 ++++++++++++-
kernel/printk/printk_ringbuffer.h | 2 ++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index dc8bc0890fd2..ccb916688178 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -2,11 +2,12 @@
/*
* internal.h - printk internal definitions
*/
-#include <linux/percpu.h>
#include <linux/console.h>
-#include "printk_ringbuffer.h"
+#include <linux/percpu.h>
+#include <linux/types.h>
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
+struct ctl_table;
void __init printk_sysctl_init(void);
int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos);
@@ -43,6 +44,9 @@ enum printk_info_flags {
LOG_CONT = 8, /* text is a fragment of a continuation line */
};
+struct printk_ringbuffer;
+struct dev_printk_info;
+
extern struct printk_ringbuffer *prb;
__printf(4, 0)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 61f0ae6a4809..e8ddcb6f7053 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -2,13 +2,24 @@
// Copyright (C) 2022 Linutronix GmbH, John Ogness
// Copyright (C) 2022 Intel, Thomas Gleixner
-#include <linux/kernel.h>
+#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/console.h>
#include <linux/delay.h>
+#include <linux/errno.h>
#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/minmax.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/types.h>
#include "internal.h"
+#include "printk_ringbuffer.h"
/*
* Printk console printing implementation for consoles which does not depend
* on the legacy style console_lock mechanism.
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 52626d0f1fa3..bd2a892deac1 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -5,6 +5,8 @@
#include <linux/atomic.h>
#include <linux/dev_printk.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
/*
* Meta information about each stored message.
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 16/35] printk: Make console_is_usable() available to nbcon.c
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (14 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 15/35] printk: nbcon: Do not rely on proxy headers John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 17/35] printk: Let console_is_usable() handle nbcon John Ogness
` (19 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Move console_is_usable() as-is into internal.h so that it can
be used by nbcon printing functions as well.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 32 ++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 30 ------------------------------
2 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index ccb916688178..5d9deb56b582 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -84,6 +84,36 @@ void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
+/*
+ * Check if the given console is currently capable and allowed to print
+ * records.
+ *
+ * Requires the console_srcu_read_lock.
+ */
+static inline bool console_is_usable(struct console *con)
+{
+ short flags = console_srcu_read_flags(con);
+
+ if (!(flags & CON_ENABLED))
+ return false;
+
+ if ((flags & CON_SUSPENDED))
+ return false;
+
+ if (!con->write)
+ return false;
+
+ /*
+ * Console drivers may assume that per-cpu resources have been
+ * allocated. So unless they're explicitly marked as being able to
+ * cope (CON_ANYTIME) don't call them until this CPU is officially up.
+ */
+ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
+ return false;
+
+ return true;
+}
+
#else
#define PRINTK_PREFIX_MAX 0
@@ -104,6 +134,8 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
+static inline bool console_is_usable(struct console *con) { return false; }
+
#endif /* CONFIG_PRINTK */
extern struct printk_buffers printk_shared_pbufs;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 4cd2c50dd06d..b9c8fff9a493 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2767,36 +2767,6 @@ int is_console_locked(void)
}
EXPORT_SYMBOL(is_console_locked);
-/*
- * Check if the given console is currently capable and allowed to print
- * records.
- *
- * Requires the console_srcu_read_lock.
- */
-static inline bool console_is_usable(struct console *con)
-{
- short flags = console_srcu_read_flags(con);
-
- if (!(flags & CON_ENABLED))
- return false;
-
- if ((flags & CON_SUSPENDED))
- return false;
-
- if (!con->write)
- return false;
-
- /*
- * Console drivers may assume that per-cpu resources have been
- * allocated. So unless they're explicitly marked as being able to
- * cope (CON_ANYTIME) don't call them until this CPU is officially up.
- */
- if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
- return false;
-
- return true;
-}
-
static void __console_unlock(void)
{
console_locked = 0;
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 17/35] printk: Let console_is_usable() handle nbcon
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (15 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 16/35] printk: Make console_is_usable() available to nbcon.c John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 18/35] printk: Add @flags argument for console_is_usable() John Ogness
` (18 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
The nbcon consoles use a different printing callback. For nbcon
consoles, check for the write_atomic() callback instead of
write().
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 5d9deb56b582..448a5fcd5228 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -86,6 +86,8 @@ void nbcon_free(struct console *con);
/*
* Check if the given console is currently capable and allowed to print
+ * records. Note that this function does not consider the current context,
+ * which can also play a role in deciding if @con can be used to print
* records.
*
* Requires the console_srcu_read_lock.
@@ -100,8 +102,13 @@ static inline bool console_is_usable(struct console *con)
if ((flags & CON_SUSPENDED))
return false;
- if (!con->write)
- return false;
+ if (flags & CON_NBCON) {
+ if (!con->write_atomic)
+ return false;
+ } else {
+ if (!con->write)
+ return false;
+ }
/*
* Console drivers may assume that per-cpu resources have been
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 18/35] printk: Add @flags argument for console_is_usable()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (16 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 17/35] printk: Let console_is_usable() handle nbcon John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 19/35] printk: nbcon: Add helper to assign priority based on CPU state John Ogness
` (17 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
The caller of console_is_usable() usually needs @console->flags
for its own checks. Rather than having console_is_usable() read
its own copy, make the caller pass in the @flags. This also
ensures that the caller saw the same @flags value.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 8 ++------
kernel/printk/printk.c | 5 +++--
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 448a5fcd5228..fe8d84d78f1c 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -89,13 +89,9 @@ void nbcon_free(struct console *con);
* records. Note that this function does not consider the current context,
* which can also play a role in deciding if @con can be used to print
* records.
- *
- * Requires the console_srcu_read_lock.
*/
-static inline bool console_is_usable(struct console *con)
+static inline bool console_is_usable(struct console *con, short flags)
{
- short flags = console_srcu_read_flags(con);
-
if (!(flags & CON_ENABLED))
return false;
@@ -141,7 +137,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
-static inline bool console_is_usable(struct console *con) { return false; }
+static inline bool console_is_usable(struct console *con, short flags) { return false; }
#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b9c8fff9a493..ffb56c2150b0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3012,9 +3012,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
+ short flags = console_srcu_read_flags(con);
bool progress;
- if (!console_is_usable(con))
+ if (!console_is_usable(con, flags))
continue;
any_usable = true;
@@ -3925,7 +3926,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
* that they make forward progress, so only increment
* @diff for usable consoles.
*/
- if (!console_is_usable(c))
+ if (!console_is_usable(c, flags))
continue;
if (flags & CON_NBCON) {
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 19/35] printk: nbcon: Add helper to assign priority based on CPU state
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (17 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 18/35] printk: Add @flags argument for console_is_usable() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 20/35] printk: nbcon: Provide function to flush using write_atomic() John Ogness
` (16 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Add a helper function to use the current state of the CPU to
determine which priority to assign to the printing context.
The EMERGENCY priority handling is added in a follow-up commit.
It will use a per-CPU variable.
Note: nbcon_device_try_acquire(), which is used by console
drivers to acquire the nbcon console for non-printing
activities, is hard-coded to always use NORMAL priority.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/nbcon.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index fe8d84d78f1c..72f229382cfa 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -83,6 +83,7 @@ u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
+enum nbcon_prio nbcon_get_default_prio(void);
/*
* Check if the given console is currently capable and allowed to print
@@ -136,6 +137,7 @@ static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
+static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index e8ddcb6f7053..c6a9aa9f62f6 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -973,6 +973,25 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
return nbcon_context_exit_unsafe(ctxt);
}
+/**
+ * nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
+ * printing on the current CPU
+ *
+ * Context: Any context.
+ * Return: The nbcon_prio to use for acquiring an nbcon console in this
+ * context for printing.
+ *
+ * The function is safe for reading per-CPU data in any context because
+ * preemption is disabled if the current CPU is in the panic state.
+ */
+enum nbcon_prio nbcon_get_default_prio(void)
+{
+ if (this_cpu_in_panic())
+ return NBCON_PRIO_PANIC;
+
+ return NBCON_PRIO_NORMAL;
+}
+
/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 20/35] printk: nbcon: Provide function to flush using write_atomic()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (18 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 19/35] printk: nbcon: Add helper to assign priority based on CPU state John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 21/35] printk: Track registered boot consoles John Ogness
` (15 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
From: Thomas Gleixner <tglx@linutronix.de>
Provide nbcon_atomic_flush_pending() to perform flushing of all
registered nbcon consoles using their write_atomic() callback.
Unlike console_flush_all(), nbcon_atomic_flush_pending() will
only flush up through the newest record at the time of the
call. This prevents a CPU from printing unbounded when other
CPUs are adding records. If new records are added while
flushing, it is expected that the dedicated printer threads
will print those records. If the printer thread is not
available (which is always the case at this point in the
rework), nbcon_atomic_flush_pending() _will_ flush all records
in the ringbuffer.
Unlike console_flush_all(), nbcon_atomic_flush_pending() will
fully flush one console before flushing the next. This helps to
guarantee that a block of pending records (such as a stack
trace in an emergency situation) can be printed atomically at
once before releasing console ownership.
nbcon_atomic_flush_pending() is safe in any context because it
uses write_atomic() and acquires with unsafe_takeover disabled.
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>
---
kernel/printk/internal.h | 2 +
kernel/printk/nbcon.c | 151 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 152 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 72f229382cfa..0dc9b92b5dd0 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -84,6 +84,7 @@ void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
enum nbcon_prio nbcon_get_default_prio(void);
+void nbcon_atomic_flush_pending(void);
/*
* Check if the given console is currently capable and allowed to print
@@ -138,6 +139,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
+static inline void nbcon_atomic_flush_pending(void) { }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index c6a9aa9f62f6..3982d68979d6 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -886,7 +886,6 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
* When true is returned, @wctxt->ctxt.backlog indicates whether there are
* still records pending in the ringbuffer,
*/
-__maybe_unused
static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
@@ -992,6 +991,156 @@ enum nbcon_prio nbcon_get_default_prio(void)
return NBCON_PRIO_NORMAL;
}
+/*
+ * __nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
+ * write_atomic() callback
+ * @con: The nbcon console to flush
+ * @stop_seq: Flush up until this record
+ *
+ * Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on
+ * failure.
+ *
+ * Errors:
+ *
+ * -EPERM: Unable to acquire console ownership.
+ *
+ * -EAGAIN: Another context took over ownership while printing.
+ *
+ * -ENOENT: A record before @stop_seq is not available.
+ *
+ * If flushing up to @stop_seq was not successful, it only makes sense for the
+ * caller to try again when -EAGAIN was returned. When -EPERM is returned,
+ * this context is not allowed to acquire the console. When -ENOENT is
+ * returned, it cannot be expected that the unfinalized record will become
+ * available.
+ */
+static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+{
+ struct nbcon_write_context wctxt = { };
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
+ int err = 0;
+
+ ctxt->console = con;
+ ctxt->spinwait_max_us = 2000;
+ ctxt->prio = nbcon_get_default_prio();
+
+ if (!nbcon_context_try_acquire(ctxt))
+ return -EPERM;
+
+ while (nbcon_seq_read(con) < stop_seq) {
+ /*
+ * nbcon_emit_next_record() returns false when the console was
+ * handed over or taken over. In both cases the context is no
+ * longer valid.
+ */
+ if (!nbcon_emit_next_record(&wctxt))
+ return -EAGAIN;
+
+ if (!ctxt->backlog) {
+ /* Are there reserved but not yet finalized records? */
+ if (nbcon_seq_read(con) < stop_seq)
+ err = -ENOENT;
+ break;
+ }
+ }
+
+ nbcon_context_release(ctxt);
+ return err;
+}
+
+/**
+ * nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
+ * write_atomic() callback
+ * @con: The nbcon console to flush
+ * @stop_seq: Flush up until this record
+ *
+ * This will stop flushing before @stop_seq if another context has ownership.
+ * That context is then responsible for the flushing. Likewise, if new records
+ * are added while this context was flushing and there is no other context
+ * to handle the printing, this context must also flush those records.
+ */
+static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+{
+ unsigned long flags;
+ int err;
+
+again:
+ /*
+ * Atomic flushing does not use console driver synchronization (i.e.
+ * it does not hold the port lock for uart consoles). Therefore IRQs
+ * must be disabled to avoid being interrupted and then calling into
+ * a driver that will deadlock trying to acquire console ownership.
+ */
+ local_irq_save(flags);
+
+ err = __nbcon_atomic_flush_pending_con(con, stop_seq);
+
+ local_irq_restore(flags);
+
+ /*
+ * If there was a new owner (-EPERM, -EAGAIN), that context is
+ * responsible for completing.
+ *
+ * Do not wait for records not yet finalized (-ENOENT) to avoid a
+ * possible deadlock. They will either get flushed by the writer or
+ * eventually skipped on panic CPU.
+ */
+ if (err)
+ return;
+
+ /*
+ * If flushing was successful but more records are available, this
+ * context must flush those remaining records because there is no
+ * other context that will do it.
+ */
+ if (prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
+ stop_seq = prb_next_reserve_seq(prb);
+ goto again;
+ }
+}
+
+/**
+ * __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
+ * write_atomic() callback
+ * @stop_seq: Flush up until this record
+ */
+static void __nbcon_atomic_flush_pending(u64 stop_seq)
+{
+ struct console *con;
+ int cookie;
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(con) {
+ short flags = console_srcu_read_flags(con);
+
+ if (!(flags & CON_NBCON))
+ continue;
+
+ if (!console_is_usable(con, flags))
+ continue;
+
+ if (nbcon_seq_read(con) >= stop_seq)
+ continue;
+
+ nbcon_atomic_flush_pending_con(con, stop_seq);
+ }
+ console_srcu_read_unlock(cookie);
+}
+
+/**
+ * nbcon_atomic_flush_pending - Flush all nbcon consoles using their
+ * write_atomic() callback
+ *
+ * Flush the backlog up through the currently newest record. Any new
+ * records added while flushing will not be flushed if there is another
+ * context available to handle the flushing. This is to avoid one CPU
+ * printing unbounded because other CPUs continue to add records.
+ */
+void nbcon_atomic_flush_pending(void)
+{
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+}
+
/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 21/35] printk: Track registered boot consoles
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (19 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 20/35] printk: nbcon: Provide function to flush using write_atomic() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 22/35] printk: nbcon: Use nbcon consoles in console_flush_all() John Ogness
` (14 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Unfortunately it is not known if a boot console and a regular
(legacy or nbcon) console use the same hardware. For this reason
they must not be allowed to print simultaneously.
For legacy consoles this is not an issue because they are
already synchronized with the boot consoles using the console
lock. However nbcon consoles can be triggered separately.
Add a global flag @have_boot_console to identify if any boot
consoles are registered. This will be used in follow-up commits
to ensure that boot consoles and nbcon consoles cannot print
simultaneously.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index ffb56c2150b0..b8634a153d1d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -463,6 +463,14 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
static DEFINE_MUTEX(syslog_lock);
+/*
+ * Specifies if a boot console is registered. If boot consoles are present,
+ * nbcon consoles cannot print simultaneously and must be synchronized by
+ * the console lock. This is because boot consoles and nbcon consoles may
+ * have mapped the same hardware.
+ */
+static bool have_boot_console;
+
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -3610,6 +3618,9 @@ void register_console(struct console *newcon)
newcon->seq = init_seq;
}
+ if (newcon->flags & CON_BOOT)
+ have_boot_console = true;
+
/*
* If another context is actively using the hardware of this new
* console, it will not be aware of the nbcon synchronization. This
@@ -3680,7 +3691,9 @@ EXPORT_SYMBOL(register_console);
static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ bool found_boot_con = false;
unsigned long flags;
+ struct console *c;
int res;
lockdep_assert_console_list_lock_held();
@@ -3738,6 +3751,17 @@ static int unregister_console_locked(struct console *console)
if (console->exit)
res = console->exit(console);
+ /*
+ * With this console gone, the global flags tracking registered
+ * console types may have changed. Update them.
+ */
+ for_each_console(c) {
+ if (c->flags & CON_BOOT)
+ found_boot_con = true;
+ }
+ if (!found_boot_con)
+ have_boot_console = found_boot_con;
+
return res;
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 22/35] printk: nbcon: Use nbcon consoles in console_flush_all()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (20 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 21/35] printk: Track registered boot consoles John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 23/35] printk: Add is_printk_legacy_deferred() John Ogness
` (13 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Allow nbcon consoles to print messages in the legacy printk()
caller context (printing via unlock) by integrating them into
console_flush_all(). The write_atomic() callback is used for
printing.
Provide nbcon_legacy_emit_next_record(), which acts as the
nbcon variant of console_emit_next_record(). Call this variant
within console_flush_all() for nbcon consoles. Since nbcon
consoles use their own @nbcon_seq variable to track the next
record to print, this also must be appropriately handled in
console_flush_all().
Note that the legacy printing logic uses @handover to detect
handovers for printing all consoles. For nbcon consoles,
handovers/takeovers occur on a per-console basis and thus do
not cause the console_flush_all() loop to abort.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 6 +++
kernel/printk/nbcon.c | 87 ++++++++++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 17 +++++---
3 files changed, 105 insertions(+), 5 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 0dc9b92b5dd0..44468f3828f3 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -78,6 +78,8 @@ void defer_console_output(void);
u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags);
+void console_lock_spinning_enable(void);
+int console_lock_spinning_disable_and_check(int cookie);
u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
@@ -85,6 +87,8 @@ bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
enum nbcon_prio nbcon_get_default_prio(void);
void nbcon_atomic_flush_pending(void);
+bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie);
/*
* Check if the given console is currently capable and allowed to print
@@ -140,6 +144,8 @@ static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
static inline void nbcon_atomic_flush_pending(void) { }
+static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie) { return false; }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3982d68979d6..d09c084c9af4 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -992,6 +992,93 @@ enum nbcon_prio nbcon_get_default_prio(void)
}
/*
+ * nbcon_atomic_emit_one - Print one record for an nbcon console using the
+ * write_atomic() callback
+ * @wctxt: An initialized write context struct to use for this context
+ *
+ * Return: True, when a record has been printed and there are still
+ * pending records. The caller might want to continue flushing.
+ *
+ * False, when there is no pending record, or when the console
+ * context cannot be acquired, or the ownership has been lost.
+ * The caller should give up. Either the job is done, cannot be
+ * done, or will be handled by the owning context.
+ *
+ * This is an internal helper to handle the locking of the console before
+ * calling nbcon_emit_next_record().
+ */
+static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+
+ if (!nbcon_context_try_acquire(ctxt))
+ return false;
+
+ /*
+ * nbcon_emit_next_record() returns false when the console was
+ * handed over or taken over. In both cases the context is no
+ * longer valid.
+ *
+ * The higher priority printing context takes over responsibility
+ * to print the pending records.
+ */
+ if (!nbcon_emit_next_record(wctxt))
+ return false;
+
+ nbcon_context_release(ctxt);
+
+ return ctxt->backlog;
+}
+
+/**
+ * nbcon_legacy_emit_next_record - Print one record for an nbcon console
+ * in legacy contexts
+ * @con: The console to print on
+ * @handover: Will be set to true if a printk waiter has taken over the
+ * console_lock, in which case the caller is no longer holding
+ * both the console_lock and the SRCU read lock. Otherwise it
+ * is set to false.
+ * @cookie: The cookie from the SRCU read lock.
+ *
+ * Context: Any context except NMI.
+ * Return: True, when a record has been printed and there are still
+ * pending records. The caller might want to continue flushing.
+ *
+ * False, when there is no pending record, or when the console
+ * context cannot be acquired, or the ownership has been lost.
+ * The caller should give up. Either the job is done, cannot be
+ * done, or will be handled by the owning context.
+ *
+ * This function is meant to be called by console_flush_all() to print records
+ * on nbcon consoles from legacy context (printing via console unlocking).
+ * Essentially it is the nbcon version of console_emit_next_record().
+ */
+bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie)
+{
+ struct nbcon_write_context wctxt = { };
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
+ unsigned long flags;
+ bool progress;
+
+ /* Use the same procedure as console_emit_next_record(). */
+ printk_safe_enter_irqsave(flags);
+ console_lock_spinning_enable();
+ stop_critical_timings();
+
+ ctxt->console = con;
+ ctxt->prio = nbcon_get_default_prio();
+
+ progress = nbcon_atomic_emit_one(&wctxt);
+
+ start_critical_timings();
+ *handover = console_lock_spinning_disable_and_check(cookie);
+ printk_safe_exit_irqrestore(flags);
+
+ return progress;
+}
+
+/**
* __nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
* write_atomic() callback
* @con: The nbcon console to flush
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b8634a153d1d..f08bf5e82fc7 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1860,7 +1860,7 @@ static bool console_waiter;
* there may be a waiter spinning (like a spinlock). Also it must be
* ready to hand over the lock at the end of the section.
*/
-static void console_lock_spinning_enable(void)
+void console_lock_spinning_enable(void)
{
/*
* Do not use spinning in panic(). The panic CPU wants to keep the lock.
@@ -1899,7 +1899,7 @@ static void console_lock_spinning_enable(void)
*
* Return: 1 if the lock rights were passed, 0 otherwise.
*/
-static int console_lock_spinning_disable_and_check(int cookie)
+int console_lock_spinning_disable_and_check(int cookie)
{
int waiter;
@@ -3021,13 +3021,20 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
short flags = console_srcu_read_flags(con);
+ u64 printk_seq;
bool progress;
if (!console_is_usable(con, flags))
continue;
any_usable = true;
- progress = console_emit_next_record(con, handover, cookie);
+ if (flags & CON_NBCON) {
+ progress = nbcon_legacy_emit_next_record(con, handover, cookie);
+ printk_seq = nbcon_seq_read(con);
+ } else {
+ progress = console_emit_next_record(con, handover, cookie);
+ printk_seq = con->seq;
+ }
/*
* If a handover has occurred, the SRCU read lock
@@ -3037,8 +3044,8 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
return false;
/* Track the next of the highest seq flushed. */
- if (con->seq > *next_seq)
- *next_seq = con->seq;
+ if (printk_seq > *next_seq)
+ *next_seq = printk_seq;
if (!progress)
continue;
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 23/35] printk: Add is_printk_legacy_deferred()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (21 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 22/35] printk: nbcon: Use nbcon consoles in console_flush_all() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 24/35] printk: nbcon: Flush new records on device_release() John Ogness
` (12 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
If printk has been explicitly deferred or is called from NMI
context, legacy console printing must be deferred to an irq_work
context. Introduce a helper function is_printk_legacy_deferred()
for a CPU to query if it must defer legacy console printing.
In follow-up commits this helper will be needed at other call
sites as well.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/printk_safe.c | 11 ++++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 44468f3828f3..84706c1c934b 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -75,6 +75,7 @@ bool printk_percpu_data_ready(void);
} while (0)
void defer_console_output(void);
+bool is_printk_legacy_deferred(void);
u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags);
@@ -138,6 +139,7 @@ static inline bool console_is_usable(struct console *con, short flags)
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
static inline bool printk_percpu_data_ready(void) { return false; }
+static inline bool is_printk_legacy_deferred(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 4421ccac3113..86439fd20aab 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -38,6 +38,15 @@ void __printk_deferred_exit(void)
__printk_safe_exit();
}
+bool is_printk_legacy_deferred(void)
+{
+ /*
+ * The per-CPU variable @printk_context can be read safely in any
+ * context. CPU migration is always disabled when set.
+ */
+ return (this_cpu_read(printk_context) || in_nmi());
+}
+
asmlinkage int vprintk(const char *fmt, va_list args)
{
#ifdef CONFIG_KGDB_KDB
@@ -50,7 +59,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
* Use the main logbuf even in NMI. But avoid calling console
* drivers that might have their own locks.
*/
- if (this_cpu_read(printk_context) || in_nmi())
+ if (is_printk_legacy_deferred())
return vprintk_deferred(fmt, args);
/* No obstacles. */
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 24/35] printk: nbcon: Flush new records on device_release()
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (22 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 23/35] printk: Add is_printk_legacy_deferred() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 25/35] printk: Flush nbcon consoles first on panic John Ogness
` (11 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
There may be new records that were added while a driver was
holding the nbcon context for non-printing purposes. These
new records must be flushed by the nbcon_device_release()
context because no other context will do it.
If boot consoles are registered, the legacy loop is used
(either direct or per irq_work) to handle the flushing.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/nbcon.c | 20 ++++++++++++++++++++
kernel/printk/printk.c | 2 +-
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 84706c1c934b..7679e18f24b3 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -153,6 +153,8 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
+extern bool have_boot_console;
+
extern struct printk_buffers printk_shared_pbufs;
/**
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index d09c084c9af4..269aeed18064 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1326,10 +1326,30 @@ EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
void nbcon_device_release(struct console *con)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
+ int cookie;
if (!nbcon_context_exit_unsafe(ctxt))
return;
nbcon_context_release(ctxt);
+
+ /*
+ * This context must flush any new records added while the console
+ * was locked. The console_srcu_read_lock must be taken to ensure
+ * the console is usable throughout flushing.
+ */
+ cookie = console_srcu_read_lock();
+ if (console_is_usable(con, console_srcu_read_flags(con)) &&
+ prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
+ if (!have_boot_console) {
+ __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));
+ } else if (!is_printk_legacy_deferred()) {
+ if (console_trylock())
+ console_unlock();
+ } else {
+ printk_trigger_flush();
+ }
+ }
+ console_srcu_read_unlock(cookie);
}
EXPORT_SYMBOL_GPL(nbcon_device_release);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index f08bf5e82fc7..7c9f8f6e1738 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -469,7 +469,7 @@ static DEFINE_MUTEX(syslog_lock);
* the console lock. This is because boot consoles and nbcon consoles may
* have mapped the same hardware.
*/
-static bool have_boot_console;
+bool have_boot_console;
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 25/35] printk: Flush nbcon consoles first on panic
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (23 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 24/35] printk: nbcon: Flush new records on device_release() John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 26/35] printk: nbcon: Add unsafe flushing " John Ogness
` (10 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
In console_flush_on_panic(), flush the nbcon consoles before
flushing legacy consoles. The legacy write() callbacks are not
fully safe when oops_in_progress is set.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7c9f8f6e1738..c6e633329e4d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3269,6 +3269,9 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL)
__console_rewind_all();
+ if (!have_boot_console)
+ nbcon_atomic_flush_pending();
+
console_flush_all(false, &next_seq, &handover);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 26/35] printk: nbcon: Add unsafe flushing on panic
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (24 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 25/35] printk: Flush nbcon consoles first on panic John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 27/35] printk: Avoid console_lock dance if no legacy or boot consoles John Ogness
` (9 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andrew Morton, Jani Nikula, Greg Kroah-Hartman, Ryo Takakura,
Uros Bizjak, Joel Granados
Add nbcon_atomic_flush_unsafe() to flush all nbcon consoles
using the write_atomic() callback and allowing unsafe hostile
takeovers. Call this at the end of panic() as a final attempt
to flush any pending messages.
Note that legacy consoles use unsafe methods for flushing
from the beginning of panic (see bust_spinlocks()). Therefore,
systems using both legacy and nbcon consoles may still fail to
see panic messages due to unsafe legacy console usage.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 5 +++++
kernel/panic.c | 1 +
kernel/printk/nbcon.c | 32 +++++++++++++++++++++++++-------
3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9687089f5ace..2e083f01f8a3 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -202,6 +202,7 @@ 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);
+void nbcon_atomic_flush_unsafe(void);
#else
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
@@ -294,6 +295,10 @@ static inline void nbcon_device_release(struct console *con)
{
}
+static inline void nbcon_atomic_flush_unsafe(void)
+{
+}
+
#endif
bool this_cpu_in_panic(void);
diff --git a/kernel/panic.c b/kernel/panic.c
index 2a0449144f82..df37c913b010 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -463,6 +463,7 @@ void panic(const char *fmt, ...)
* Explicitly flush the kernel log buffer one last time.
*/
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
+ nbcon_atomic_flush_unsafe();
local_irq_enable();
for (i = 0; ; i += PANIC_TIMER_STEP) {
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 269aeed18064..afdb16c1c733 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1083,6 +1083,7 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
* write_atomic() callback
* @con: The nbcon console to flush
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*
* Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on
* failure.
@@ -1101,7 +1102,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
* returned, it cannot be expected that the unfinalized record will become
* available.
*/
-static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
+ bool allow_unsafe_takeover)
{
struct nbcon_write_context wctxt = { };
struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
@@ -1110,6 +1112,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
ctxt->console = con;
ctxt->spinwait_max_us = 2000;
ctxt->prio = nbcon_get_default_prio();
+ ctxt->allow_unsafe_takeover = allow_unsafe_takeover;
if (!nbcon_context_try_acquire(ctxt))
return -EPERM;
@@ -1140,13 +1143,15 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
* write_atomic() callback
* @con: The nbcon console to flush
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*
* This will stop flushing before @stop_seq if another context has ownership.
* That context is then responsible for the flushing. Likewise, if new records
* are added while this context was flushing and there is no other context
* to handle the printing, this context must also flush those records.
*/
-static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
+ bool allow_unsafe_takeover)
{
unsigned long flags;
int err;
@@ -1160,7 +1165,7 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
*/
local_irq_save(flags);
- err = __nbcon_atomic_flush_pending_con(con, stop_seq);
+ err = __nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
local_irq_restore(flags);
@@ -1190,8 +1195,9 @@ static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
* __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
* write_atomic() callback
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*/
-static void __nbcon_atomic_flush_pending(u64 stop_seq)
+static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeover)
{
struct console *con;
int cookie;
@@ -1209,7 +1215,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
if (nbcon_seq_read(con) >= stop_seq)
continue;
- nbcon_atomic_flush_pending_con(con, stop_seq);
+ nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
}
console_srcu_read_unlock(cookie);
}
@@ -1225,7 +1231,19 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
*/
void nbcon_atomic_flush_pending(void)
{
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
+}
+
+/**
+ * nbcon_atomic_flush_unsafe - Flush all nbcon consoles using their
+ * write_atomic() callback and allowing unsafe hostile takeovers
+ *
+ * Flush the backlog up through the currently newest record. Unsafe hostile
+ * takeovers will be performed, if necessary.
+ */
+void nbcon_atomic_flush_unsafe(void)
+{
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
}
/**
@@ -1342,7 +1360,7 @@ void nbcon_device_release(struct console *con)
if (console_is_usable(con, console_srcu_read_flags(con)) &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
if (!have_boot_console) {
- __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
} else if (!is_printk_legacy_deferred()) {
if (console_trylock())
console_unlock();
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 27/35] printk: Avoid console_lock dance if no legacy or boot consoles
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (25 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 26/35] printk: nbcon: Add unsafe flushing " John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 28/35] printk: Track nbcon consoles John Ogness
` (8 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Currently the console lock is used to attempt legacy-type
printing even if there are no legacy or boot consoles registered.
If no such consoles are registered, the console lock does not
need to be taken.
Add tracking of legacy console registration and use it with
boot console tracking to avoid unnecessary code paths, i.e.
do not use the console lock if there are no boot consoles
and no legacy consoles.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c6e633329e4d..b3ddcf39a53c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -463,6 +463,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
static DEFINE_MUTEX(syslog_lock);
+/*
+ * Specifies if a legacy console is registered. If legacy consoles are
+ * present, it is necessary to perform the console lock/unlock dance
+ * whenever console flushing should occur.
+ */
+static bool have_legacy_console;
+
/*
* Specifies if a boot console is registered. If boot consoles are present,
* nbcon consoles cannot print simultaneously and must be synchronized by
@@ -471,6 +478,14 @@ static DEFINE_MUTEX(syslog_lock);
*/
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)
+
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -2339,7 +2354,7 @@ asmlinkage int vprintk_emit(int facility, int level,
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
/* If called from the scheduler, we can not call up(). */
- if (!in_sched) {
+ if (!in_sched && printing_via_unlock) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2359,7 +2374,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (in_sched)
+ if (in_sched && printing_via_unlock)
defer_console_output();
else
wake_up_klogd();
@@ -2718,7 +2733,7 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
- if (!cpuhp_tasks_frozen) {
+ if (!cpuhp_tasks_frozen && printing_via_unlock) {
/* If trylock fails, someone else is doing the printing */
if (console_trylock())
console_unlock();
@@ -3625,6 +3640,7 @@ void register_console(struct console *newcon)
if (newcon->flags & CON_NBCON) {
nbcon_seq_force(newcon, init_seq);
} else {
+ have_legacy_console = true;
newcon->seq = init_seq;
}
@@ -3701,6 +3717,7 @@ EXPORT_SYMBOL(register_console);
static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ bool found_legacy_con = false;
bool found_boot_con = false;
unsigned long flags;
struct console *c;
@@ -3768,9 +3785,13 @@ static int unregister_console_locked(struct console *console)
for_each_console(c) {
if (c->flags & CON_BOOT)
found_boot_con = true;
+ if (!(c->flags & CON_NBCON))
+ found_legacy_con = true;
}
if (!found_boot_con)
have_boot_console = found_boot_con;
+ if (!found_legacy_con)
+ have_legacy_console = found_legacy_con;
return res;
}
@@ -3931,8 +3952,10 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
seq = prb_next_reserve_seq(prb);
/* Flush the consoles so that records up to @seq are printed. */
- console_lock();
- console_unlock();
+ if (printing_via_unlock) {
+ console_lock();
+ console_unlock();
+ }
for (;;) {
unsigned long begin_jiffies;
@@ -3945,6 +3968,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
* console->seq. Releasing console_lock flushes more
* records in case @seq is still not printed on all
* usable consoles.
+ *
+ * Holding the console_lock is not necessary if there
+ * are no legacy or boot consoles. However, such a
+ * console could register at any time. Always hold the
+ * console_lock as a precaution rather than
+ * synchronizing against register_console().
*/
console_lock();
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 28/35] printk: Track nbcon consoles
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (26 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 27/35] printk: Avoid console_lock dance if no legacy or boot consoles John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 29/35] printk: Coordinate direct printing in panic John Ogness
` (7 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
Add a global flag @have_nbcon_console to identify if any nbcon
consoles are registered. This will be used in follow-up commits
to preserve legacy behavior when no nbcon consoles are registered.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b3ddcf39a53c..e30107d216a5 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -470,6 +470,11 @@ static DEFINE_MUTEX(syslog_lock);
*/
static bool have_legacy_console;
+/*
+ * Specifies if an nbcon console is registered.
+ */
+static bool have_nbcon_console;
+
/*
* Specifies if a boot console is registered. If boot consoles are present,
* nbcon consoles cannot print simultaneously and must be synchronized by
@@ -3638,6 +3643,7 @@ void register_console(struct console *newcon)
init_seq = get_init_console_seq(newcon, bootcon_registered);
if (newcon->flags & CON_NBCON) {
+ have_nbcon_console = true;
nbcon_seq_force(newcon, init_seq);
} else {
have_legacy_console = true;
@@ -3718,6 +3724,7 @@ static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
bool found_legacy_con = false;
+ bool found_nbcon_con = false;
bool found_boot_con = false;
unsigned long flags;
struct console *c;
@@ -3785,13 +3792,18 @@ static int unregister_console_locked(struct console *console)
for_each_console(c) {
if (c->flags & CON_BOOT)
found_boot_con = true;
- if (!(c->flags & CON_NBCON))
+
+ if (c->flags & CON_NBCON)
+ found_nbcon_con = true;
+ else
found_legacy_con = true;
}
if (!found_boot_con)
have_boot_console = found_boot_con;
if (!found_legacy_con)
have_legacy_console = found_legacy_con;
+ if (!found_nbcon_con)
+ have_nbcon_console = found_nbcon_con;
return res;
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 29/35] printk: Coordinate direct printing in panic
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (27 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 28/35] printk: Track nbcon consoles John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-08-20 15:21 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 30/35] printk: Add helper for flush type logic John Ogness
` (6 subsequent siblings)
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andrew Morton, Jani Nikula, Greg Kroah-Hartman, Ryo Takakura,
Joel Granados, Lukas Wunner, Uros Bizjak
If legacy and nbcon consoles are registered and the nbcon
consoles are allowed to flush (i.e. no boot consoles
registered), the legacy consoles will no longer perform
direct printing on the panic CPU until after the backtrace
has been stored. This will give the safe nbcon consoles a
chance to print the panic messages before allowing the
unsafe legacy consoles to print.
If no nbcon consoles are registered or they are not allowed
to flush because boot consoles are registered, there is no
change in behavior (i.e. legacy consoles will always attempt
to print from the printk() caller context).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
include/linux/printk.h | 5 ++++
kernel/panic.c | 2 ++
kernel/printk/internal.h | 1 +
kernel/printk/printk.c | 55 +++++++++++++++++++++++++++++++++++-----
4 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 2e083f01f8a3..eca9bb2ee637 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -200,6 +200,7 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
extern asmlinkage void dump_stack(void) __cold;
void printk_trigger_flush(void);
void console_try_replay_all(void);
+void printk_legacy_allow_panic_sync(void);
extern bool nbcon_device_try_acquire(struct console *con);
extern void nbcon_device_release(struct console *con);
void nbcon_atomic_flush_unsafe(void);
@@ -286,6 +287,10 @@ static inline void console_try_replay_all(void)
{
}
+static inline void printk_legacy_allow_panic_sync(void)
+{
+}
+
static inline bool nbcon_device_try_acquire(struct console *con)
{
return false;
diff --git a/kernel/panic.c b/kernel/panic.c
index df37c913b010..93096d5abcc7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -374,6 +374,8 @@ void panic(const char *fmt, ...)
panic_other_cpus_shutdown(_crash_kexec_post_notifiers);
+ printk_legacy_allow_panic_sync();
+
/*
* Run any panic handlers, including those that might need to
* add information to the kmsg dump output.
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 7679e18f24b3..6b61350a3026 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -154,6 +154,7 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
+extern bool legacy_allow_panic_sync;
extern struct printk_buffers printk_shared_pbufs;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e30107d216a5..fc3f8970eea2 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -471,7 +471,9 @@ static DEFINE_MUTEX(syslog_lock);
static bool have_legacy_console;
/*
- * Specifies if an nbcon console is registered.
+ * Specifies if an nbcon console is registered. If nbcon consoles are present,
+ * synchronous printing of legacy consoles will not occur during panic until
+ * the backtrace has been stored to the ringbuffer.
*/
static bool have_nbcon_console;
@@ -483,6 +485,9 @@ static bool have_nbcon_console;
*/
bool have_boot_console;
+/* See printk_legacy_allow_panic_sync() for details. */
+bool legacy_allow_panic_sync;
+
/*
* Specifies if the console lock/unlock dance is needed for console
* printing. If @have_boot_console is true, the nbcon consoles will
@@ -2330,12 +2335,28 @@ int vprintk_store(int facility, int level,
return ret;
}
+/*
+ * This acts as a one-way switch to allow legacy consoles to print from
+ * the printk() caller context on a panic CPU. It also attempts to flush
+ * the legacy consoles in this context.
+ */
+void printk_legacy_allow_panic_sync(void)
+{
+ legacy_allow_panic_sync = true;
+
+ if (printing_via_unlock && !is_printk_legacy_deferred()) {
+ if (console_trylock())
+ console_unlock();
+ }
+}
+
asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
+ bool do_trylock_unlock = printing_via_unlock;
+ bool defer_legacy = false;
int printed_len;
- bool in_sched = false;
/* Suppress unimportant messages after panic happens */
if (unlikely(suppress_printk))
@@ -2349,17 +2370,35 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
return 0;
+ /* If called from the scheduler, we can not call up(). */
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
- in_sched = true;
+ defer_legacy = do_trylock_unlock;
+ do_trylock_unlock = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
- /* If called from the scheduler, we can not call up(). */
- if (!in_sched && printing_via_unlock) {
+ if (have_nbcon_console && !have_boot_console) {
+ nbcon_atomic_flush_pending();
+
+ /*
+ * In panic, the legacy consoles are not allowed to print from
+ * the printk calling context unless explicitly allowed. This
+ * gives the safe nbcon consoles a chance to print out all the
+ * panic messages first. This restriction only applies if
+ * there are nbcon consoles registered and they are allowed to
+ * flush.
+ */
+ if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
+ do_trylock_unlock = false;
+ defer_legacy = false;
+ }
+ }
+
+ if (do_trylock_unlock) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2379,7 +2418,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (in_sched && printing_via_unlock)
+ if (defer_legacy)
defer_console_output();
else
wake_up_klogd();
@@ -3292,7 +3331,9 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (!have_boot_console)
nbcon_atomic_flush_pending();
- console_flush_all(false, &next_seq, &handover);
+ /* Flush legacy consoles once allowed, even when dangerous. */
+ if (legacy_allow_panic_sync)
+ console_flush_all(false, &next_seq, &handover);
}
/*
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 30/35] printk: Add helper for flush type logic
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (28 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 29/35] printk: Coordinate direct printing in panic John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-08-21 9:11 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections John Ogness
` (5 subsequent siblings)
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
There are many call sites where console flushing occur.
Depending on the system state and types of consoles, the flush
methods to use are different. A flush call site generally must
consider:
@have_boot_console
@have_nbcon_console
@have_legacy_console
@legacy_allow_panic_sync
is_printk_preferred()
and take into account the current CPU state:
NBCON_PRIO_NORMAL
NBCON_PRIO_EMERGENCY
NBCON_PRIO_PANIC
in order to decide if it should:
flush nbcon directly via atomic_write() callback
flush legacy directly via console_unlock
flush legacy via offload to irq_work
All of these call sites use their own logic to make this
decision, which is complicated and error prone. Especially
later when two more flush methods will be introduced:
flush nbcon via offload to kthread
flush legacy via offload to kthread
Introduce a new internal struct console_flush_type that
specifies the flush method(s) that are available for a
particular call site to use.
Introduce a helper function to fill out console_flush_type to
be used for flushing call sites.
Replace the logic of all flushing call sites to use the new
helper.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
kernel/printk/internal.h | 73 ++++++++++++++++++++++++++++++++++++++++
kernel/printk/nbcon.c | 12 +++++--
kernel/printk/printk.c | 68 +++++++++++++++++--------------------
3 files changed, 112 insertions(+), 41 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 6b61350a3026..ba2e0f1940bd 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -154,8 +154,81 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
+extern bool have_nbcon_console;
+extern bool have_legacy_console;
extern bool legacy_allow_panic_sync;
+/**
+ * struct console_flush_type - Define available console flush methods
+ * @nbcon_atomic: Flush directly using nbcon_atomic() callback
+ * @legacy_direct: Call the legacy loop in this context
+ * @legacy_offload: Offload the legacy loop into IRQ
+ *
+ * Note that the legacy loop also flushes the nbcon consoles.
+ */
+struct console_flush_type {
+ bool nbcon_atomic;
+ bool legacy_direct;
+ bool legacy_offload;
+};
+
+/*
+ * Identify which console flushing methods should be used in the context of
+ * the caller.
+ */
+static inline void printk_get_console_flush_type(struct console_flush_type *ft)
+{
+ memset(ft, 0, sizeof(*ft));
+
+ switch (nbcon_get_default_prio()) {
+ case NBCON_PRIO_NORMAL:
+ if (have_nbcon_console && !have_boot_console)
+ ft->nbcon_atomic = true;
+
+ /* Legacy consoles are flushed directly when possible. */
+ if (have_legacy_console || have_boot_console) {
+ if (!is_printk_legacy_deferred())
+ ft->legacy_direct = true;
+ else
+ ft->legacy_offload = true;
+ }
+ break;
+
+ case NBCON_PRIO_PANIC:
+ /*
+ * In panic, the nbcon consoles will directly print. But
+ * only allowed if there are no boot consoles.
+ */
+ if (have_nbcon_console && !have_boot_console)
+ ft->nbcon_atomic = true;
+
+ if (have_legacy_console || have_boot_console) {
+ /*
+ * This is the same decision as NBCON_PRIO_NORMAL
+ * except that offloading never occurs in panic.
+ *
+ * Note that console_flush_on_panic() will flush
+ * legacy consoles anyway, even if unsafe.
+ */
+ if (!is_printk_legacy_deferred())
+ ft->legacy_direct = true;
+
+ /*
+ * In panic, if nbcon atomic printing occurs,
+ * the legacy consoles must remain silent until
+ * explicitly allowed.
+ */
+ if (ft->nbcon_atomic && !legacy_allow_panic_sync)
+ ft->legacy_direct = false;
+ }
+ break;
+
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
extern struct printk_buffers printk_shared_pbufs;
/**
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index afdb16c1c733..18488d6c17c0 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1344,6 +1344,7 @@ EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
void nbcon_device_release(struct console *con)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
+ struct console_flush_type ft;
int cookie;
if (!nbcon_context_exit_unsafe(ctxt))
@@ -1359,12 +1360,17 @@ void nbcon_device_release(struct console *con)
cookie = console_srcu_read_lock();
if (console_is_usable(con, console_srcu_read_flags(con)) &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
- if (!have_boot_console) {
+ /*
+ * If nbcon_atomic flushing is not available, fallback to
+ * using the legacy loop.
+ */
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic) {
__nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
- } else if (!is_printk_legacy_deferred()) {
+ } else if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
- } else {
+ } else if (ft.legacy_offload) {
printk_trigger_flush();
}
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index fc3f8970eea2..6accd1704e73 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -468,14 +468,14 @@ 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,
* synchronous printing of legacy consoles will not occur during panic until
* the backtrace has been stored to the ringbuffer.
*/
-static bool have_nbcon_console;
+bool have_nbcon_console;
/*
* Specifies if a boot console is registered. If boot consoles are present,
@@ -488,14 +488,6 @@ bool have_boot_console;
/* See printk_legacy_allow_panic_sync() for details. */
bool legacy_allow_panic_sync;
-/*
- * 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)
-
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -2342,9 +2334,12 @@ int vprintk_store(int facility, int level,
*/
void printk_legacy_allow_panic_sync(void)
{
+ struct console_flush_type ft;
+
legacy_allow_panic_sync = true;
- if (printing_via_unlock && !is_printk_legacy_deferred()) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
@@ -2354,8 +2349,7 @@ asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
- bool do_trylock_unlock = printing_via_unlock;
- bool defer_legacy = false;
+ struct console_flush_type ft;
int printed_len;
/* Suppress unimportant messages after panic happens */
@@ -2370,35 +2364,23 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
return 0;
+ printk_get_console_flush_type(&ft);
+
/* If called from the scheduler, we can not call up(). */
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
- defer_legacy = do_trylock_unlock;
- do_trylock_unlock = false;
+ ft.legacy_offload |= ft.legacy_direct;
+ ft.legacy_direct = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
- if (have_nbcon_console && !have_boot_console) {
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
- /*
- * In panic, the legacy consoles are not allowed to print from
- * the printk calling context unless explicitly allowed. This
- * gives the safe nbcon consoles a chance to print out all the
- * panic messages first. This restriction only applies if
- * there are nbcon consoles registered and they are allowed to
- * flush.
- */
- if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
- do_trylock_unlock = false;
- defer_legacy = false;
- }
- }
-
- if (do_trylock_unlock) {
+ if (ft.legacy_direct) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2418,7 +2400,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (defer_legacy)
+ if (ft.legacy_offload)
defer_console_output();
else
wake_up_klogd();
@@ -2777,10 +2759,16 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
- if (!cpuhp_tasks_frozen && printing_via_unlock) {
- /* If trylock fails, someone else is doing the printing */
- if (console_trylock())
- console_unlock();
+ struct console_flush_type ft;
+
+ if (!cpuhp_tasks_frozen) {
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
+ nbcon_atomic_flush_pending();
+ if (ft.legacy_direct) {
+ if (console_trylock())
+ console_unlock();
+ }
}
return 0;
}
@@ -3305,6 +3293,7 @@ static void __console_rewind_all(void)
*/
void console_flush_on_panic(enum con_flush_mode mode)
{
+ struct console_flush_type ft;
bool handover;
u64 next_seq;
@@ -3328,7 +3317,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL)
__console_rewind_all();
- if (!have_boot_console)
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
/* Flush legacy consoles once allowed, even when dangerous. */
@@ -3992,6 +3982,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
{
unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
unsigned long remaining_jiffies = timeout_jiffies;
+ struct console_flush_type ft;
struct console *c;
u64 last_diff = 0;
u64 printk_seq;
@@ -4005,7 +3996,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
seq = prb_next_reserve_seq(prb);
/* Flush the consoles so that records up to @seq are printed. */
- if (printing_via_unlock) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
console_lock();
console_unlock();
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (29 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 30/35] printk: Add helper for flush type logic John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-08-27 14:19 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Implement emergency sections tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 32/35] panic: Mark emergency section in warn John Ogness
` (4 subsequent siblings)
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman
From: Thomas Gleixner <tglx@linutronix.de>
In emergency situations (something has gone wrong but the
system continues to operate), usually important information
(such as a backtrace) is generated via printk(). This
information should be pushed out to the consoles ASAP.
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.
Perform direct console flushing at the emergency priority if
the current CPU is in an emergency state and it is safe to do
so.
Note that the emergency state is not system-wide. While one CPU
is in an emergency state, another CPU may attempt to print
console messages at normal priority.
Also note that printk() already attempts to flush consoles in
the caller context for normal priority. However, follow-up
changes will introduce printing kthreads, in which case the
normal priority printk() calls will offload to the kthreads.
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>
---
include/linux/console.h | 4 +++
kernel/printk/internal.h | 1 +
kernel/printk/nbcon.c | 75 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 3706f944de46..9a13f91b0c43 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -553,10 +553,14 @@ static inline bool console_is_registered(const struct console *con)
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 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 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; }
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index ba2e0f1940bd..8e36d8695f81 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -182,6 +182,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
switch (nbcon_get_default_prio()) {
case NBCON_PRIO_NORMAL:
+ case NBCON_PRIO_EMERGENCY:
if (have_nbcon_console && !have_boot_console)
ft->nbcon_atomic = true;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 18488d6c17c0..92ac5c590927 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -972,6 +972,36 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
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
+ *
+ * Context: For reading, any context. For writing, any context which could
+ * not be migrated to another CPU.
+ * Return: Either a pointer to the per CPU emergency nesting counter of
+ * the current CPU or to the init data during early boot.
+ *
+ * The function is safe for reading per-CPU variables in any context because
+ * preemption is disabled if the current CPU is in the emergency state. See
+ * also nbcon_cpu_emergency_enter().
+ */
+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;
+
+ /* Open code this_cpu_ptr() without checking migration. */
+ return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
+}
+
/**
* nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
* printing on the current CPU
@@ -981,13 +1011,20 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
* context for printing.
*
* The function is safe for reading per-CPU data in any context because
- * preemption is disabled if the current CPU is in the panic state.
+ * preemption is disabled if the current CPU is in the emergency or panic
+ * state.
*/
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;
}
@@ -1246,6 +1283,42 @@ void nbcon_atomic_flush_unsafe(void)
__nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
}
+/**
+ * nbcon_cpu_emergency_enter - Enter an emergency section where printk()
+ * messages for that CPU are flushed directly
+ *
+ * Context: Any context. Disables preemption.
+ *
+ * When within an emergency section, printk() calls will attempt to flush any
+ * pending messages in the ringbuffer.
+ */
+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
+ *
+ * Context: Within an emergency section. Enables preemption.
+ */
+void nbcon_cpu_emergency_exit(void)
+{
+ unsigned int *cpu_emergency_nesting;
+
+ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
+
+ if (!WARN_ON_ONCE(*cpu_emergency_nesting == 0))
+ (*cpu_emergency_nesting)--;
+
+ preempt_enable();
+}
+
/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 32/35] panic: Mark emergency section in warn
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (30 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 33/35] panic: Mark emergency section in oops John Ogness
` (3 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andrew Morton, Greg Kroah-Hartman, Jani Nikula, Uros Bizjak,
Feng Tang
From: Thomas Gleixner <tglx@linutronix.de>
Mark the full contents of __warn() as an emergency section. In
this section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
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>
---
kernel/panic.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/panic.c b/kernel/panic.c
index 93096d5abcc7..1a10b6e2a855 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -718,6 +718,8 @@ struct warn_args {
void __warn(const char *file, int line, void *caller, unsigned taint,
struct pt_regs *regs, struct warn_args *args)
{
+ nbcon_cpu_emergency_enter();
+
disable_trace_on_warning();
if (file)
@@ -753,6 +755,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
/* Just a warning, don't kill lockdep. */
add_taint(taint, LOCKDEP_STILL_OK);
+
+ nbcon_cpu_emergency_exit();
}
#ifdef CONFIG_BUG
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 33/35] panic: Mark emergency section in oops
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (31 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 32/35] panic: Mark emergency section in warn John Ogness
@ 2024-08-20 6:29 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:30 ` [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls John Ogness
` (2 subsequent siblings)
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:29 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andrew Morton, Greg Kroah-Hartman, Jani Nikula, Baoquan He,
Joel Granados, Feng Tang, Uros Bizjak
Mark an emergency section beginning with oops_enter() until the
end of oops_exit(). In this section, every printk() call will
attempt to directly flush to the consoles using the EMERGENCY
priority.
The very end of oops_exit() performs a kmsg_dump(). This is not
included in the emergency section because it is another
flushing mechanism that should occur after the consoles have
flushed the oops messages.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/panic.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/panic.c b/kernel/panic.c
index 1a10b6e2a855..753d12f4dc8f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -685,6 +685,7 @@ bool oops_may_print(void)
*/
void oops_enter(void)
{
+ nbcon_cpu_emergency_enter();
tracing_off();
/* can't trust the integrity of the kernel anymore: */
debug_locks_off();
@@ -707,6 +708,7 @@ void oops_exit(void)
{
do_oops_enter_exit();
print_oops_end_marker();
+ nbcon_cpu_emergency_exit();
kmsg_dump(KMSG_DUMP_OOPS);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (32 preceding siblings ...)
2024-08-20 6:29 ` [PATCH printk v8 33/35] panic: Mark emergency section in oops John Ogness
@ 2024-08-20 6:30 ` John Ogness
2024-08-20 17:48 ` Paul E. McKenney
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:30 ` [PATCH printk v8 35/35] lockdep: Mark emergency sections in lockdep splats John Ogness
2024-08-21 9:21 ` [PATCH printk v8 00/35] wire up write_atomic() printing Petr Mladek
35 siblings, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:30 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Paul E. McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Boqun Feng, Uladzislau Rezki,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu
Mark emergency sections wherever multiple lines of
rcu stall information are generated. In an emergency
section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/rcu/tree_exp.h | 7 +++++++
kernel/rcu/tree_stall.h | 9 +++++++++
2 files changed, 16 insertions(+)
diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index 4acd29d16fdb..f6b35a0585a8 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -7,6 +7,7 @@
* Authors: Paul E. McKenney <paulmck@linux.ibm.com>
*/
+#include <linux/console.h>
#include <linux/lockdep.h>
static void rcu_exp_handler(void *unused);
@@ -590,6 +591,9 @@ static void synchronize_rcu_expedited_wait(void)
return;
if (rcu_stall_is_suppressed())
continue;
+
+ nbcon_cpu_emergency_enter();
+
j = jiffies;
rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_EXP, (void *)(j - jiffies_start));
trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
@@ -643,6 +647,9 @@ static void synchronize_rcu_expedited_wait(void)
rcu_exp_print_detail_task_stall_rnp(rnp);
}
jiffies_stall = 3 * rcu_exp_jiffies_till_stall_check() + 3;
+
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
}
}
diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
index 4b0e9d7c4c68..b3a6943127bc 100644
--- a/kernel/rcu/tree_stall.h
+++ b/kernel/rcu/tree_stall.h
@@ -7,6 +7,7 @@
* Author: Paul E. McKenney <paulmck@linux.ibm.com>
*/
+#include <linux/console.h>
#include <linux/kvm_para.h>
#include <linux/rcu_notifier.h>
@@ -605,6 +606,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
if (rcu_stall_is_suppressed())
return;
+ nbcon_cpu_emergency_enter();
+
/*
* OK, time to rat on our buddy...
* See Documentation/RCU/stallwarn.rst for info on how to debug
@@ -657,6 +660,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
rcu_check_gp_kthread_expired_fqs_timer();
rcu_check_gp_kthread_starvation();
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
rcu_force_quiescent_state(); /* Kick them all. */
@@ -677,6 +682,8 @@ static void print_cpu_stall(unsigned long gps)
if (rcu_stall_is_suppressed())
return;
+ nbcon_cpu_emergency_enter();
+
/*
* OK, time to rat on ourselves...
* See Documentation/RCU/stallwarn.rst for info on how to debug
@@ -706,6 +713,8 @@ static void print_cpu_stall(unsigned long gps)
jiffies + 3 * rcu_jiffies_till_stall_check() + 3);
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
/*
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [PATCH printk v8 35/35] lockdep: Mark emergency sections in lockdep splats
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (33 preceding siblings ...)
2024-08-20 6:30 ` [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls John Ogness
@ 2024-08-20 6:30 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-21 9:21 ` [PATCH printk v8 00/35] wire up write_atomic() printing Petr Mladek
35 siblings, 1 reply; 84+ messages in thread
From: John Ogness @ 2024-08-20 6:30 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Peter Zijlstra, Ingo Molnar, Will Deacon, Waiman Long, Boqun Feng
Mark emergency sections wherever multiple lines of
lock debugging output are generated. In an emergency
section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
Note that debug_show_all_locks() and
lockdep_print_held_locks() rely on their callers to
enter the emergency section. This is because these
functions can also be called in non-emergency
situations (such as sysrq).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
---
kernel/locking/lockdep.c | 83 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 81 insertions(+), 2 deletions(-)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 58c88220a478..fea538f7d131 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -56,6 +56,7 @@
#include <linux/kprobes.h>
#include <linux/lockdep.h>
#include <linux/context_tracking.h>
+#include <linux/console.h>
#include <asm/sections.h>
@@ -573,8 +574,10 @@ static struct lock_trace *save_trace(void)
if (!debug_locks_off_graph_unlock())
return NULL;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_STACK_TRACE_ENTRIES too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
@@ -887,11 +890,13 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
instrumentation_begin();
debug_locks_off();
+ nbcon_cpu_emergency_enter();
printk(KERN_ERR
"BUG: looking up invalid subclass: %u\n", subclass);
printk(KERN_ERR
"turning off the locking correctness validator.\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
instrumentation_end();
return NULL;
}
@@ -968,11 +973,13 @@ static bool assign_lock_key(struct lockdep_map *lock)
else {
/* Debug-check: all keys must be persistent! */
debug_locks_off();
+ nbcon_cpu_emergency_enter();
pr_err("INFO: trying to register non-static key.\n");
pr_err("The code is fine but needs lockdep annotation, or maybe\n");
pr_err("you didn't initialize this object before use?\n");
pr_err("turning off the locking correctness validator.\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
return false;
}
@@ -1316,8 +1323,10 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
return NULL;
}
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
nr_lock_classes++;
@@ -1349,11 +1358,13 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
if (verbose(class)) {
graph_unlock();
+ nbcon_cpu_emergency_enter();
printk("\nnew class %px: %s", class->key, class->name);
if (class->name_version > 1)
printk(KERN_CONT "#%d", class->name_version);
printk(KERN_CONT "\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
if (!graph_lock()) {
return NULL;
@@ -1392,8 +1403,10 @@ static struct lock_list *alloc_list_entry(void)
if (!debug_locks_off_graph_unlock())
return NULL;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_ENTRIES too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
nr_list_entries++;
@@ -2039,6 +2052,8 @@ static noinline void print_circular_bug(struct lock_list *this,
depth = get_lock_depth(target);
+ nbcon_cpu_emergency_enter();
+
print_circular_bug_header(target, depth, check_src, check_tgt);
parent = get_lock_parent(target);
@@ -2057,6 +2072,8 @@ static noinline void print_circular_bug(struct lock_list *this,
printk("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static noinline void print_bfs_bug(int ret)
@@ -2569,6 +2586,8 @@ print_bad_irq_dependency(struct task_struct *curr,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=====================================================\n");
pr_warn("WARNING: %s-safe -> %s-unsafe lock order detected\n",
@@ -2618,11 +2637,13 @@ print_bad_irq_dependency(struct task_struct *curr,
pr_warn(" and %s-irq-unsafe lock:\n", irqclass);
next_root->trace = save_trace();
if (!next_root->trace)
- return;
+ goto out;
print_shortest_lock_dependencies(forwards_entry, next_root);
pr_warn("\nstack backtrace:\n");
dump_stack();
+out:
+ nbcon_cpu_emergency_exit();
}
static const char *state_names[] = {
@@ -2987,6 +3008,8 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("============================================\n");
pr_warn("WARNING: possible recursive locking detected\n");
@@ -3009,6 +3032,8 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
/*
@@ -3606,6 +3631,8 @@ static void print_collision(struct task_struct *curr,
struct held_lock *hlock_next,
struct lock_chain *chain)
{
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("============================\n");
pr_warn("WARNING: chain_key collision\n");
@@ -3622,6 +3649,8 @@ static void print_collision(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
#endif
@@ -3712,8 +3741,10 @@ static inline int add_chain_cache(struct task_struct *curr,
if (!debug_locks_off_graph_unlock())
return 0;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
chain->chain_key = chain_key;
@@ -3730,8 +3761,10 @@ static inline int add_chain_cache(struct task_struct *curr,
if (!debug_locks_off_graph_unlock())
return 0;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
@@ -3970,6 +4003,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
if (!debug_locks_off() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("================================\n");
pr_warn("WARNING: inconsistent lock state\n");
@@ -3998,6 +4033,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
/*
@@ -4032,6 +4069,8 @@ print_irq_inversion_bug(struct task_struct *curr,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("========================================================\n");
pr_warn("WARNING: possible irq lock inversion dependency detected\n");
@@ -4072,11 +4111,13 @@ print_irq_inversion_bug(struct task_struct *curr,
pr_warn("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
root->trace = save_trace();
if (!root->trace)
- return;
+ goto out;
print_shortest_lock_dependencies(other, root);
pr_warn("\nstack backtrace:\n");
dump_stack();
+out:
+ nbcon_cpu_emergency_exit();
}
/*
@@ -4153,6 +4194,8 @@ void print_irqtrace_events(struct task_struct *curr)
{
const struct irqtrace_events *trace = &curr->irqtrace;
+ nbcon_cpu_emergency_enter();
+
printk("irq event stamp: %u\n", trace->irq_events);
printk("hardirqs last enabled at (%u): [<%px>] %pS\n",
trace->hardirq_enable_event, (void *)trace->hardirq_enable_ip,
@@ -4166,6 +4209,8 @@ void print_irqtrace_events(struct task_struct *curr)
printk("softirqs last disabled at (%u): [<%px>] %pS\n",
trace->softirq_disable_event, (void *)trace->softirq_disable_ip,
(void *)trace->softirq_disable_ip);
+
+ nbcon_cpu_emergency_exit();
}
static int HARDIRQ_verbose(struct lock_class *class)
@@ -4686,10 +4731,12 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
* We must printk outside of the graph_lock:
*/
if (ret == 2) {
+ nbcon_cpu_emergency_enter();
printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
print_lock(this);
print_irqtrace_events(curr);
dump_stack();
+ nbcon_cpu_emergency_exit();
}
return ret;
@@ -4730,6 +4777,8 @@ print_lock_invalid_wait_context(struct task_struct *curr,
if (debug_locks_silent)
return 0;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=============================\n");
pr_warn("[ BUG: Invalid wait context ]\n");
@@ -4749,6 +4798,8 @@ print_lock_invalid_wait_context(struct task_struct *curr,
pr_warn("stack backtrace:\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
+
return 0;
}
@@ -4956,6 +5007,8 @@ print_lock_nested_lock_not_held(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("==================================\n");
pr_warn("WARNING: Nested lock was not taken\n");
@@ -4976,6 +5029,8 @@ print_lock_nested_lock_not_held(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static int __lock_is_held(const struct lockdep_map *lock, int read);
@@ -5024,11 +5079,13 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
debug_class_ops_inc(class);
if (very_verbose(class)) {
+ nbcon_cpu_emergency_enter();
printk("\nacquire class [%px] %s", class->key, class->name);
if (class->name_version > 1)
printk(KERN_CONT "#%d", class->name_version);
printk(KERN_CONT "\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
}
/*
@@ -5155,6 +5212,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
#endif
if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
debug_locks_off();
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCK_DEPTH too low!");
printk(KERN_DEBUG "depth: %i max: %lu!\n",
curr->lockdep_depth, MAX_LOCK_DEPTH);
@@ -5162,6 +5220,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
lockdep_print_held_locks(current);
debug_show_all_locks();
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
@@ -5181,6 +5240,8 @@ static void print_unlock_imbalance_bug(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=====================================\n");
pr_warn("WARNING: bad unlock balance detected!\n");
@@ -5197,6 +5258,8 @@ static void print_unlock_imbalance_bug(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static noinstr int match_held_lock(const struct held_lock *hlock,
@@ -5901,6 +5964,8 @@ static void print_lock_contention_bug(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=================================\n");
pr_warn("WARNING: bad contention detected!\n");
@@ -5917,6 +5982,8 @@ static void print_lock_contention_bug(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static void
@@ -6530,6 +6597,8 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=========================\n");
pr_warn("WARNING: held lock freed!\n");
@@ -6542,6 +6611,8 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static inline int not_in_range(const void* mem_from, unsigned long mem_len,
@@ -6588,6 +6659,8 @@ static void print_held_locks_bug(void)
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("====================================\n");
pr_warn("WARNING: %s/%d still has locks held!\n",
@@ -6597,6 +6670,8 @@ static void print_held_locks_bug(void)
lockdep_print_held_locks(current);
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
void debug_check_no_locks_held(void)
@@ -6654,6 +6729,7 @@ asmlinkage __visible void lockdep_sys_exit(void)
if (unlikely(curr->lockdep_depth)) {
if (!debug_locks_off())
return;
+ nbcon_cpu_emergency_enter();
pr_warn("\n");
pr_warn("================================================\n");
pr_warn("WARNING: lock held when returning to user space!\n");
@@ -6662,6 +6738,7 @@ asmlinkage __visible void lockdep_sys_exit(void)
pr_warn("%s/%d is leaving the kernel with locks still held!\n",
curr->comm, curr->pid);
lockdep_print_held_locks(curr);
+ nbcon_cpu_emergency_exit();
}
/*
@@ -6678,6 +6755,7 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
bool rcu = warn_rcu_enter();
/* Note: the following can be executed concurrently, so be careful. */
+ nbcon_cpu_emergency_enter();
pr_warn("\n");
pr_warn("=============================\n");
pr_warn("WARNING: suspicious RCU usage\n");
@@ -6716,6 +6794,7 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
lockdep_print_held_locks(curr);
pr_warn("\nstack backtrace:\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
warn_rcu_exit(rcu);
}
EXPORT_SYMBOL_GPL(lockdep_rcu_suspicious);
--
2.39.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons
2024-08-20 6:29 ` [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons John Ogness
@ 2024-08-20 11:12 ` Ilpo Järvinen
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: Ilpo Järvinen @ 2024-08-20 11:12 UTC (permalink / raw)
To: John Ogness
Cc: Petr Mladek, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
LKML, Greg Kroah-Hartman, Jiri Slaby, Russell King, Tony Lindgren,
Andy Shevchenko, Geert Uytterhoeven, Arnd Bergmann,
Uwe Kleine-König, Théo Lebrun, Linus Walleij,
Lino Sanfilippo, Konrad Dybcio, Sebastian Andrzej Siewior,
linux-serial
[-- Attachment #1: Type: text/plain, Size: 4812 bytes --]
On Tue, 20 Aug 2024, John Ogness wrote:
> Introduce uart_port_set_cons() as a wrapper to set @cons of a
> uart_port. The wrapper sets @cons under the port lock in order
> to prevent @cons from disappearing while another context is
> holding the port lock. This is necessary for a follow-up
> commit relating to the port lock wrappers, which rely on @cons
> not changing between lock and unlock.
>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> Tested-by: Théo Lebrun <theo.lebrun@bootlin.com> # EyeQ5, AMBA-PL011
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
--
i.
> ---
> drivers/tty/serial/8250/8250_core.c | 6 +++---
> drivers/tty/serial/amba-pl011.c | 2 +-
> drivers/tty/serial/serial_core.c | 16 ++++++++--------
> include/linux/serial_core.h | 17 +++++++++++++++++
> 4 files changed, 29 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index 29e4b83e0376..5f9f06911795 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -423,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
>
> port = &serial8250_ports[co->index].port;
> /* link port to console */
> - port->cons = co;
> + uart_port_set_cons(port, co);
>
> retval = serial8250_console_setup(port, options, false);
> if (retval != 0)
> - port->cons = NULL;
> + uart_port_set_cons(port, NULL);
> return retval;
> }
>
> @@ -485,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
> continue;
>
> co->index = i;
> - port->cons = co;
> + uart_port_set_cons(port, co);
> return serial8250_console_setup(port, options, true);
> }
>
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 8b1644f5411e..7d0134ecd82f 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -2480,7 +2480,7 @@ static int pl011_console_match(struct console *co, char *name, int idx,
> continue;
>
> co->index = i;
> - port->cons = co;
> + uart_port_set_cons(port, co);
> return pl011_console_setup(co, options);
> }
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 9a18d0b95a41..61c7e1268957 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -3168,8 +3168,15 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
> state->uart_port = uport;
> uport->state = state;
>
> + /*
> + * If this port is in use as a console then the spinlock is already
> + * initialised.
> + */
> + if (!uart_console_registered(uport))
> + uart_port_spin_lock_init(uport);
> +
> state->pm_state = UART_PM_STATE_UNDEFINED;
> - uport->cons = drv->cons;
> + uart_port_set_cons(uport, drv->cons);
> uport->minor = drv->tty_driver->minor_start + uport->line;
> uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
> drv->tty_driver->name_base + uport->line);
> @@ -3178,13 +3185,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
> goto out;
> }
>
> - /*
> - * If this port is in use as a console then the spinlock is already
> - * initialised.
> - */
> - if (!uart_console_registered(uport))
> - uart_port_spin_lock_init(uport);
> -
> if (uport->cons && uport->dev)
> of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
>
> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
> index 8872cd21e70a..2cf03ff2056a 100644
> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -608,6 +608,23 @@ static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned
> spin_unlock_irqrestore(&up->lock, flags);
> }
>
> +/**
> + * uart_port_set_cons - Safely set the @cons field for a uart
> + * @up: The uart port to set
> + * @con: The new console to set to
> + *
> + * This function must be used to set @up->cons. It uses the port lock to
> + * synchronize with the port lock wrappers in order to ensure that the console
> + * cannot change or disappear while another context is holding the port lock.
> + */
> +static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
> +{
> + unsigned long flags;
> +
> + __uart_port_lock_irqsave(up, &flags);
> + up->cons = con;
> + __uart_port_unlock_irqrestore(up, flags);
> +}
> /**
> * uart_port_lock - Lock the UART port
> * @up: Pointer to UART port structure
>
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 29/35] printk: Coordinate direct printing in panic
2024-08-20 6:29 ` [PATCH printk v8 29/35] printk: Coordinate direct printing in panic John Ogness
@ 2024-08-20 15:21 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: Petr Mladek @ 2024-08-20 15:21 UTC (permalink / raw)
To: John Ogness
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Andrew Morton, Jani Nikula, Greg Kroah-Hartman, Ryo Takakura,
Joel Granados, Lukas Wunner, Uros Bizjak
On Tue 2024-08-20 08:35:55, John Ogness wrote:
> If legacy and nbcon consoles are registered and the nbcon
> consoles are allowed to flush (i.e. no boot consoles
> registered), the legacy consoles will no longer perform
> direct printing on the panic CPU until after the backtrace
> has been stored. This will give the safe nbcon consoles a
> chance to print the panic messages before allowing the
> unsafe legacy consoles to print.
>
> If no nbcon consoles are registered or they are not allowed
> to flush because boot consoles are registered, there is no
> change in behavior (i.e. legacy consoles will always attempt
> to print from the printk() caller context).
>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Best Regards,
Petr
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls
2024-08-20 6:30 ` [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls John Ogness
@ 2024-08-20 17:48 ` Paul E. McKenney
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: Paul E. McKenney @ 2024-08-20 17:48 UTC (permalink / raw)
To: John Ogness
Cc: Petr Mladek, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Joel Fernandes, Josh Triplett, Boqun Feng, Uladzislau Rezki,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu
On Tue, Aug 20, 2024 at 08:36:00AM +0206, John Ogness wrote:
> Mark emergency sections wherever multiple lines of
> rcu stall information are generated. In an emergency
> section, every printk() call will attempt to directly
> flush to the consoles using the EMERGENCY priority.
>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
I am guessing that this should go with the rest of this series, so:
Acked-by: Paul E. McKenney <paulmck@kernel.org>
> ---
> kernel/rcu/tree_exp.h | 7 +++++++
> kernel/rcu/tree_stall.h | 9 +++++++++
> 2 files changed, 16 insertions(+)
>
> diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
> index 4acd29d16fdb..f6b35a0585a8 100644
> --- a/kernel/rcu/tree_exp.h
> +++ b/kernel/rcu/tree_exp.h
> @@ -7,6 +7,7 @@
> * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
> */
>
> +#include <linux/console.h>
> #include <linux/lockdep.h>
>
> static void rcu_exp_handler(void *unused);
> @@ -590,6 +591,9 @@ static void synchronize_rcu_expedited_wait(void)
> return;
> if (rcu_stall_is_suppressed())
> continue;
> +
> + nbcon_cpu_emergency_enter();
> +
> j = jiffies;
> rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_EXP, (void *)(j - jiffies_start));
> trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
> @@ -643,6 +647,9 @@ static void synchronize_rcu_expedited_wait(void)
> rcu_exp_print_detail_task_stall_rnp(rnp);
> }
> jiffies_stall = 3 * rcu_exp_jiffies_till_stall_check() + 3;
> +
> + nbcon_cpu_emergency_exit();
> +
> panic_on_rcu_stall();
> }
> }
> diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
> index 4b0e9d7c4c68..b3a6943127bc 100644
> --- a/kernel/rcu/tree_stall.h
> +++ b/kernel/rcu/tree_stall.h
> @@ -7,6 +7,7 @@
> * Author: Paul E. McKenney <paulmck@linux.ibm.com>
> */
>
> +#include <linux/console.h>
> #include <linux/kvm_para.h>
> #include <linux/rcu_notifier.h>
>
> @@ -605,6 +606,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
> if (rcu_stall_is_suppressed())
> return;
>
> + nbcon_cpu_emergency_enter();
> +
> /*
> * OK, time to rat on our buddy...
> * See Documentation/RCU/stallwarn.rst for info on how to debug
> @@ -657,6 +660,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
> rcu_check_gp_kthread_expired_fqs_timer();
> rcu_check_gp_kthread_starvation();
>
> + nbcon_cpu_emergency_exit();
> +
> panic_on_rcu_stall();
>
> rcu_force_quiescent_state(); /* Kick them all. */
> @@ -677,6 +682,8 @@ static void print_cpu_stall(unsigned long gps)
> if (rcu_stall_is_suppressed())
> return;
>
> + nbcon_cpu_emergency_enter();
> +
> /*
> * OK, time to rat on ourselves...
> * See Documentation/RCU/stallwarn.rst for info on how to debug
> @@ -706,6 +713,8 @@ static void print_cpu_stall(unsigned long gps)
> jiffies + 3 * rcu_jiffies_till_stall_check() + 3);
> raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
>
> + nbcon_cpu_emergency_exit();
> +
> panic_on_rcu_stall();
>
> /*
> --
> 2.39.2
>
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 01/35] printk: Add notation to console_srcu locking
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
@ 2024-08-20 17:49 ` Paul E. McKenney
2024-09-09 17:28 ` [tip: sched/rt] " tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: Paul E. McKenney @ 2024-08-20 17:49 UTC (permalink / raw)
To: John Ogness
Cc: Petr Mladek, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
linux-kernel, Miguel Ojeda
On Tue, Aug 20, 2024 at 08:35:27AM +0206, John Ogness wrote:
> kernel/printk/printk.c:284:5: sparse: sparse: context imbalance in
> 'console_srcu_read_lock' - wrong count at exit
> include/linux/srcu.h:301:9: sparse: sparse: context imbalance in
> 'console_srcu_read_unlock' - unexpected unlock
>
> Fixes: 6c4afa79147e ("printk: Prepare for SRCU console list protection")
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
> ---
> kernel/printk/printk.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index c22b07049c38..93c67eb7ca9e 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -282,6 +282,7 @@ EXPORT_SYMBOL(console_list_unlock);
> * Return: A cookie to pass to console_srcu_read_unlock().
> */
> int console_srcu_read_lock(void)
> + __acquires(&console_srcu)
> {
> return srcu_read_lock_nmisafe(&console_srcu);
> }
> @@ -295,6 +296,7 @@ EXPORT_SYMBOL(console_srcu_read_lock);
> * Counterpart to console_srcu_read_lock()
> */
> void console_srcu_read_unlock(int cookie)
> + __releases(&console_srcu)
> {
> srcu_read_unlock_nmisafe(&console_srcu, cookie);
> }
> --
> 2.39.2
>
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 30/35] printk: Add helper for flush type logic
2024-08-20 6:29 ` [PATCH printk v8 30/35] printk: Add helper for flush type logic John Ogness
@ 2024-08-21 9:11 ` Petr Mladek
2024-08-23 5:25 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
1 sibling, 1 reply; 84+ messages in thread
From: Petr Mladek @ 2024-08-21 9:11 UTC (permalink / raw)
To: John Ogness
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
On Tue 2024-08-20 08:35:56, John Ogness wrote:
> There are many call sites where console flushing occur.
> Depending on the system state and types of consoles, the flush
> methods to use are different. A flush call site generally must
> consider:
>
> @have_boot_console
> @have_nbcon_console
> @have_legacy_console
> @legacy_allow_panic_sync
> is_printk_preferred()
>
> and take into account the current CPU state:
>
> NBCON_PRIO_NORMAL
> NBCON_PRIO_EMERGENCY
> NBCON_PRIO_PANIC
>
> in order to decide if it should:
>
> flush nbcon directly via atomic_write() callback
> flush legacy directly via console_unlock
> flush legacy via offload to irq_work
>
> All of these call sites use their own logic to make this
> decision, which is complicated and error prone. Especially
> later when two more flush methods will be introduced:
>
> flush nbcon via offload to kthread
> flush legacy via offload to kthread
>
> Introduce a new internal struct console_flush_type that
> specifies the flush method(s) that are available for a
> particular call site to use.
The function behaves a bit different in this version of the patch.
The paragraph should be updated according the current description
of the function:
<proposal>
Introduce a new internal struct console_flush_type that specifies which
which console flushing methods should be used in the context of
the caller.
</proposal>
> Introduce a helper function to fill out console_flush_type to
> be used for flushing call sites.
>
> Replace the logic of all flushing call sites to use the new
> helper.
I would add:
<proposal>
This change standardizes behavior, leading to both fixes and optimizations
across various call sites. For instance, in console_cpu_notify(), the new
logic ensures that nbcon consoles are flushed when they aren’t managed
by the legacy loop. Similarly, in console_flush_on_panic(), the system
no longer needs to flush nbcon consoles if none are present.
</proposal>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
With the above changes:
Reviewed-by: Petr Mladek <pmladek@suse.com>
Best Regards,
Petr
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 00/35] wire up write_atomic() printing
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
` (34 preceding siblings ...)
2024-08-20 6:30 ` [PATCH printk v8 35/35] lockdep: Mark emergency sections in lockdep splats John Ogness
@ 2024-08-21 9:21 ` Petr Mladek
2024-08-21 9:28 ` Sebastian Andrzej Siewior
35 siblings, 1 reply; 84+ messages in thread
From: Petr Mladek @ 2024-08-21 9:21 UTC (permalink / raw)
To: John Ogness
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Miguel Ojeda, Paul E. McKenney, Greg Kroah-Hartman, Jiri Slaby,
linux-serial, Russell King, Tony Lindgren, Andy Shevchenko,
Geert Uytterhoeven, Arnd Bergmann, Uwe Kleine-König,
Théo Lebrun, Linus Walleij, Lino Sanfilippo,
Ilpo Järvinen, Konrad Dybcio, Sebastian Andrzej Siewior,
Andrew Morton, Jani Nikula, Ryo Takakura, Uros Bizjak,
Joel Granados, Lukas Wunner, Feng Tang, Baoquan He,
Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Mathieu Desnoyers,
Lai Jiangshan, Zqiang, rcu, Peter Zijlstra, Ingo Molnar,
Will Deacon, Waiman Long
On Tue 2024-08-20 08:35:26, John Ogness wrote:
> Hi,
>
> This is v8 of a series to wire up the nbcon consoles so that
> they actually perform printing using their write_atomic()
> callback. v7 is here [0]. For information about the motivation
> of the atomic consoles, please read the cover letter of v1 [1].
>
> The main focus of this series:
>
> - For nbcon consoles, always call write_atomic() directly from
> printk() caller context for the panic CPU.
>
> - For nbcon consoles, call write_atomic() when unlocking the
> console lock.
>
> - Only perform the console lock/unlock dance if legacy or boot
> consoles are registered.
>
> - For legacy consoles, if nbcon consoles are registered, do not
> attempt to print from printk() caller context for the panic
> CPU until nbcon consoles have had a chance to print the most
> significant messages.
>
> - Mark emergency sections. In these sections, every printk()
> call will attempt to directly flush to the consoles using the
> EMERGENCY priority.
>
> This series does _not_ include threaded printing or nbcon
> drivers. Those features will be added in separate follow-up
> series.
The series seems to be ready for linux-next from my POV.
I am going to push it there once I get approval from John about
the proposed update of the commit message for the 30th patch,
see https://lore.kernel.org/r/ZsWvRETyuh1Yq80j@pathway.suse.cz
Best Regards,
Petr
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 00/35] wire up write_atomic() printing
2024-08-21 9:21 ` [PATCH printk v8 00/35] wire up write_atomic() printing Petr Mladek
@ 2024-08-21 9:28 ` Sebastian Andrzej Siewior
2024-08-21 14:09 ` Petr Mladek
0 siblings, 1 reply; 84+ messages in thread
From: Sebastian Andrzej Siewior @ 2024-08-21 9:28 UTC (permalink / raw)
To: Petr Mladek
Cc: John Ogness, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
linux-kernel, Miguel Ojeda, Paul E. McKenney, Greg Kroah-Hartman,
Jiri Slaby, linux-serial, Russell King, Tony Lindgren,
Andy Shevchenko, Geert Uytterhoeven, Arnd Bergmann,
Uwe Kleine-König, Théo Lebrun, Linus Walleij,
Lino Sanfilippo, Ilpo Järvinen, Konrad Dybcio, Andrew Morton,
Jani Nikula, Ryo Takakura, Uros Bizjak, Joel Granados,
Lukas Wunner, Feng Tang, Baoquan He, Frederic Weisbecker,
Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Boqun Feng,
Uladzislau Rezki, Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu,
Peter Zijlstra, Ingo Molnar, Will Deacon, Waiman Long
On 2024-08-21 11:21:41 [+0200], Petr Mladek wrote:
> The series seems to be ready for linux-next from my POV.
>
> I am going to push it there once I get approval from John about
> the proposed update of the commit message for the 30th patch,
> see https://lore.kernel.org/r/ZsWvRETyuh1Yq80j@pathway.suse.cz
If it is just the commit message, couldn't you push it now to next now
and then simply rebase it with an updated commit message?
> Best Regards,
> Petr
Sebastian
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 00/35] wire up write_atomic() printing
2024-08-21 9:28 ` Sebastian Andrzej Siewior
@ 2024-08-21 14:09 ` Petr Mladek
2024-08-21 14:20 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 84+ messages in thread
From: Petr Mladek @ 2024-08-21 14:09 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: John Ogness, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
linux-kernel, Miguel Ojeda, Paul E. McKenney, Greg Kroah-Hartman,
Jiri Slaby, linux-serial, Russell King, Tony Lindgren,
Andy Shevchenko, Geert Uytterhoeven, Arnd Bergmann,
Uwe Kleine-König, Théo Lebrun, Linus Walleij,
Lino Sanfilippo, Ilpo Järvinen, Konrad Dybcio, Andrew Morton,
Jani Nikula, Ryo Takakura, Uros Bizjak, Joel Granados,
Lukas Wunner, Feng Tang, Baoquan He, Frederic Weisbecker,
Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Boqun Feng,
Uladzislau Rezki, Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu,
Peter Zijlstra, Ingo Molnar, Will Deacon, Waiman Long
On Wed 2024-08-21 11:28:41, Sebastian Andrzej Siewior wrote:
> On 2024-08-21 11:21:41 [+0200], Petr Mladek wrote:
> > The series seems to be ready for linux-next from my POV.
> >
> > I am going to push it there once I get approval from John about
> > the proposed update of the commit message for the 30th patch,
> > see https://lore.kernel.org/r/ZsWvRETyuh1Yq80j@pathway.suse.cz
>
> If it is just the commit message, couldn't you push it now to next now
> and then simply rebase it with an updated commit message?
I see. It seems that John has vacation and can't respond quickly.
OK, I have pushed the patchset into printk/linux.git,
branch rework/write_atomic. It should appear in
the next rebase of linux-next.
Best Regards,
Petr
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 00/35] wire up write_atomic() printing
2024-08-21 14:09 ` Petr Mladek
@ 2024-08-21 14:20 ` Sebastian Andrzej Siewior
0 siblings, 0 replies; 84+ messages in thread
From: Sebastian Andrzej Siewior @ 2024-08-21 14:20 UTC (permalink / raw)
To: Petr Mladek
Cc: John Ogness, Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner,
linux-kernel, Miguel Ojeda, Paul E. McKenney, Greg Kroah-Hartman,
Jiri Slaby, linux-serial, Russell King, Tony Lindgren,
Andy Shevchenko, Geert Uytterhoeven, Arnd Bergmann,
Uwe Kleine-König, Théo Lebrun, Linus Walleij,
Lino Sanfilippo, Ilpo Järvinen, Konrad Dybcio, Andrew Morton,
Jani Nikula, Ryo Takakura, Uros Bizjak, Joel Granados,
Lukas Wunner, Feng Tang, Baoquan He, Frederic Weisbecker,
Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Boqun Feng,
Uladzislau Rezki, Mathieu Desnoyers, Lai Jiangshan, Zqiang, rcu,
Peter Zijlstra, Ingo Molnar, Will Deacon, Waiman Long
On 2024-08-21 16:09:59 [+0200], Petr Mladek wrote:
> I see. It seems that John has vacation and can't respond quickly.
>
> OK, I have pushed the patchset into printk/linux.git,
> branch rework/write_atomic. It should appear in
> the next rebase of linux-next.
Thank you.
> Best Regards,
> Petr
Sebastian
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 30/35] printk: Add helper for flush type logic
2024-08-21 9:11 ` Petr Mladek
@ 2024-08-23 5:25 ` John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: John Ogness @ 2024-08-23 5:25 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel
On 2024-08-21, Petr Mladek <pmladek@suse.com> wrote:
> <proposal>
> Introduce a new internal struct console_flush_type that specifies which
> which console flushing methods should be used in the context of
> the caller.
> </proposal>
>
>> Introduce a helper function to fill out console_flush_type to
>> be used for flushing call sites.
>>
>> Replace the logic of all flushing call sites to use the new
>> helper.
>
> I would add:
>
> <proposal>
> This change standardizes behavior, leading to both fixes and optimizations
> across various call sites. For instance, in console_cpu_notify(), the new
> logic ensures that nbcon consoles are flushed when they aren’t managed
> by the legacy loop. Similarly, in console_flush_on_panic(), the system
> no longer needs to flush nbcon consoles if none are present.
> </proposal>
Sure. It is a nice addition of details. Thanks.
John
^ permalink raw reply [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections
2024-08-20 6:29 ` [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections John Ogness
@ 2024-08-27 14:19 ` John Ogness
2024-09-04 10:34 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Use raw_cpu_ptr() instead of open coding tip-bot2 for John Ogness
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Implement emergency sections tip-bot2 for Thomas Gleixner
1 sibling, 2 replies; 84+ messages in thread
From: John Ogness @ 2024-08-27 14:19 UTC (permalink / raw)
To: Petr Mladek
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman, Sebastian Siewior
Hi Petr,
On 2024-08-20, John Ogness <john.ogness@linutronix.de> wrote:
> +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;
> +
> + /* Open code this_cpu_ptr() without checking migration. */
> + return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
> +}
It was pointed out to me that raw_cpu_ptr() exists exactly for this
purpose. There is no need to open code it. Perhaps you can fold the
following patch into this one for linux-next?
John
------------8<--------------
From fe50e9646c44360d88749c2c24c109405b27ad9e Mon Sep 17 00:00:00 2001
From: John Ogness <john.ogness@linutronix.de>
Date: Tue, 27 Aug 2024 14:06:19 +0000
Subject: [PATCH] printk: nbcon: Use raw_cpu_ptr() instead of open coding
There is no need to open code a non-migration-checking
this_cpu_ptr(). That is exactly what raw_cpu_ptr() is.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
kernel/printk/nbcon.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 92ac5c590927..cf62f675c673 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -998,8 +998,7 @@ static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
if (!printk_percpu_data_ready())
return &early_nbcon_pcpu_emergency_nesting;
- /* Open code this_cpu_ptr() without checking migration. */
- return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
+ return raw_cpu_ptr(&nbcon_pcpu_emergency_nesting);
}
/**
--
2.30.2
^ permalink raw reply related [flat|nested] 84+ messages in thread
* Re: [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections
2024-08-27 14:19 ` John Ogness
@ 2024-09-04 10:34 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Use raw_cpu_ptr() instead of open coding tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: Petr Mladek @ 2024-09-04 10:34 UTC (permalink / raw)
To: John Ogness
Cc: Sergey Senozhatsky, Steven Rostedt, Thomas Gleixner, linux-kernel,
Greg Kroah-Hartman, Sebastian Siewior
On Tue 2024-08-27 16:25:31, John Ogness wrote:
> Hi Petr,
>
> On 2024-08-20, John Ogness <john.ogness@linutronix.de> wrote:
> > +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;
> > +
> > + /* Open code this_cpu_ptr() without checking migration. */
> > + return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
> > +}
>
> It was pointed out to me that raw_cpu_ptr() exists exactly for this
> purpose. There is no need to open code it.
Good to know!
> ------------8<--------------
> >From fe50e9646c44360d88749c2c24c109405b27ad9e Mon Sep 17 00:00:00 2001
> From: John Ogness <john.ogness@linutronix.de>
> Date: Tue, 27 Aug 2024 14:06:19 +0000
> Subject: [PATCH] printk: nbcon: Use raw_cpu_ptr() instead of open coding
>
> There is no need to open code a non-migration-checking
> this_cpu_ptr(). That is exactly what raw_cpu_ptr() is.
>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
I wanted to avoid rebase when it was not really necessary. So, I have
committed the patch into printk/linux.git, branch rework/write_atomic
on top of the existing patches.
Best Regards,
Petr
^ permalink raw reply [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Use raw_cpu_ptr() instead of open coding
2024-08-27 14:19 ` John Ogness
2024-09-04 10:34 ` Petr Mladek
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: d33d5e683b0d3b4f5fc6a49ce17583f8ca663944
Gitweb: https://git.kernel.org/tip/d33d5e683b0d3b4f5fc6a49ce17583f8ca663944
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 27 Aug 2024 16:25:31 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 04 Sep 2024 12:28:25 +02:00
printk: nbcon: Use raw_cpu_ptr() instead of open coding
There is no need to open code a non-migration-checking
this_cpu_ptr(). That is exactly what raw_cpu_ptr() is.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/87plpum4jw.fsf@jogness.linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/nbcon.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 92ac5c5..cf62f67 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -998,8 +998,7 @@ static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
if (!printk_percpu_data_ready())
return &early_nbcon_pcpu_emergency_nesting;
- /* Open code this_cpu_ptr() without checking migration. */
- return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
+ return raw_cpu_ptr(&nbcon_pcpu_emergency_nesting);
}
/**
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] panic: Mark emergency section in oops
2024-08-20 6:29 ` [PATCH printk v8 33/35] panic: Mark emergency section in oops John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 4bdfa0d8e920c391e6cc0aa1feef8ed91d81f724
Gitweb: https://git.kernel.org/tip/4bdfa0d8e920c391e6cc0aa1feef8ed91d81f724
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:59 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 15:03:04 +02:00
panic: Mark emergency section in oops
Mark an emergency section beginning with oops_enter() until the
end of oops_exit(). In this section, every printk() call will
attempt to directly flush to the consoles using the EMERGENCY
priority.
The very end of oops_exit() performs a kmsg_dump(). This is not
included in the emergency section because it is another
flushing mechanism that should occur after the consoles have
flushed the oops messages.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-34-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/panic.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/panic.c b/kernel/panic.c
index 1a10b6e..753d12f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -685,6 +685,7 @@ bool oops_may_print(void)
*/
void oops_enter(void)
{
+ nbcon_cpu_emergency_enter();
tracing_off();
/* can't trust the integrity of the kernel anymore: */
debug_locks_off();
@@ -707,6 +708,7 @@ void oops_exit(void)
{
do_oops_enter_exit();
print_oops_end_marker();
+ nbcon_cpu_emergency_exit();
kmsg_dump(KMSG_DUMP_OOPS);
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] rcu: Mark emergency sections in rcu stalls
2024-08-20 6:30 ` [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls John Ogness
2024-08-20 17:48 ` Paul E. McKenney
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Petr Mladek, Paul E. McKenney, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 8c03273a509c88b12c53a9ddf07702f83983e4de
Gitweb: https://git.kernel.org/tip/8c03273a509c88b12c53a9ddf07702f83983e4de
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:36:00 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 15:03:04 +02:00
rcu: Mark emergency sections in rcu stalls
Mark emergency sections wherever multiple lines of
rcu stall information are generated. In an emergency
section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20240820063001.36405-35-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/rcu/tree_exp.h | 7 +++++++
kernel/rcu/tree_stall.h | 9 +++++++++
2 files changed, 16 insertions(+)
diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index 4acd29d..f6b35a0 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -7,6 +7,7 @@
* Authors: Paul E. McKenney <paulmck@linux.ibm.com>
*/
+#include <linux/console.h>
#include <linux/lockdep.h>
static void rcu_exp_handler(void *unused);
@@ -590,6 +591,9 @@ static void synchronize_rcu_expedited_wait(void)
return;
if (rcu_stall_is_suppressed())
continue;
+
+ nbcon_cpu_emergency_enter();
+
j = jiffies;
rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_EXP, (void *)(j - jiffies_start));
trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
@@ -643,6 +647,9 @@ static void synchronize_rcu_expedited_wait(void)
rcu_exp_print_detail_task_stall_rnp(rnp);
}
jiffies_stall = 3 * rcu_exp_jiffies_till_stall_check() + 3;
+
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
}
}
diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
index 4b0e9d7..b3a6943 100644
--- a/kernel/rcu/tree_stall.h
+++ b/kernel/rcu/tree_stall.h
@@ -7,6 +7,7 @@
* Author: Paul E. McKenney <paulmck@linux.ibm.com>
*/
+#include <linux/console.h>
#include <linux/kvm_para.h>
#include <linux/rcu_notifier.h>
@@ -605,6 +606,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
if (rcu_stall_is_suppressed())
return;
+ nbcon_cpu_emergency_enter();
+
/*
* OK, time to rat on our buddy...
* See Documentation/RCU/stallwarn.rst for info on how to debug
@@ -657,6 +660,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
rcu_check_gp_kthread_expired_fqs_timer();
rcu_check_gp_kthread_starvation();
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
rcu_force_quiescent_state(); /* Kick them all. */
@@ -677,6 +682,8 @@ static void print_cpu_stall(unsigned long gps)
if (rcu_stall_is_suppressed())
return;
+ nbcon_cpu_emergency_enter();
+
/*
* OK, time to rat on ourselves...
* See Documentation/RCU/stallwarn.rst for info on how to debug
@@ -706,6 +713,8 @@ static void print_cpu_stall(unsigned long gps)
jiffies + 3 * rcu_jiffies_till_stall_check() + 3);
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+ nbcon_cpu_emergency_exit();
+
panic_on_rcu_stall();
/*
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] lockdep: Mark emergency sections in lockdep splats
2024-08-20 6:30 ` [PATCH printk v8 35/35] lockdep: Mark emergency sections in lockdep splats John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 59cd94ef80094857f0d0085daa2e32badc4cddf4
Gitweb: https://git.kernel.org/tip/59cd94ef80094857f0d0085daa2e32badc4cddf4
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:36:01 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 15:03:04 +02:00
lockdep: Mark emergency sections in lockdep splats
Mark emergency sections wherever multiple lines of
lock debugging output are generated. In an emergency
section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
Note that debug_show_all_locks() and
lockdep_print_held_locks() rely on their callers to
enter the emergency section. This is because these
functions can also be called in non-emergency
situations (such as sysrq).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-36-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/locking/lockdep.c | 83 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 81 insertions(+), 2 deletions(-)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 0349f95..7963dea 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -56,6 +56,7 @@
#include <linux/kprobes.h>
#include <linux/lockdep.h>
#include <linux/context_tracking.h>
+#include <linux/console.h>
#include <asm/sections.h>
@@ -573,8 +574,10 @@ static struct lock_trace *save_trace(void)
if (!debug_locks_off_graph_unlock())
return NULL;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_STACK_TRACE_ENTRIES too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
@@ -887,11 +890,13 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
instrumentation_begin();
debug_locks_off();
+ nbcon_cpu_emergency_enter();
printk(KERN_ERR
"BUG: looking up invalid subclass: %u\n", subclass);
printk(KERN_ERR
"turning off the locking correctness validator.\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
instrumentation_end();
return NULL;
}
@@ -968,11 +973,13 @@ static bool assign_lock_key(struct lockdep_map *lock)
else {
/* Debug-check: all keys must be persistent! */
debug_locks_off();
+ nbcon_cpu_emergency_enter();
pr_err("INFO: trying to register non-static key.\n");
pr_err("The code is fine but needs lockdep annotation, or maybe\n");
pr_err("you didn't initialize this object before use?\n");
pr_err("turning off the locking correctness validator.\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
return false;
}
@@ -1316,8 +1323,10 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
return NULL;
}
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
nr_lock_classes++;
@@ -1349,11 +1358,13 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
if (verbose(class)) {
graph_unlock();
+ nbcon_cpu_emergency_enter();
printk("\nnew class %px: %s", class->key, class->name);
if (class->name_version > 1)
printk(KERN_CONT "#%d", class->name_version);
printk(KERN_CONT "\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
if (!graph_lock()) {
return NULL;
@@ -1392,8 +1403,10 @@ static struct lock_list *alloc_list_entry(void)
if (!debug_locks_off_graph_unlock())
return NULL;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_ENTRIES too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return NULL;
}
nr_list_entries++;
@@ -2039,6 +2052,8 @@ static noinline void print_circular_bug(struct lock_list *this,
depth = get_lock_depth(target);
+ nbcon_cpu_emergency_enter();
+
print_circular_bug_header(target, depth, check_src, check_tgt);
parent = get_lock_parent(target);
@@ -2057,6 +2072,8 @@ static noinline void print_circular_bug(struct lock_list *this,
printk("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static noinline void print_bfs_bug(int ret)
@@ -2569,6 +2586,8 @@ print_bad_irq_dependency(struct task_struct *curr,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=====================================================\n");
pr_warn("WARNING: %s-safe -> %s-unsafe lock order detected\n",
@@ -2618,11 +2637,13 @@ print_bad_irq_dependency(struct task_struct *curr,
pr_warn(" and %s-irq-unsafe lock:\n", irqclass);
next_root->trace = save_trace();
if (!next_root->trace)
- return;
+ goto out;
print_shortest_lock_dependencies(forwards_entry, next_root);
pr_warn("\nstack backtrace:\n");
dump_stack();
+out:
+ nbcon_cpu_emergency_exit();
}
static const char *state_names[] = {
@@ -2987,6 +3008,8 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("============================================\n");
pr_warn("WARNING: possible recursive locking detected\n");
@@ -3009,6 +3032,8 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
/*
@@ -3606,6 +3631,8 @@ static void print_collision(struct task_struct *curr,
struct held_lock *hlock_next,
struct lock_chain *chain)
{
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("============================\n");
pr_warn("WARNING: chain_key collision\n");
@@ -3622,6 +3649,8 @@ static void print_collision(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
#endif
@@ -3712,8 +3741,10 @@ static inline int add_chain_cache(struct task_struct *curr,
if (!debug_locks_off_graph_unlock())
return 0;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
chain->chain_key = chain_key;
@@ -3730,8 +3761,10 @@ static inline int add_chain_cache(struct task_struct *curr,
if (!debug_locks_off_graph_unlock())
return 0;
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low!");
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
@@ -3970,6 +4003,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
if (!debug_locks_off() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("================================\n");
pr_warn("WARNING: inconsistent lock state\n");
@@ -3998,6 +4033,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
/*
@@ -4032,6 +4069,8 @@ print_irq_inversion_bug(struct task_struct *curr,
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("========================================================\n");
pr_warn("WARNING: possible irq lock inversion dependency detected\n");
@@ -4072,11 +4111,13 @@ print_irq_inversion_bug(struct task_struct *curr,
pr_warn("\nthe shortest dependencies between 2nd lock and 1st lock:\n");
root->trace = save_trace();
if (!root->trace)
- return;
+ goto out;
print_shortest_lock_dependencies(other, root);
pr_warn("\nstack backtrace:\n");
dump_stack();
+out:
+ nbcon_cpu_emergency_exit();
}
/*
@@ -4153,6 +4194,8 @@ void print_irqtrace_events(struct task_struct *curr)
{
const struct irqtrace_events *trace = &curr->irqtrace;
+ nbcon_cpu_emergency_enter();
+
printk("irq event stamp: %u\n", trace->irq_events);
printk("hardirqs last enabled at (%u): [<%px>] %pS\n",
trace->hardirq_enable_event, (void *)trace->hardirq_enable_ip,
@@ -4166,6 +4209,8 @@ void print_irqtrace_events(struct task_struct *curr)
printk("softirqs last disabled at (%u): [<%px>] %pS\n",
trace->softirq_disable_event, (void *)trace->softirq_disable_ip,
(void *)trace->softirq_disable_ip);
+
+ nbcon_cpu_emergency_exit();
}
static int HARDIRQ_verbose(struct lock_class *class)
@@ -4686,10 +4731,12 @@ unlock:
* We must printk outside of the graph_lock:
*/
if (ret == 2) {
+ nbcon_cpu_emergency_enter();
printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
print_lock(this);
print_irqtrace_events(curr);
dump_stack();
+ nbcon_cpu_emergency_exit();
}
return ret;
@@ -4730,6 +4777,8 @@ print_lock_invalid_wait_context(struct task_struct *curr,
if (debug_locks_silent)
return 0;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=============================\n");
pr_warn("[ BUG: Invalid wait context ]\n");
@@ -4749,6 +4798,8 @@ print_lock_invalid_wait_context(struct task_struct *curr,
pr_warn("stack backtrace:\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
+
return 0;
}
@@ -4956,6 +5007,8 @@ print_lock_nested_lock_not_held(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("==================================\n");
pr_warn("WARNING: Nested lock was not taken\n");
@@ -4976,6 +5029,8 @@ print_lock_nested_lock_not_held(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static int __lock_is_held(const struct lockdep_map *lock, int read);
@@ -5024,11 +5079,13 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
debug_class_ops_inc(class);
if (very_verbose(class)) {
+ nbcon_cpu_emergency_enter();
printk("\nacquire class [%px] %s", class->key, class->name);
if (class->name_version > 1)
printk(KERN_CONT "#%d", class->name_version);
printk(KERN_CONT "\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
}
/*
@@ -5155,6 +5212,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
#endif
if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
debug_locks_off();
+ nbcon_cpu_emergency_enter();
print_lockdep_off("BUG: MAX_LOCK_DEPTH too low!");
printk(KERN_DEBUG "depth: %i max: %lu!\n",
curr->lockdep_depth, MAX_LOCK_DEPTH);
@@ -5162,6 +5220,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
lockdep_print_held_locks(current);
debug_show_all_locks();
dump_stack();
+ nbcon_cpu_emergency_exit();
return 0;
}
@@ -5181,6 +5240,8 @@ static void print_unlock_imbalance_bug(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=====================================\n");
pr_warn("WARNING: bad unlock balance detected!\n");
@@ -5197,6 +5258,8 @@ static void print_unlock_imbalance_bug(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static noinstr int match_held_lock(const struct held_lock *hlock,
@@ -5901,6 +5964,8 @@ static void print_lock_contention_bug(struct task_struct *curr,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=================================\n");
pr_warn("WARNING: bad contention detected!\n");
@@ -5917,6 +5982,8 @@ static void print_lock_contention_bug(struct task_struct *curr,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static void
@@ -6536,6 +6603,8 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("=========================\n");
pr_warn("WARNING: held lock freed!\n");
@@ -6548,6 +6617,8 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
static inline int not_in_range(const void* mem_from, unsigned long mem_len,
@@ -6594,6 +6665,8 @@ static void print_held_locks_bug(void)
if (debug_locks_silent)
return;
+ nbcon_cpu_emergency_enter();
+
pr_warn("\n");
pr_warn("====================================\n");
pr_warn("WARNING: %s/%d still has locks held!\n",
@@ -6603,6 +6676,8 @@ static void print_held_locks_bug(void)
lockdep_print_held_locks(current);
pr_warn("\nstack backtrace:\n");
dump_stack();
+
+ nbcon_cpu_emergency_exit();
}
void debug_check_no_locks_held(void)
@@ -6660,6 +6735,7 @@ asmlinkage __visible void lockdep_sys_exit(void)
if (unlikely(curr->lockdep_depth)) {
if (!debug_locks_off())
return;
+ nbcon_cpu_emergency_enter();
pr_warn("\n");
pr_warn("================================================\n");
pr_warn("WARNING: lock held when returning to user space!\n");
@@ -6668,6 +6744,7 @@ asmlinkage __visible void lockdep_sys_exit(void)
pr_warn("%s/%d is leaving the kernel with locks still held!\n",
curr->comm, curr->pid);
lockdep_print_held_locks(curr);
+ nbcon_cpu_emergency_exit();
}
/*
@@ -6684,6 +6761,7 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
bool rcu = warn_rcu_enter();
/* Note: the following can be executed concurrently, so be careful. */
+ nbcon_cpu_emergency_enter();
pr_warn("\n");
pr_warn("=============================\n");
pr_warn("WARNING: suspicious RCU usage\n");
@@ -6722,6 +6800,7 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
lockdep_print_held_locks(curr);
pr_warn("\nstack backtrace:\n");
dump_stack();
+ nbcon_cpu_emergency_exit();
warn_rcu_exit(rcu);
}
EXPORT_SYMBOL_GPL(lockdep_rcu_suspicious);
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Implement emergency sections
2024-08-20 6:29 ` [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections John Ogness
2024-08-27 14:19 ` John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for Thomas Gleixner
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Thomas Gleixner (Intel), Petr Mladek, x86,
linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: ecb5e1aa82c86642ec1eaafefd4e317dfba3a238
Gitweb: https://git.kernel.org/tip/ecb5e1aa82c86642ec1eaafefd4e317dfba3a238
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:57 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 15:03:04 +02:00
printk: nbcon: Implement emergency sections
In emergency situations (something has gone wrong but the
system continues to operate), usually important information
(such as a backtrace) is generated via printk(). This
information should be pushed out to the consoles ASAP.
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.
Perform direct console flushing at the emergency priority if
the current CPU is in an emergency state and it is safe to do
so.
Note that the emergency state is not system-wide. While one CPU
is in an emergency state, another CPU may attempt to print
console messages at normal priority.
Also note that printk() already attempts to flush consoles in
the caller context for normal priority. However, follow-up
changes will introduce printing kthreads, in which case the
normal priority printk() calls will offload to the kthreads.
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>
Link: https://lore.kernel.org/r/20240820063001.36405-32-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 4 ++-
kernel/printk/internal.h | 1 +-
kernel/printk/nbcon.c | 75 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 3706f94..9a13f91 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -553,10 +553,14 @@ static inline bool console_is_registered(const struct console *con)
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 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 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; }
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index ba2e0f1..8e36d86 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -182,6 +182,7 @@ static inline void printk_get_console_flush_type(struct console_flush_type *ft)
switch (nbcon_get_default_prio()) {
case NBCON_PRIO_NORMAL:
+ case NBCON_PRIO_EMERGENCY:
if (have_nbcon_console && !have_boot_console)
ft->nbcon_atomic = true;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 18488d6..92ac5c5 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -972,6 +972,36 @@ update_con:
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
+ *
+ * Context: For reading, any context. For writing, any context which could
+ * not be migrated to another CPU.
+ * Return: Either a pointer to the per CPU emergency nesting counter of
+ * the current CPU or to the init data during early boot.
+ *
+ * The function is safe for reading per-CPU variables in any context because
+ * preemption is disabled if the current CPU is in the emergency state. See
+ * also nbcon_cpu_emergency_enter().
+ */
+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;
+
+ /* Open code this_cpu_ptr() without checking migration. */
+ return per_cpu_ptr(&nbcon_pcpu_emergency_nesting, raw_smp_processor_id());
+}
+
/**
* nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
* printing on the current CPU
@@ -981,13 +1011,20 @@ update_con:
* context for printing.
*
* The function is safe for reading per-CPU data in any context because
- * preemption is disabled if the current CPU is in the panic state.
+ * preemption is disabled if the current CPU is in the emergency or panic
+ * state.
*/
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;
}
@@ -1247,6 +1284,42 @@ void nbcon_atomic_flush_unsafe(void)
}
/**
+ * nbcon_cpu_emergency_enter - Enter an emergency section where printk()
+ * messages for that CPU are flushed directly
+ *
+ * Context: Any context. Disables preemption.
+ *
+ * When within an emergency section, printk() calls will attempt to flush any
+ * pending messages in the ringbuffer.
+ */
+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
+ *
+ * Context: Within an emergency section. Enables preemption.
+ */
+void nbcon_cpu_emergency_exit(void)
+{
+ unsigned int *cpu_emergency_nesting;
+
+ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
+
+ if (!WARN_ON_ONCE(*cpu_emergency_nesting == 0))
+ (*cpu_emergency_nesting)--;
+
+ preempt_enable();
+}
+
+/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
*
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Add helper for flush type logic
2024-08-20 6:29 ` [PATCH printk v8 30/35] printk: Add helper for flush type logic John Ogness
2024-08-21 9:11 ` Petr Mladek
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 6690d6b52726bcb2b743466a1833e0b9f049b9d7
Gitweb: https://git.kernel.org/tip/6690d6b52726bcb2b743466a1833e0b9f049b9d7
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:56 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:49 +02:00
printk: Add helper for flush type logic
There are many call sites where console flushing occur.
Depending on the system state and types of consoles, the flush
methods to use are different. A flush call site generally must
consider:
@have_boot_console
@have_nbcon_console
@have_legacy_console
@legacy_allow_panic_sync
is_printk_preferred()
and take into account the current CPU state:
NBCON_PRIO_NORMAL
NBCON_PRIO_EMERGENCY
NBCON_PRIO_PANIC
in order to decide if it should:
flush nbcon directly via atomic_write() callback
flush legacy directly via console_unlock
flush legacy via offload to irq_work
All of these call sites use their own logic to make this
decision, which is complicated and error prone. Especially
later when two more flush methods will be introduced:
flush nbcon via offload to kthread
flush legacy via offload to kthread
Introduce a new internal struct console_flush_type that specifies
which console flushing methods should be used in the context of
the caller.
Introduce a helper function to fill out console_flush_type to
be used for flushing call sites.
Replace the logic of all flushing call sites to use the new
helper.
This change standardizes behavior, leading to both fixes and
optimizations across various call sites. For instance, in
console_cpu_notify(), the new logic ensures that nbcon consoles
are flushed when they aren’t managed by the legacy loop.
Similarly, in console_flush_on_panic(), the system no longer
needs to flush nbcon consoles if none are present.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-31-john.ogness@linutronix.de
[pmladek@suse.com: Updated the commit message.]
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 73 +++++++++++++++++++++++++++++++++++++++-
kernel/printk/nbcon.c | 12 ++++--
kernel/printk/printk.c | 68 +++++++++++++++---------------------
3 files changed, 112 insertions(+), 41 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 6b61350..ba2e0f1 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -154,8 +154,81 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
+extern bool have_nbcon_console;
+extern bool have_legacy_console;
extern bool legacy_allow_panic_sync;
+/**
+ * struct console_flush_type - Define available console flush methods
+ * @nbcon_atomic: Flush directly using nbcon_atomic() callback
+ * @legacy_direct: Call the legacy loop in this context
+ * @legacy_offload: Offload the legacy loop into IRQ
+ *
+ * Note that the legacy loop also flushes the nbcon consoles.
+ */
+struct console_flush_type {
+ bool nbcon_atomic;
+ bool legacy_direct;
+ bool legacy_offload;
+};
+
+/*
+ * Identify which console flushing methods should be used in the context of
+ * the caller.
+ */
+static inline void printk_get_console_flush_type(struct console_flush_type *ft)
+{
+ memset(ft, 0, sizeof(*ft));
+
+ switch (nbcon_get_default_prio()) {
+ case NBCON_PRIO_NORMAL:
+ if (have_nbcon_console && !have_boot_console)
+ ft->nbcon_atomic = true;
+
+ /* Legacy consoles are flushed directly when possible. */
+ if (have_legacy_console || have_boot_console) {
+ if (!is_printk_legacy_deferred())
+ ft->legacy_direct = true;
+ else
+ ft->legacy_offload = true;
+ }
+ break;
+
+ case NBCON_PRIO_PANIC:
+ /*
+ * In panic, the nbcon consoles will directly print. But
+ * only allowed if there are no boot consoles.
+ */
+ if (have_nbcon_console && !have_boot_console)
+ ft->nbcon_atomic = true;
+
+ if (have_legacy_console || have_boot_console) {
+ /*
+ * This is the same decision as NBCON_PRIO_NORMAL
+ * except that offloading never occurs in panic.
+ *
+ * Note that console_flush_on_panic() will flush
+ * legacy consoles anyway, even if unsafe.
+ */
+ if (!is_printk_legacy_deferred())
+ ft->legacy_direct = true;
+
+ /*
+ * In panic, if nbcon atomic printing occurs,
+ * the legacy consoles must remain silent until
+ * explicitly allowed.
+ */
+ if (ft->nbcon_atomic && !legacy_allow_panic_sync)
+ ft->legacy_direct = false;
+ }
+ break;
+
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
extern struct printk_buffers printk_shared_pbufs;
/**
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index afdb16c..18488d6 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1344,6 +1344,7 @@ EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
void nbcon_device_release(struct console *con)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
+ struct console_flush_type ft;
int cookie;
if (!nbcon_context_exit_unsafe(ctxt))
@@ -1359,12 +1360,17 @@ void nbcon_device_release(struct console *con)
cookie = console_srcu_read_lock();
if (console_is_usable(con, console_srcu_read_flags(con)) &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
- if (!have_boot_console) {
+ /*
+ * If nbcon_atomic flushing is not available, fallback to
+ * using the legacy loop.
+ */
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic) {
__nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
- } else if (!is_printk_legacy_deferred()) {
+ } else if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
- } else {
+ } else if (ft.legacy_offload) {
printk_trigger_flush();
}
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index fc3f897..6accd17 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -468,14 +468,14 @@ 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,
* synchronous printing of legacy consoles will not occur during panic until
* the backtrace has been stored to the ringbuffer.
*/
-static bool have_nbcon_console;
+bool have_nbcon_console;
/*
* Specifies if a boot console is registered. If boot consoles are present,
@@ -488,14 +488,6 @@ bool have_boot_console;
/* See printk_legacy_allow_panic_sync() for details. */
bool legacy_allow_panic_sync;
-/*
- * 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)
-
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -2342,9 +2334,12 @@ out:
*/
void printk_legacy_allow_panic_sync(void)
{
+ struct console_flush_type ft;
+
legacy_allow_panic_sync = true;
- if (printing_via_unlock && !is_printk_legacy_deferred()) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
if (console_trylock())
console_unlock();
}
@@ -2354,8 +2349,7 @@ asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
- bool do_trylock_unlock = printing_via_unlock;
- bool defer_legacy = false;
+ struct console_flush_type ft;
int printed_len;
/* Suppress unimportant messages after panic happens */
@@ -2370,35 +2364,23 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
return 0;
+ printk_get_console_flush_type(&ft);
+
/* If called from the scheduler, we can not call up(). */
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
- defer_legacy = do_trylock_unlock;
- do_trylock_unlock = false;
+ ft.legacy_offload |= ft.legacy_direct;
+ ft.legacy_direct = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
- if (have_nbcon_console && !have_boot_console) {
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
- /*
- * In panic, the legacy consoles are not allowed to print from
- * the printk calling context unless explicitly allowed. This
- * gives the safe nbcon consoles a chance to print out all the
- * panic messages first. This restriction only applies if
- * there are nbcon consoles registered and they are allowed to
- * flush.
- */
- if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
- do_trylock_unlock = false;
- defer_legacy = false;
- }
- }
-
- if (do_trylock_unlock) {
+ if (ft.legacy_direct) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2418,7 +2400,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (defer_legacy)
+ if (ft.legacy_offload)
defer_console_output();
else
wake_up_klogd();
@@ -2777,10 +2759,16 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
- if (!cpuhp_tasks_frozen && printing_via_unlock) {
- /* If trylock fails, someone else is doing the printing */
- if (console_trylock())
- console_unlock();
+ struct console_flush_type ft;
+
+ if (!cpuhp_tasks_frozen) {
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
+ nbcon_atomic_flush_pending();
+ if (ft.legacy_direct) {
+ if (console_trylock())
+ console_unlock();
+ }
}
return 0;
}
@@ -3305,6 +3293,7 @@ static void __console_rewind_all(void)
*/
void console_flush_on_panic(enum con_flush_mode mode)
{
+ struct console_flush_type ft;
bool handover;
u64 next_seq;
@@ -3328,7 +3317,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL)
__console_rewind_all();
- if (!have_boot_console)
+ printk_get_console_flush_type(&ft);
+ if (ft.nbcon_atomic)
nbcon_atomic_flush_pending();
/* Flush legacy consoles once allowed, even when dangerous. */
@@ -3992,6 +3982,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
{
unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
unsigned long remaining_jiffies = timeout_jiffies;
+ struct console_flush_type ft;
struct console *c;
u64 last_diff = 0;
u64 printk_seq;
@@ -4005,7 +3996,8 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
seq = prb_next_reserve_seq(prb);
/* Flush the consoles so that records up to @seq are printed. */
- if (printing_via_unlock) {
+ printk_get_console_flush_type(&ft);
+ if (ft.legacy_direct) {
console_lock();
console_unlock();
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] panic: Mark emergency section in warn
2024-08-20 6:29 ` [PATCH printk v8 32/35] panic: Mark emergency section in warn John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Thomas Gleixner (Intel), Petr Mladek, x86,
linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 4833794db61c8cc4de4563a2754c7aedaffbb684
Gitweb: https://git.kernel.org/tip/4833794db61c8cc4de4563a2754c7aedaffbb684
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:58 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 15:03:04 +02:00
panic: Mark emergency section in warn
Mark the full contents of __warn() as an emergency section. In
this section, every printk() call will attempt to directly
flush to the consoles using the EMERGENCY priority.
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>
Link: https://lore.kernel.org/r/20240820063001.36405-33-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/panic.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/panic.c b/kernel/panic.c
index 93096d5..1a10b6e 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -718,6 +718,8 @@ struct warn_args {
void __warn(const char *file, int line, void *caller, unsigned taint,
struct pt_regs *regs, struct warn_args *args)
{
+ nbcon_cpu_emergency_enter();
+
disable_trace_on_warning();
if (file)
@@ -753,6 +755,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
/* Just a warning, don't kill lockdep. */
add_taint(taint, LOCKDEP_STILL_OK);
+
+ nbcon_cpu_emergency_exit();
}
#ifdef CONFIG_BUG
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Track nbcon consoles
2024-08-20 6:29 ` [PATCH printk v8 28/35] printk: Track nbcon consoles John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: bebd87ae27e052e390c203893c7ee46f54b0bf9e
Gitweb: https://git.kernel.org/tip/bebd87ae27e052e390c203893c7ee46f54b0bf9e
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:54 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:25 +02:00
printk: Track nbcon consoles
Add a global flag @have_nbcon_console to identify if any nbcon
consoles are registered. This will be used in follow-up commits
to preserve legacy behavior when no nbcon consoles are registered.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-29-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b3ddcf3..e30107d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -471,6 +471,11 @@ static DEFINE_MUTEX(syslog_lock);
static bool have_legacy_console;
/*
+ * Specifies if an nbcon console is registered.
+ */
+static bool have_nbcon_console;
+
+/*
* Specifies if a boot console is registered. If boot consoles are present,
* nbcon consoles cannot print simultaneously and must be synchronized by
* the console lock. This is because boot consoles and nbcon consoles may
@@ -3638,6 +3643,7 @@ void register_console(struct console *newcon)
init_seq = get_init_console_seq(newcon, bootcon_registered);
if (newcon->flags & CON_NBCON) {
+ have_nbcon_console = true;
nbcon_seq_force(newcon, init_seq);
} else {
have_legacy_console = true;
@@ -3718,6 +3724,7 @@ static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
bool found_legacy_con = false;
+ bool found_nbcon_con = false;
bool found_boot_con = false;
unsigned long flags;
struct console *c;
@@ -3785,13 +3792,18 @@ static int unregister_console_locked(struct console *console)
for_each_console(c) {
if (c->flags & CON_BOOT)
found_boot_con = true;
- if (!(c->flags & CON_NBCON))
+
+ if (c->flags & CON_NBCON)
+ found_nbcon_con = true;
+ else
found_legacy_con = true;
}
if (!found_boot_con)
have_boot_console = found_boot_con;
if (!found_legacy_con)
have_legacy_console = found_legacy_con;
+ if (!found_nbcon_con)
+ have_nbcon_console = found_nbcon_con;
return res;
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Avoid console_lock dance if no legacy or boot consoles
2024-08-20 6:29 ` [PATCH printk v8 27/35] printk: Avoid console_lock dance if no legacy or boot consoles John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 60013065fdc677df7b71f9a0bac501020e3bbd4f
Gitweb: https://git.kernel.org/tip/60013065fdc677df7b71f9a0bac501020e3bbd4f
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:53 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Avoid console_lock dance if no legacy or boot consoles
Currently the console lock is used to attempt legacy-type
printing even if there are no legacy or boot consoles registered.
If no such consoles are registered, the console lock does not
need to be taken.
Add tracking of legacy console registration and use it with
boot console tracking to avoid unnecessary code paths, i.e.
do not use the console lock if there are no boot consoles
and no legacy consoles.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-28-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c6e6333..b3ddcf3 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -464,6 +464,13 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
static DEFINE_MUTEX(syslog_lock);
/*
+ * Specifies if a legacy console is registered. If legacy consoles are
+ * present, it is necessary to perform the console lock/unlock dance
+ * whenever console flushing should occur.
+ */
+static bool have_legacy_console;
+
+/*
* Specifies if a boot console is registered. If boot consoles are present,
* nbcon consoles cannot print simultaneously and must be synchronized by
* the console lock. This is because boot consoles and nbcon consoles may
@@ -471,6 +478,14 @@ static DEFINE_MUTEX(syslog_lock);
*/
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)
+
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -2339,7 +2354,7 @@ asmlinkage int vprintk_emit(int facility, int level,
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
/* If called from the scheduler, we can not call up(). */
- if (!in_sched) {
+ if (!in_sched && printing_via_unlock) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2359,7 +2374,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (in_sched)
+ if (in_sched && printing_via_unlock)
defer_console_output();
else
wake_up_klogd();
@@ -2718,7 +2733,7 @@ void resume_console(void)
*/
static int console_cpu_notify(unsigned int cpu)
{
- if (!cpuhp_tasks_frozen) {
+ if (!cpuhp_tasks_frozen && printing_via_unlock) {
/* If trylock fails, someone else is doing the printing */
if (console_trylock())
console_unlock();
@@ -3625,6 +3640,7 @@ void register_console(struct console *newcon)
if (newcon->flags & CON_NBCON) {
nbcon_seq_force(newcon, init_seq);
} else {
+ have_legacy_console = true;
newcon->seq = init_seq;
}
@@ -3701,6 +3717,7 @@ EXPORT_SYMBOL(register_console);
static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ bool found_legacy_con = false;
bool found_boot_con = false;
unsigned long flags;
struct console *c;
@@ -3768,9 +3785,13 @@ static int unregister_console_locked(struct console *console)
for_each_console(c) {
if (c->flags & CON_BOOT)
found_boot_con = true;
+ if (!(c->flags & CON_NBCON))
+ found_legacy_con = true;
}
if (!found_boot_con)
have_boot_console = found_boot_con;
+ if (!found_legacy_con)
+ have_legacy_console = found_legacy_con;
return res;
}
@@ -3931,8 +3952,10 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
seq = prb_next_reserve_seq(prb);
/* Flush the consoles so that records up to @seq are printed. */
- console_lock();
- console_unlock();
+ if (printing_via_unlock) {
+ console_lock();
+ console_unlock();
+ }
for (;;) {
unsigned long begin_jiffies;
@@ -3945,6 +3968,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
* console->seq. Releasing console_lock flushes more
* records in case @seq is still not printed on all
* usable consoles.
+ *
+ * Holding the console_lock is not necessary if there
+ * are no legacy or boot consoles. However, such a
+ * console could register at any time. Always hold the
+ * console_lock as a precaution rather than
+ * synchronizing against register_console().
*/
console_lock();
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Coordinate direct printing in panic
2024-08-20 6:29 ` [PATCH printk v8 29/35] printk: Coordinate direct printing in panic John Ogness
2024-08-20 15:21 ` Petr Mladek
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: e35a8884270bae11196eedf3b0a5bf22619f11f2
Gitweb: https://git.kernel.org/tip/e35a8884270bae11196eedf3b0a5bf22619f11f2
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:55 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:25 +02:00
printk: Coordinate direct printing in panic
If legacy and nbcon consoles are registered and the nbcon
consoles are allowed to flush (i.e. no boot consoles
registered), the legacy consoles will no longer perform
direct printing on the panic CPU until after the backtrace
has been stored. This will give the safe nbcon consoles a
chance to print the panic messages before allowing the
unsafe legacy consoles to print.
If no nbcon consoles are registered or they are not allowed
to flush because boot consoles are registered, there is no
change in behavior (i.e. legacy consoles will always attempt
to print from the printk() caller context).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-30-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 5 ++++-
kernel/panic.c | 2 +-
kernel/printk/internal.h | 1 +-
kernel/printk/printk.c | 55 ++++++++++++++++++++++++++++++++++-----
4 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 2e083f0..eca9bb2 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -200,6 +200,7 @@ extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
extern asmlinkage void dump_stack(void) __cold;
void printk_trigger_flush(void);
void console_try_replay_all(void);
+void printk_legacy_allow_panic_sync(void);
extern bool nbcon_device_try_acquire(struct console *con);
extern void nbcon_device_release(struct console *con);
void nbcon_atomic_flush_unsafe(void);
@@ -286,6 +287,10 @@ static inline void console_try_replay_all(void)
{
}
+static inline void printk_legacy_allow_panic_sync(void)
+{
+}
+
static inline bool nbcon_device_try_acquire(struct console *con)
{
return false;
diff --git a/kernel/panic.c b/kernel/panic.c
index df37c91..93096d5 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -374,6 +374,8 @@ void panic(const char *fmt, ...)
panic_other_cpus_shutdown(_crash_kexec_post_notifiers);
+ printk_legacy_allow_panic_sync();
+
/*
* Run any panic handlers, including those that might need to
* add information to the kmsg dump output.
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 7679e18..6b61350 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -154,6 +154,7 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
+extern bool legacy_allow_panic_sync;
extern struct printk_buffers printk_shared_pbufs;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e30107d..fc3f897 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -471,7 +471,9 @@ static DEFINE_MUTEX(syslog_lock);
static bool have_legacy_console;
/*
- * Specifies if an nbcon console is registered.
+ * Specifies if an nbcon console is registered. If nbcon consoles are present,
+ * synchronous printing of legacy consoles will not occur during panic until
+ * the backtrace has been stored to the ringbuffer.
*/
static bool have_nbcon_console;
@@ -483,6 +485,9 @@ static bool have_nbcon_console;
*/
bool have_boot_console;
+/* See printk_legacy_allow_panic_sync() for details. */
+bool legacy_allow_panic_sync;
+
/*
* Specifies if the console lock/unlock dance is needed for console
* printing. If @have_boot_console is true, the nbcon consoles will
@@ -2330,12 +2335,28 @@ out:
return ret;
}
+/*
+ * This acts as a one-way switch to allow legacy consoles to print from
+ * the printk() caller context on a panic CPU. It also attempts to flush
+ * the legacy consoles in this context.
+ */
+void printk_legacy_allow_panic_sync(void)
+{
+ legacy_allow_panic_sync = true;
+
+ if (printing_via_unlock && !is_printk_legacy_deferred()) {
+ if (console_trylock())
+ console_unlock();
+ }
+}
+
asmlinkage int vprintk_emit(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
+ bool do_trylock_unlock = printing_via_unlock;
+ bool defer_legacy = false;
int printed_len;
- bool in_sched = false;
/* Suppress unimportant messages after panic happens */
if (unlikely(suppress_printk))
@@ -2349,17 +2370,35 @@ asmlinkage int vprintk_emit(int facility, int level,
if (other_cpu_in_panic() && !panic_triggering_all_cpu_backtrace)
return 0;
+ /* If called from the scheduler, we can not call up(). */
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
- in_sched = true;
+ defer_legacy = do_trylock_unlock;
+ do_trylock_unlock = false;
}
printk_delay(level);
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
- /* If called from the scheduler, we can not call up(). */
- if (!in_sched && printing_via_unlock) {
+ if (have_nbcon_console && !have_boot_console) {
+ nbcon_atomic_flush_pending();
+
+ /*
+ * In panic, the legacy consoles are not allowed to print from
+ * the printk calling context unless explicitly allowed. This
+ * gives the safe nbcon consoles a chance to print out all the
+ * panic messages first. This restriction only applies if
+ * there are nbcon consoles registered and they are allowed to
+ * flush.
+ */
+ if (this_cpu_in_panic() && !legacy_allow_panic_sync) {
+ do_trylock_unlock = false;
+ defer_legacy = false;
+ }
+ }
+
+ if (do_trylock_unlock) {
/*
* The caller may be holding system-critical or
* timing-sensitive locks. Disable preemption during
@@ -2379,7 +2418,7 @@ asmlinkage int vprintk_emit(int facility, int level,
preempt_enable();
}
- if (in_sched && printing_via_unlock)
+ if (defer_legacy)
defer_console_output();
else
wake_up_klogd();
@@ -3292,7 +3331,9 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (!have_boot_console)
nbcon_atomic_flush_pending();
- console_flush_all(false, &next_seq, &handover);
+ /* Flush legacy consoles once allowed, even when dangerous. */
+ if (legacy_allow_panic_sync)
+ console_flush_all(false, &next_seq, &handover);
}
/*
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Flush nbcon consoles first on panic
2024-08-20 6:29 ` [PATCH printk v8 25/35] printk: Flush nbcon consoles first on panic John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: d2e85ca7a736d2d889bac9aef6ede0a67f6870b2
Gitweb: https://git.kernel.org/tip/d2e85ca7a736d2d889bac9aef6ede0a67f6870b2
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:51 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Flush nbcon consoles first on panic
In console_flush_on_panic(), flush the nbcon consoles before
flushing legacy consoles. The legacy write() callbacks are not
fully safe when oops_in_progress is set.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-26-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7c9f8f6..c6e6333 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3269,6 +3269,9 @@ void console_flush_on_panic(enum con_flush_mode mode)
if (mode == CONSOLE_REPLAY_ALL)
__console_rewind_all();
+ if (!have_boot_console)
+ nbcon_atomic_flush_pending();
+
console_flush_all(false, &next_seq, &handover);
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Flush new records on device_release()
2024-08-20 6:29 ` [PATCH printk v8 24/35] printk: nbcon: Flush new records on device_release() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 8ba77712a7501ca941603d6d5ed650cd0d42cafb
Gitweb: https://git.kernel.org/tip/8ba77712a7501ca941603d6d5ed650cd0d42cafb
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:50 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: nbcon: Flush new records on device_release()
There may be new records that were added while a driver was
holding the nbcon context for non-printing purposes. These
new records must be flushed by the nbcon_device_release()
context because no other context will do it.
If boot consoles are registered, the legacy loop is used
(either direct or per irq_work) to handle the flushing.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-25-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/nbcon.c | 20 ++++++++++++++++++++
kernel/printk/printk.c | 2 +-
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 84706c1..7679e18 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -153,6 +153,8 @@ static inline bool console_is_usable(struct console *con, short flags) { return
#endif /* CONFIG_PRINTK */
+extern bool have_boot_console;
+
extern struct printk_buffers printk_shared_pbufs;
/**
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index d09c084..269aeed 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1326,10 +1326,30 @@ EXPORT_SYMBOL_GPL(nbcon_device_try_acquire);
void nbcon_device_release(struct console *con)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(con, nbcon_device_ctxt);
+ int cookie;
if (!nbcon_context_exit_unsafe(ctxt))
return;
nbcon_context_release(ctxt);
+
+ /*
+ * This context must flush any new records added while the console
+ * was locked. The console_srcu_read_lock must be taken to ensure
+ * the console is usable throughout flushing.
+ */
+ cookie = console_srcu_read_lock();
+ if (console_is_usable(con, console_srcu_read_flags(con)) &&
+ prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
+ if (!have_boot_console) {
+ __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));
+ } else if (!is_printk_legacy_deferred()) {
+ if (console_trylock())
+ console_unlock();
+ } else {
+ printk_trigger_flush();
+ }
+ }
+ console_srcu_read_unlock(cookie);
}
EXPORT_SYMBOL_GPL(nbcon_device_release);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index f08bf5e..7c9f8f6 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -469,7 +469,7 @@ static DEFINE_MUTEX(syslog_lock);
* the console lock. This is because boot consoles and nbcon consoles may
* have mapped the same hardware.
*/
-static bool have_boot_console;
+bool have_boot_console;
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Add unsafe flushing on panic
2024-08-20 6:29 ` [PATCH printk v8 26/35] printk: nbcon: Add unsafe flushing " John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 5dde3b7354133846079fa51e55e74ef90a836759
Gitweb: https://git.kernel.org/tip/5dde3b7354133846079fa51e55e74ef90a836759
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:52 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: nbcon: Add unsafe flushing on panic
Add nbcon_atomic_flush_unsafe() to flush all nbcon consoles
using the write_atomic() callback and allowing unsafe hostile
takeovers. Call this at the end of panic() as a final attempt
to flush any pending messages.
Note that legacy consoles use unsafe methods for flushing
from the beginning of panic (see bust_spinlocks()). Therefore,
systems using both legacy and nbcon consoles may still fail to
see panic messages due to unsafe legacy console usage.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-27-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 5 +++++
kernel/panic.c | 1 +
kernel/printk/nbcon.c | 32 +++++++++++++++++++++++++-------
3 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 9687089..2e083f0 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -202,6 +202,7 @@ 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);
+void nbcon_atomic_flush_unsafe(void);
#else
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
@@ -294,6 +295,10 @@ static inline void nbcon_device_release(struct console *con)
{
}
+static inline void nbcon_atomic_flush_unsafe(void)
+{
+}
+
#endif
bool this_cpu_in_panic(void);
diff --git a/kernel/panic.c b/kernel/panic.c
index 2a04491..df37c91 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -463,6 +463,7 @@ void panic(const char *fmt, ...)
* Explicitly flush the kernel log buffer one last time.
*/
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
+ nbcon_atomic_flush_unsafe();
local_irq_enable();
for (i = 0; ; i += PANIC_TIMER_STEP) {
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 269aeed..afdb16c 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1083,6 +1083,7 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
* write_atomic() callback
* @con: The nbcon console to flush
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*
* Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on
* failure.
@@ -1101,7 +1102,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
* returned, it cannot be expected that the unfinalized record will become
* available.
*/
-static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
+ bool allow_unsafe_takeover)
{
struct nbcon_write_context wctxt = { };
struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
@@ -1110,6 +1112,7 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
ctxt->console = con;
ctxt->spinwait_max_us = 2000;
ctxt->prio = nbcon_get_default_prio();
+ ctxt->allow_unsafe_takeover = allow_unsafe_takeover;
if (!nbcon_context_try_acquire(ctxt))
return -EPERM;
@@ -1140,13 +1143,15 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
* write_atomic() callback
* @con: The nbcon console to flush
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*
* This will stop flushing before @stop_seq if another context has ownership.
* That context is then responsible for the flushing. Likewise, if new records
* are added while this context was flushing and there is no other context
* to handle the printing, this context must also flush those records.
*/
-static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
+ bool allow_unsafe_takeover)
{
unsigned long flags;
int err;
@@ -1160,7 +1165,7 @@ again:
*/
local_irq_save(flags);
- err = __nbcon_atomic_flush_pending_con(con, stop_seq);
+ err = __nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
local_irq_restore(flags);
@@ -1190,8 +1195,9 @@ again:
* __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
* write_atomic() callback
* @stop_seq: Flush up until this record
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
*/
-static void __nbcon_atomic_flush_pending(u64 stop_seq)
+static void __nbcon_atomic_flush_pending(u64 stop_seq, bool allow_unsafe_takeover)
{
struct console *con;
int cookie;
@@ -1209,7 +1215,7 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
if (nbcon_seq_read(con) >= stop_seq)
continue;
- nbcon_atomic_flush_pending_con(con, stop_seq);
+ nbcon_atomic_flush_pending_con(con, stop_seq, allow_unsafe_takeover);
}
console_srcu_read_unlock(cookie);
}
@@ -1225,7 +1231,19 @@ static void __nbcon_atomic_flush_pending(u64 stop_seq)
*/
void nbcon_atomic_flush_pending(void)
{
- __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), false);
+}
+
+/**
+ * nbcon_atomic_flush_unsafe - Flush all nbcon consoles using their
+ * write_atomic() callback and allowing unsafe hostile takeovers
+ *
+ * Flush the backlog up through the currently newest record. Unsafe hostile
+ * takeovers will be performed, if necessary.
+ */
+void nbcon_atomic_flush_unsafe(void)
+{
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb), true);
}
/**
@@ -1342,7 +1360,7 @@ void nbcon_device_release(struct console *con)
if (console_is_usable(con, console_srcu_read_flags(con)) &&
prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
if (!have_boot_console) {
- __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb));
+ __nbcon_atomic_flush_pending_con(con, prb_next_reserve_seq(prb), false);
} else if (!is_printk_legacy_deferred()) {
if (console_trylock())
console_unlock();
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Add is_printk_legacy_deferred()
2024-08-20 6:29 ` [PATCH printk v8 23/35] printk: Add is_printk_legacy_deferred() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 70411bf8d22ab3d2f794f199d81d70b62d3a85fa
Gitweb: https://git.kernel.org/tip/70411bf8d22ab3d2f794f199d81d70b62d3a85fa
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:49 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Add is_printk_legacy_deferred()
If printk has been explicitly deferred or is called from NMI
context, legacy console printing must be deferred to an irq_work
context. Introduce a helper function is_printk_legacy_deferred()
for a CPU to query if it must defer legacy console printing.
In follow-up commits this helper will be needed at other call
sites as well.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-24-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/printk_safe.c | 11 ++++++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 44468f3..84706c1 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -75,6 +75,7 @@ bool printk_percpu_data_ready(void);
} while (0)
void defer_console_output(void);
+bool is_printk_legacy_deferred(void);
u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags);
@@ -138,6 +139,7 @@ static inline bool console_is_usable(struct console *con, short flags)
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
static inline bool printk_percpu_data_ready(void) { return false; }
+static inline bool is_printk_legacy_deferred(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 4421cca..86439fd 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -38,6 +38,15 @@ void __printk_deferred_exit(void)
__printk_safe_exit();
}
+bool is_printk_legacy_deferred(void)
+{
+ /*
+ * The per-CPU variable @printk_context can be read safely in any
+ * context. CPU migration is always disabled when set.
+ */
+ return (this_cpu_read(printk_context) || in_nmi());
+}
+
asmlinkage int vprintk(const char *fmt, va_list args)
{
#ifdef CONFIG_KGDB_KDB
@@ -50,7 +59,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
* Use the main logbuf even in NMI. But avoid calling console
* drivers that might have their own locks.
*/
- if (this_cpu_read(printk_context) || in_nmi())
+ if (is_printk_legacy_deferred())
return vprintk_deferred(fmt, args);
/* No obstacles. */
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Use nbcon consoles in console_flush_all()
2024-08-20 6:29 ` [PATCH printk v8 22/35] printk: nbcon: Use nbcon consoles in console_flush_all() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: c158834b223fbfab3a14855ac203b8d9cddbbefd
Gitweb: https://git.kernel.org/tip/c158834b223fbfab3a14855ac203b8d9cddbbefd
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:48 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: nbcon: Use nbcon consoles in console_flush_all()
Allow nbcon consoles to print messages in the legacy printk()
caller context (printing via unlock) by integrating them into
console_flush_all(). The write_atomic() callback is used for
printing.
Provide nbcon_legacy_emit_next_record(), which acts as the
nbcon variant of console_emit_next_record(). Call this variant
within console_flush_all() for nbcon consoles. Since nbcon
consoles use their own @nbcon_seq variable to track the next
record to print, this also must be appropriately handled in
console_flush_all().
Note that the legacy printing logic uses @handover to detect
handovers for printing all consoles. For nbcon consoles,
handovers/takeovers occur on a per-console basis and thus do
not cause the console_flush_all() loop to abort.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-23-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 6 +++-
kernel/printk/nbcon.c | 87 +++++++++++++++++++++++++++++++++++++++-
kernel/printk/printk.c | 17 +++++---
3 files changed, 105 insertions(+), 5 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 0dc9b92..44468f3 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -78,6 +78,8 @@ void defer_console_output(void);
u16 printk_parse_prefix(const char *text, int *level,
enum printk_info_flags *flags);
+void console_lock_spinning_enable(void);
+int console_lock_spinning_disable_and_check(int cookie);
u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
@@ -85,6 +87,8 @@ bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
enum nbcon_prio nbcon_get_default_prio(void);
void nbcon_atomic_flush_pending(void);
+bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie);
/*
* Check if the given console is currently capable and allowed to print
@@ -140,6 +144,8 @@ static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
static inline void nbcon_atomic_flush_pending(void) { }
+static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie) { return false; }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 3982d68..d09c084 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -992,6 +992,93 @@ enum nbcon_prio nbcon_get_default_prio(void)
}
/*
+ * nbcon_atomic_emit_one - Print one record for an nbcon console using the
+ * write_atomic() callback
+ * @wctxt: An initialized write context struct to use for this context
+ *
+ * Return: True, when a record has been printed and there are still
+ * pending records. The caller might want to continue flushing.
+ *
+ * False, when there is no pending record, or when the console
+ * context cannot be acquired, or the ownership has been lost.
+ * The caller should give up. Either the job is done, cannot be
+ * done, or will be handled by the owning context.
+ *
+ * This is an internal helper to handle the locking of the console before
+ * calling nbcon_emit_next_record().
+ */
+static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+
+ if (!nbcon_context_try_acquire(ctxt))
+ return false;
+
+ /*
+ * nbcon_emit_next_record() returns false when the console was
+ * handed over or taken over. In both cases the context is no
+ * longer valid.
+ *
+ * The higher priority printing context takes over responsibility
+ * to print the pending records.
+ */
+ if (!nbcon_emit_next_record(wctxt))
+ return false;
+
+ nbcon_context_release(ctxt);
+
+ return ctxt->backlog;
+}
+
+/**
+ * nbcon_legacy_emit_next_record - Print one record for an nbcon console
+ * in legacy contexts
+ * @con: The console to print on
+ * @handover: Will be set to true if a printk waiter has taken over the
+ * console_lock, in which case the caller is no longer holding
+ * both the console_lock and the SRCU read lock. Otherwise it
+ * is set to false.
+ * @cookie: The cookie from the SRCU read lock.
+ *
+ * Context: Any context except NMI.
+ * Return: True, when a record has been printed and there are still
+ * pending records. The caller might want to continue flushing.
+ *
+ * False, when there is no pending record, or when the console
+ * context cannot be acquired, or the ownership has been lost.
+ * The caller should give up. Either the job is done, cannot be
+ * done, or will be handled by the owning context.
+ *
+ * This function is meant to be called by console_flush_all() to print records
+ * on nbcon consoles from legacy context (printing via console unlocking).
+ * Essentially it is the nbcon version of console_emit_next_record().
+ */
+bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
+ int cookie)
+{
+ struct nbcon_write_context wctxt = { };
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
+ unsigned long flags;
+ bool progress;
+
+ /* Use the same procedure as console_emit_next_record(). */
+ printk_safe_enter_irqsave(flags);
+ console_lock_spinning_enable();
+ stop_critical_timings();
+
+ ctxt->console = con;
+ ctxt->prio = nbcon_get_default_prio();
+
+ progress = nbcon_atomic_emit_one(&wctxt);
+
+ start_critical_timings();
+ *handover = console_lock_spinning_disable_and_check(cookie);
+ printk_safe_exit_irqrestore(flags);
+
+ return progress;
+}
+
+/**
* __nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
* write_atomic() callback
* @con: The nbcon console to flush
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b8634a1..f08bf5e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1860,7 +1860,7 @@ static bool console_waiter;
* there may be a waiter spinning (like a spinlock). Also it must be
* ready to hand over the lock at the end of the section.
*/
-static void console_lock_spinning_enable(void)
+void console_lock_spinning_enable(void)
{
/*
* Do not use spinning in panic(). The panic CPU wants to keep the lock.
@@ -1899,7 +1899,7 @@ lockdep:
*
* Return: 1 if the lock rights were passed, 0 otherwise.
*/
-static int console_lock_spinning_disable_and_check(int cookie)
+int console_lock_spinning_disable_and_check(int cookie)
{
int waiter;
@@ -3021,13 +3021,20 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
short flags = console_srcu_read_flags(con);
+ u64 printk_seq;
bool progress;
if (!console_is_usable(con, flags))
continue;
any_usable = true;
- progress = console_emit_next_record(con, handover, cookie);
+ if (flags & CON_NBCON) {
+ progress = nbcon_legacy_emit_next_record(con, handover, cookie);
+ printk_seq = nbcon_seq_read(con);
+ } else {
+ progress = console_emit_next_record(con, handover, cookie);
+ printk_seq = con->seq;
+ }
/*
* If a handover has occurred, the SRCU read lock
@@ -3037,8 +3044,8 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
return false;
/* Track the next of the highest seq flushed. */
- if (con->seq > *next_seq)
- *next_seq = con->seq;
+ if (printk_seq > *next_seq)
+ *next_seq = printk_seq;
if (!progress)
continue;
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Track registered boot consoles
2024-08-20 6:29 ` [PATCH printk v8 21/35] printk: Track registered boot consoles John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 97ea9bccfcbe4c97f127e736823cc8d984d781bf
Gitweb: https://git.kernel.org/tip/97ea9bccfcbe4c97f127e736823cc8d984d781bf
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:47 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Track registered boot consoles
Unfortunately it is not known if a boot console and a regular
(legacy or nbcon) console use the same hardware. For this reason
they must not be allowed to print simultaneously.
For legacy consoles this is not an issue because they are
already synchronized with the boot consoles using the console
lock. However nbcon consoles can be triggered separately.
Add a global flag @have_boot_console to identify if any boot
consoles are registered. This will be used in follow-up commits
to ensure that boot consoles and nbcon consoles cannot print
simultaneously.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-22-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index ffb56c2..b8634a1 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -463,6 +463,14 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
static DEFINE_MUTEX(syslog_lock);
+/*
+ * Specifies if a boot console is registered. If boot consoles are present,
+ * nbcon consoles cannot print simultaneously and must be synchronized by
+ * the console lock. This is because boot consoles and nbcon consoles may
+ * have mapped the same hardware.
+ */
+static bool have_boot_console;
+
#ifdef CONFIG_PRINTK
DECLARE_WAIT_QUEUE_HEAD(log_wait);
/* All 3 protected by @syslog_lock. */
@@ -3610,6 +3618,9 @@ void register_console(struct console *newcon)
newcon->seq = init_seq;
}
+ if (newcon->flags & CON_BOOT)
+ have_boot_console = true;
+
/*
* If another context is actively using the hardware of this new
* console, it will not be aware of the nbcon synchronization. This
@@ -3680,7 +3691,9 @@ EXPORT_SYMBOL(register_console);
static int unregister_console_locked(struct console *console)
{
bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ bool found_boot_con = false;
unsigned long flags;
+ struct console *c;
int res;
lockdep_assert_console_list_lock_held();
@@ -3738,6 +3751,17 @@ static int unregister_console_locked(struct console *console)
if (console->exit)
res = console->exit(console);
+ /*
+ * With this console gone, the global flags tracking registered
+ * console types may have changed. Update them.
+ */
+ for_each_console(c) {
+ if (c->flags & CON_BOOT)
+ found_boot_con = true;
+ }
+ if (!found_boot_con)
+ have_boot_console = found_boot_con;
+
return res;
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Add helper to assign priority based on CPU state
2024-08-20 6:29 ` [PATCH printk v8 19/35] printk: nbcon: Add helper to assign priority based on CPU state John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 06683a6649895ccf279c35ca2fb77fd7afb7a6c5
Gitweb: https://git.kernel.org/tip/06683a6649895ccf279c35ca2fb77fd7afb7a6c5
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:45 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: nbcon: Add helper to assign priority based on CPU state
Add a helper function to use the current state of the CPU to
determine which priority to assign to the printing context.
The EMERGENCY priority handling is added in a follow-up commit.
It will use a per-CPU variable.
Note: nbcon_device_try_acquire(), which is used by console
drivers to acquire the nbcon console for non-printing
activities, is hard-coded to always use NORMAL priority.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-20-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 ++
kernel/printk/nbcon.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index fe8d84d..72f2293 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -83,6 +83,7 @@ u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
+enum nbcon_prio nbcon_get_default_prio(void);
/*
* Check if the given console is currently capable and allowed to print
@@ -136,6 +137,7 @@ static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
+static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index e8ddcb6..c6a9aa9 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -974,6 +974,25 @@ update_con:
}
/**
+ * nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
+ * printing on the current CPU
+ *
+ * Context: Any context.
+ * Return: The nbcon_prio to use for acquiring an nbcon console in this
+ * context for printing.
+ *
+ * The function is safe for reading per-CPU data in any context because
+ * preemption is disabled if the current CPU is in the panic state.
+ */
+enum nbcon_prio nbcon_get_default_prio(void)
+{
+ if (this_cpu_in_panic())
+ return NBCON_PRIO_PANIC;
+
+ return NBCON_PRIO_NORMAL;
+}
+
+/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
*
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Provide function to flush using write_atomic()
2024-08-20 6:29 ` [PATCH printk v8 20/35] printk: nbcon: Provide function to flush using write_atomic() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Thomas Gleixner (Intel), Petr Mladek, x86,
linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: d3a9f82ec5c095d6eb1eb94ecaa494470b4cef70
Gitweb: https://git.kernel.org/tip/d3a9f82ec5c095d6eb1eb94ecaa494470b4cef70
Author: Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:46 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: nbcon: Provide function to flush using write_atomic()
Provide nbcon_atomic_flush_pending() to perform flushing of all
registered nbcon consoles using their write_atomic() callback.
Unlike console_flush_all(), nbcon_atomic_flush_pending() will
only flush up through the newest record at the time of the
call. This prevents a CPU from printing unbounded when other
CPUs are adding records. If new records are added while
flushing, it is expected that the dedicated printer threads
will print those records. If the printer thread is not
available (which is always the case at this point in the
rework), nbcon_atomic_flush_pending() _will_ flush all records
in the ringbuffer.
Unlike console_flush_all(), nbcon_atomic_flush_pending() will
fully flush one console before flushing the next. This helps to
guarantee that a block of pending records (such as a stack
trace in an emergency situation) can be printed atomically at
once before releasing console ownership.
nbcon_atomic_flush_pending() is safe in any context because it
uses write_atomic() and acquires with unsafe_takeover disabled.
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>
Link: https://lore.kernel.org/r/20240820063001.36405-21-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 +-
kernel/printk/nbcon.c | 151 +++++++++++++++++++++++++++++++++++++-
2 files changed, 152 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 72f2293..0dc9b92 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -84,6 +84,7 @@ void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
enum nbcon_prio nbcon_get_default_prio(void);
+void nbcon_atomic_flush_pending(void);
/*
* Check if the given console is currently capable and allowed to print
@@ -138,6 +139,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
+static inline void nbcon_atomic_flush_pending(void) { }
static inline bool console_is_usable(struct console *con, short flags) { return false; }
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index c6a9aa9..3982d68 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -886,7 +886,6 @@ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
* When true is returned, @wctxt->ctxt.backlog indicates whether there are
* still records pending in the ringbuffer,
*/
-__maybe_unused
static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
{
struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
@@ -992,6 +991,156 @@ enum nbcon_prio nbcon_get_default_prio(void)
return NBCON_PRIO_NORMAL;
}
+/*
+ * __nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
+ * write_atomic() callback
+ * @con: The nbcon console to flush
+ * @stop_seq: Flush up until this record
+ *
+ * Return: 0 if @con was flushed up to @stop_seq Otherwise, error code on
+ * failure.
+ *
+ * Errors:
+ *
+ * -EPERM: Unable to acquire console ownership.
+ *
+ * -EAGAIN: Another context took over ownership while printing.
+ *
+ * -ENOENT: A record before @stop_seq is not available.
+ *
+ * If flushing up to @stop_seq was not successful, it only makes sense for the
+ * caller to try again when -EAGAIN was returned. When -EPERM is returned,
+ * this context is not allowed to acquire the console. When -ENOENT is
+ * returned, it cannot be expected that the unfinalized record will become
+ * available.
+ */
+static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+{
+ struct nbcon_write_context wctxt = { };
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
+ int err = 0;
+
+ ctxt->console = con;
+ ctxt->spinwait_max_us = 2000;
+ ctxt->prio = nbcon_get_default_prio();
+
+ if (!nbcon_context_try_acquire(ctxt))
+ return -EPERM;
+
+ while (nbcon_seq_read(con) < stop_seq) {
+ /*
+ * nbcon_emit_next_record() returns false when the console was
+ * handed over or taken over. In both cases the context is no
+ * longer valid.
+ */
+ if (!nbcon_emit_next_record(&wctxt))
+ return -EAGAIN;
+
+ if (!ctxt->backlog) {
+ /* Are there reserved but not yet finalized records? */
+ if (nbcon_seq_read(con) < stop_seq)
+ err = -ENOENT;
+ break;
+ }
+ }
+
+ nbcon_context_release(ctxt);
+ return err;
+}
+
+/**
+ * nbcon_atomic_flush_pending_con - Flush specified nbcon console using its
+ * write_atomic() callback
+ * @con: The nbcon console to flush
+ * @stop_seq: Flush up until this record
+ *
+ * This will stop flushing before @stop_seq if another context has ownership.
+ * That context is then responsible for the flushing. Likewise, if new records
+ * are added while this context was flushing and there is no other context
+ * to handle the printing, this context must also flush those records.
+ */
+static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
+{
+ unsigned long flags;
+ int err;
+
+again:
+ /*
+ * Atomic flushing does not use console driver synchronization (i.e.
+ * it does not hold the port lock for uart consoles). Therefore IRQs
+ * must be disabled to avoid being interrupted and then calling into
+ * a driver that will deadlock trying to acquire console ownership.
+ */
+ local_irq_save(flags);
+
+ err = __nbcon_atomic_flush_pending_con(con, stop_seq);
+
+ local_irq_restore(flags);
+
+ /*
+ * If there was a new owner (-EPERM, -EAGAIN), that context is
+ * responsible for completing.
+ *
+ * Do not wait for records not yet finalized (-ENOENT) to avoid a
+ * possible deadlock. They will either get flushed by the writer or
+ * eventually skipped on panic CPU.
+ */
+ if (err)
+ return;
+
+ /*
+ * If flushing was successful but more records are available, this
+ * context must flush those remaining records because there is no
+ * other context that will do it.
+ */
+ if (prb_read_valid(prb, nbcon_seq_read(con), NULL)) {
+ stop_seq = prb_next_reserve_seq(prb);
+ goto again;
+ }
+}
+
+/**
+ * __nbcon_atomic_flush_pending - Flush all nbcon consoles using their
+ * write_atomic() callback
+ * @stop_seq: Flush up until this record
+ */
+static void __nbcon_atomic_flush_pending(u64 stop_seq)
+{
+ struct console *con;
+ int cookie;
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(con) {
+ short flags = console_srcu_read_flags(con);
+
+ if (!(flags & CON_NBCON))
+ continue;
+
+ if (!console_is_usable(con, flags))
+ continue;
+
+ if (nbcon_seq_read(con) >= stop_seq)
+ continue;
+
+ nbcon_atomic_flush_pending_con(con, stop_seq);
+ }
+ console_srcu_read_unlock(cookie);
+}
+
+/**
+ * nbcon_atomic_flush_pending - Flush all nbcon consoles using their
+ * write_atomic() callback
+ *
+ * Flush the backlog up through the currently newest record. Any new
+ * records added while flushing will not be flushed if there is another
+ * context available to handle the flushing. This is to avoid one CPU
+ * printing unbounded because other CPUs continue to add records.
+ */
+void nbcon_atomic_flush_pending(void)
+{
+ __nbcon_atomic_flush_pending(prb_next_reserve_seq(prb));
+}
+
/**
* nbcon_alloc - Allocate and init the nbcon console specific data
* @con: Console to initialize
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Let console_is_usable() handle nbcon
2024-08-20 6:29 ` [PATCH printk v8 17/35] printk: Let console_is_usable() handle nbcon John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 20846d1ce2adacd2b1f8672e24d6acb26b2e757b
Gitweb: https://git.kernel.org/tip/20846d1ce2adacd2b1f8672e24d6acb26b2e757b
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:43 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Let console_is_usable() handle nbcon
The nbcon consoles use a different printing callback. For nbcon
consoles, check for the write_atomic() callback instead of
write().
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-18-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 5d9deb5..448a5fc 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -86,6 +86,8 @@ void nbcon_free(struct console *con);
/*
* Check if the given console is currently capable and allowed to print
+ * records. Note that this function does not consider the current context,
+ * which can also play a role in deciding if @con can be used to print
* records.
*
* Requires the console_srcu_read_lock.
@@ -100,8 +102,13 @@ static inline bool console_is_usable(struct console *con)
if ((flags & CON_SUSPENDED))
return false;
- if (!con->write)
- return false;
+ if (flags & CON_NBCON) {
+ if (!con->write_atomic)
+ return false;
+ } else {
+ if (!con->write)
+ return false;
+ }
/*
* Console drivers may assume that per-cpu resources have been
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Add @flags argument for console_is_usable()
2024-08-20 6:29 ` [PATCH printk v8 18/35] printk: Add @flags argument for console_is_usable() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: fc400d5f63570afdadd718ae962cf5aa0feeace6
Gitweb: https://git.kernel.org/tip/fc400d5f63570afdadd718ae962cf5aa0feeace6
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:44 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:24 +02:00
printk: Add @flags argument for console_is_usable()
The caller of console_is_usable() usually needs @console->flags
for its own checks. Rather than having console_is_usable() read
its own copy, make the caller pass in the @flags. This also
ensures that the caller saw the same @flags value.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-19-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 8 ++------
kernel/printk/printk.c | 5 +++--
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 448a5fc..fe8d84d 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -89,13 +89,9 @@ void nbcon_free(struct console *con);
* records. Note that this function does not consider the current context,
* which can also play a role in deciding if @con can be used to print
* records.
- *
- * Requires the console_srcu_read_lock.
*/
-static inline bool console_is_usable(struct console *con)
+static inline bool console_is_usable(struct console *con, short flags)
{
- short flags = console_srcu_read_flags(con);
-
if (!(flags & CON_ENABLED))
return false;
@@ -141,7 +137,7 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
-static inline bool console_is_usable(struct console *con) { return false; }
+static inline bool console_is_usable(struct console *con, short flags) { return false; }
#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b9c8fff..ffb56c2 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3012,9 +3012,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
cookie = console_srcu_read_lock();
for_each_console_srcu(con) {
+ short flags = console_srcu_read_flags(con);
bool progress;
- if (!console_is_usable(con))
+ if (!console_is_usable(con, flags))
continue;
any_usable = true;
@@ -3925,7 +3926,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
* that they make forward progress, so only increment
* @diff for usable consoles.
*/
- if (!console_is_usable(c))
+ if (!console_is_usable(c, flags))
continue;
if (flags & CON_NBCON) {
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Make console_is_usable() available to nbcon.c
2024-08-20 6:29 ` [PATCH printk v8 16/35] printk: Make console_is_usable() available to nbcon.c John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 864c25c83d834bdf2cb5a24c768d37236b418410
Gitweb: https://git.kernel.org/tip/864c25c83d834bdf2cb5a24c768d37236b418410
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:42 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: Make console_is_usable() available to nbcon.c
Move console_is_usable() as-is into internal.h so that it can
be used by nbcon printing functions as well.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-17-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 32 ++++++++++++++++++++++++++++++++
kernel/printk/printk.c | 30 ------------------------------
2 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index ccb9166..5d9deb5 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -84,6 +84,36 @@ void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
void nbcon_free(struct console *con);
+/*
+ * Check if the given console is currently capable and allowed to print
+ * records.
+ *
+ * Requires the console_srcu_read_lock.
+ */
+static inline bool console_is_usable(struct console *con)
+{
+ short flags = console_srcu_read_flags(con);
+
+ if (!(flags & CON_ENABLED))
+ return false;
+
+ if ((flags & CON_SUSPENDED))
+ return false;
+
+ if (!con->write)
+ return false;
+
+ /*
+ * Console drivers may assume that per-cpu resources have been
+ * allocated. So unless they're explicitly marked as being able to
+ * cope (CON_ANYTIME) don't call them until this CPU is officially up.
+ */
+ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
+ return false;
+
+ return true;
+}
+
#else
#define PRINTK_PREFIX_MAX 0
@@ -104,6 +134,8 @@ static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
static inline void nbcon_free(struct console *con) { }
+static inline bool console_is_usable(struct console *con) { return false; }
+
#endif /* CONFIG_PRINTK */
extern struct printk_buffers printk_shared_pbufs;
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 4cd2c50..b9c8fff 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2767,36 +2767,6 @@ int is_console_locked(void)
}
EXPORT_SYMBOL(is_console_locked);
-/*
- * Check if the given console is currently capable and allowed to print
- * records.
- *
- * Requires the console_srcu_read_lock.
- */
-static inline bool console_is_usable(struct console *con)
-{
- short flags = console_srcu_read_flags(con);
-
- if (!(flags & CON_ENABLED))
- return false;
-
- if ((flags & CON_SUSPENDED))
- return false;
-
- if (!con->write)
- return false;
-
- /*
- * Console drivers may assume that per-cpu resources have been
- * allocated. So unless they're explicitly marked as being able to
- * cope (CON_ANYTIME) don't call them until this CPU is officially up.
- */
- if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
- return false;
-
- return true;
-}
-
static void __console_unlock(void)
{
console_locked = 0;
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Do not rely on proxy headers
2024-08-20 6:29 ` [PATCH printk v8 15/35] printk: nbcon: Do not rely on proxy headers John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: Andy Shevchenko, John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 1c17ebb7907a809a92f978995c27a53ead2526ee
Gitweb: https://git.kernel.org/tip/1c17ebb7907a809a92f978995c27a53ead2526ee
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:41 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: nbcon: Do not rely on proxy headers
The headers kernel.h, serial_core.h, and console.h allow for the
definitions of many types and functions from other headers.
Rather than relying on these as proxy headers, explicitly
include all headers providing needed definitions. Also sort the
list alphabetically to be able to easily detect duplicates.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-16-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 8 ++++++--
kernel/printk/nbcon.c | 13 ++++++++++++-
kernel/printk/printk_ringbuffer.h | 2 ++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index dc8bc08..ccb9166 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -2,11 +2,12 @@
/*
* internal.h - printk internal definitions
*/
-#include <linux/percpu.h>
#include <linux/console.h>
-#include "printk_ringbuffer.h"
+#include <linux/percpu.h>
+#include <linux/types.h>
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
+struct ctl_table;
void __init printk_sysctl_init(void);
int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos);
@@ -43,6 +44,9 @@ enum printk_info_flags {
LOG_CONT = 8, /* text is a fragment of a continuation line */
};
+struct printk_ringbuffer;
+struct dev_printk_info;
+
extern struct printk_ringbuffer *prb;
__printf(4, 0)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 61f0ae6..e8ddcb6 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -2,13 +2,24 @@
// Copyright (C) 2022 Linutronix GmbH, John Ogness
// Copyright (C) 2022 Intel, Thomas Gleixner
-#include <linux/kernel.h>
+#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/console.h>
#include <linux/delay.h>
+#include <linux/errno.h>
#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/irqflags.h>
+#include <linux/minmax.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/types.h>
#include "internal.h"
+#include "printk_ringbuffer.h"
/*
* Printk console printing implementation for consoles which does not depend
* on the legacy style console_lock mechanism.
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
index 52626d0..bd2a892 100644
--- a/kernel/printk/printk_ringbuffer.h
+++ b/kernel/printk/printk_ringbuffer.h
@@ -5,6 +5,8 @@
#include <linux/atomic.h>
#include <linux/dev_printk.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
/*
* Meta information about each stored message.
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] nbcon: Add API to acquire context for non-printing operations
2024-08-20 6:29 ` [PATCH printk v8 13/35] nbcon: Add API to acquire context for non-printing operations John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: adf6f37d142e14896115929f3892bbc0a86e25bf
Gitweb: https://git.kernel.org/tip/adf6f37d142e14896115929f3892bbc0a86e25bf
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:39 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
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: 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>
---
include/linux/console.h | 2 +-
include/linux/printk.h | 14 ++++++++++-
kernel/printk/nbcon.c | 58 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index aafe312..3706f94 100644
--- 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;
};
diff --git a/include/linux/printk.h b/include/linux/printk.h
index eee8e97..9687089 100644
--- 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(const char *log_lvl) __cold;
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(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
bool this_cpu_in_panic(void);
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index f279f83..61f0ae6 100644
--- 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_pbufs;
* 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_pbufs;
* 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);
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] serial: core: Acquire nbcon context in port->lock wrapper
2024-08-20 6:29 ` [PATCH printk v8 14/35] serial: core: Acquire nbcon context in port->lock wrapper John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Greg Kroah-Hartman, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 4126f149c48b2ae757d11ea24675f7071ab22ebf
Gitweb: https://git.kernel.org/tip/4126f149c48b2ae757d11ea24675f7071ab22ebf
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:40 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
serial: core: Acquire nbcon context in port->lock wrapper
Currently the port->lock wrappers uart_port_lock(),
uart_port_unlock() (and their variants) only lock/unlock
the spin_lock.
If the port is an nbcon console that has implemented the
write_atomic() callback, the wrappers must also acquire/release
the console context and mark the region as unsafe. This allows
general port->lock synchronization to be synchronized against
the nbcon write_atomic() callback.
Note that __uart_port_using_nbcon() relies on the port->lock
being held while a console is added and removed from the
console list (i.e. all uart nbcon drivers *must* take the
port->lock in their device_lock() callbacks).
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-15-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/serial_core.h | 82 +++++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 2 deletions(-)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 2cf03ff..4ab6587 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -11,6 +11,8 @@
#include <linux/compiler.h>
#include <linux/console.h>
#include <linux/interrupt.h>
+#include <linux/lockdep.h>
+#include <linux/printk.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -625,6 +627,60 @@ static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
up->cons = con;
__uart_port_unlock_irqrestore(up, flags);
}
+
+/* Only for internal port lock wrapper usage. */
+static inline bool __uart_port_using_nbcon(struct uart_port *up)
+{
+ lockdep_assert_held_once(&up->lock);
+
+ if (likely(!uart_console(up)))
+ return false;
+
+ /*
+ * @up->cons is only modified under the port lock. Therefore it is
+ * certain that it cannot disappear here.
+ *
+ * @up->cons->node is added/removed from the console list under the
+ * port lock. Therefore it is certain that the registration status
+ * cannot change here, thus @up->cons->flags can be read directly.
+ */
+ if (hlist_unhashed_lockless(&up->cons->node) ||
+ !(up->cons->flags & CON_NBCON) ||
+ !up->cons->write_atomic) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline bool __uart_port_nbcon_try_acquire(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return true;
+
+ return nbcon_device_try_acquire(up->cons);
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline void __uart_port_nbcon_acquire(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return;
+
+ while (!nbcon_device_try_acquire(up->cons))
+ cpu_relax();
+}
+
+/* Only for internal port lock wrapper usage. */
+static inline void __uart_port_nbcon_release(struct uart_port *up)
+{
+ if (!__uart_port_using_nbcon(up))
+ return;
+
+ nbcon_device_release(up->cons);
+}
+
/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
@@ -632,6 +688,7 @@ static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
static inline void uart_port_lock(struct uart_port *up)
{
spin_lock(&up->lock);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -641,6 +698,7 @@ static inline void uart_port_lock(struct uart_port *up)
static inline void uart_port_lock_irq(struct uart_port *up)
{
spin_lock_irq(&up->lock);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -651,6 +709,7 @@ static inline void uart_port_lock_irq(struct uart_port *up)
static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
{
spin_lock_irqsave(&up->lock, *flags);
+ __uart_port_nbcon_acquire(up);
}
/**
@@ -661,7 +720,15 @@ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *f
*/
static inline bool uart_port_trylock(struct uart_port *up)
{
- return spin_trylock(&up->lock);
+ if (!spin_trylock(&up->lock))
+ return false;
+
+ if (!__uart_port_nbcon_try_acquire(up)) {
+ spin_unlock(&up->lock);
+ return false;
+ }
+
+ return true;
}
/**
@@ -673,7 +740,15 @@ static inline bool uart_port_trylock(struct uart_port *up)
*/
static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags)
{
- return spin_trylock_irqsave(&up->lock, *flags);
+ if (!spin_trylock_irqsave(&up->lock, *flags))
+ return false;
+
+ if (!__uart_port_nbcon_try_acquire(up)) {
+ spin_unlock_irqrestore(&up->lock, *flags);
+ return false;
+ }
+
+ return true;
}
/**
@@ -682,6 +757,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
*/
static inline void uart_port_unlock(struct uart_port *up)
{
+ __uart_port_nbcon_release(up);
spin_unlock(&up->lock);
}
@@ -691,6 +767,7 @@ static inline void uart_port_unlock(struct uart_port *up)
*/
static inline void uart_port_unlock_irq(struct uart_port *up)
{
+ __uart_port_nbcon_release(up);
spin_unlock_irq(&up->lock);
}
@@ -701,6 +778,7 @@ static inline void uart_port_unlock_irq(struct uart_port *up)
*/
static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
{
+ __uart_port_nbcon_release(up);
spin_unlock_irqrestore(&up->lock, flags);
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] console: Improve console_srcu_read_flags() comments
2024-08-20 6:29 ` [PATCH printk v8 12/35] console: Improve console_srcu_read_flags() comments John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: dc219d8d858d95549543aa7a41b6e64a0da9e406
Gitweb: https://git.kernel.org/tip/dc219d8d858d95549543aa7a41b6e64a0da9e406
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:38 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
console: Improve console_srcu_read_flags() comments
It was not clear when exactly console_srcu_read_flags() must be
used vs. directly reading @console->flags.
Refactor and clarify that console_srcu_read_flags() is only
needed if the console is registered or the caller is in a
context where the registration status of the console may change
(due to another context).
The function requires the caller holds @console_srcu, which will
ensure that the caller sees an appropriate @flags value for the
registered console and that exit/cleanup routines will not run
if the console is in the process of unregistration.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-13-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 46b3c21..aafe312 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -446,28 +446,34 @@ extern void console_list_unlock(void) __releases(console_mutex);
extern struct hlist_head console_list;
/**
- * console_srcu_read_flags - Locklessly read the console flags
+ * console_srcu_read_flags - Locklessly read flags of a possibly registered
+ * console
* @con: struct console pointer of console to read flags from
*
- * This function provides the necessary READ_ONCE() and data_race()
- * notation for locklessly reading the console flags. The READ_ONCE()
- * in this function matches the WRITE_ONCE() when @flags are modified
- * for registered consoles with console_srcu_write_flags().
+ * Locklessly reading @con->flags provides a consistent read value because
+ * there is at most one CPU modifying @con->flags and that CPU is using only
+ * read-modify-write operations to do so.
*
- * Only use this function to read console flags when locklessly
- * iterating the console list via srcu.
+ * Requires console_srcu_read_lock to be held, which implies that @con might
+ * be a registered console. The purpose of holding console_srcu_read_lock is
+ * to guarantee that the console state is valid (CON_SUSPENDED/CON_ENABLED)
+ * and that no exit/cleanup routines will run if the console is currently
+ * undergoing unregistration.
+ *
+ * If the caller is holding the console_list_lock or it is _certain_ that
+ * @con is not and will not become registered, the caller may read
+ * @con->flags directly instead.
*
* Context: Any context.
+ * Return: The current value of the @con->flags field.
*/
static inline short console_srcu_read_flags(const struct console *con)
{
WARN_ON_ONCE(!console_srcu_read_lock_is_held());
/*
- * Locklessly reading console->flags provides a consistent
- * read value because there is at most one CPU modifying
- * console->flags and that CPU is using only read-modify-write
- * operations to do so.
+ * The READ_ONCE() matches the WRITE_ONCE() when @flags are modified
+ * for registered consoles with console_srcu_write_flags().
*/
return data_race(READ_ONCE(con->flags));
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] serial: core: Introduce wrapper to set @uart_port->cons
2024-08-20 6:29 ` [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons John Ogness
2024-08-20 11:12 ` Ilpo Järvinen
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, theo.lebrun, Greg Kroah-Hartman, Petr Mladek,
ilpo.jarvinen, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: eabd4600dafacf9895184259373f2445ff748654
Gitweb: https://git.kernel.org/tip/eabd4600dafacf9895184259373f2445ff748654
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:37 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
serial: core: Introduce wrapper to set @uart_port->cons
Introduce uart_port_set_cons() as a wrapper to set @cons of a
uart_port. The wrapper sets @cons under the port lock in order
to prevent @cons from disappearing while another context is
holding the port lock. This is necessary for a follow-up
commit relating to the port lock wrappers, which rely on @cons
not changing between lock and unlock.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Tested-by: Théo Lebrun <theo.lebrun@bootlin.com> # EyeQ5, AMBA-PL011
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20240820063001.36405-12-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
drivers/tty/serial/8250/8250_core.c | 6 +++---
drivers/tty/serial/amba-pl011.c | 2 +-
drivers/tty/serial/serial_core.c | 16 ++++++++--------
include/linux/serial_core.h | 17 +++++++++++++++++
4 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 29e4b83..5f9f069 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -423,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
port = &serial8250_ports[co->index].port;
/* link port to console */
- port->cons = co;
+ uart_port_set_cons(port, co);
retval = serial8250_console_setup(port, options, false);
if (retval != 0)
- port->cons = NULL;
+ uart_port_set_cons(port, NULL);
return retval;
}
@@ -485,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return serial8250_console_setup(port, options, true);
}
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8b1644f..7d0134e 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2480,7 +2480,7 @@ static int pl011_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return pl011_console_setup(co, options);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 5bea3af..1e3e28e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3176,8 +3176,15 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->uart_port = uport;
uport->state = state;
+ /*
+ * If this port is in use as a console then the spinlock is already
+ * initialised.
+ */
+ if (!uart_console_registered(uport))
+ uart_port_spin_lock_init(uport);
+
state->pm_state = UART_PM_STATE_UNDEFINED;
- uport->cons = drv->cons;
+ uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
drv->tty_driver->name_base + uport->line);
@@ -3186,13 +3193,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
goto out;
}
- /*
- * If this port is in use as a console then the spinlock is already
- * initialised.
- */
- if (!uart_console_registered(uport))
- uart_port_spin_lock_init(uport);
-
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 8872cd2..2cf03ff 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -609,6 +609,23 @@ static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned
}
/**
+ * uart_port_set_cons - Safely set the @cons field for a uart
+ * @up: The uart port to set
+ * @con: The new console to set to
+ *
+ * This function must be used to set @up->cons. It uses the port lock to
+ * synchronize with the port lock wrappers in order to ensure that the console
+ * cannot change or disappear while another context is holding the port lock.
+ */
+static inline void uart_port_set_cons(struct uart_port *up, struct console *con)
+{
+ unsigned long flags;
+
+ __uart_port_lock_irqsave(up, &flags);
+ up->cons = con;
+ __uart_port_unlock_irqrestore(up, flags);
+}
+/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
*/
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] serial: core: Provide low-level functions to lock port
2024-08-20 6:29 ` [PATCH printk v8 10/35] serial: core: Provide low-level functions to lock port John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Petr Mladek, Greg Kroah-Hartman, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 77e73c0687f5bc884fa1b0cb97aca912bcc01957
Gitweb: https://git.kernel.org/tip/77e73c0687f5bc884fa1b0cb97aca912bcc01957
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:36 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
serial: core: Provide low-level functions to lock port
It will be necessary at times for the uart nbcon console
drivers to acquire the port lock directly (without the
additional nbcon functionality of the port lock wrappers).
These are special cases such as the implementation of the
device_lock()/device_unlock() callbacks or for internal
port lock wrapper synchronization.
Provide low-level variants __uart_port_lock_irqsave() and
__uart_port_unlock_irqrestore() for this purpose.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20240820063001.36405-11-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/serial_core.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index aea25ee..8872cd2 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -590,6 +590,24 @@ struct uart_port {
void *private_data; /* generic platform data pointer */
};
+/*
+ * Only for console->device_lock()/_unlock() callbacks and internal
+ * port lock wrapper synchronization.
+ */
+static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
+{
+ spin_lock_irqsave(&up->lock, *flags);
+}
+
+/*
+ * Only for console->device_lock()/_unlock() callbacks and internal
+ * port lock wrapper synchronization.
+ */
+static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
+{
+ spin_unlock_irqrestore(&up->lock, flags);
+}
+
/**
* uart_port_lock - Lock the UART port
* @up: Pointer to UART port structure
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Add callbacks to synchronize with driver
2024-08-20 6:29 ` [PATCH printk v8 08/35] printk: nbcon: Add callbacks to synchronize with driver John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 7a16a771890746b4060333d665ebe674945a3cfa
Gitweb: https://git.kernel.org/tip/7a16a771890746b4060333d665ebe674945a3cfa
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:34 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: nbcon: Add callbacks to synchronize with driver
Console drivers typically must deal with access to the hardware
via user input/output (such as an interactive login shell) and
output of kernel messages via printk() calls. To provide the
necessary synchronization, usually some driver-specific locking
mechanism is used (for example, the port spinlock for uart
serial consoles).
Until now, usage of this driver-specific locking has been hidden
from the printk-subsystem and implemented within the various
console callbacks. However, nbcon consoles would need to use it
even in the generic code.
Add device_lock() and device_unlock() callback which will need
to get implemented by nbcon consoles.
The callbacks will use whatever synchronization mechanism the
driver is using for itself. The minimum requirement is to
prevent CPU migration. It would allow a context friendly
acquiring of nbcon console ownership in non-emergency and
non-panic context.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-9-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 43 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+)
diff --git a/include/linux/console.h b/include/linux/console.h
index 35c64ee..46b3c21 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -372,6 +372,49 @@ struct console {
*/
void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
+ /**
+ * @device_lock:
+ *
+ * NBCON callback to begin synchronization with driver code.
+ *
+ * Console drivers typically must deal with access to the hardware
+ * via user input/output (such as an interactive login shell) and
+ * output of kernel messages via printk() calls. This callback is
+ * called by the printk-subsystem whenever it needs to synchronize
+ * with hardware access by the driver. It should be implemented to
+ * use whatever synchronization mechanism the driver is using for
+ * itself (for example, the port lock for uart serial consoles).
+ *
+ * The callback is always called from task context. It may use any
+ * synchronization method required by the driver.
+ *
+ * IMPORTANT: The callback MUST disable migration. The console driver
+ * may be using a synchronization mechanism that already takes
+ * care of this (such as spinlocks). Otherwise this function must
+ * explicitly call migrate_disable().
+ *
+ * The flags argument is provided as a convenience to the driver. It
+ * will be passed again to device_unlock(). It can be ignored if the
+ * driver does not need it.
+ */
+ void (*device_lock)(struct console *con, unsigned long *flags);
+
+ /**
+ * @device_unlock:
+ *
+ * NBCON callback to finish synchronization with driver code.
+ *
+ * It is the counterpart to device_lock().
+ *
+ * This callback is always called from task context. It must
+ * appropriately re-enable migration (depending on how device_lock()
+ * disabled migration).
+ *
+ * The flags argument is the value of the same variable that was
+ * passed to device_lock().
+ */
+ void (*device_unlock)(struct console *con, unsigned long flags);
+
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
struct printk_buffers *pbufs;
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Use driver synchronization while (un)registering
2024-08-20 6:29 ` [PATCH printk v8 09/35] printk: nbcon: Use driver synchronization while (un)registering John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: e55c3bcf380c7593d768f31994eff63935081d06
Gitweb: https://git.kernel.org/tip/e55c3bcf380c7593d768f31994eff63935081d06
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:35 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: nbcon: Use driver synchronization while (un)registering
Console drivers typically have to deal with access to the
hardware via user input/output (such as an interactive login
shell) and output of kernel messages via printk() calls.
They use some classic driver-specific locking mechanism in most
situations. But console->write_atomic() callbacks, used by nbcon
consoles, are synchronized only by acquiring the console
context.
The synchronization via the console context ownership is possible
only when the console driver is registered. It is when a
particular device driver is connected with a particular console
driver.
The two synchronization mechanisms must be synchronized between
each other. It is tricky because the console context ownership
is quite special. It might be taken over by a higher priority
context. Also CPU migration must be disabled. The most tricky
part is to (dis)connect these two mechanisms during the console
(un)registration.
Use the driver-specific locking callbacks: device_lock(),
device_unlock(). They allow taking the device-specific lock
while the device is being (un)registered by the related console
driver.
For example, these callbacks lock/unlock the port lock for
serial port drivers.
Note that the driver-specific locking is only needed during
(un)register if it is an nbcon console with the write_atomic()
callback implemented. If write_atomic() is not implemented, the
driver should never attempt to access the hardware without
first acquiring its driver-specific lock.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-10-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 20c3950..4cd2c50 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3548,9 +3548,11 @@ static int unregister_console_locked(struct console *console);
*/
void register_console(struct console *newcon)
{
- struct console *con;
+ bool use_device_lock = (newcon->flags & CON_NBCON) && newcon->write_atomic;
bool bootcon_registered = false;
bool realcon_registered = false;
+ struct console *con;
+ unsigned long flags;
u64 init_seq;
int err;
@@ -3638,6 +3640,19 @@ void register_console(struct console *newcon)
}
/*
+ * If another context is actively using the hardware of this new
+ * console, it will not be aware of the nbcon synchronization. This
+ * is a risk that two contexts could access the hardware
+ * simultaneously if this new console is used for atomic printing
+ * and the other context is still using the hardware.
+ *
+ * Use the driver synchronization to ensure that the hardware is not
+ * in use while this new console transitions to being registered.
+ */
+ if (use_device_lock)
+ newcon->device_lock(newcon, &flags);
+
+ /*
* Put this console in the list - keep the
* preferred driver at the head of the list.
*/
@@ -3661,6 +3676,10 @@ void register_console(struct console *newcon)
* register_console() completes.
*/
+ /* This new console is now registered. */
+ if (use_device_lock)
+ newcon->device_unlock(newcon, flags);
+
console_sysfs_notify();
/*
@@ -3689,6 +3708,8 @@ EXPORT_SYMBOL(register_console);
/* Must be called under console_list_lock(). */
static int unregister_console_locked(struct console *console)
{
+ bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic;
+ unsigned long flags;
int res;
lockdep_assert_console_list_lock_held();
@@ -3707,8 +3728,18 @@ static int unregister_console_locked(struct console *console)
if (!console_is_registered_locked(console))
return -ENODEV;
+ /*
+ * Use the driver synchronization to ensure that the hardware is not
+ * in use while this console transitions to being unregistered.
+ */
+ if (use_device_lock)
+ console->device_lock(console, &flags);
+
hlist_del_init_rcu(&console->node);
+ if (use_device_lock)
+ console->device_unlock(console, flags);
+
/*
* <HISTORICAL>
* If this isn't the last console and it has CON_CONSDEV set, we
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Add detailed doc for write_atomic()
2024-08-20 6:29 ` [PATCH printk v8 07/35] printk: nbcon: Add detailed doc " John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 7d56936c1e5208b5eeea2a9a2f70e85248f6da49
Gitweb: https://git.kernel.org/tip/7d56936c1e5208b5eeea2a9a2f70e85248f6da49
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:33 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: nbcon: Add detailed doc for write_atomic()
The write_atomic() callback has special requirements and is
allowed to use special helper functions. Provide detailed
documentation of the callback so that a developer has a
chance of implementing it correctly.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-8-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 577b157..35c64ee 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -303,7 +303,7 @@ struct nbcon_write_context {
/**
* struct console - The console descriptor structure
* @name: The name of the console driver
- * @write: Write callback to output messages (Optional)
+ * @write: Legacy write callback to output messages (Optional)
* @read: Read callback for console input (Optional)
* @device: The underlying TTY device driver (Optional)
* @unblank: Callback to unblank the console (Optional)
@@ -320,7 +320,6 @@ struct nbcon_write_context {
* @data: Driver private data
* @node: hlist node for the console list
*
- * @write_atomic: Write callback for atomic context
* @nbcon_state: State for nbcon consoles
* @nbcon_seq: Sequence number of the next record for nbcon to print
* @pbufs: Pointer to nbcon private buffer
@@ -345,8 +344,34 @@ struct console {
struct hlist_node node;
/* nbcon console specific members */
- void (*write_atomic)(struct console *con,
- struct nbcon_write_context *wctxt);
+
+ /**
+ * @write_atomic:
+ *
+ * NBCON callback to write out text in any context. (Optional)
+ *
+ * This callback is called with the console already acquired. However,
+ * a higher priority context is allowed to take it over by default.
+ *
+ * The callback must call nbcon_enter_unsafe() and nbcon_exit_unsafe()
+ * around any code where the takeover is not safe, for example, when
+ * manipulating the serial port registers.
+ *
+ * nbcon_enter_unsafe() will fail if the context has lost the console
+ * ownership in the meantime. In this case, the callback is no longer
+ * allowed to go forward. It must back out immediately and carefully.
+ * The buffer content is also no longer trusted since it no longer
+ * belongs to the context.
+ *
+ * The callback should allow the takeover whenever it is safe. It
+ * increases the chance to see messages when the system is in trouble.
+ *
+ * The callback can be called from any context (including NMI).
+ * Therefore it must avoid usage of any locking and instead rely
+ * on the console ownership for synchronization.
+ */
+ void (*write_atomic)(struct console *con, struct nbcon_write_context *wctxt);
+
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
struct printk_buffers *pbufs;
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Remove return value for write_atomic()
2024-08-20 6:29 ` [PATCH printk v8 06/35] printk: nbcon: Remove return value for write_atomic() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: b7049d88c1763d5f133b0e93e39da8e89a9f944b
Gitweb: https://git.kernel.org/tip/b7049d88c1763d5f133b0e93e39da8e89a9f944b
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:32 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:23 +02:00
printk: nbcon: Remove return value for write_atomic()
The return value of write_atomic() does not provide any useful
information. On the contrary, it makes things more complicated
for the caller to appropriately deal with the information.
Change write_atomic() to not have a return value. If the
message did not get printed due to loss of ownership, the
caller will notice this on its own. If ownership was not lost,
it will be assumed that the driver successfully printed the
message and the sequence number for that console will be
incremented.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-7-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/console.h | 2 +-
kernel/printk/nbcon.c | 15 +++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index 31a8f5b..577b157 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -345,7 +345,7 @@ struct console {
struct hlist_node node;
/* nbcon console specific members */
- bool (*write_atomic)(struct console *con,
+ void (*write_atomic)(struct console *con,
struct nbcon_write_context *wctxt);
atomic_t __private nbcon_state;
atomic_long_t __private nbcon_seq;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 931b8f0..f279f83 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -885,7 +885,6 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
unsigned long con_dropped;
struct nbcon_state cur;
unsigned long dropped;
- bool done;
/*
* The printk buffers are filled within an unsafe section. This
@@ -925,16 +924,16 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt)
wctxt->unsafe_takeover = cur.unsafe_takeover;
if (con->write_atomic) {
- done = con->write_atomic(con, wctxt);
+ con->write_atomic(con, wctxt);
} else {
- nbcon_context_release(ctxt);
+ /*
+ * This function should never be called for legacy consoles.
+ * Handle it as if ownership was lost and try to continue.
+ */
WARN_ON_ONCE(1);
- done = false;
- }
-
- /* If not done, the emit was aborted. */
- if (!done)
+ nbcon_context_release(ctxt);
return false;
+ }
/*
* Since any dropped message was successfully output, reset the
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Clarify rules of the owner/waiter matching
2024-08-20 6:29 ` [PATCH printk v8 05/35] printk: nbcon: Clarify rules of the owner/waiter matching John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 8c9dab2c55ad74680728c72949971b20d70b56ca
Gitweb: https://git.kernel.org/tip/8c9dab2c55ad74680728c72949971b20d70b56ca
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:31 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:22 +02:00
printk: nbcon: Clarify rules of the owner/waiter matching
The functions nbcon_owner_matches() and nbcon_waiter_matches()
use a minimal set of data to determine if a context matches.
The existing kerneldoc and comments were not clear enough and
caused the printk folks to re-prove that the functions are
indeed reliable in all cases.
Update and expand the explanations so that it is clear that the
implementations are sufficient for all cases.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-6-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/nbcon.c | 56 ++++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 776746d..931b8f0 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -228,6 +228,13 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
struct nbcon_state new;
do {
+ /*
+ * Panic does not imply that the console is owned. However, it
+ * is critical that non-panic CPUs during panic are unable to
+ * acquire ownership in order to satisfy the assumptions of
+ * nbcon_waiter_matches(). In particular, the assumption that
+ * lower priorities are ignored during panic.
+ */
if (other_cpu_in_panic())
return -EPERM;
@@ -259,18 +266,29 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
/*
* The request context is well defined by the @req_prio because:
*
- * - Only a context with a higher priority can take over the request.
+ * - Only a context with a priority higher than the owner can become
+ * a waiter.
+ * - Only a context with a priority higher than the waiter can
+ * directly take over the request.
* - There are only three priorities.
* - Only one CPU is allowed to request PANIC priority.
* - Lower priorities are ignored during panic() until reboot.
*
* As a result, the following scenario is *not* possible:
*
- * 1. Another context with a higher priority directly takes ownership.
- * 2. The higher priority context releases the ownership.
- * 3. A lower priority context takes the ownership.
- * 4. Another context with the same priority as this context
+ * 1. This context is currently a waiter.
+ * 2. Another context with a higher priority than this context
+ * directly takes ownership.
+ * 3. The higher priority context releases the ownership.
+ * 4. Another lower priority context takes the ownership.
+ * 5. Another context with the same priority as this context
* creates a request and starts waiting.
+ *
+ * Event #1 implies this context is EMERGENCY.
+ * Event #2 implies the new context is PANIC.
+ * Event #3 occurs when panic() has flushed the console.
+ * Events #4 and #5 are not possible due to the other_cpu_in_panic()
+ * check in nbcon_context_try_acquire_direct().
*/
return (cur->req_prio == expected_prio);
@@ -578,11 +596,29 @@ static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu,
int expected_prio)
{
/*
- * Since consoles can only be acquired by higher priorities,
- * owning contexts are uniquely identified by @prio. However,
- * since contexts can unexpectedly lose ownership, it is
- * possible that later another owner appears with the same
- * priority. For this reason @cpu is also needed.
+ * A similar function, nbcon_waiter_matches(), only deals with
+ * EMERGENCY and PANIC priorities. However, this function must also
+ * deal with the NORMAL priority, which requires additional checks
+ * and constraints.
+ *
+ * For the case where preemption and interrupts are disabled, it is
+ * enough to also verify that the owning CPU has not changed.
+ *
+ * For the case where preemption or interrupts are enabled, an
+ * external synchronization method *must* be used. In particular,
+ * the driver-specific locking mechanism used in device_lock()
+ * (including disabling migration) should be used. It prevents
+ * scenarios such as:
+ *
+ * 1. [Task A] owns a context with NBCON_PRIO_NORMAL on [CPU X] and
+ * is scheduled out.
+ * 2. Another context takes over the lock with NBCON_PRIO_EMERGENCY
+ * and releases it.
+ * 3. [Task B] acquires a context with NBCON_PRIO_NORMAL on [CPU X]
+ * and is scheduled out.
+ * 4. [Task A] gets running on [CPU X] and sees that the console is
+ * still owned by a task on [CPU X] with NBON_PRIO_NORMAL. Thus
+ * [Task A] thinks it is the owner when it is not.
*/
if (cur->prio != expected_prio)
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Properly deal with nbcon consoles on seq init
2024-08-20 6:29 ` [PATCH printk v8 03/35] printk: Properly deal with nbcon consoles on seq init John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for Petr Mladek
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for Petr Mladek @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: d3ff380d47b6312d537c00829008528d1caad639
Gitweb: https://git.kernel.org/tip/d3ff380d47b6312d537c00829008528d1caad639
Author: Petr Mladek <pmladek@suse.com>
AuthorDate: Tue, 20 Aug 2024 08:35:29 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:22 +02:00
printk: Properly deal with nbcon consoles on seq init
If a non-boot console is registering and boot consoles exist,
the consoles are flushed before being unregistered. This allows
the non-boot console to continue where the boot console left
off.
If for whatever reason flushing fails, the lowest seq found from
any of the enabled boot consoles is used. Until now con->seq was
checked. However, if it is an nbcon boot console, the function
nbcon_seq_read() must be used to read seq because con->seq is
not updated for nbcon consoles.
Check if it is an nbcon boot console and if so call
nbcon_seq_read() to read seq.
Also, avoid usage of con->seq as temporary storage of the
starting record. Instead, rename console_init_seq() to
get_init_console_seq() and just return the value. For nbcon
consoles set the sequence via nbcon_seq_force(), for legacy
consoles set con->seq.
The cleaned design should make sure that the value stays and is
set before the console is added to the console list. It also
unifies the sequence number initialization for legacy and nbcon
consoles.
Reviewed-by: John Ogness <john.ogness@linutronix.de>
Link: https://lore.kernel.org/r/20240820063001.36405-4-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/nbcon.c | 3 +---
kernel/printk/printk.c | 41 +++++++++++++++++++++++++++++------------
2 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 670692d..776746d 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -172,9 +172,6 @@ void nbcon_seq_force(struct console *con, u64 seq)
u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb));
atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq));
-
- /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */
- con->seq = 0;
}
/**
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index a47017c..20c3950 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3448,19 +3448,21 @@ static void try_enable_default_console(struct console *newcon)
newcon->flags |= CON_CONSDEV;
}
-static void console_init_seq(struct console *newcon, bool bootcon_registered)
+/* Return the starting sequence number for a newly registered console. */
+static u64 get_init_console_seq(struct console *newcon, bool bootcon_registered)
{
struct console *con;
bool handover;
+ u64 init_seq;
if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) {
/* Get a consistent copy of @syslog_seq. */
mutex_lock(&syslog_lock);
- newcon->seq = syslog_seq;
+ init_seq = syslog_seq;
mutex_unlock(&syslog_lock);
} else {
/* Begin with next message added to ringbuffer. */
- newcon->seq = prb_next_seq(prb);
+ init_seq = prb_next_seq(prb);
/*
* If any enabled boot consoles are due to be unregistered
@@ -3481,7 +3483,7 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)
* Flush all consoles and set the console to start at
* the next unprinted sequence number.
*/
- if (!console_flush_all(true, &newcon->seq, &handover)) {
+ if (!console_flush_all(true, &init_seq, &handover)) {
/*
* Flushing failed. Just choose the lowest
* sequence of the enabled boot consoles.
@@ -3494,19 +3496,30 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)
if (handover)
console_lock();
- newcon->seq = prb_next_seq(prb);
+ init_seq = prb_next_seq(prb);
for_each_console(con) {
- if ((con->flags & CON_BOOT) &&
- (con->flags & CON_ENABLED) &&
- con->seq < newcon->seq) {
- newcon->seq = con->seq;
+ u64 seq;
+
+ if (!(con->flags & CON_BOOT) ||
+ !(con->flags & CON_ENABLED)) {
+ continue;
}
+
+ if (con->flags & CON_NBCON)
+ seq = nbcon_seq_read(con);
+ else
+ seq = con->seq;
+
+ if (seq < init_seq)
+ init_seq = seq;
}
}
console_unlock();
}
}
+
+ return init_seq;
}
#define console_first() \
@@ -3538,6 +3551,7 @@ void register_console(struct console *newcon)
struct console *con;
bool bootcon_registered = false;
bool realcon_registered = false;
+ u64 init_seq;
int err;
console_list_lock();
@@ -3615,10 +3629,13 @@ void register_console(struct console *newcon)
}
newcon->dropped = 0;
- console_init_seq(newcon, bootcon_registered);
+ init_seq = get_init_console_seq(newcon, bootcon_registered);
- if (newcon->flags & CON_NBCON)
- nbcon_seq_force(newcon, newcon->seq);
+ if (newcon->flags & CON_NBCON) {
+ nbcon_seq_force(newcon, init_seq);
+ } else {
+ newcon->seq = init_seq;
+ }
/*
* Put this console in the list - keep the
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: nbcon: Consolidate alloc() and init()
2024-08-20 6:29 ` [PATCH printk v8 02/35] printk: nbcon: Consolidate alloc() and init() John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for John Ogness
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits; +Cc: John Ogness, Petr Mladek, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: f37b105faef637cdaff334c0369b451410566ca0
Gitweb: https://git.kernel.org/tip/f37b105faef637cdaff334c0369b451410566ca0
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:28 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:22 +02:00
printk: nbcon: Consolidate alloc() and init()
Rather than splitting the nbcon allocation and initialization into
two pieces, perform all initialization in nbcon_alloc(). Later,
the initial sequence is calculated and can be explicitly set using
nbcon_seq_force(). This removes the need for the strong rules of
nbcon_init() that even included a BUG_ON().
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-3-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/internal.h | 2 --
kernel/printk/nbcon.c | 37 +++++++++++--------------------------
kernel/printk/printk.c | 2 +-
3 files changed, 12 insertions(+), 29 deletions(-)
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 19dcc58..398ecb4 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -75,7 +75,6 @@ u16 printk_parse_prefix(const char *text, int *level,
u64 nbcon_seq_read(struct console *con);
void nbcon_seq_force(struct console *con, u64 seq);
bool nbcon_alloc(struct console *con);
-void nbcon_init(struct console *con);
void nbcon_free(struct console *con);
#else
@@ -96,7 +95,6 @@ static inline bool printk_percpu_data_ready(void) { return false; }
static inline u64 nbcon_seq_read(struct console *con) { return 0; }
static inline void nbcon_seq_force(struct console *con, u64 seq) { }
static inline bool nbcon_alloc(struct console *con) { return false; }
-static inline void nbcon_init(struct console *con) { }
static inline void nbcon_free(struct console *con) { }
#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index c8093bc..670692d 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -929,17 +929,22 @@ update_con:
}
/**
- * nbcon_alloc - Allocate buffers needed by the nbcon console
- * @con: Console to allocate buffers for
+ * nbcon_alloc - Allocate and init the nbcon console specific data
+ * @con: Console to initialize
*
- * Return: True on success. False otherwise and the console cannot
- * be used.
+ * Return: True if the console was fully allocated and initialized.
+ * Otherwise @con must not be registered.
*
- * This is not part of nbcon_init() because buffer allocation must
- * be performed earlier in the console registration process.
+ * When allocation and init was successful, the console must be properly
+ * freed using nbcon_free() once it is no longer needed.
*/
bool nbcon_alloc(struct console *con)
{
+ struct nbcon_state state = { };
+
+ nbcon_state_set(con, &state);
+ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), 0);
+
if (con->flags & CON_BOOT) {
/*
* Boot console printing is synchronized with legacy console
@@ -959,26 +964,6 @@ bool nbcon_alloc(struct console *con)
}
/**
- * nbcon_init - Initialize the nbcon console specific data
- * @con: Console to initialize
- *
- * nbcon_alloc() *must* be called and succeed before this function
- * is called.
- *
- * This function expects that the legacy @con->seq has been set.
- */
-void nbcon_init(struct console *con)
-{
- struct nbcon_state state = { };
-
- /* nbcon_alloc() must have been called and successful! */
- BUG_ON(!con->pbufs);
-
- nbcon_seq_force(con, con->seq);
- nbcon_state_set(con, &state);
-}
-
-/**
* nbcon_free - Free and cleanup the nbcon console specific data
* @con: Console to free/cleanup nbcon data
*/
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 93c67eb..a47017c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3618,7 +3618,7 @@ void register_console(struct console *newcon)
console_init_seq(newcon, bootcon_registered);
if (newcon->flags & CON_NBCON)
- nbcon_init(newcon);
+ nbcon_seq_force(newcon, newcon->seq);
/*
* Put this console in the list - keep the
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Check printk_deferred_enter()/_exit() usage
2024-08-20 6:29 ` [PATCH printk v8 04/35] printk: Check printk_deferred_enter()/_exit() usage John Ogness
@ 2024-09-09 17:27 ` tip-bot2 for Sebastian Andrzej Siewior
0 siblings, 0 replies; 84+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2024-09-09 17:27 UTC (permalink / raw)
To: linux-tip-commits
Cc: Sebastian Andrzej Siewior, John Ogness, Petr Mladek, x86,
linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: 0e1d5731d3c1e2214249ef36dcd13ad51ad304cf
Gitweb: https://git.kernel.org/tip/0e1d5731d3c1e2214249ef36dcd13ad51ad304cf
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:30 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:22 +02:00
printk: Check printk_deferred_enter()/_exit() usage
Add validation that printk_deferred_enter()/_exit() are called in
non-migration contexts.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20240820063001.36405-5-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
include/linux/printk.h | 9 +++++----
kernel/printk/internal.h | 3 +++
kernel/printk/printk_safe.c | 12 ++++++++++++
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index b937cef..eee8e97 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -161,15 +161,16 @@ int _printk(const char *fmt, ...);
*/
__printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
-extern void __printk_safe_enter(void);
-extern void __printk_safe_exit(void);
+extern void __printk_deferred_enter(void);
+extern void __printk_deferred_exit(void);
+
/*
* The printk_deferred_enter/exit macros are available only as a hack for
* some code paths that need to defer all printk console printing. Interrupts
* must be disabled for the deferred duration.
*/
-#define printk_deferred_enter __printk_safe_enter
-#define printk_deferred_exit __printk_safe_exit
+#define printk_deferred_enter() __printk_deferred_enter()
+#define printk_deferred_exit() __printk_deferred_exit()
/*
* Please don't use printk_ratelimit(), because it shares ratelimiting state
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 398ecb4..dc8bc08 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -53,6 +53,9 @@ int vprintk_store(int facility, int level,
__printf(1, 0) int vprintk_default(const char *fmt, va_list args);
__printf(1, 0) int vprintk_deferred(const char *fmt, va_list args);
+void __printk_safe_enter(void);
+void __printk_safe_exit(void);
+
bool printk_percpu_data_ready(void);
#define printk_safe_enter_irqsave(flags) \
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
index 6d10927..4421cca 100644
--- a/kernel/printk/printk_safe.c
+++ b/kernel/printk/printk_safe.c
@@ -26,6 +26,18 @@ void __printk_safe_exit(void)
this_cpu_dec(printk_context);
}
+void __printk_deferred_enter(void)
+{
+ cant_migrate();
+ __printk_safe_enter();
+}
+
+void __printk_deferred_exit(void)
+{
+ cant_migrate();
+ __printk_safe_exit();
+}
+
asmlinkage int vprintk(const char *fmt, va_list args)
{
#ifdef CONFIG_KGDB_KDB
^ permalink raw reply related [flat|nested] 84+ messages in thread
* [tip: sched/rt] printk: Add notation to console_srcu locking
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
2024-08-20 17:49 ` Paul E. McKenney
@ 2024-09-09 17:28 ` tip-bot2 for John Ogness
1 sibling, 0 replies; 84+ messages in thread
From: tip-bot2 for John Ogness @ 2024-09-09 17:28 UTC (permalink / raw)
To: linux-tip-commits
Cc: John Ogness, Petr Mladek, Paul E. McKenney, x86, linux-kernel
The following commit has been merged into the sched/rt branch of tip:
Commit-ID: eda25860bf6e71932311f1b5acdf8fc05cd84ff3
Gitweb: https://git.kernel.org/tip/eda25860bf6e71932311f1b5acdf8fc05cd84ff3
Author: John Ogness <john.ogness@linutronix.de>
AuthorDate: Tue, 20 Aug 2024 08:35:27 +02:06
Committer: Petr Mladek <pmladek@suse.com>
CommitterDate: Wed, 21 Aug 2024 14:56:22 +02:00
printk: Add notation to console_srcu locking
kernel/printk/printk.c:284:5: sparse: sparse: context imbalance in
'console_srcu_read_lock' - wrong count at exit
include/linux/srcu.h:301:9: sparse: sparse: context imbalance in
'console_srcu_read_unlock' - unexpected unlock
Fixes: 6c4afa79147e ("printk: Prepare for SRCU console list protection")
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20240820063001.36405-2-john.ogness@linutronix.de
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c22b070..93c67eb 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -282,6 +282,7 @@ EXPORT_SYMBOL(console_list_unlock);
* Return: A cookie to pass to console_srcu_read_unlock().
*/
int console_srcu_read_lock(void)
+ __acquires(&console_srcu)
{
return srcu_read_lock_nmisafe(&console_srcu);
}
@@ -295,6 +296,7 @@ EXPORT_SYMBOL(console_srcu_read_lock);
* Counterpart to console_srcu_read_lock()
*/
void console_srcu_read_unlock(int cookie)
+ __releases(&console_srcu)
{
srcu_read_unlock_nmisafe(&console_srcu, cookie);
}
^ permalink raw reply related [flat|nested] 84+ messages in thread
end of thread, other threads:[~2024-09-09 17:28 UTC | newest]
Thread overview: 84+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-20 6:29 [PATCH printk v8 00/35] wire up write_atomic() printing John Ogness
2024-08-20 6:29 ` [PATCH printk v8 01/35] printk: Add notation to console_srcu locking John Ogness
2024-08-20 17:49 ` Paul E. McKenney
2024-09-09 17:28 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 02/35] printk: nbcon: Consolidate alloc() and init() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 03/35] printk: Properly deal with nbcon consoles on seq init John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Petr Mladek
2024-08-20 6:29 ` [PATCH printk v8 04/35] printk: Check printk_deferred_enter()/_exit() usage John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Sebastian Andrzej Siewior
2024-08-20 6:29 ` [PATCH printk v8 05/35] printk: nbcon: Clarify rules of the owner/waiter matching John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 06/35] printk: nbcon: Remove return value for write_atomic() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 07/35] printk: nbcon: Add detailed doc " John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 08/35] printk: nbcon: Add callbacks to synchronize with driver John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 09/35] printk: nbcon: Use driver synchronization while (un)registering John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 10/35] serial: core: Provide low-level functions to lock port John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 11/35] serial: core: Introduce wrapper to set @uart_port->cons John Ogness
2024-08-20 11:12 ` Ilpo Järvinen
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 12/35] console: Improve console_srcu_read_flags() comments John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 13/35] nbcon: Add API to acquire context for non-printing operations John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 14/35] serial: core: Acquire nbcon context in port->lock wrapper John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 15/35] printk: nbcon: Do not rely on proxy headers John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 16/35] printk: Make console_is_usable() available to nbcon.c John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 17/35] printk: Let console_is_usable() handle nbcon John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 18/35] printk: Add @flags argument for console_is_usable() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 19/35] printk: nbcon: Add helper to assign priority based on CPU state John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 20/35] printk: nbcon: Provide function to flush using write_atomic() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 21/35] printk: Track registered boot consoles John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 22/35] printk: nbcon: Use nbcon consoles in console_flush_all() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 23/35] printk: Add is_printk_legacy_deferred() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 24/35] printk: nbcon: Flush new records on device_release() John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 25/35] printk: Flush nbcon consoles first on panic John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 26/35] printk: nbcon: Add unsafe flushing " John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 27/35] printk: Avoid console_lock dance if no legacy or boot consoles John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 28/35] printk: Track nbcon consoles John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 29/35] printk: Coordinate direct printing in panic John Ogness
2024-08-20 15:21 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 30/35] printk: Add helper for flush type logic John Ogness
2024-08-21 9:11 ` Petr Mladek
2024-08-23 5:25 ` John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:29 ` [PATCH printk v8 31/35] printk: nbcon: Implement emergency sections John Ogness
2024-08-27 14:19 ` John Ogness
2024-09-04 10:34 ` Petr Mladek
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Use raw_cpu_ptr() instead of open coding tip-bot2 for John Ogness
2024-09-09 17:27 ` [tip: sched/rt] printk: nbcon: Implement emergency sections tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 32/35] panic: Mark emergency section in warn John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for Thomas Gleixner
2024-08-20 6:29 ` [PATCH printk v8 33/35] panic: Mark emergency section in oops John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:30 ` [PATCH printk v8 34/35] rcu: Mark emergency sections in rcu stalls John Ogness
2024-08-20 17:48 ` Paul E. McKenney
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-20 6:30 ` [PATCH printk v8 35/35] lockdep: Mark emergency sections in lockdep splats John Ogness
2024-09-09 17:27 ` [tip: sched/rt] " tip-bot2 for John Ogness
2024-08-21 9:21 ` [PATCH printk v8 00/35] wire up write_atomic() printing Petr Mladek
2024-08-21 9:28 ` Sebastian Andrzej Siewior
2024-08-21 14:09 ` Petr Mladek
2024-08-21 14:20 ` Sebastian Andrzej Siewior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox