Module Name:    src
Committed By:   riastradh
Date:           Sat Sep  2 17:44:23 UTC 2023

Modified Files:
        src/sys/kern: kern_heartbeat.c

Log Message:
heartbeat(9): Ignore stale tc if primary CPU heartbeat is suspended.

The timecounter ticks only on the primary CPU, so of course it will
go stale if it's suspended.

(It is, perhaps, a mistake that it only ticks on the primary CPU,
even if the primary CPU is offlined or in a polled-input console
loop, but that's a separate issue.)


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/kern/kern_heartbeat.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_heartbeat.c
diff -u src/sys/kern/kern_heartbeat.c:1.6 src/sys/kern/kern_heartbeat.c:1.7
--- src/sys/kern/kern_heartbeat.c:1.6	Sat Sep  2 17:43:37 2023
+++ src/sys/kern/kern_heartbeat.c	Sat Sep  2 17:44:23 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_heartbeat.c,v 1.6 2023/09/02 17:43:37 riastradh Exp $	*/
+/*	$NetBSD: kern_heartbeat.c,v 1.7 2023/09/02 17:44:23 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2023 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.6 2023/09/02 17:43:37 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_heartbeat.c,v 1.7 2023/09/02 17:44:23 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -199,6 +199,41 @@ heartbeat_resume(void)
 }
 
 /*
+ * heartbeat_timecounter_suspended()
+ *
+ *	True if timecounter heartbeat checks are suspended because the
+ *	timecounter may not be advancing, false if heartbeat checks
+ *	should check for timecounter progress.
+ */
+static bool
+heartbeat_timecounter_suspended(void)
+{
+	CPU_INFO_ITERATOR cii;
+	struct cpu_info *ci;
+
+	/*
+	 * The timecounter ticks only on the primary CPU.  Check
+	 * whether it's suspended.
+	 *
+	 * XXX Would be nice if we could find the primary CPU without
+	 * iterating over all CPUs.
+	 */
+	for (CPU_INFO_FOREACH(cii, ci)) {
+		if (CPU_IS_PRIMARY(ci)) {
+			return ci->ci_schedstate.spc_flags &
+			    SPCF_HEARTBEATSUSPENDED;
+		}
+	}
+
+	/*
+	 * This should be unreachable -- there had better be a primary
+	 * CPU in the system!  If not, the timecounter will be busted
+	 * anyway.
+	 */
+	panic("no primary CPU");
+}
+
+/*
  * heartbeat_reset_xc(a, b)
  *
  *	Cross-call handler to reset heartbeat state just prior to
@@ -598,7 +633,8 @@ heartbeat(void)
 		/*
 		 * Timecounter hasn't advanced by more than a second.
 		 * Make sure the timecounter isn't stuck according to
-		 * our heartbeats.
+		 * our heartbeats -- unless timecounter heartbeats are
+		 * suspended too.
 		 *
 		 * Our own heartbeat count can't roll back, and
 		 * time_uptime should be updated before it wraps
@@ -608,7 +644,8 @@ heartbeat(void)
 		stamp =
 		    atomic_load_relaxed(&curcpu()->ci_heartbeat_uptime_stamp);
 		d = count - stamp;
-		if (__predict_false(d > period_ticks)) {
+		if (__predict_false(d > period_ticks) &&
+		    !heartbeat_timecounter_suspended()) {
 			panic("%s: time has not advanced in %u heartbeats",
 			    cpu_name(curcpu()), d);
 		}

Reply via email to