NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/59339: heartbeat watchdog fires since 10.99.14



> Date: Fri, 9 May 2025 14:59:02 +0200
> From: Thomas Klausner <wiz%NetBSD.org@localhost>
> 
> Seems to have been the same problem both times:
> 
> (gdb) bt
> #4  0xffffffff80dff166 in itimer_arm_real (it=0xffff89c5007f1e80) at /usr/src/sys/kern/kern_time.c:837
> #5  0xffffffff80e007eb in itimer_settime (it=it@entry=0xffff89c5007f1e80) at /usr/src/sys/kern/kern_time.c:946

OK, that patch was a dud -- the assertion may not pass in that path,
but it should pass via itimer_callout.  Try the attached one instead?
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1746796090 0
#      Fri May 09 13:08:10 2025 +0000
# Branch trunk
# Node ID 05a98ecf5eda0704c8b94356f22e97870c808378
# Parent  55a6ded9e19ed0908fbb94d13fa69cda6d0b4571
# EXP-Topic riastradh-pr59339-heartbeat
WIP: Rearming a timer should never go backwards.  Assert it.

Handle overflow case gracefully while here (not likely relevant to
the symptoms we've seen, though).

PR kern/59339: heartbeat watchdog fires since 10.99.14

diff -r 55a6ded9e19e -r 05a98ecf5eda sys/kern/kern_time.c
--- a/sys/kern/kern_time.c	Thu May 08 20:51:40 2025 +0000
+++ b/sys/kern/kern_time.c	Fri May 09 13:08:10 2025 +0000
@@ -837,6 +837,55 @@ itimer_arm_real(struct itimer * const it
 }
 
 /*
+ * itimer_rearm_real:
+ *
+ *	Re-arm a non-virtual timer, given the current clock readout.
+ */
+static void
+itimer_rearm_real(struct itimer * const it, const struct timespec * const now)
+{
+	const struct timespec * const interval = &it->it_time.it_interval;
+	const struct timespec * const next = &it->it_time.it_value;
+	struct timespec delta;
+	int ticks;
+
+	KASSERT(!it->it_dying);
+	KASSERT(!CLOCK_VIRTUAL_P(it->it_clockid));
+	KASSERT(!callout_pending(&it->it_ch));
+
+	if (__predict_true(timespecisset(next))) {
+		KASSERTMSG(timespeccmp(now, next, <),
+		    "[clock %u]"
+		    " now=%lld.%09ld interval=%lld.%09ld then=%lld.%09ld",
+		    it->it_clockid,
+		    (long long)now->tv_sec, (long)now->tv_nsec,
+		    (long long)interval->tv_sec, (long)interval->tv_nsec,
+		    (long long)next->tv_sec, (long)next->tv_nsec);
+		timespecsub(next, now, &delta);
+	} else {
+		/*
+		 * If the arithmetic overflowed, just take the interval
+		 * as the time to wait.  This is unlikely to happen
+		 * unless you are messing with your clock to set it
+		 * ahead by hundreds of years.
+		 */
+		delta = it->it_time.it_interval; /* overflow */
+	}
+	ticks = tstohz(&delta);
+	KASSERTMSG(ticks > 0,
+	    "[clock %u]"
+	    " now=%lld.%09ld interval=%lld.%09ld then=%lld.%09ld"
+	    " delta=%lld.%09ld ticks=%d",
+	    it->it_clockid,
+	    (long long)now->tv_sec, (long)now->tv_nsec,
+	    (long long)interval->tv_sec, (long)interval->tv_nsec,
+	    (long long)next->tv_sec, (long)next->tv_nsec,
+	    (long long)delta.tv_sec, (long)delta.tv_nsec,
+	    ticks);
+	callout_schedule(&it->it_ch, ticks);
+}
+
+/*
  * itimer_callout:
  *
  *	Callout to expire a non-virtual timer.  Queue it up for processing,
@@ -872,6 +921,18 @@ itimer_callout(void *arg)
 	 * now, compute the next itimer value and count overruns.
 	 */
 	itimer_transition(&it->it_time, &now, &next, &overruns);
+	KASSERTMSG(timespeccmp(&now, &next, <),
+	    "[clock %u]"
+	    " it->it_time.it_value=%lld.%09ld"
+	    " it->it_time.it_interval=%lld.%09ld"
+	    " now=%lld.%09ld next=%lld.%09ld",
+	    it->it_clockid,
+	    (long long)it->it_time.it_value.tv_sec,
+	    (long)it->it_time.it_value.tv_nsec,
+	    (long long)it->it_time.it_interval.tv_sec,
+	    (long)it->it_time.it_interval.tv_nsec,
+	    (long long)now.tv_sec, (long)now.tv_nsec,
+	    (long long)next.tv_sec, (long)next.tv_nsec);
 	it->it_time.it_value = next;
 	it->it_overruns += overruns;
 
@@ -879,7 +940,7 @@ itimer_callout(void *arg)
 	 * Reset the callout, if it's not going away.
 	 */
 	if (!it->it_dying)
-		itimer_arm_real(it);
+		itimer_rearm_real(it, &now);
 	itimer_unlock();
 }
 


Home | Main Index | Thread Index | Old Index