From: John Ogness Date: Wed, 4 Sep 2024 14:11:23 +0206 Subject: [PATCH 41/54] printk: nbcon: Add context to usable() and emit() Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.11/older/patches-6.11-rt7.tar.xz The nbcon consoles will have two callbacks to be used for different contexts. In order to determine if an nbcon console is usable, console_is_usable() must know if it is a context that will need to use the optional write_atomic() callback. Also, nbcon_emit_next_record() must know which callback it needs to call. Add an extra parameter @use_atomic to console_is_usable() and nbcon_emit_next_record() to specify this. Since so far only the write_atomic() callback exists, @use_atomic is set to true for all call sites. For legacy consoles, @use_atomic is not used. Signed-off-by: John Ogness Reviewed-by: Petr Mladek Link: https://lore.kernel.org/r/20240904120536.115780-5-john.ogness@linutronix.de Signed-off-by: Petr Mladek Signed-off-by: Sebastian Andrzej Siewior --- kernel/printk/internal.h | 8 +++++--- kernel/printk/nbcon.c | 34 +++++++++++++++++++--------------- kernel/printk/printk.c | 6 +++--- 3 files changed, 27 insertions(+), 21 deletions(-) --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -97,7 +97,7 @@ bool nbcon_legacy_emit_next_record(struc * which can also play a role in deciding if @con can be used to print * records. */ -static inline bool console_is_usable(struct console *con, short flags) +static inline bool console_is_usable(struct console *con, short flags, bool use_atomic) { if (!(flags & CON_ENABLED)) return false; @@ -106,7 +106,8 @@ static inline bool console_is_usable(str return false; if (flags & CON_NBCON) { - if (!con->write_atomic) + /* The write_atomic() callback is optional. */ + if (use_atomic && !con->write_atomic) return false; } else { if (!con->write) @@ -149,7 +150,8 @@ static inline void nbcon_atomic_flush_pe 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; } +static inline bool console_is_usable(struct console *con, short flags, + bool use_atomic) { return false; } #endif /* CONFIG_PRINTK */ --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -922,6 +922,7 @@ EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf) /** * 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 * * Return: True if this context still owns the console. False if * ownership was handed over or taken. @@ -935,7 +936,7 @@ EXPORT_SYMBOL_GPL(nbcon_reacquire_nobuf) * When true is returned, @wctxt->ctxt.backlog indicates whether there are * still records pending in the ringbuffer, */ -static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt) +static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_atomic) { struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt); struct console *con = ctxt->console; @@ -947,6 +948,18 @@ static bool nbcon_emit_next_record(struc unsigned long dropped; /* + * This function should never be called for consoles that have not + * implemented the necessary callback for writing: i.e. legacy + * consoles and, when atomic, nbcon consoles with no write_atomic(). + * Handle it as if ownership was lost and try to continue. + */ + if (WARN_ON_ONCE((use_atomic && !con->write_atomic) || + !(console_srcu_read_flags(con) & CON_NBCON))) { + nbcon_context_release(ctxt); + return false; + } + + /* * The printk buffers are filled within an unsafe section. This * prevents NBCON_PRIO_NORMAL and NBCON_PRIO_EMERGENCY from * clobbering each other. @@ -980,17 +993,8 @@ static bool nbcon_emit_next_record(struc /* Initialize the write context for driver callbacks. */ nbcon_write_context_set_buf(wctxt, &pmsg.pbufs->outbuf[0], pmsg.outbuf_len); - if (con->write_atomic) { + if (use_atomic) con->write_atomic(con, wctxt); - } else { - /* - * This function should never be called for legacy consoles. - * Handle it as if ownership was lost and try to continue. - */ - WARN_ON_ONCE(1); - nbcon_context_release(ctxt); - return false; - } if (!wctxt->outbuf) { /* @@ -1118,7 +1122,7 @@ static bool nbcon_atomic_emit_one(struct * The higher priority printing context takes over responsibility * to print the pending records. */ - if (!nbcon_emit_next_record(wctxt)) + if (!nbcon_emit_next_record(wctxt, true)) return false; nbcon_context_release(ctxt); @@ -1219,7 +1223,7 @@ static int __nbcon_atomic_flush_pending_ * handed over or taken over. In both cases the context is no * longer valid. */ - if (!nbcon_emit_next_record(&wctxt)) + if (!nbcon_emit_next_record(&wctxt, true)) return -EAGAIN; if (!ctxt->backlog) { @@ -1305,7 +1309,7 @@ static void __nbcon_atomic_flush_pending if (!(flags & CON_NBCON)) continue; - if (!console_is_usable(con, flags)) + if (!console_is_usable(con, flags, true)) continue; if (nbcon_seq_read(con) >= stop_seq) @@ -1490,7 +1494,7 @@ void nbcon_device_release(struct console * the console is usable throughout flushing. */ cookie = console_srcu_read_lock(); - if (console_is_usable(con, console_srcu_read_flags(con)) && + if (console_is_usable(con, console_srcu_read_flags(con), true) && prb_read_valid(prb, nbcon_seq_read(con), NULL)) { /* * If nbcon_atomic flushing is not available, fallback to --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3072,7 +3072,7 @@ static bool console_flush_all(bool do_co u64 printk_seq; bool progress; - if (!console_is_usable(con, flags)) + if (!console_is_usable(con, flags, true)) continue; any_usable = true; @@ -3774,7 +3774,7 @@ static int unregister_console_locked(str if (!console_is_registered_locked(console)) res = -ENODEV; - else if (console_is_usable(console, console->flags)) + else if (console_is_usable(console, console->flags, true)) __pr_flush(console, 1000, true); /* Disable it unconditionally */ @@ -4044,7 +4044,7 @@ static bool __pr_flush(struct console *c * that they make forward progress, so only increment * @diff for usable consoles. */ - if (!console_is_usable(c, flags)) + if (!console_is_usable(c, flags, true)) continue; if (flags & CON_NBCON) {