kdb: Adapt kdb_msg_write to work with NBCON consoles

Function kdb_msg_write was calling con->write for any found console,
but it won't work on NBCON consoles. In this case we should acquire the
ownership of the console using NBCON_PRIO_EMERGENCY, since printing
kdb messages should only be interrupted by a panic.

At this point, the console is required to use the atomic callback. The
console is skipped if the write_atomic callback is not set or if the
context could not be acquired. The validation of NBCON is done by the
console_is_usable helper. The context is released right after
write_atomic finishes.

The oops_in_progress handling is only needed in the legacy consoles,
so it was moved around the con->write callback.

Suggested-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
Link: https://patch.msgid.link/20251016-nbcon-kgdboc-v6-5-866aac60a80e@suse.com
[pmladek@suse.com: Fixed compilation with !CONFIG_PRINTK.]
Signed-off-by: Petr Mladek <pmladek@suse.com>
This commit is contained in:
Marcos Paulo de Souza 2025-10-16 11:47:58 -03:00 committed by Petr Mladek
parent 4349cf0df3
commit 62627bf0ca
2 changed files with 33 additions and 16 deletions

View File

@ -664,7 +664,7 @@ static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return
static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
static inline bool nbcon_kdb_try_acquire(struct console *con,
struct nbcon_write_context *wctxt) { return false; }
static inline void nbcon_kdb_release(struct console *con) { }
static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
static inline bool console_is_usable(struct console *con, short flags,
bool use_atomic) { return false; }
#endif

View File

@ -589,24 +589,41 @@ static void kdb_msg_write(const char *msg, int msg_len)
*/
cookie = console_srcu_read_lock();
for_each_console_srcu(c) {
if (!(console_srcu_read_flags(c) & CON_ENABLED))
short flags = console_srcu_read_flags(c);
if (!console_is_usable(c, flags, true))
continue;
if (c == dbg_io_ops->cons)
continue;
if (!c->write)
continue;
/*
* Set oops_in_progress to encourage the console drivers to
* disregard their internal spin locks: in the current calling
* context the risk of deadlock is a bigger problem than risks
* due to re-entering the console driver. We operate directly on
* oops_in_progress rather than using bust_spinlocks() because
* the calls bust_spinlocks() makes on exit are not appropriate
* for this calling context.
*/
++oops_in_progress;
c->write(c, msg, msg_len);
--oops_in_progress;
if (flags & CON_NBCON) {
struct nbcon_write_context wctxt = { };
/*
* Do not continue if the console is NBCON and the context
* can't be acquired.
*/
if (!nbcon_kdb_try_acquire(c, &wctxt))
continue;
nbcon_write_context_set_buf(&wctxt, (char *)msg, msg_len);
c->write_atomic(c, &wctxt);
nbcon_kdb_release(&wctxt);
} else {
/*
* Set oops_in_progress to encourage the console drivers to
* disregard their internal spin locks: in the current calling
* context the risk of deadlock is a bigger problem than risks
* due to re-entering the console driver. We operate directly on
* oops_in_progress rather than using bust_spinlocks() because
* the calls bust_spinlocks() makes on exit are not appropriate
* for this calling context.
*/
++oops_in_progress;
c->write(c, msg, msg_len);
--oops_in_progress;
}
touch_nmi_watchdog();
}
console_srcu_read_unlock(cookie);