From: John Ogness Date: Fri, 20 Oct 2023 10:01:58 +0000 Subject: [PATCH 41/46] printk: nbcon: Provide function to reacquire ownership Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.9/older/patches-6.9-rt5.tar.xz Contexts may become nbcon owners for various reasons, not just for printing. Indeed, the port->lock wrapper takes ownership for anything relating to the hardware. Since ownership can be lost at any time due to handover or takeover, a context _should_ be prepared to back out immediately and carefully. However, there are many scenarios where the context _must_ reacquire ownership in order to finalize or revert hardware changes. One such example is when interrupts are disabled by a context. No other context will automagically re-enable the interrupts. For this case, the disabling context _must_ reacquire nbcon ownership so that it can re-enable the interrupts. Provide nbcon_reacquire() for exactly this purpose. Note that for printing contexts, after a successful reacquire the context will have no output buffer because that has been lost. nbcon_reacquire() cannot be used to resume printing. Signed-off-by: John Ogness Signed-off-by: Sebastian Andrzej Siewior --- include/linux/console.h | 7 +++++++ kernel/printk/nbcon.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) --- a/include/linux/console.h +++ b/include/linux/console.h @@ -373,6 +373,11 @@ struct console { * The callback should allow the takeover whenever it is safe. It * increases the chance to see messages when the system is in trouble. * + * If the driver must reacquire ownership in order to finalize or + * revert hardware changes, nbcon_reacquire() can be used. However, + * on reacquire the buffer content is no longer available. A + * reacquire cannot be used to resume printing. + * * 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. @@ -591,6 +596,7 @@ extern void nbcon_cpu_emergency_flush(vo 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); +extern void nbcon_reacquire(struct nbcon_write_context *wctxt); #else static inline void nbcon_cpu_emergency_enter(void) { } static inline void nbcon_cpu_emergency_exit(void) { } @@ -598,6 +604,7 @@ static inline void nbcon_cpu_emergency_f 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; } +static inline void nbcon_reacquire(struct nbcon_write_context *wctxt) { } #endif extern int console_set_on_cmdline; --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -839,6 +839,38 @@ bool nbcon_exit_unsafe(struct nbcon_writ EXPORT_SYMBOL_GPL(nbcon_exit_unsafe); /** + * nbcon_reacquire - Reacquire a console after losing ownership + * @wctxt: The write context that was handed to the write function + * + * Since ownership can be lost at any time due to handover or takeover, a + * printing context _should_ be prepared to back out immediately and + * carefully. However, there are many scenarios where the context _must_ + * reacquire ownership in order to finalize or revert hardware changes. + * + * This function allows a context to reacquire ownership using the same + * priority as its previous ownership. + * + * Note that for printing contexts, after a successful reacquire the + * context will have no output buffer because that has been lost. This + * function cannot be used to resume printing. + */ +void nbcon_reacquire(struct nbcon_write_context *wctxt) +{ + struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); + struct console *con = ctxt->console; + struct nbcon_state cur; + + while (!nbcon_context_try_acquire(ctxt)) + cpu_relax(); + + wctxt->outbuf = NULL; + wctxt->len = 0; + nbcon_state_read(con, &cur); + wctxt->unsafe_takeover = cur.unsafe_takeover; +} +EXPORT_SYMBOL_GPL(nbcon_reacquire); + +/** * nbcon_emit_next_record - Emit a record in the acquired context * @wctxt: The write context that will be handed to the write function * @use_atomic: True if the write_atomic callback is to be used @@ -944,6 +976,15 @@ static bool nbcon_emit_next_record(struc nbcon_context_release(ctxt); return false; } + + if (!wctxt->outbuf) { + /* + * Ownership was lost and reacquired by the driver. + * Handle it as if ownership was lost and try to continue. + */ + nbcon_context_release(ctxt); + return false; + } /* * Since any dropped message was successfully output, reset the