Commit c748fc3b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents a1505c47 16767502
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -156,7 +156,10 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);

#else /* !CONFIG_BUG */
#ifndef HAVE_ARCH_BUG
#define BUG() do {} while (1)
#define BUG() do {		\
	do {} while (1);	\
	unreachable();		\
} while (0)
#endif

#ifndef HAVE_ARCH_BUG_ON
+1 −1
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ do { \
# define lockdep_softirq_enter()		do { } while (0)
# define lockdep_softirq_exit()			do { } while (0)
# define lockdep_hrtimer_enter(__hrtimer)	false
# define lockdep_hrtimer_exit(__context)	do { } while (0)
# define lockdep_hrtimer_exit(__context)	do { (void)(__context); } while (0)
# define lockdep_posixtimer_enter()		do { } while (0)
# define lockdep_posixtimer_exit()		do { } while (0)
# define lockdep_irq_work_enter(__work)		do { } while (0)
+9 −8
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar
 * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner
 */
#include <linux/compiler.h>
#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/hrtimer.h>
@@ -84,7 +85,7 @@ int tick_is_oneshot_available(void)
 */
static void tick_periodic(int cpu)
{
	if (tick_do_timer_cpu == cpu) {
	if (READ_ONCE(tick_do_timer_cpu) == cpu) {
		raw_spin_lock(&jiffies_lock);
		write_seqcount_begin(&jiffies_seq);

@@ -215,8 +216,8 @@ static void tick_setup_device(struct tick_device *td,
		 * If no cpu took the do_timer update, assign it to
		 * this cpu:
		 */
		if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
			tick_do_timer_cpu = cpu;
		if (READ_ONCE(tick_do_timer_cpu) == TICK_DO_TIMER_BOOT) {
			WRITE_ONCE(tick_do_timer_cpu, cpu);
			tick_next_period = ktime_get();
#ifdef CONFIG_NO_HZ_FULL
			/*
@@ -232,7 +233,7 @@ static void tick_setup_device(struct tick_device *td,
						!tick_nohz_full_cpu(cpu)) {
			tick_take_do_timer_from_boot();
			tick_do_timer_boot_cpu = -1;
			WARN_ON(tick_do_timer_cpu != cpu);
			WARN_ON(READ_ONCE(tick_do_timer_cpu) != cpu);
#endif
		}

@@ -406,10 +407,10 @@ void tick_assert_timekeeping_handover(void)
int tick_cpu_dying(unsigned int dying_cpu)
{
	/*
	 * If the current CPU is the timekeeper, it's the only one that
	 * can safely hand over its duty. Also all online CPUs are in
	 * stop machine, guaranteed not to be idle, therefore it's safe
	 * to pick any online successor.
	 * If the current CPU is the timekeeper, it's the only one that can
	 * safely hand over its duty. Also all online CPUs are in stop
	 * machine, guaranteed not to be idle, therefore there is no
	 * concurrency and it's safe to pick any online successor.
	 */
	if (tick_do_timer_cpu == dying_cpu)
		tick_do_timer_cpu = cpumask_first(cpu_online_mask);
+22 −14
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 *
 *  Started by: Thomas Gleixner and Ingo Molnar
 */
#include <linux/compiler.h>
#include <linux/cpu.h>
#include <linux/err.h>
#include <linux/hrtimer.h>
@@ -204,7 +205,7 @@ static inline void tick_sched_flag_clear(struct tick_sched *ts,

static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
{
	int cpu = smp_processor_id();
	int tick_cpu, cpu = smp_processor_id();

	/*
	 * 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)
	 * If nohz_full is enabled, this should not happen because the
	 * 'tick_do_timer_cpu' CPU never relinquishes.
	 */
	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) &&
	    unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) {
	tick_cpu = READ_ONCE(tick_do_timer_cpu);

	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && unlikely(tick_cpu == TICK_DO_TIMER_NONE)) {
#ifdef CONFIG_NO_HZ_FULL
		WARN_ON_ONCE(tick_nohz_full_running);
#endif
		tick_do_timer_cpu = cpu;
		WRITE_ONCE(tick_do_timer_cpu, cpu);
		tick_cpu = cpu;
	}

	/* Check if jiffies need an update */
	if (tick_do_timer_cpu == cpu)
	if (tick_cpu == cpu)
		tick_do_update_jiffies64(now);

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

	basemono = get_jiffies_update(&basejiff);
	ts->last_jiffies = basejiff;
@@ -947,9 +951,9 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
	 * Otherwise we can sleep as long as we want.
	 */
	delta = timekeeping_max_deferment();
	if (cpu != tick_do_timer_cpu &&
	    (tick_do_timer_cpu != TICK_DO_TIMER_NONE ||
	     !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
	tick_cpu = READ_ONCE(tick_do_timer_cpu);
	if (tick_cpu != cpu &&
	    (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
		delta = KTIME_MAX;

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

	/* 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)
	 * do_timer() never gets invoked. Keep track of the fact that it
	 * was the one which had the do_timer() duty last.
	 */
	if (cpu == tick_do_timer_cpu) {
		tick_do_timer_cpu = TICK_DO_TIMER_NONE;
	tick_cpu = READ_ONCE(tick_do_timer_cpu);
	if (tick_cpu == cpu) {
		WRITE_ONCE(tick_do_timer_cpu, TICK_DO_TIMER_NONE);
		tick_sched_flag_set(ts, TS_FLAG_DO_TIMER_LAST);
	} else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) {
	} else if (tick_cpu != TICK_DO_TIMER_NONE) {
		tick_sched_flag_clear(ts, TS_FLAG_DO_TIMER_LAST);
	}

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

	if (tick_nohz_full_enabled()) {
		int tick_cpu = READ_ONCE(tick_do_timer_cpu);

		/*
		 * Keep the tick alive to guarantee timekeeping progression
		 * if there are full dynticks CPUs around
		 */
		if (tick_do_timer_cpu == cpu)
		if (tick_cpu == cpu)
			return false;

		/* Should not happen for nohz-full */
		if (WARN_ON_ONCE(tick_do_timer_cpu == TICK_DO_TIMER_NONE))
		if (WARN_ON_ONCE(tick_cpu == TICK_DO_TIMER_NONE))
			return false;
	}

+27 −6
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <sys/utsname.h>
#endif

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

#ifndef __noreturn
#define __noreturn       __attribute__((__noreturn__))
#endif
#define __printf(a, b)   __attribute__((format(printf, a, b)))

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

static inline int ksft_exit_pass(void)
static inline __noreturn int ksft_exit_pass(void)
{
	ksft_print_cnts();
	exit(KSFT_PASS);
}

static inline int ksft_exit_fail(void)
static inline __noreturn int ksft_exit_fail(void)
{
	ksft_print_cnts();
	exit(KSFT_FAIL);
@@ -332,7 +336,7 @@ static inline int ksft_exit_fail(void)
		  ksft_cnt.ksft_xfail +	\
		  ksft_cnt.ksft_xskip)

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

static inline int ksft_exit_xfail(void)
static inline __noreturn int ksft_exit_xfail(void)
{
	ksft_print_cnts();
	exit(KSFT_XFAIL);
}

static inline int ksft_exit_xpass(void)
static inline __noreturn int ksft_exit_xpass(void)
{
	ksft_print_cnts();
	exit(KSFT_XPASS);
}

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

static inline int ksft_min_kernel_version(unsigned int min_major,
					  unsigned int min_minor)
{
#ifdef NOLIBC
	ksft_print_msg("NOLIBC: Can't check kernel version: Function not implemented\n");
	return 0;
#else
	unsigned int major, minor;
	struct utsname info;

	if (uname(&info) || sscanf(info.release, "%u.%u.", &major, &minor) != 2)
		ksft_exit_fail_msg("Can't parse kernel version\n");

	return major > min_major || (major == min_major && minor >= min_minor);
#endif
}

#endif /* __KSELFTEST_H */
Loading