From nobody Mon Jun 8 23:58:07 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A552538A70C for ; Mon, 25 May 2026 13:59:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717565; cv=none; b=Z0d5/Tpj0jGhGYIq2BO6OhM4UMZgDxwQlXAjgvbiYRwgHSNXAmT5xqNp6HbC9dm3vowYq2E0QFNppPerENuXyrtJeRt6rUWoPLRiiWBhyRFRjMMzbBWC0Kmhawot5gjYWezhncYDbqgt2ysazgVVxSTHBRjUMIidFqh2upRqWH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717565; c=relaxed/simple; bh=Ymshpxts35jtznKhArfX/R613HuA86pKX1gp5ZhctLU=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MgzAO0Jyc6vA/q6leOwWpWUtXduyQEaATmyUluYVsI+ULps9TFf58socqEGiPSSA6mOYjnQZzlizMt4DKTW9j6ceAGblU1T0or7yqj5fREIL5pFIOfDpgZc4d3U7DX0CpmeiDfwEUaP6DVHLOuY7/HFoHarhvFT2jPzOqwhjqEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=desiato.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=dj2xT286; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=desiato.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="dj2xT286" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=ls9Wyv1Fa/gNVOsC4hng3TBpLmPYrLEVnG7kPOtVWWo=; b=dj2xT286EQBBO3MgTmtq6KOb10 0IVsbJI8hmUZpxwTSWm+S2cmSGRQaQ9xi+HMPfzsN7aoxOXHRCRjgAKHUKp7kAl6o7fVIny0O+XgD EIYeFqXvdnZ7lon0L2dQ5AJn0oR/huDE39G2xhHI65uLj8+pD+kdQsNELSKka5v8CRSr9g1s9G+94 z9peESdCZovKSlrRyiOUnqQ8w0dx00l7CpsPO5z+sK/0hQ9RmV4WIM6xipqa/0i/DfsNW2gKKYfEL d7hS5Co/2JISmUqCMZUmgQhytyjvM1Rscb0C0tmKkts02J0BWYsY76bsc6ey/9rInzyht0ZlFoeKk kOmVIO4A==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpj-00000009LYA-2Rh4; Mon, 25 May 2026 13:59:08 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrg-1Cpe; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 1/7] MAINTAINERS: Add Miroslav as timekeeping reviewer Date: Mon, 25 May 2026 14:54:33 +0100 Message-ID: <20260525135904.126282-2-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html Content-Type: text/plain; charset="utf-8" From: David Woodhouse If Thomas is going to nudge me on IRC to add Miroslav to Cc on timekeeping patches, then he might as well actually be listed in the MAINTAINERS file. Signed-off-by: David Woodhouse Acked-by: John Stultz --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 882214b0e7db..de39cc3e7e68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26877,6 +26877,7 @@ TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER M: John Stultz M: Thomas Gleixner R: Stephen Boyd +R: Miroslav Lichvar L: linux-kernel@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/co= re --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 445F938A715 for ; Mon, 25 May 2026 13:59:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717568; cv=none; b=JghfoBwU62omb3MWpSCQRNV4jelat/Rt84XuHzcBTL5Vke4yxSn2HWIF2KIGUn4uRc64/AaPUzIfvas6rttm6shwKMQUnlGB2E2OPM8M4OR/BEL0daWq73fuoYpCASEseZox2CBsDiJ0xZC6Yw/bDzPqwNWLiMU36p2pm4VqmIQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717568; c=relaxed/simple; bh=5QuOCLE6wRO2zGg5F/CjdzTLiXCu4VVieFa4jZGpmCE=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gOBD2Lc1zb4un4PiBdTpxXjMFvRnS7sFzPEWntMvqumcs2BI/bIN9MbFNwAERp3w77R30ncIBNP0q5b80ACOp5hy0vn3bY7xeV1GSGmQsJb/bnK1mevypF0LapjglH8/4qV9JCGZJdHUYTYZfJYX9v8kbGTrub1OL0N6lEtSvas= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=DNrKo6X7; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="DNrKo6X7" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=AoVB82RYSrEcrW+Hmsx7WZg+eBnBz48ovK1HfN21KQ4=; b=DNrKo6X7skvbhQy5B6v0MTbzBK Im2odVmp+cdzXfkHePkPK8HvyrFvZPur/5fmQTqIZvJCySskNA5ENiIS4xkTvQg5se5oyw8imr/jc 60ahE81UOSEn2gFbMIbx9tGSdnLQUYAF/oGumQW6XntW7EL7bDsr1WH/97/eo53QzMl6spTIHiFQi v99epnSGGALo4uwdGgiP0nv+dQL4VpeGyCzPeURRKoiG6I34PE2ueKXVDlCmCG9mlFPFb8pjutt8t 4yvaQVHKYW9i1/lkw42e03EcJzXV3i78FMq6mj+Ij3jcmSXIx2rGeyv6xBhx7J6ys4PB4EmQD0pP+ RSODeRYw==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpk-0000000HBAQ-02iF; Mon, 25 May 2026 13:59:09 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrj-1MT4; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 2/7] timekeeping: Remove xtime_remainder from ntp_error accumulation Date: Mon, 25 May 2026 14:54:34 +0100 Message-ID: <20260525135904.126282-3-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Content-Type: text/plain; charset="utf-8" From: David Woodhouse The ntp_error accumulator tracks the difference between the time actually reported to consumers in xtime, and the *intended* time. The former is subject to a sawtooth effect due to the quantisation of 'mult', which means that it actually advances by 'xtime_interval' each tick, while the intended clock advances by 'ntp_tick'. By dithering between adjacent integer values of 'mult' which result in an 'xtime_interval' slightly higher/lower than the intended tick length, the advancement of xtime is kept on average to the intended rate. The accounting should therefore adjust ntp_error by adding ntp_tick and subtracting xtime_interval on each tick. Since commit a386b5af8edd ("time: Compensate for rounding on odd-frequency clocksources") the value subtracted has been (xtime_interval + xtime_remainder), which is wrong. The effect is a systematic drift whose magnitude depends on the value of xtime_remainder and the NTP frequency correction. NTP masks this by continuously adjusting the frequency to compensate, but with a fixed frequency (or an external reference clock like vmclock), the drift is exposed. The value of xtime_remainder actually does represent the difference between the tick period and xtime_interval, so simply adding it instead of (+ tick length - xtime_remainder) might have made sense... except that it's only calculated once at boot time, so it's inaccurate anyway. So just kill it with fire. Also remove it from the mult computation in timekeeping_adjust(), which used it to offset the division for the same (incorrect) reason. Fixes: a386b5af8edd ("time: Compensate for rounding on odd-frequency clocks= ources") Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- include/linux/timekeeper_internal.h | 3 --- kernel/time/timekeeping.c | 8 +++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper= _internal.h index e36d11e33e0c..da6cf383bedc 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -84,8 +84,6 @@ struct tk_read_base { * @cycle_interval: Number of clock cycles in one NTP interval * @xtime_interval: Number of clock shifted nano seconds in one NTP * interval. - * @xtime_remainder: Shifted nano seconds left over when rounding - * @cycle_interval * @raw_interval: Shifted raw nano seconds accumulated per NTP interval. * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second * @ntp_tick: The ntp_tick_length() value currently being @@ -178,7 +176,6 @@ struct timekeeper { =20 u64 cycle_interval; u64 xtime_interval; - s64 xtime_remainder; u64 raw_interval; =20 ktime_t next_leap_ktime; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index b53225b91b4b..9b20f2101c45 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -365,7 +365,6 @@ static void tk_setup_internals(struct timekeeper *tk, s= truct clocksource *clock) =20 /* Go back from cycles -> shifted ns */ tk->xtime_interval =3D interval * clock->mult; - tk->xtime_remainder =3D ntpinterval - tk->xtime_interval; tk->raw_interval =3D interval * clock->mult; =20 /* if changing clocks, convert xtime_nsec shift units */ @@ -2400,8 +2399,8 @@ static void timekeeping_adjust(struct timekeeper *tk,= s64 offset) mult =3D tk->tkr_mono.mult - tk->ntp_err_mult; } else { tk->ntp_tick =3D ntp_tl; - mult =3D div64_u64((tk->ntp_tick >> tk->ntp_error_shift) - - tk->xtime_remainder, tk->cycle_interval); + mult =3D div64_u64(tk->ntp_tick >> tk->ntp_error_shift, + tk->cycle_interval); } =20 /* @@ -2526,8 +2525,7 @@ static u64 logarithmic_accumulation(struct timekeeper= *tk, u64 offset, =20 /* Accumulate error between NTP and clock interval */ tk->ntp_error +=3D tk->ntp_tick << shift; - tk->ntp_error -=3D (tk->xtime_interval + tk->xtime_remainder) << - (tk->ntp_error_shift + shift); + tk->ntp_error -=3D tk->xtime_interval << (tk->ntp_error_shift + shift); =20 return offset; } --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF0F138837F for ; Mon, 25 May 2026 13:59:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; cv=none; b=bdrStdYorl6xL8B1QwBeIgXO014J2/PiVB4lDfjWuNwnhFRUBsyc2MLYMH0x4VVFFLBk4JYMzHiUtAjS6dlgBLiNZUsKyJmokGjpzs9cDzmsg/u7fsciBf2saMwbECY482rnme+JqV5828iFe0PEIj63KQ2xd8Rz+B1kPC8V4yI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; c=relaxed/simple; bh=3hdep/dulKQxLuOlATGj/Mx34hvs6qQIceBqIiqiArU=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VawYGt0pbCEbSB0d+xugEn7fYMl08QZQR8FYHgFeltLMwyLQdorErArC6Ck58T/tJGNfzbxBoyD3adzJ7tp4S7wmJtLFYX8nMGXlr8uJ+ofrpLSoYqp3Kr2je8Ji5cimTJE3wC2Q3lNerf6KRlSwyJFbERUxI3Cy+mIUPpVbDNA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=CCvlRLDd; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="CCvlRLDd" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=a/rPZ4E/zvVHn7LDXbUEIhghNUx1QKG7bBITqNAGv0s=; b=CCvlRLDd/uR8vi4cvnPzuZf//O rEr09gJhJ1ZRTIjkGOd+OKq0I7shgCAcpbq1V5f5Laf19WYoe3C1wGhrDQtJZYJAJfUrPO2gn+2Jy 6CDUA8MvPtjq7Tis3KwnNL3i88kvL9zg7npDwk8XKudzq8aSJeR334ZYnvOqu3EMOq+4MQvhUc5vW hBSaLVH/AbZajb0NmXNbS0QMSNTs19nmrlySGd9Nk1vekYDNQJj40YKuHG/hl6x/VassD1EYxyj5p vGbDOW6DDgKVkMRJ8Bm8A8h9cc971pOoq75d++19Aet4/1PJ/bhu5p4A9axpGF+NRdklz2kQ/M9kG hynGHwpg==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpk-0000000HBAR-03Sg; Mon, 25 May 2026 13:59:08 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrm-1b6B; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 3/7] timekeeping: Account for monotonicity adjustment in ntp_error Date: Mon, 25 May 2026 14:54:35 +0100 Message-ID: <20260525135904.126282-4-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html From: David Woodhouse timekeeping_apply_adjustment() modifies xtime_nsec to maintain vDSO monotonicity when mult changes: xtime_nsec -=3D offset This ensures that the time reported to userspace does not jump when the multiplier is adjusted from one tick to the next. However, the ntp_error accumulator which tracks the difference between intended and actual clock position was not being updated updated to reflect this additional discrepancy. An earlier attempt at this compensation existed as: ntp_error -=3D (interval - offset) << ntp_error_shift but was removed in commit c2cda2a5bda9 ("timekeeping/ntp: Don't align NTP frequency adjustments to ticks") because it was a major source of NTP error. That's because (interval - offset) was wrong: the subtraction of "interval" prematurely accounted for the changed xtime_interval of the next tick, which would be correctly accounted in the next accumulation anyway =E2=80=94 a double subtraction. What is actually needed is just the "offset" part: ntp_error must be told that xtime_nsec moved by "offset" without a corresponding change in the intended position. For the normal =C2=B11 mult dithering this is negligible (the adjustments cancel over time), but for larger mult changes =E2=80=94 such as when an external reference clock sets a new frequency =E2=80=94 the one-time uncompensated offset is significant. Fix by adjusting ntp_error by the correct amount: ntp_error +=3D offset << ntp_error_shift This keeps ntp_error consistent with the actual xtime_nsec position after the adjustment. Fixes: c2cda2a5bda9 ("timekeeping/ntp: Don't align NTP frequency adjustment= s to ticks") Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m Acked-by: John Stultz --- kernel/time/timekeeping.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 9b20f2101c45..3473a91b11df 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2370,6 +2370,11 @@ static __always_inline void timekeeping_apply_adjust= ment(struct timekeeper *tk, * xtime_nsec_2 =3D xtime_nsec_1 - offset * Which simplifies to: * xtime_nsec -=3D offset + * + * When subtracting offset from xtime_nsec, the same amount + * (in appropriate units) has to be added to ntp_error, in + * order to correctly track the delta between the time + * reported in xtime_nsec, and the intended time. */ if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) { /* NTP adjustment caused clocksource mult overflow */ @@ -2380,6 +2385,7 @@ static __always_inline void timekeeping_apply_adjustm= ent(struct timekeeper *tk, tk->tkr_mono.mult +=3D mult_adj; tk->xtime_interval +=3D interval; tk->tkr_mono.xtime_nsec -=3D offset; + tk->ntp_error +=3D offset << tk->ntp_error_shift; } =20 /* --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF0AE381B17 for ; Mon, 25 May 2026 13:59:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; cv=none; b=Fa1vgJl7sOt3wpihnVL24fWa6w/kze3rr65r+8m/f42UndxhZmAaT11MD61X/Q0Z/Ek5NoQnl2OBw9oog41Pzp+r85L0bnYknU3yNlw5LdvcSiLy8E3BmXMR1Sj1cw8hyCaOqutMYlQLz+jkX0Uuaf+L1tddGu6ISkRED1G3Izw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; c=relaxed/simple; bh=+dDUd7fR+X2Q+YKJ8JU4CXSQVbDKTKql/7qWzoG865g=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BiwoeiYWmox+jW4Yb7dO8HtmzrS9CsYeAs9yGBKgzVcMrCVdRWAOJSxg3Iyqz/Q3sKkc9b3Xgp3jZbPDnq+VtCvkhjOgQpyz+g9vkUkf0GC7QTGmNjQhZhHbGO3+zzCvHaS7v1O0tctcDOGMvOXYa2uswcUQMSws++oCPXBaphw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=wXn8VC4y; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="wXn8VC4y" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=uaV8Vb/1AjjJbguyhoit8VsIvlwFRGKv5dqschWpeI4=; b=wXn8VC4yZEV8a1TwknGxZS092Q ArxIllHjOXdS6itaAqy74tPZSgN6DEUuvU1ioslDKActXjYa/niRZi1oByZOQwlAYTXh/B48nA2KW n5eUEs3zYuslrEfYN397s1pSgxIKUsClkGrAFIQ8xwkRNTqE838oy2bfU9OvWo2we7VfH2IIXK8sX UEsRTRyBH44VZeAZ5dofJZ7VUB8U79bhroodRnq0zG+Vj7Zr83XiibRxCCLhWely3MmBclMizariL ZU0IlcL7/q3OYo9c7PLPgh6YRq7jBL/8fLSPc8QTIumqDzZLhlBWvsWH8cXevXTah+Mqdi/c3xJvD /o7uuk+w==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpk-0000000HBAP-00MF; Mon, 25 May 2026 13:59:08 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrp-1vio; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 4/7] timekeeping: Guard against divide-by-zero in timekeeping_adjust Date: Mon, 25 May 2026 14:54:36 +0100 Message-ID: <20260525135904.126282-5-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Content-Type: text/plain; charset="utf-8" From: David Woodhouse When the TSC clocksource is recalibrated (e.g. on KVM guests with clocksource=3Dtsc), cycle_interval can momentarily be zero during the transition. Guard the div64_u64 in timekeeping_adjust() to prevent a divide-by-zero oops. This can be triggered on KVM guests that force clocksource=3Dtsc when the guest's measured TSC frequency doesn't match what KVM reported, causing a recalibration during boot. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m Acked-by: John Stultz --- kernel/time/timekeeping.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 3473a91b11df..75397f5caace 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2404,6 +2404,8 @@ static void timekeeping_adjust(struct timekeeper *tk,= s64 offset) if (likely(tk->ntp_tick =3D=3D ntp_tl)) { mult =3D tk->tkr_mono.mult - tk->ntp_err_mult; } else { + if (unlikely(!tk->cycle_interval)) + return; tk->ntp_tick =3D ntp_tl; mult =3D div64_u64(tk->ntp_tick >> tk->ntp_error_shift, tk->cycle_interval); --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A560438A71E for ; Mon, 25 May 2026 13:59:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; cv=none; b=CK3hNLgyYnBUOZpGb5yz2/LYqdXLLp1oz0mCtINJNfI6T7Bq0DFKt7z3oLb7+AFsy00tepJS9kVLhdux4CyrGBqk1MaQ8zwDfV4AtAqQOHNcuTrsniCxoxsSH0E9uDN3/zjd/Mk23p0DI31T1wKvf2CZ5xDRRkC3SK0ErmS+BTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; c=relaxed/simple; bh=dQW7DXputbkHHc4Y7Ymc6lD2lHxXGz40NEWqrf34Gc4=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZXFCZOJbT1KZayFB40N/HNYBafcGGheTnEBBo5CmXYx/ZD+YKWdwrhEuv6wx2uxqVyYZ3VO3OHVWgjuEpaJyZtBgGsrhEQYBMosa7Kbt7g62rlp4Ea6E198+KHAHF7ODfQMBp4J1MmhXPUgXQiwxkg1yhlOrF9shb9DzX2jKrj4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=desiato.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=GuU9d1bu; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=desiato.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="GuU9d1bu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=TEcQ8f3gawo1FhVv9quxtxrOT04gh21a17hjCfwcE+0=; b=GuU9d1buuJX745DKyiqbMzVb6V CojuEKdqyqgrE/e4XQS4s1xMYah5ohIeJwDb9+MqFIH31FX29mlz+OHSvwD6T2dXvOwf0oFis0v2+ Jff2zJVJMa7eCEZkee4CFYxRMvQ5G55YM8Y2aCWuIGMNQVeS0dDHAfSsxXFWXTitHNEhDETp97XhO FWvZ7q7lLdMDOm4X1jVq13b3/7A9okq3Ns3qjZ39tYOt7Ik+INuIXxdAObiErW319pnVA+k9x6TId P00Lvg7+yQvKwfGvb6qjSDdQK4toaoWVYIUk01m556wqmzxRdC75cSbkMAqNI8IGj+a2g43LS31g0 Bl5M7F/g==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpj-00000009LY9-2Ri4; Mon, 25 May 2026 13:59:08 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrs-2G1h; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 5/7] timekeeping: Drive time_offset skew via per-tick ntp_error transfer Date: Mon, 25 May 2026 14:54:37 +0100 Message-ID: <20260525135904.126282-6-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html From: David Woodhouse Instead of inflating tick_length to effect the time_offset slew, transfer the skew to ntp_error per-tick and drain time_offset at the equivalent per-tick rate: - ntp_error +=3D skew_delta << shift (biases dithering to deliver skew) - time_offset -=3D skew_delta / NTP_INTERVAL_FREQ (per-tick drain) Compute mult from (ntp_tick + skew_delta) so the dithering has enough bandwidth to deliver the skew rate by selecting between mult and mult+1. This is equivalent to the old tick_length +=3D delta approach but without modifying tick_length, and with exact per-tick accounting of the time_offset drain. To eliminate remainder error in the per-tick division, skew_delta is rounded to a multiple of NTP_INTERVAL_FREQ in second_overflow(). second_overflow() computes skew_delta (the exponential decay rate) but no longer drains time_offset or inflates tick_length directly. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- include/linux/timekeeper_internal.h | 1 + kernel/time/ntp.c | 35 +++++++++++++++++++++++++++-- kernel/time/ntp_internal.h | 2 ++ kernel/time/timekeeping.c | 29 +++++++++++++++++++----- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper= _internal.h index da6cf383bedc..9de6b5b94dc0 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -184,6 +184,7 @@ struct timekeeper { u32 ntp_error_shift; u32 ntp_err_mult; u32 skip_second_overflow; + s64 skew_delta; s32 tai_offset; }; =20 diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 97fa99b96dd0..3c1e287eb384 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -63,6 +63,7 @@ struct ntp_data { int time_state; int time_status; s64 time_offset; + s64 skew_delta; long time_constant; long time_maxerror; long time_esterror; @@ -364,6 +365,31 @@ u64 ntp_tick_length(unsigned int tkid) return tk_ntp_data[tkid].tick_length; } =20 +s64 ntp_get_skew_delta(unsigned int tkid) +{ + return tk_ntp_data[tkid].skew_delta; +} + +s64 ntp_drain_time_offset(unsigned int tkid, s64 amount) +{ + struct ntp_data *ntpdata =3D &tk_ntp_data[tkid]; + + /* Only drain if amount and time_offset have the same sign */ + if (!amount || (amount > 0) !=3D (ntpdata->time_offset > 0)) + return amount; + + /* Clamp: don't overshoot zero */ + if (abs(amount) > abs(ntpdata->time_offset)) { + s64 undrained =3D amount - ntpdata->time_offset; + + ntpdata->time_offset =3D 0; + return undrained; + } + + ntpdata->time_offset -=3D amount; + return 0; +} + /** * ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime= _t * @tkid: Timekeeper ID @@ -460,9 +486,14 @@ int second_overflow(unsigned int tkid, time64_t secs) /* Compute the phase adjustment for the next second */ ntpdata->tick_length =3D ntpdata->tick_length_base; =20 + /* + * Set the per-tick skew rate for the tick code. This is in the + * same units as tick_length (ns << NTP_SCALE_SHIFT), and is + * rounded to a multiple of NTP_INTERVAL_FREQ so that the per-tick + * division in the tick code is exact. + */ delta =3D ntp_offset_chunk(ntpdata, ntpdata->time_offset); - ntpdata->time_offset -=3D delta; - ntpdata->tick_length +=3D delta; + ntpdata->skew_delta =3D div_s64(delta, NTP_INTERVAL_FREQ) * NTP_INTERVAL= _FREQ; =20 /* Check PPS signal */ pps_dec_valid(ntpdata); diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index 7084d839c207..05e5dd5e1b70 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h @@ -6,6 +6,8 @@ extern void ntp_init(void); extern void ntp_clear(unsigned int tkid); /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ extern u64 ntp_tick_length(unsigned int tkid); +extern s64 ntp_get_skew_delta(unsigned int tkid); +extern s64 ntp_drain_time_offset(unsigned int tkid, s64 amount); extern ktime_t ntp_get_next_leap(unsigned int tkid); extern int second_overflow(unsigned int tkid, time64_t secs); extern int ntp_adjtimex(unsigned int tkid, struct __kernel_timex *txc, con= st struct timespec64 *ts, diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 75397f5caace..780f66b12916 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2395,20 +2395,23 @@ static __always_inline void timekeeping_apply_adjus= tment(struct timekeeper *tk, static void timekeeping_adjust(struct timekeeper *tk, s64 offset) { u64 ntp_tl =3D ntp_tick_length(tk->id); + s64 skew =3D ntp_get_skew_delta(tk->id); u32 mult; =20 /* - * Determine the multiplier from the current NTP tick length. - * Avoid expensive division when the tick length doesn't change. + * Determine the multiplier from the current NTP tick length plus + * skew_delta. The skew biases mult so that =C2=B11 dithering can deliver + * the time_offset slew rate. Recompute when either changes. */ - if (likely(tk->ntp_tick =3D=3D ntp_tl)) { + if (likely(tk->ntp_tick =3D=3D ntp_tl && tk->skew_delta =3D=3D skew)) { mult =3D tk->tkr_mono.mult - tk->ntp_err_mult; } else { if (unlikely(!tk->cycle_interval)) return; tk->ntp_tick =3D ntp_tl; - mult =3D div64_u64(tk->ntp_tick >> tk->ntp_error_shift, - tk->cycle_interval); + tk->skew_delta =3D skew; + mult =3D div64_u64((tk->ntp_tick + skew) >> tk->ntp_error_shift, + tk->cycle_interval); } =20 /* @@ -2535,6 +2538,22 @@ static u64 logarithmic_accumulation(struct timekeepe= r *tk, u64 offset, tk->ntp_error +=3D tk->ntp_tick << shift; tk->ntp_error -=3D tk->xtime_interval << (tk->ntp_error_shift + shift); =20 + /* + * During clock skew driven by ntpdata->time_offset, transfer a + * *portion* of the requested total delta into ntp_error from + * time_offset each tick. The second_overflow() function sets + * the rate of skew, and the value of 'mult' has been selected + * in order to allow the dithering to keep ntp_error around zero + * even while this adjustment is being applied. + */ + if (tk->skew_delta) { + s64 drain =3D div_s64(tk->skew_delta << shift, + NTP_INTERVAL_FREQ); + + tk->ntp_error +=3D (tk->skew_delta << shift) - + ntp_drain_time_offset(tk->id, drain); + } + return offset; } =20 --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B916438E8C4 for ; Mon, 25 May 2026 13:59:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717567; cv=none; b=AU7hEXuQCSxAmud9mezduxth1rRCHYtp/JR2zDbvEqSUXLtIqVzcXTClHYjbeqMkjcO7iIHFKsHdrnMr/t2+rfJq8Ti0AOcQJCXvWykuXrFXEOuu8Dd++5FD1a6pXNSRLaIKSxyl+uT7wXm0OeBuejAFAV0G/OZmc9eVMubwMZI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717567; c=relaxed/simple; bh=PCLO3OEf87WDllRIKNMlxuD7QUmJuw7t0DYRQPuvNdI=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=A1YLn4Dcgty1pjfNGXKGe8sI0u1pSzCEGT+AJpR1vfxDdwvmN5C/8p7qBvdSZIiVtQgd/JLvEvmC0B2MsCH4K0i/WkSkJEpF7+5MpivnmSEtN493+nz8s5gj62WPpYzXlm7pRgIGAiUPrtIM/bZmcse+JchivgOuV/puIX2iz2c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=uxvk5pId; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="uxvk5pId" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=Jw8tHlyE9aUzK3gHALYldRzQuZl0TzGi9RnJwmOSqhU=; b=uxvk5pId4jX8xDRnd1Xre1zfp8 x0DcBXhEul8blUKwfP/6qPyxMp482uYPLnLjOBrqUtspCSYU+//mCb1XuwSELtVFMvGLlBBG6+oFT U4x8yUbV/ySDeZAUet1WBiq1OrhaSP1GXD4BlWB6Ti8OjBl7DocZroTHT5h1fNBec4zHFO7jKxCdl QkjblzMar6IS92r7h4S+XUDGFTWWoPtih+fDFzrtxKYxKfxwsJM3+Drx2uzbzvEcFju4FCbEcvrEd gvy3xmjxKs+TXcue2N28A4NdbRF7/V4czlgYT0y52zLcdwO5daZTqqQMR1Y7MprBgTXt4vvuLOblp 8i6z6EPQ==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpk-0000000HBAS-038J; Mon, 25 May 2026 13:59:08 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wrv-2aHI; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 6/7] ntp: Convert adjtime() to use time_offset instead of tick_length inflation Date: Mon, 25 May 2026 14:54:38 +0100 Message-ID: <20260525135904.126282-7-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html From: David Woodhouse The legacy adjtime() syscall (ADJ_ADJTIME/ADJ_OFFSET_SINGLESHOT) used to slew the clock by inflating tick_length directly via time_adjust. This was the last remaining user of tick_length !=3D tick_length_base. Convert it to fold time_adjust into time_offset each second (up to MAX_TICKADJ per second, same rate limit as before). The existing time_offset skew mechanism then delivers it via the per-tick ntp_error transfer and mult adjustment. Introduce ntp_set_time_offset() helper for setting time_offset from a nanosecond value, and refactor ntp_update_offset() to use it. This helper will also be used by the feed-forward reference clock API in a subsequent commit. This eliminates the last source of tick_length inflation, making tick_length always equal tick_length_base. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- kernel/time/ntp.c | 52 ++++++++++++++++++++++++-------------- kernel/time/ntp_internal.h | 1 + 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 3c1e287eb384..9470ac1f597b 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -329,7 +329,7 @@ static void ntp_update_offset(struct ntp_data *ntpdata,= long offset) =20 ntpdata->time_freq =3D max(freq_adj, -MAXFREQ_SCALED); =20 - ntpdata->time_offset =3D div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVA= L_FREQ); + ntp_set_time_offset(ntpdata - tk_ntp_data, offset64); } =20 static void __ntp_clear(struct ntp_data *ntpdata) @@ -390,6 +390,24 @@ s64 ntp_drain_time_offset(unsigned int tkid, s64 amoun= t) return 0; } =20 +/** + * ntp_set_time_offset - Set the NTP time offset (phase correction) + * @tkid: Timekeeper ID + * @offset_ns: Desired offset in nanoseconds + * + * Converts nanoseconds to internal time_offset units and stores it. + * Also clears time_adjust since a new offset supersedes any pending + * adjtime() slew. + */ +void ntp_set_time_offset(unsigned int tkid, s64 offset_ns) +{ + struct ntp_data *ntpdata =3D &tk_ntp_data[tkid]; + + ntpdata->time_offset =3D div_s64((s64)offset_ns << NTP_SCALE_SHIFT, + NTP_INTERVAL_FREQ); + ntpdata->time_adjust =3D 0; +} + /** * ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime= _t * @tkid: Timekeeper ID @@ -498,26 +516,22 @@ int second_overflow(unsigned int tkid, time64_t secs) /* Check PPS signal */ pps_dec_valid(ntpdata); =20 - if (!ntpdata->time_adjust) - goto out; - - if (ntpdata->time_adjust > MAX_TICKADJ) { - ntpdata->time_adjust -=3D MAX_TICKADJ; - ntpdata->tick_length +=3D MAX_TICKADJ_SCALED; - goto out; - } - - if (ntpdata->time_adjust < -MAX_TICKADJ) { - ntpdata->time_adjust +=3D MAX_TICKADJ; - ntpdata->tick_length -=3D MAX_TICKADJ_SCALED; - goto out; + /* + * Fold any pending time_adjust (from adjtime()) into time_offset. + * This used to inflate tick_length directly; now it uses the same + * per-tick skew mechanism as NTP's time_offset. Rate-limited to + * MAX_TICKADJ (500=C2=B5s) per second. + */ + if (ntpdata->time_adjust) { + long adj =3D clamp(ntpdata->time_adjust, + (long)-MAX_TICKADJ, (long)MAX_TICKADJ); + + ntpdata->time_adjust -=3D adj; + ntpdata->time_offset +=3D div_s64( + (s64)adj * NSEC_PER_USEC << NTP_SCALE_SHIFT, + NTP_INTERVAL_FREQ); } =20 - ntpdata->tick_length +=3D (s64)(ntpdata->time_adjust * NSEC_PER_USEC / NT= P_INTERVAL_FREQ) - << NTP_SCALE_SHIFT; - ntpdata->time_adjust =3D 0; - -out: return leap; } =20 diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index 05e5dd5e1b70..639860ff2baf 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h @@ -8,6 +8,7 @@ extern void ntp_clear(unsigned int tkid); extern u64 ntp_tick_length(unsigned int tkid); extern s64 ntp_get_skew_delta(unsigned int tkid); extern s64 ntp_drain_time_offset(unsigned int tkid, s64 amount); +extern void ntp_set_time_offset(unsigned int tkid, s64 offset_ns); extern ktime_t ntp_get_next_leap(unsigned int tkid); extern int second_overflow(unsigned int tkid, time64_t secs); extern int ntp_adjtimex(unsigned int tkid, struct __kernel_timex *txc, con= st struct timespec64 *ts, --=20 2.54.0 From nobody Mon Jun 8 23:58:07 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 334CE38F226 for ; Mon, 25 May 2026 13:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; cv=none; b=bCIybs8M83MK6Bwb9khsjEWZEKAsHtrvTF57/7FQEgORSnzzvw9iQGAap/H6X3M96bUFhctUpHMJIeceDVAHpf4JNlpTofrsonafymCxeBd8Wb1KUsYhXgr3c/PbsChj/kUFSwVmxHFzfl3LROjJ6OFuBcW1j5ncPUJQiWR3ApA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779717566; c=relaxed/simple; bh=vc+e7V00gwoKxn4OFAlN3GWqF8P8cAniiqmQFkOUzEQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nvYCT4CxxxG/h1tpPEUoVSjvwN6l2CWrcNtHccP6nu43Hx+ItmdDPn2qgEVghxGnk4cJWA/a8C/0yHhRGLyzPOXRStuUAYzUM40cuQDRZmoH/Qtw7EEvE+n/G19rIBtfZwyNezBdV39CjOFGZwG13fwPX+26yEJikU7DfM3lK78= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=KiU6q1o/; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="KiU6q1o/" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=0r/pLZwrX+mj1wjtsqI+lYHgSVd1l0kXfa8s67RNoPY=; b=KiU6q1o/tZL51ePM5nWLfJrEBR lmGoJ377XijzboJSmrCr8Frjc3TAymsP4eHxMAn77Dp61aMcHwdvLYyidP15+ZJL+CkzWZ/DsXoxF rAthYylQRDnXAFIlMb/r+rr5ns87XNTXimnaDFqUq4YULfbhjngbnFXumpgJZSZQTe2uxRuXvGKlv YISe5lnVY35DpUWVHsiLtfpMQToTSFCzUCdmBtjpCclJCKz52jeWRlFdcAPTXO5HEVNp5D0j7cT6e j2nGX6HxxtVQe9Z6dJxk+xScYPPYfNMtYhprdYmIJwMSOt+WU0oqulPimt/e5xEoUjqXz+TbjJQVe EzwU9MKw==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wRVpk-0000000HBAT-039j; Mon, 25 May 2026 13:59:09 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wRVpj-00000000Wry-2uXx; Mon, 25 May 2026 14:59:07 +0100 From: David Woodhouse To: Richard Cochran , Wen Gu , David Woodhouse , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , John Stultz , Thomas Gleixner , Stephen Boyd , Anna-Maria Behnsen , Frederic Weisbecker , Shuah Khan , Peter Zijlstra , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Arnd Bergmann , Miroslav Lichvar , Julien Ridoux , Ryan Luu , linux-kernel@vger.kernel.org Subject: [PATCH v4 7/7] ntp: Remove tick_length_base, use tick_length directly Date: Mon, 25 May 2026 14:54:39 +0100 Message-ID: <20260525135904.126282-8-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260525135904.126282-1-dwmw2@infradead.org> References: <20260525135904.126282-1-dwmw2@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that nothing inflates tick_length beyond tick_length_base (the adjtime path was converted to use time_offset in the previous commit), the two fields are always equal. Remove tick_length_base and keep tick_length as the single field. Remove the per-second reset and the delta update in ntp_update_frequency() since there is no separate base to track. No functional change intended. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- kernel/time/ntp.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 9470ac1f597b..2aada891aead 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -26,8 +26,7 @@ /** * struct ntp_data - Structure holding all NTP related state * @tick_usec: USER_HZ period in microseconds - * @tick_length: Adjusted tick length - * @tick_length_base: Base value for @tick_length + * @tick_length: Tick length in ns << NTP_SCALE_SHIFT * @time_state: State of the clock synchronization * @time_status: Clock status bits * @time_offset: Time adjustment in nanoseconds @@ -59,7 +58,6 @@ struct ntp_data { unsigned long tick_usec; u64 tick_length; - u64 tick_length_base; int time_state; int time_status; s64 time_offset; @@ -246,8 +244,7 @@ static inline void pps_fill_timex(struct ntp_data *ntpd= ata, struct __kernel_time #endif /* CONFIG_NTP_PPS */ =20 /* - * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_a= dj and - * time_freq: + * Update tick_length based on tick_usec, ntp_tick_adj and time_freq: */ static void ntp_update_frequency(struct ntp_data *ntpdata) { @@ -264,8 +261,7 @@ static void ntp_update_frequency(struct ntp_data *ntpda= ta) * Don't wait for the next second_overflow, apply the change to the * tick length immediately: */ - ntpdata->tick_length +=3D new_base - ntpdata->tick_length_base; - ntpdata->tick_length_base =3D new_base; + ntpdata->tick_length =3D new_base; } =20 static inline s64 ntp_update_offset_fll(struct ntp_data *ntpdata, s64 offs= et64, long secs) @@ -342,7 +338,6 @@ static void __ntp_clear(struct ntp_data *ntpdata) =20 ntp_update_frequency(ntpdata); =20 - ntpdata->tick_length =3D ntpdata->tick_length_base; ntpdata->time_offset =3D 0; =20 ntpdata->ntp_next_leap_sec =3D TIME64_MAX; @@ -502,7 +497,6 @@ int second_overflow(unsigned int tkid, time64_t secs) } =20 /* Compute the phase adjustment for the next second */ - ntpdata->tick_length =3D ntpdata->tick_length_base; =20 /* * Set the per-tick skew rate for the tick code. This is in the --=20 2.54.0