]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
timekeeping: Add auxiliary clock support to __timekeeping_inject_offset()
authorThomas Gleixner <tglx@linutronix.de>
Wed, 25 Jun 2025 18:38:42 +0000 (20:38 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 27 Jun 2025 18:13:13 +0000 (20:13 +0200)
Redirect the relative offset adjustment to the auxiliary clock offset
instead of modifying CLOCK_REALTIME, which has no meaning in context of
these clocks.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: John Stultz <jstultz@google.com>
Link: https://lore.kernel.org/all/20250625183758.124057787@linutronix.de
kernel/time/timekeeping.c

index 2d294cfe185eba2138b5209df6a1132424b59c74..e893557cd53f51af7a67b9c7c4cd62f52db9ae37 100644 (file)
@@ -1431,6 +1431,11 @@ int do_settimeofday64(const struct timespec64 *ts)
 }
 EXPORT_SYMBOL(do_settimeofday64);
 
+static inline bool timekeeper_is_core_tk(struct timekeeper *tk)
+{
+       return !IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) || tk->id == TIMEKEEPER_CORE;
+}
+
 /**
  * __timekeeping_inject_offset - Adds or subtracts from the current time.
  * @tkd:       Pointer to the timekeeper to modify
@@ -1448,16 +1453,34 @@ static int __timekeeping_inject_offset(struct tk_data *tkd, const struct timespe
 
        timekeeping_forward_now(tks);
 
-       /* Make sure the proposed value is valid */
-       tmp = timespec64_add(tk_xtime(tks), *ts);
-       if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
-           !timespec64_valid_settod(&tmp)) {
-               timekeeping_restore_shadow(tkd);
-               return -EINVAL;
+       if (timekeeper_is_core_tk(tks)) {
+               /* Make sure the proposed value is valid */
+               tmp = timespec64_add(tk_xtime(tks), *ts);
+               if (timespec64_compare(&tks->wall_to_monotonic, ts) > 0 ||
+                   !timespec64_valid_settod(&tmp)) {
+                       timekeeping_restore_shadow(tkd);
+                       return -EINVAL;
+               }
+
+               tk_xtime_add(tks, ts);
+               tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
+       } else {
+               struct tk_read_base *tkr_mono = &tks->tkr_mono;
+               ktime_t now, offs;
+
+               /* Get the current time */
+               now = ktime_add_ns(tkr_mono->base, timekeeping_get_ns(tkr_mono));
+               /* Add the relative offset change */
+               offs = ktime_add(tks->offs_aux, timespec64_to_ktime(*ts));
+
+               /* Prevent that the resulting time becomes negative */
+               if (ktime_add(now, offs) < 0) {
+                       timekeeping_restore_shadow(tkd);
+                       return -EINVAL;
+               }
+               tks->offs_aux = offs;
        }
 
-       tk_xtime_add(tks, ts);
-       tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, *ts));
        timekeeping_update_from_shadow(tkd, TK_UPDATE_ALL);
        return 0;
 }