Subject: [PATCH 43/48] printk: nbcon: Provide function to reacquire ownership
From: John Ogness <[email-masked]>
Date: Fri, 20 Oct 2023 10:01:58 +0000

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 <[email-masked]>
Signed-off-by: Sebastian Andrzej Siewior <[email-masked]>
---
 include/linux/console.h |    7 +++++++
 kernel/printk/nbcon.c   |   41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

Index: linux-6.8.2-rt10/include/linux/console.h
===================================================================
--- linux-6.8.2-rt10.orig/include/linux/console.h
+++ linux-6.8.2-rt10/include/linux/console.h
@@ -371,6 +371,11 @@ struct console {
 	 * functions are also points of possible ownership transfer. If
 	 * either function returns false, ownership has been lost.
 	 *
+	 * 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.
+	 *
 	 * This 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.
@@ -595,12 +600,14 @@ extern void nbcon_cpu_emergency_exit(voi
 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) { }
 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;
Index: linux-6.8.2-rt10/kernel/printk/nbcon.c
===================================================================
--- linux-6.8.2-rt10.orig/kernel/printk/nbcon.c
+++ linux-6.8.2-rt10/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