Re: [patch 20/48] clocksource: Update clocksource::freq_khz on registration
From: Nathan Chancellor
Date: Wed Mar 04 2026 - 17:58:11 EST
On Wed, Mar 04, 2026 at 07:49:29PM +0100, Thomas Gleixner wrote:
> Borislav reported a division by zero in the timekeeping code and random
> hangs with the new coupled clocksource/clockevent functionality.
>
> It turned out that the TSC clocksource is not always updating the
> freq_khz field of the clocksource on registration. The coupled mode
> conversion calculation requires the frequency and as it's not
> initialized the resulting factor is zero or a random value. As a
> consequence this causes a division by zero or random boot hangs.
>
> Instead of chasing down all clocksources which fail to update that
> member, fill it in at registration time where the caller has to supply
> the frequency anyway. Except for special clocksources like jiffies which
> never can have coupled mode.
>
> To make this more robust put a check into the registration function to
> validate that the caller supplied a frequency if the coupled mode
> feature bit is set. If not, emit a warning and clear the feature bit.
>
> Fixes: cd38bdb8e696 ("timekeeping: Provide infrastructure for coupled clockevents")
> Reported-by: Borislav Petkov <bp@xxxxxxxxx>
> Reported-by: Nathan Chancellor <nathan@xxxxxxxxxx>
> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Tested-by: Nathan Chancellor <nathan@xxxxxxxxxx>
> ---
> kernel/time/clocksource.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> --- a/kernel/time/clocksource.c
> +++ b/kernel/time/clocksource.c
> @@ -1169,6 +1169,9 @@ void __clocksource_update_freq_scale(str
>
> clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
> NSEC_PER_SEC / scale, sec * scale);
> +
> + /* Update cs::freq_khz */
> + cs->freq_khz = div_u64((u64)freq * scale, 1000);
> }
>
> /*
> @@ -1241,6 +1244,10 @@ int __clocksource_register_scale(struct
>
> if (WARN_ON_ONCE((unsigned int)cs->id >= CSID_MAX))
> cs->id = CSID_GENERIC;
> +
> + if (WARN_ON_ONCE(!freq && cs->flags & CLOCK_SOURCE_HAS_COUPLED_CLOCK_EVENT))
> + cs->flags &= ~CLOCK_SOURCE_HAS_COUPLED_CLOCK_EVENT;
> +
> if (cs->vdso_clock_mode < 0 ||
> cs->vdso_clock_mode >= VDSO_CLOCKMODE_MAX) {
> pr_warn("clocksource %s registered with invalid VDSO mode %d. Disabling VDSO support.\n",