git: 95007bfd64c6 - stable/14 - vt(4): Skip vt_window_switch() for nested panics

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Sat, 17 Feb 2024 21:32:29 UTC
The branch stable/14 has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=95007bfd64c63f217c97210cd4cdf2d729f2f696

commit 95007bfd64c63f217c97210cd4cdf2d729f2f696
Author:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2023-11-24 17:30:33 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2024-02-17 20:58:34 +0000

    vt(4): Skip vt_window_switch() for nested panics
    
    [Why]
    The same protection was added to vt_flush() in the previous commit. We
    want the same one in vt_window_switch(): if e.g. the DRM driver panics
    while handling a call to vt_window_switch(), we don't want to
    recursively call vt_window_switch() again and trigger another panic.
    
    Reviewed by:    imp, manu
    Approved by:    imp, manu
    Differential Revision:  https://reviews.freebsd.org/D42750
    
    (cherry picked from commit 24d6f256f825e5d7f8ca6b5d16499f13614f9cdd)
---
 sys/dev/vt/vt_core.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 406472a8fbf6..6d44c81181a3 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -275,6 +275,7 @@ SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade,
     &vt_consdev);
 
 static bool inside_vt_flush = false;
+static bool inside_vt_window_switch = false;
 
 /* Initialize locks/mem depended members. */
 static void
@@ -564,6 +565,11 @@ vt_window_switch(struct vt_window *vw)
 	struct vt_window *curvw = vd->vd_curwindow;
 	keyboard_t *kbd;
 
+	if (inside_vt_window_switch && KERNEL_PANICKED())
+		return (0);
+
+	inside_vt_window_switch = true;
+
 	if (kdb_active) {
 		/*
 		 * When grabbing the console for the debugger, avoid
@@ -575,13 +581,16 @@ vt_window_switch(struct vt_window *vw)
 		 */
 		if (curvw == vw)
 			return (0);
-		if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE)))
+		if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
+			inside_vt_window_switch = false;
 			return (EINVAL);
+		}
 
 		vd->vd_curwindow = vw;
 		vd->vd_flags |= VDF_INVALID;
 		if (vd->vd_driver->vd_postswitch)
 			vd->vd_driver->vd_postswitch(vd);
+		inside_vt_window_switch = false;
 		return (0);
 	}
 
@@ -595,10 +604,12 @@ vt_window_switch(struct vt_window *vw)
 		if ((kdb_active || KERNEL_PANICKED()) &&
 		    vd->vd_driver->vd_postswitch)
 			vd->vd_driver->vd_postswitch(vd);
+		inside_vt_window_switch = false;
 		VT_UNLOCK(vd);
 		return (0);
 	}
 	if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
+		inside_vt_window_switch = false;
 		VT_UNLOCK(vd);
 		return (EINVAL);
 	}
@@ -627,6 +638,7 @@ vt_window_switch(struct vt_window *vw)
 	mtx_unlock(&Giant);
 	DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
 
+	inside_vt_window_switch = false;
 	return (0);
 }