Skip to content

Commit c748fc3

Browse files
committed
Merge tag 'timers-urgent-2024-04-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fixes from Ingo Molnar: - Address a (valid) W=1 build warning - Fix timer self-tests - Annotate a KCSAN warning wrt. accesses to the tick_do_timer_cpu global variable - Address a !CONFIG_BUG build warning * tag 'timers-urgent-2024-04-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: selftests: kselftest: Fix build failure with NOLIBC selftests: timers: Fix abs() warning in posix_timers test selftests: kselftest: Mark functions that unconditionally call exit() as __noreturn selftests: timers: Fix posix_timers ksft_print_msg() warning selftests: timers: Fix valid-adjtimex signed left-shift undefined behavior bug: Fix no-return-statement warning with !CONFIG_BUG timekeeping: Use READ/WRITE_ONCE() for tick_do_timer_cpu selftests/timers/posix_timers: Reimplement check_timer_distribution() irqflags: Explicitly ignore lockdep_hrtimer_exit() argument
2 parents a1505c4 + 1676750 commit c748fc3

File tree

7 files changed

+147
-124
lines changed

7 files changed

+147
-124
lines changed

include/asm-generic/bug.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
156156

157157
#else /* !CONFIG_BUG */
158158
#ifndef HAVE_ARCH_BUG
159-
#define BUG() do {} while (1)
159+
#define BUG() do { \
160+
do {} while (1); \
161+
unreachable(); \
162+
} while (0)
160163
#endif
161164

162165
#ifndef HAVE_ARCH_BUG_ON

