Skip to content

Commit

Permalink
timekeeping: Rework do_settimeofday64() to use shadow_timekeeper
Browse files Browse the repository at this point in the history
Updates of the timekeeper can be done by operating on the shadow timekeeper
and afterwards copying the result into the real timekeeper. This has the
advantage, that the sequence count write protected region is kept as small
as possible.

Convert do_settimeofday64() to use this scheme.

That allows to use a scoped_guard() for locking the timekeeper lock as the
usage of the shadow timekeeper allows a rollback in the error case instead
of the full timekeeper update of the original code.

Signed-off-by: Anna-Maria Behnsen <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Acked-by: John Stultz <[email protected]>
Link: https://lore.kernel.org/all/20241009-devel-anna-maria-b4-timers-ptp-timekeeping-v2-16-554456a44a15@linutronix.de
  • Loading branch information
anna-marialx authored and KAGA-KOKO committed Oct 25, 2024
1 parent 97e5379 commit bba9898
Showing 1 changed file with 16 additions and 26 deletions.
42 changes: 16 additions & 26 deletions kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -1510,45 +1510,35 @@ EXPORT_SYMBOL_GPL(timekeeping_clocksource_has_base);
*/
int do_settimeofday64(const struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts_delta, xt;
unsigned long flags;
int ret = 0;

if (!timespec64_valid_settod(ts))
return -EINVAL;

raw_spin_lock_irqsave(&tk_core.lock, flags);
write_seqcount_begin(&tk_core.seq);

timekeeping_forward_now(tk);

xt = tk_xtime(tk);
ts_delta = timespec64_sub(*ts, xt);
scoped_guard (raw_spinlock_irqsave, &tk_core.lock) {
struct timekeeper *tks = &tk_core.shadow_timekeeper;

if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
ret = -EINVAL;
goto out;
}
timekeeping_forward_now(tks);

tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
xt = tk_xtime(tks);
ts_delta = timespec64_sub(*ts, xt);

tk_set_xtime(tk, ts);
out:
timekeeping_update(&tk_core, tk, TK_UPDATE_ALL | TK_MIRROR);
if (timespec64_compare(&tks->wall_to_monotonic, &ts_delta) > 0) {
timekeeping_restore_shadow(&tk_core);
return -EINVAL;
}

write_seqcount_end(&tk_core.seq);
raw_spin_unlock_irqrestore(&tk_core.lock, flags);
tk_set_wall_to_mono(tks, timespec64_sub(tks->wall_to_monotonic, ts_delta));
tk_set_xtime(tks, ts);
timekeeping_update_from_shadow(&tk_core, TK_UPDATE_ALL);
}

/* Signal hrtimers about time change */
clock_was_set(CLOCK_SET_WALL);

if (!ret) {
audit_tk_injoffset(ts_delta);
add_device_randomness(ts, sizeof(*ts));
}

return ret;
audit_tk_injoffset(ts_delta);
add_device_randomness(ts, sizeof(*ts));
return 0;
}
EXPORT_SYMBOL(do_settimeofday64);

Expand Down

0 comments on commit bba9898

Please sign in to comment.