[tip: timers/core] timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing
From: tip-bot2 for Thomas Weißschuh
Date: Tue Sep 29 2026 - 15:16:59 EST
The following commit has been merged into the timers/core branch of tip:
Commit-ID: bc5b66c300b87544e6861b8dff8c45958603cba5
Gitweb: https://git.kernel.org/tip/bc5b66c300b87544e6861b8dff8c45958603cba5
Author: Thomas Weißschuh <thomas.weissschuh@xxxxxxxxxxxxx>
AuthorDate: Thu, 03 Sep 2026 09:11:47 +02:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Tue, 29 Sep 2026 21:13:26 +02:00
timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing
The timekeeper update path uses a bulk memcpy() to synchronize the
timekeeper structure, which is not guaranteed to be atomic. This allows for
torn reads in ktime_get_seconds() which bypasses the sequence counter
protection for performance.
To prevent reading a torn ktime_sec value, enforce atomic-like
access by using WRITE_ONCE() for the critical field before the bulk
memcpy() in timekeeping_update_from_shadow(). Correspondingly, use
READ_ONCE() in ktime_get_seconds() to ensure a fresh, consistent load
from memory.
The same was done for xtime_sec and ktime_get_real_seconds() in commit
d7fc133bf91f ("timekeeping: Use READ_ONCE/WRITE_ONCE() for xtime_sec to
prevent tearing").
Signed-off-by: Thomas Weißschuh (Schneider Electric) <thomas.weissschuh@xxxxxxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Acked-by: John Stultz <jstultz@xxxxxxxxxx>
Link: https://patch.msgid.link/20260903-timekeeping-ktime_sec-v1-1-b33017536aa9@xxxxxxxxxxxxx
---
kernel/time/timekeeping.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index ea2e6e5..d54c4d3 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -861,8 +861,10 @@ static void timekeeping_update_from_shadow(struct tk_data *tkd, unsigned int act
*
* Write xtime_sec first so that even if the memcpy() tears the store
* data integrity is provided for ktime_get_real_seconds().
+ * The same goes for ktime_sec and ktime_get_seconds().
*/
WRITE_ONCE(tkd->timekeeper.xtime_sec, tk->xtime_sec);
+ WRITE_ONCE(tkd->timekeeper.ktime_sec, tk->ktime_sec);
memcpy(&tkd->timekeeper, tk, sizeof(*tk));
write_seqcount_end(&tkd->seq);
}
@@ -1169,7 +1171,7 @@ time64_t ktime_get_seconds(void)
struct timekeeper *tk = &tk_core.timekeeper;
WARN_ON(timekeeping_suspended);
- return tk->ktime_sec;
+ return READ_ONCE(tk->ktime_sec);
}
EXPORT_SYMBOL_GPL(ktime_get_seconds);