include/linux/irqflags.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ do { \
114114
# define lockdep_softirq_enter() do { } while (0)
115115
# define lockdep_softirq_exit() do { } while (0)
116116
# define lockdep_hrtimer_enter(__hrtimer) false
117-
# define lockdep_hrtimer_exit(__context) do { } while (0)
117+
# define lockdep_hrtimer_exit(__context) do { (void)(__context); } while (0)
118118
# define lockdep_posixtimer_enter() do { } while (0)
119119
# define lockdep_posixtimer_exit() do { } while (0)
120120
# define lockdep_irq_work_enter(__work) do { } while (0)

kernel/time/tick-common.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar
88
* Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner
99
*/
10+
#include <linux/compiler.h>
1011
#include <linux/cpu.h>
1112
#include <linux/err.h>
1213
#include <linux/hrtimer.h>
@@ -84,7 +85,7 @@ int tick_is_oneshot_available(void)
8485
*/
8586
static void tick_periodic(int cpu)
8687
{
87-
if (tick_do_timer_cpu == cpu) {
88+
if (READ_ONCE(tick_do_timer_cpu) == cpu) {
8889
raw_spin_lock(&jiffies_lock);
8990
write_seqcount_begin(&jiffies_seq);
9091

@@ -215,8 +216,8 @@ static void tick_setup_device(struct tick_device *td,
215216
* If no cpu took the do_timer update, assign it to
216217
* this cpu:
217218
*/
218-
if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
219-
tick_do_timer_cpu = cpu;
219+
if (READ_ONCE(tick_do_timer_cpu) == TICK_DO_TIMER_BOOT) {
220+
WRITE_ONCE(tick_do_timer_cpu, cpu);
220221
tick_next_period = ktime_get();
221222
#ifdef CONFIG_NO_HZ_FULL
222223
/*
@@ -232,7 +233,7 @@ static void tick_setup_device(struct tick_device *td,
232233
!tick_nohz_full_cpu(cpu)) {
233234
tick_take_do_timer_from_boot();
234235
tick_do_timer_boot_cpu = -1;
235-
WARN_ON(tick_do_timer_cpu != cpu);
236+
WARN_ON(READ_ONCE(tick_do_timer_cpu) != cpu);
236237
#endif
237238
}
238239

@@ -406,10 +407,10 @@ void tick_assert_timekeeping_handover(void)
406407
int tick_cpu_dying(unsigned int dying_cpu)
407408
{
408409
/*
409-
* If the current CPU is the timekeeper, it's the only one that
410-
* can safely hand over its duty. Also all online CPUs are in
411-
* stop machine, guaranteed not to be idle, therefore it's safe
412-
* to pick any online successor.
410+
* If the current CPU is the timekeeper, it's the only one that can
411+
* safely hand over its duty. Also all online CPUs are in stop
412+
* machine, guaranteed not to be idle, therefore there is no
413+
* concurrency and it's safe to pick any online successor.
413414
*/
414415
if (tick_do_timer_cpu == dying_cpu)
415416
tick_do_timer_cpu = cpumask_first(cpu_online_mask);

kernel/time/tick-sched.c

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*
99
* Started by: Thomas Gleixner and Ingo Molnar
1010
*/
11+
#include <linux/compiler.h>
1112
#include <linux/cpu.h>
1213
#include <linux/err.h>
1314
#include <linux/hrtimer.h>
@@ -204,7 +205,7 @@ static inline void tick_sched_flag_clear(struct tick_sched *ts,
204205

205206
static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
206207
{
207-
int cpu = smp_processor_id();
208+
int tick_cpu, cpu = smp_processor_id();
208209

209210
/*
210211
* Check if the do_timer duty was dropped. We don't care about
@@ -216,16 +217,18 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
216217
* If nohz_full is enabled, this should not happen because the
217218
* 'tick_do_timer_cpu' CPU never relinquishes.
218219
*/
219-
if (IS_ENABLED(CONFIG_NO_HZ_COMMON) &&
220-
unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) {
220+
tick_cpu = READ_ONCE(tick_do_timer_cpu);
221+
222+
if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && unlikely(tick_cpu == TICK_DO_TIMER_NONE)) {
221223
#ifdef CONFIG_NO_HZ_FULL
222224
WARN_ON_ONCE(tick_nohz_full_running);
223225
#endif
224-
tick_do_timer_cpu = cpu;
226+
WRITE_ONCE(tick_do_timer_cpu, cpu);
227+
tick_cpu = cpu;
225228
}
226229

227230
/* Check if jiffies need an update */
228-
if (tick_do_timer_cpu == cpu)
231+
if (tick_cpu == cpu)
229232
tick_do_update_jiffies64(now);
230233

231234
/*
@@ -610,7 +613,7 @@ bool tick_nohz_cpu_hotpluggable(unsigned int cpu)
610613
* timers, workqueues, timekeeping, ...) on behalf of full dynticks
611614
* CPUs. It must remain online when nohz full is enabled.
612615
*/
613-
if (tick_nohz_full_running && tick_do_timer_cpu == cpu)
616+
if (tick_nohz_full_running && READ_ONCE(tick_do_timer_cpu) == cpu)
614617
return false;
615618
return true;
616619
}
@@ -891,6 +894,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
891894
{
892895
u64 basemono, next_tick, delta, expires;
893896
unsigned long basejiff;
897+
int tick_cpu;
894898

895899
basemono = get_jiffies_update(&basejiff);
896900
ts->last_jiffies = basejiff;
@@ -947,9 +951,9 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
947951
* Otherwise we can sleep as long as we want.
948952
*/
949953
delta = timekeeping_max_deferment();
950-
if (cpu != tick_do_timer_cpu &&
951-
(tick_do_timer_cpu != TICK_DO_TIMER_NONE ||
952-
!tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
954+
tick_cpu = READ_ONCE(tick_do_timer_cpu);
955+
if (tick_cpu != cpu &&
956+
(tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
953957
delta = KTIME_MAX;
954958

955959
/* Calculate the next expiry time */
@@ -970,6 +974,7 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
970974
unsigned long basejiff = ts->last_jiffies;
971975
u64 basemono = ts->timer_expires_base;
972976
bool timer_idle = tick_sched_flag_test(ts, TS_FLAG_STOPPED);
977+
int tick_cpu;
973978
u64 expires;
974979

975980
/* Make sure we won't be trying to stop it twice in a row. */
@@ -1007,10 +1012,11 @@ static void tick_nohz_stop_tick(struct tick_sched *ts, int cpu)
10071012
* do_timer() never gets invoked. Keep track of the fact that it
10081013
* was the one which had the do_timer() duty last.
10091014
*/
1010-
if (cpu == tick_do_timer_cpu) {
1011-
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
1015+
tick_cpu = READ_ONCE(tick_do_timer_cpu);
1016+
if (tick_cpu == cpu) {
1017+
WRITE_ONCE(tick_do_timer_cpu, TICK_DO_TIMER_NONE);
10121018
tick_sched_flag_set(ts, TS_FLAG_DO_TIMER_LAST);
1013-
} else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
1019+
} else if (tick_cpu != TICK_DO_TIMER_NONE) {
10141020
tick_sched_flag_clear(ts, TS_FLAG_DO_TIMER_LAST);
10151021
}
10161022

@@ -1173,15 +1179,17 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
11731179
return false;
11741180

11751181
if (tick_nohz_full_enabled()) {
1182+
int tick_cpu = READ_ONCE(tick_do_timer_cpu);
1183+
11761184
/*
11771185
* Keep the tick alive to guarantee timekeeping progression
11781186
* if there are full dynticks CPUs around
11791187
*/
1180-
if (tick_do_timer_cpu == cpu)
1188+
if (tick_cpu == cpu)
11811189
return false;
11821190

11831191
/* Should not happen for nohz-full */
1184-
if (WARN_ON_ONCE(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
1192+
if (WARN_ON_ONCE(tick_cpu == TICK_DO_TIMER_NONE))
11851193
return false;
11861194
}
11871195

tools/testing/selftests/kselftest.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <stdarg.h>
5252
#include <string.h>
5353
#include <stdio.h>
54+
#include <sys/utsname.h>
5455
#endif
5556

5657
#ifndef ARRAY_SIZE
@@ -79,6 +80,9 @@
7980
#define KSFT_XPASS 3
8081
#define KSFT_SKIP 4
8182

83+
#ifndef __noreturn
84+
#define __noreturn __attribute__((__noreturn__))
85+
#endif
8286
#define __printf(a, b) __attribute__((format(printf, a, b)))
8387

8488
/* counters */
@@ -299,13 +303,13 @@ void ksft_test_result_code(int exit_code, const char *test_name,
299303
va_end(args);
300304
}
301305

302-
static inline int ksft_exit_pass(void)
306+
static inline __noreturn int ksft_exit_pass(void)
303307
{
304308
ksft_print_cnts();
305309
exit(KSFT_PASS);
306310
}
307311

308-
static inline int ksft_exit_fail(void)
312+
static inline __noreturn int ksft_exit_fail(void)
309313
{
310314
ksft_print_cnts();
311315
exit(KSFT_FAIL);
@@ -332,7 +336,7 @@ static inline int ksft_exit_fail(void)
332336
ksft_cnt.ksft_xfail + \
333337
ksft_cnt.ksft_xskip)
334338

335-
static inline __printf(1, 2) int ksft_exit_fail_msg(const char *msg, ...)
339+
static inline __noreturn __printf(1, 2) int ksft_exit_fail_msg(const char *msg, ...)
336340
{
337341
int saved_errno = errno;
338342
va_list args;
@@ -347,19 +351,19 @@ static inline __printf(1, 2) int ksft_exit_fail_msg(const char *msg, ...)
347351
exit(KSFT_FAIL);
348352
}
349353

350-
static inline int ksft_exit_xfail(void)
354+
static inline __noreturn int ksft_exit_xfail(void)
351355
{
352356
ksft_print_cnts();
353357
exit(KSFT_XFAIL);
354358
}
355359

356-
static inline int ksft_exit_xpass(void)
360+
static inline __noreturn int ksft_exit_xpass(void)
357361
{
358362
ksft_print_cnts();
359363
exit(KSFT_XPASS);
360364
}
361365

362-
static inline __printf(1, 2) int ksft_exit_skip(const char *msg, ...)
366+
static inline __noreturn __printf(1, 2) int ksft_exit_skip(const char *msg, ...)
363367
{
364368
int saved_errno = errno;
365369
va_list args;
@@ -388,4 +392,21 @@ static inline __printf(1, 2) int ksft_exit_skip(const char *msg, ...)
388392
exit(KSFT_SKIP);
389393
}
390394

395+
static inline int ksft_min_kernel_version(unsigned int min_major,
396+
unsigned int min_minor)
397+
{
398+
#ifdef NOLIBC
399+
ksft_print_msg("NOLIBC: Can't check kernel version: Function not implemented\n");
400+
return 0;
401+
#else
402+
unsigned int major, minor;
403+
struct utsname info;
404+
405+
if (uname(&info) || sscanf(info.release, "%u.%u.", &major, &minor) != 2)
406+
ksft_exit_fail_msg("Can't parse kernel version\n");
407+
408+
return major > min_major || (major == min_major && minor >= min_minor);
409+
#endif
410+
}
411+
391412
#endif /* __KSELFTEST_H */

0 commit comments

Comments
 (0)