Re: [REGRESSION] clocksource: delayed watchdog can mark TSC unstable

From: Thomas Gleixner

Date: Thu Oct 15 2026 - 14:34:13 EST


On Sat, Oct 10 2026 at 08:55, Karl Mehltretter wrote:
> Since the watchdog rewrite in v7.1, the TSC can be marked unstable
> after a delayed watchdog run under QEMU TCG. Without injected stalls,
> this happened on 5 of 12 boots on a loaded host and 0 of 6 on an idle
> host.
>
> The delayed run re-arms the timer with an expiry already in the past.
> The watchdog then runs again almost immediately and rejects the TSC
> based on a roughly 75 us measurement interval.
>
> #regzbot introduced: 763aacf86f1b
>
> v7.3-rc5, 4 vCPUs, after vCPU 0 was stopped for 0.8 s:
>
> clocksource: Marking clocksource tsc unstable due to frequency skew
> clocksource: Watchdog hpet interval: 74940ns
> clocksource: Clocksource tsc interval: 74251ns
> clocksource: Switched to clocksource hpet
>
> The intervals are 75 us, not the 500 ms watchdog period. A function
> trace of clocksource_watchdog() from the same boot:
>
> busybox-79 [000] ..s1. 15.168486: clocksource_watchdog <-call_timer_fn
> busybox-79 [000] .Ns.. 16.269726: clocksource_watchdog <-call_timer_fn
> busybox-79 [000] .Ns.. 16.269820: clocksource_watchdog <-call_timer_fn

I did not think about that scenario obvioulsy. The code is resilient
against long intervals between two measurements, so the easy and
straight forward fix is indeed what you (or the LLM) suggested.

Thanks,

tglx
---
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -673,7 +673,7 @@ static void clocksource_watchdog(struct

/* Could have been rearmed by a stop/start cycle */
if (!timer_pending(&watchdog_timer)) {
- watchdog_timer.expires += WATCHDOG_INTERVAL;
+ watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
add_timer_local(&watchdog_timer);
}
}