Subject: [PATCH 07/48] printk: Properly deal with nbcon consoles on seq init
From: John Ogness <[email-masked]>
Date: Wed, 22 Nov 2023 11:23:43 +0000

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 setup the nbcon sequence number and reset the legacy
sequence number from register_console() (rather than in
nbcon_init() and nbcon_seq_force()). This removes all legacy
sequence handling from nbcon.c so the code is easier to follow
and maintain.

Signed-off-by: John Ogness <[email-masked]>
Signed-off-by: Sebastian Andrzej Siewior <[email-masked]>
---
 kernel/printk/nbcon.c  |    7 +------
 kernel/printk/printk.c |   29 ++++++++++++++++++++++++-----
 2 files changed, 25 insertions(+), 11 deletions(-)

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
@@ -172,9 +172,6 @@ void nbcon_seq_force(struct console *con
 	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;
 }
 
 /**
@@ -964,8 +961,6 @@ bool nbcon_alloc(struct console *con)
  *
  * 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)
 {
@@ -974,7 +969,7 @@ void nbcon_init(struct console *con)
 	/* nbcon_alloc() must have been called and successful! */
 	BUG_ON(!con->pbufs);
 
-	nbcon_seq_force(con, con->seq);
+	nbcon_seq_force(con, 0);
 	nbcon_state_set(con, &state);
 }
 
Index: linux-6.8.2-rt10/kernel/printk/printk.c
===================================================================
--- linux-6.8.2-rt10.orig/kernel/printk/printk.c
+++ linux-6.8.2-rt10/kernel/printk/printk.c
@@ -3353,6 +3353,7 @@ static void try_enable_default_console(s
 		newcon->flags |= CON_CONSDEV;
 }
 
+/* Set @newcon->seq to the first record this console should print. */
 static void console_init_seq(struct console *newcon, bool bootcon_registered)
 {
 	struct console *con;
@@ -3401,11 +3402,20 @@ static void console_init_seq(struct cons
 
 				newcon->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 < newcon->seq)
+						newcon->seq = seq;
 				}
 			}
 
@@ -3522,9 +3532,18 @@ void register_console(struct console *ne
 	newcon->dropped = 0;
 	console_init_seq(newcon, bootcon_registered);
 
-	if (newcon->flags & CON_NBCON)
+	if (newcon->flags & CON_NBCON) {
 		nbcon_init(newcon);
 
+		/*
+		 * nbcon consoles have their own sequence counter. The legacy
+		 * sequence counter is reset so that it is clear it is not
+		 * being used.
+		 */
+		nbcon_seq_force(newcon, newcon->seq);
+		newcon->seq = 0;
+	}
+
 	/*
 	 * Put this console in the list - keep the
 	 * preferred driver at the head of the list.