Skip to content

Commit ac814cb

Browse files
committed
Merge tag 'timers-urgent-2025-05-11' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull misc timers fixes from Ingo Molnar: - Fix time keeping bugs in CLOCK_MONOTONIC_COARSE clocks - Work around absolute relocations into vDSO code that GCC erroneously emits in certain arm64 build environments - Fix a false positive lockdep warning in the i8253 clocksource driver * tag 'timers-urgent-2025-05-11' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clocksource/i8253: Use raw_spinlock_irqsave() in clockevent_i8253_disable() arm64: vdso: Work around invalid absolute relocations from GCC timekeeping: Prevent coarse clocks going backwards
2 parents fea9123 + 94cff94 commit ac814cb

File tree

5 files changed

+63
-16
lines changed

5 files changed

+63
-16
lines changed

arch/arm64/include/asm/vdso/gettimeofday.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
9999
return res;
100100
}
101101

102+
#if IS_ENABLED(CONFIG_CC_IS_GCC) && IS_ENABLED(CONFIG_PAGE_SIZE_64KB)
103+
static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
104+
{
105+
const struct vdso_time_data *ret = &vdso_u_time_data;
106+
107+
/* Work around invalid absolute relocations */
108+
OPTIMIZER_HIDE_VAR(ret);
109+
110+
return ret;
111+
}
112+
#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
113+
#endif /* IS_ENABLED(CONFIG_CC_IS_GCC) && IS_ENABLED(CONFIG_PAGE_SIZE_64KB) */
114+
102115
#endif /* !__ASSEMBLY__ */
103116

104117
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */

drivers/clocksource/i8253.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ int __init clocksource_i8253_init(void)
103103
#ifdef CONFIG_CLKEVT_I8253
104104
void clockevent_i8253_disable(void)
105105
{
106-
raw_spin_lock(&i8253_lock);
106+
guard(raw_spinlock_irqsave)(&i8253_lock);
107107

108108
/*
109109
* Writing the MODE register should stop the counter, according to
@@ -132,8 +132,6 @@ void clockevent_i8253_disable(void)
132132
outb_p(0, PIT_CH0);
133133

134134
outb_p(0x30, PIT_MODE);
135-
136-
raw_spin_unlock(&i8253_lock);
137135
}
138136

139137
static int pit_shutdown(struct clock_event_device *evt)

include/linux/timekeeper_internal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct tk_read_base {
5151
* @offs_real: Offset clock monotonic -> clock realtime
5252
* @offs_boot: Offset clock monotonic -> clock boottime
5353
* @offs_tai: Offset clock monotonic -> clock tai
54-
* @tai_offset: The current UTC to TAI offset in seconds
54+
* @coarse_nsec: The nanoseconds part for coarse time getters
5555
* @tkr_raw: The readout base structure for CLOCK_MONOTONIC_RAW
5656
* @raw_sec: CLOCK_MONOTONIC_RAW time in seconds
5757
* @clock_was_set_seq: The sequence number of clock was set events
@@ -76,6 +76,7 @@ struct tk_read_base {
7676
* ntp shifted nano seconds.
7777
* @ntp_err_mult: Multiplication factor for scaled math conversion
7878
* @skip_second_overflow: Flag used to avoid updating NTP twice with same second
79+
* @tai_offset: The current UTC to TAI offset in seconds
7980
*
8081
* Note: For timespec(64) based interfaces wall_to_monotonic is what
8182
* we need to add to xtime (or xtime corrected for sub jiffy times)
@@ -100,7 +101,7 @@ struct tk_read_base {
100101
* which results in the following cacheline layout:
101102
*
102103
* 0: seqcount, tkr_mono
103-
* 1: xtime_sec ... tai_offset
104+
* 1: xtime_sec ... coarse_nsec
104105
* 2: tkr_raw, raw_sec
105106
* 3,4: Internal variables
106107
*
@@ -121,7 +122,7 @@ struct timekeeper {
121122
ktime_t offs_real;
122123
ktime_t offs_boot;
123124
ktime_t offs_tai;
124-
s32 tai_offset;
125+
u32 coarse_nsec;
125126

126127
/* Cacheline 2: */
127128
struct tk_read_base tkr_raw;
@@ -144,6 +145,7 @@ struct timekeeper {
144145
u32 ntp_error_shift;
145146
u32 ntp_err_mult;
146147
u32 skip_second_overflow;
148+
s32 tai_offset;
147149
};
148150

149151
#ifdef CONFIG_GENERIC_TIME_VSYSCALL

kernel/time/timekeeping.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,42 @@ static inline struct timespec64 tk_xtime(const struct timekeeper *tk)
164164
return ts;
165165
}
166166

