git: 8ec6d7be2e27 - main - kern: console: make /dev/console backing console more predictable

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Fri, 05 Jan 2024 15:55:03 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=8ec6d7be2e27622b8b9e192b4da9ce88a4118636

commit 8ec6d7be2e27622b8b9e192b4da9ce88a4118636
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2024-01-05 06:09:31 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2024-01-05 15:52:29 +0000

    kern: console: make /dev/console backing console more predictable
    
    Specifically, altering the console list with conscontrol has some weird
    behavior:
    
    1. If you remove the first configured console, /dev/console will become
      unconfigured
    2. Any console added becomes the /dev/console
    
    In a multicons situation, #1 is clearly a bug and #2 is perhaps slightly
    less clear.  If we have ttyu0, ttyv0, then it seems obvious that one
    would want ttyv0 to take over the console if ttyu0 is removed.  If we
    add ttyu0 back in, then it's debatable whether it should take over the
    console or not.
    
    Fix it now to make the /dev/console selection more FIFO-ish, with
    respect to how conscontrol affects it.  A `primary` verb for
    conscontrol(8) might be a good addition.
---
 sys/kern/kern_cons.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/sys/kern/kern_cons.c b/sys/kern/kern_cons.c
index 462cd0c45758..d4a858cb12fd 100644
--- a/sys/kern/kern_cons.c
+++ b/sys/kern/kern_cons.c
@@ -239,15 +239,31 @@ cnremove(struct consdev *cn)
 {
 	struct cn_device *cnd;
 	int i;
+	bool primary = true;
 
 	STAILQ_FOREACH(cnd, &cn_devlist, cnd_next) {
-		if (cnd->cnd_cn != cn)
+		if (cnd->cnd_cn != cn) {
+			primary = false;
 			continue;
-		if (STAILQ_FIRST(&cn_devlist) == cnd)
-			ttyconsdev_select(NULL);
+		}
+
 		STAILQ_REMOVE(&cn_devlist, cnd, cn_device, cnd_next);
 		cnd->cnd_cn = NULL;
 
+		/*
+		 * We only need to select a new console if we've removed all
+		 * consoles or if we're removing the primary console.
+		 */
+		if (primary) {
+			struct cn_device *next;
+
+			next = STAILQ_FIRST(&cn_devlist);
+			if (next == NULL)
+				ttyconsdev_select(NULL);
+			else
+				ttyconsdev_select(next->cnd_cn->cn_name);
+		}
+
 		/* Remove this device from available mask. */
 		for (i = 0; i < CNDEVTAB_SIZE; i++) 
 			if (cnd == &cn_devtab[i]) {
@@ -356,8 +372,6 @@ sysctl_kern_console(SYSCTL_HANDLER_ARGS)
 				error = 0;
 			} else {
 				error = cnadd(cp);
-				if (error == 0)
-					cnselect(cp);
 			}
 			break;
 		}