Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

timekeeping: Rework do_adjtimex() to use shadow_timekeeper

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_adjtimex() to use this scheme and take the opportunity to use a
scoped_guard() for locking.

That requires to have a separate function for updating the leap state so
that the update is protected by the sequence count. This also brings the
timekeeper and the shadow timekeeper in sync for this state, which was not
the case so far. That's not a correctness problem as the state is only used
at the read sides which use the real timekeeper, but it's inconsistent
nevertheless.

Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: John Stultz <jstultz@google.com>
Link: https://lore.kernel.org/all/20241009-devel-anna-maria-b4-timers-ptp-timekeeping-v2-23-554456a44a15@linutronix.de

authored by

Anna-Maria Behnsen and committed by
Thomas Gleixner
ae455cb7 d05eae87

+25 -16
+25 -16
kernel/time/timekeeping.c
··· 742 742 } 743 743 744 744 /* 745 + * Leap state update for both shadow and the real timekeeper 746 + * Separate to spare a full memcpy() of the timekeeper. 747 + */ 748 + static void tk_update_leap_state_all(struct tk_data *tkd) 749 + { 750 + write_seqcount_begin(&tkd->seq); 751 + tk_update_leap_state(&tkd->shadow_timekeeper); 752 + tkd->timekeeper.next_leap_ktime = tkd->shadow_timekeeper.next_leap_ktime; 753 + write_seqcount_end(&tkd->seq); 754 + } 755 + 756 + /* 745 757 * Update the ktime_t based scalar nsec members of the timekeeper 746 758 */ 747 759 static inline void tk_update_ktime_data(struct timekeeper *tk) ··· 2668 2656 */ 2669 2657 int do_adjtimex(struct __kernel_timex *txc) 2670 2658 { 2671 - struct timekeeper *tk = &tk_core.timekeeper; 2672 2659 struct audit_ntp_data ad; 2673 2660 bool offset_set = false; 2674 2661 bool clock_set = false; 2675 2662 struct timespec64 ts; 2676 - unsigned long flags; 2677 - s32 orig_tai, tai; 2678 2663 int ret; 2679 2664 2680 2665 /* Validate the data before disabling interrupts */ ··· 2682 2673 2683 2674 if (txc->modes & ADJ_SETOFFSET) { 2684 2675 struct timespec64 delta; 2676 + 2685 2677 delta.tv_sec = txc->time.tv_sec; 2686 2678 delta.tv_nsec = txc->time.tv_usec; 2687 2679 if (!(txc->modes & ADJ_NANO)) ··· 2700 2690 ktime_get_real_ts64(&ts); 2701 2691 add_device_randomness(&ts, sizeof(ts)); 2702 2692 2703 - raw_spin_lock_irqsave(&tk_core.lock, flags); 2704 - write_seqcount_begin(&tk_core.seq); 2693 + scoped_guard (raw_spinlock_irqsave, &tk_core.lock) { 2694 + struct timekeeper *tks = &tk_core.shadow_timekeeper; 2695 + s32 orig_tai, tai; 2705 2696 2706 - orig_tai = tai = tk->tai_offset; 2707 - ret = __do_adjtimex(txc, &ts, &tai, &ad); 2697 + orig_tai = tai = tks->tai_offset; 2698 + ret = __do_adjtimex(txc, &ts, &tai, &ad); 2708 2699 2709 - if (tai != orig_tai) { 2710 - __timekeeping_set_tai_offset(tk, tai); 2711 - timekeeping_update(&tk_core, tk, TK_MIRROR | TK_CLOCK_WAS_SET); 2712 - clock_set = true; 2713 - } else { 2714 - tk_update_leap_state(tk); 2700 + if (tai != orig_tai) { 2701 + __timekeeping_set_tai_offset(tks, tai); 2702 + timekeeping_update_from_shadow(&tk_core, TK_CLOCK_WAS_SET); 2703 + clock_set = true; 2704 + } else { 2705 + tk_update_leap_state_all(&tk_core); 2706 + } 2715 2707 } 2716 - 2717 - write_seqcount_end(&tk_core.seq); 2718 - raw_spin_unlock_irqrestore(&tk_core.lock, flags); 2719 2708 2720 2709 audit_ntp_log(&ad); 2721 2710