167+
static inline struct timespec64 tk_xtime_coarse(const struct timekeeper *tk)
168+
{
169+
struct timespec64 ts;
170+
171+
ts.tv_sec = tk->xtime_sec;
172+
ts.tv_nsec = tk->coarse_nsec;
173+
return ts;
174+
}
175+
176+
/*
177+
* Update the nanoseconds part for the coarse time keepers. They can't rely
178+
* on xtime_nsec because xtime_nsec could be adjusted by a small negative
179+
* amount when the multiplication factor of the clock is adjusted, which
180+
* could cause the coarse clocks to go slightly backwards. See
181+
* timekeeping_apply_adjustment(). Thus we keep a separate copy for the coarse
182+
* clockids which only is updated when the clock has been set or we have
183+
* accumulated time.
184+
*/
185+
static inline void tk_update_coarse_nsecs(struct timekeeper *tk)
186+
{
187+
tk->coarse_nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
188+
}
189+
167190
static void tk_set_xtime(struct timekeeper *tk, const struct timespec64 *ts)
168191
{
169192
tk->xtime_sec = ts->tv_sec;
170193
tk->tkr_mono.xtime_nsec = (u64)ts->tv_nsec << tk->tkr_mono.shift;
194+
tk_update_coarse_nsecs(tk);
171195
}
172196

173197
static void tk_xtime_add(struct timekeeper *tk, const struct timespec64 *ts)
174198
{
175199
tk->xtime_sec += ts->tv_sec;
176200
tk->tkr_mono.xtime_nsec += (u64)ts->tv_nsec << tk->tkr_mono.shift;
177201
tk_normalize_xtime(tk);
202+
tk_update_coarse_nsecs(tk);
178203
}
179204

180205
static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
@@ -708,6 +733,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)
708733
tk_normalize_xtime(tk);
709734
delta -= incr;
710735
}
736+
tk_update_coarse_nsecs(tk);
711737
}
712738

713739
/**
@@ -804,16 +830,16 @@ EXPORT_SYMBOL_GPL(ktime_get_with_offset);
804830
ktime_t ktime_get_coarse_with_offset(enum tk_offsets offs)
805831
{
806832
struct timekeeper *tk = &tk_core.timekeeper;
807-
unsigned int seq;
808833
ktime_t base, *offset = offsets[offs];
834+
unsigned int seq;
809835
u64 nsecs;
810836

811837
WARN_ON(timekeeping_suspended);
812838

813839
do {
814840
seq = read_seqcount_begin(&tk_core.seq);
815841
base = ktime_add(tk->tkr_mono.base, *offset);
816-
nsecs = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
842+
nsecs = tk->coarse_nsec;
817843

818844
} while (read_seqcount_retry(&tk_core.seq, seq));
819845

@@ -2161,7 +2187,7 @@ static bool timekeeping_advance(enum timekeeping_adv_mode mode)
21612187
struct timekeeper *real_tk = &tk_core.timekeeper;
21622188
unsigned int clock_set = 0;
21632189
int shift = 0, maxshift;
2164-
u64 offset;
2190+
u64 offset, orig_offset;
21652191

21662192
guard(raw_spinlock_irqsave)(&tk_core.lock);
21672193

@@ -2172,7 +2198,7 @@ static bool timekeeping_advance(enum timekeeping_adv_mode mode)
21722198
offset = clocksource_delta(tk_clock_read(&tk->tkr_mono),
21732199
tk->tkr_mono.cycle_last, tk->tkr_mono.mask,
21742200
tk->tkr_mono.clock->max_raw_delta);
2175-
2201+
orig_offset = offset;
21762202
/* Check if there's really nothing to do */
21772203
if (offset < real_tk->cycle_interval && mode == TK_ADV_TICK)
21782204
return false;
@@ -2205,6 +2231,14 @@ static bool timekeeping_advance(enum timekeeping_adv_mode mode)
22052231
*/
22062232
clock_set |= accumulate_nsecs_to_secs(tk);
22072233

