[PATCH printk v4 02/27] printk: Properly deal with nbcon consoles on seq init

From: John Ogness
Date: Tue Apr 02 2024 - 18:12:08 EST


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 <john.ogness@xxxxxxxxxxxxx>
---
kernel/printk/nbcon.c | 7 +------
kernel/printk/printk.c | 29 ++++++++++++++++++++++++-----
2 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index c8093bcc01fe..d741659d26ec 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -172,9 +172,6 @@ void nbcon_seq_force(struct console *con, u64 seq)
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);
}

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c7c0ee2b47eb..b7e52b3f3e96 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3348,6 +3348,7 @@ static void try_enable_default_console(struct console *newcon)
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;
@@ -3396,11 +3397,20 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)

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;
}
}

@@ -3517,9 +3527,18 @@ void register_console(struct console *newcon)
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.
--
2.39.2