2234+
/*
2235+
* To avoid inconsistencies caused adjtimex TK_ADV_FREQ calls
2236+
* making small negative adjustments to the base xtime_nsec
2237+
* value, only update the coarse clocks if we accumulated time
2238+
*/
2239+
if (orig_offset != offset)
2240+
tk_update_coarse_nsecs(tk);
2241+
22082242
timekeeping_update_from_shadow(&tk_core, clock_set);
22092243

22102244
return !!clock_set;
@@ -2248,7 +2282,7 @@ void ktime_get_coarse_real_ts64(struct timespec64 *ts)
22482282
do {
22492283
seq = read_seqcount_begin(&tk_core.seq);
22502284

2251-
*ts = tk_xtime(tk);
2285+
*ts = tk_xtime_coarse(tk);
22522286
} while (read_seqcount_retry(&tk_core.seq, seq));
22532287
}
22542288
EXPORT_SYMBOL(ktime_get_coarse_real_ts64);
@@ -2271,7 +2305,7 @@ void ktime_get_coarse_real_ts64_mg(struct timespec64 *ts)
22712305

22722306
do {
22732307
seq = read_seqcount_begin(&tk_core.seq);
2274-
*ts = tk_xtime(tk);
2308+
*ts = tk_xtime_coarse(tk);
22752309
offset = tk_core.timekeeper.offs_real;
22762310
} while (read_seqcount_retry(&tk_core.seq, seq));
22772311

@@ -2350,12 +2384,12 @@ void ktime_get_coarse_ts64(struct timespec64 *ts)
23502384
do {
23512385
seq = read_seqcount_begin(&tk_core.seq);
23522386

2353-
now = tk_xtime(tk);
2387+
now = tk_xtime_coarse(tk);
23542388
mono = tk->wall_to_monotonic;
23552389
} while (read_seqcount_retry(&tk_core.seq, seq));
23562390

23572391
set_normalized_timespec64(ts, now.tv_sec + mono.tv_sec,
2358-
now.tv_nsec + mono.tv_nsec);
2392+
now.tv_nsec + mono.tv_nsec);
23592393
}
23602394
EXPORT_SYMBOL(ktime_get_coarse_ts64);
23612395

kernel/time/vsyscall.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,12 @@ void update_vsyscall(struct timekeeper *tk)
9898
/* CLOCK_REALTIME_COARSE */
9999
vdso_ts = &vc[CS_HRES_COARSE].basetime[CLOCK_REALTIME_COARSE];
100100
vdso_ts->sec = tk->xtime_sec;
101-
vdso_ts->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
101+
vdso_ts->nsec = tk->coarse_nsec;
102102

103103
/* CLOCK_MONOTONIC_COARSE */
104104
vdso_ts = &vc[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC_COARSE];
105105
vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
106-
nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
106+
nsec = tk->coarse_nsec;
107107
nsec = nsec + tk->wall_to_monotonic.tv_nsec;
108108
vdso_ts->sec += __iter_div_u64_rem(nsec, NSEC_PER_SEC, &vdso_ts->nsec);
109109

0 commit comments

Comments
 (0)