summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/x86/include/asm/nospec-branch.h1
-rw-r--r--include/linux/hrtimer.h34
-rw-r--r--include/linux/hrtimer_bases.h (renamed from include/linux/hrtimer_defs.h)16
-rw-r--r--include/linux/hrtimer_rearm.h5
-rw-r--r--include/linux/posix-timers.h5
-rw-r--r--include/linux/posix-timers_types.h6
-rw-r--r--include/linux/timekeeper_internal.h32
-rw-r--r--include/linux/timekeeping.h24
-rw-r--r--include/uapi/linux/time_types.h2
-rw-r--r--init/Kconfig1
-rw-r--r--kernel/sched/fair.c2
-rw-r--r--kernel/time/Kconfig1
-rw-r--r--kernel/time/clocksource.c9
-rw-r--r--kernel/time/hrtimer.c64
-rw-r--r--kernel/time/itimer.c2
-rw-r--r--kernel/time/namespace.c6
-rw-r--r--kernel/time/ntp.c310
-rw-r--r--kernel/time/ntp_internal.h4
-rw-r--r--kernel/time/posix-cpu-timers.c9
-rw-r--r--kernel/time/tick-internal.h1
-rw-r--r--kernel/time/time.c1
-rw-r--r--kernel/time/timekeeping.c202
-rw-r--r--kernel/time/timekeeping.h2
-rw-r--r--kernel/time/timekeeping_internal.h21
-rw-r--r--kernel/time/timer_list.c78
-rw-r--r--kernel/time/timer_migration.c4
-rw-r--r--kernel/time/timer_migration.h2
-rw-r--r--sound/drivers/dummy.c1
-rw-r--r--tools/testing/selftests/clock-helpers.h76
-rw-r--r--tools/testing/selftests/timers/Makefile2
-rw-r--r--tools/testing/selftests/timers/adjtick.c2
-rw-r--r--tools/testing/selftests/timers/alarmtimer-suspend.c37
-rw-r--r--tools/testing/selftests/timers/inconsistency-check.c37
-rw-r--r--tools/testing/selftests/timers/leap-a-day.c21
-rw-r--r--tools/testing/selftests/timers/mqueue-lat.c2
-rw-r--r--tools/testing/selftests/timers/nanosleep.c144
-rw-r--r--tools/testing/selftests/timers/nsleep-lat.c101
-rw-r--r--tools/testing/selftests/timers/posix_timers.c34
-rw-r--r--tools/testing/selftests/timers/raw_skew.c2
-rw-r--r--tools/testing/selftests/timers/set-2038.c2
-rw-r--r--tools/testing/selftests/timers/set-timer-lat.c40
-rw-r--r--tools/testing/selftests/timers/valid-adjtimex.c2
43 files changed, 818 insertions, 530 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c62af987a23..9144c5445d5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27203,6 +27203,7 @@ TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
M: John Stultz <jstultz@google.com>
M: Thomas Gleixner <tglx@kernel.org>
R: Stephen Boyd <sboyd@kernel.org>
+R: Miroslav Lichvar <mlichvar@redhat.com>
L: linux-kernel@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 2ea6591bc7b9..1abeb9af000b 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -6,6 +6,7 @@
#include <linux/static_key.h>
#include <linux/objtool.h>
#include <linux/linkage.h>
+#include <linux/types.h>
#include <asm/alternative.h>
#include <asm/cpufeatures.h>
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 6862dea0acc5..29072d89e5cb 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -12,7 +12,6 @@
#ifndef _LINUX_HRTIMER_H
#define _LINUX_HRTIMER_H
-#include <linux/hrtimer_defs.h>
#include <linux/hrtimer_rearm.h>
#include <linux/hrtimer_types.h>
#include <linux/init.h>
@@ -287,37 +286,8 @@ static inline bool hrtimer_is_queued(struct hrtimer *timer)
return READ_ONCE(timer->is_queued);
}
-/*
- * Helper function to check, whether the timer is running the callback
- * function
- */
-static inline int hrtimer_callback_running(struct hrtimer *timer)
-{
- return timer->base->running == timer;
-}
-
-/**
- * hrtimer_update_function - Update the timer's callback function
- * @timer: Timer to update
- * @function: New callback function
- *
- * Only safe to call if the timer is not enqueued. Can be called in the callback function if the
- * timer is not enqueued at the same time (see the comments above HRTIMER_STATE_ENQUEUED).
- */
-static inline void hrtimer_update_function(struct hrtimer *timer,
- enum hrtimer_restart (*function)(struct hrtimer *))
-{
-#ifdef CONFIG_PROVE_LOCKING
- guard(raw_spinlock_irqsave)(&timer->base->cpu_base->lock);
-
- if (WARN_ON_ONCE(hrtimer_is_queued(timer)))
- return;
-
- if (WARN_ON_ONCE(!function))
- return;
-#endif
- ACCESS_PRIVATE(timer, function) = function;
-}
+void hrtimer_update_function(struct hrtimer *timer,
+ enum hrtimer_restart (*function)(struct hrtimer *));
/* Forward a hrtimer so it expires after now: */
extern u64
diff --git a/include/linux/hrtimer_defs.h b/include/linux/hrtimer_bases.h
index 52ed9e46ff13..d4c83ec5c0f8 100644
--- a/include/linux/hrtimer_defs.h
+++ b/include/linux/hrtimer_bases.h
@@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_HRTIMER_DEFS_H
-#define _LINUX_HRTIMER_DEFS_H
+#ifndef _LINUX_HRTIMER_BASES_H
+#define _LINUX_HRTIMER_BASES_H
+#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/timerqueue.h>
#include <linux/seqlock.h>
@@ -83,7 +84,7 @@ struct hrtimer_cpu_base {
raw_spinlock_t lock;
unsigned int cpu;
unsigned int active_bases;
- unsigned int clock_was_set_seq;
+ u32 clock_was_set_seq;
bool hres_active;
bool deferred_rearm;
bool deferred_needs_update;
@@ -110,4 +111,13 @@ struct hrtimer_cpu_base {
} ____cacheline_aligned;
+/*
+ * Helper function to check, whether the timer is running the callback
+ * function
+ */
+static inline int hrtimer_callback_running(struct hrtimer *timer)
+{
+ return timer->base->running == timer;
+}
+
#endif
diff --git a/include/linux/hrtimer_rearm.h b/include/linux/hrtimer_rearm.h
index a6f2e5d5e1c7..17a81826bd9a 100644
--- a/include/linux/hrtimer_rearm.h
+++ b/include/linux/hrtimer_rearm.h
@@ -2,7 +2,12 @@
#ifndef _LINUX_HRTIMER_REARM_H
#define _LINUX_HRTIMER_REARM_H
+#include <linux/types.h>
+
#ifdef CONFIG_HRTIMER_REARM_DEFERRED
+#include <linux/irqflags.h>
+#include <linux/lockdep.h>
+#include <linux/preempt.h>
#include <linux/thread_info.h>
void __hrtimer_rearm_deferred(void);
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 4d3dbcef379e..9a1a0c61361c 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -37,7 +37,7 @@ static inline int clockid_to_fd(const clockid_t clk)
return ~(clk >> 3);
}
-static inline bool clockid_aux_valid(clockid_t id)
+static inline bool clockid_is_aux_clock(clockid_t id)
{
return IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS) && id >= CLOCK_AUX && id <= CLOCK_AUX_LAST;
}
@@ -47,7 +47,7 @@ static inline bool clockid_aux_valid(clockid_t id)
#include <linux/signal_types.h>
/**
- * cpu_timer - Posix CPU timer representation for k_itimer
+ * struct cpu_timer - Posix CPU timer representation for k_itimer
* @node: timerqueue node to queue in the task/sig
* @head: timerqueue head on which this timer is queued
* @pid: Pointer to target task PID
@@ -174,6 +174,7 @@ static inline void posix_cputimers_init_work(void) { }
* @it_sigqueue_seq: The sequence count at the point where the signal was queued
* @it_sigev_notify: The notify word of sigevent struct for signal delivery
* @it_interval: The interval for periodic timers
+ * @it_pid_type: The type of the PID
* @it_signal: Pointer to the creators signal struct
* @it_pid: The pid of the process/task targeted by the signal
* @it_process: The task to wakeup on clock_nanosleep (CPU timers)
diff --git a/include/linux/posix-timers_types.h b/include/linux/posix-timers_types.h
index a4712c1008c9..b40cf352e01d 100644
--- a/include/linux/posix-timers_types.h
+++ b/include/linux/posix-timers_types.h
@@ -34,7 +34,7 @@
#ifdef CONFIG_POSIX_TIMERS
/**
- * posix_cputimer_base - Container per posix CPU clock
+ * struct posix_cputimer_base - Container per posix CPU clock
* @nextevt: Earliest-expiration cache
* @tqhead: timerqueue head for cpu_timers
*/
@@ -44,7 +44,7 @@ struct posix_cputimer_base {
};
/**
- * posix_cputimers - Container for posix CPU timer related data
+ * struct posix_cputimers - Container for posix CPU timer related data
* @bases: Base container for posix CPU clocks
* @timers_active: Timers are queued.
* @expiry_active: Timer expiry is active. Used for
@@ -60,7 +60,7 @@ struct posix_cputimers {
};
/**
- * posix_cputimers_work - Container for task work based posix CPU timer expiry
+ * struct posix_cputimers_work - Container for task work based posix CPU timer expiry
* @work: The task work to be scheduled
* @mutex: Mutex held around expiry in context of this task work
* @scheduled: @work has been scheduled already, no further processing
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 4486dfd5d0de..fe077d97b5f8 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -84,8 +84,6 @@ struct tk_read_base {
* @cycle_interval: Number of clock cycles in one NTP interval
* @xtime_interval: Number of clock shifted nano seconds in one NTP
* interval.
- * @xtime_remainder: Shifted nano seconds left over when rounding
- * @cycle_interval
* @raw_interval: Shifted raw nano seconds accumulated per NTP interval.
* @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second
* @ntp_tick: The ntp_tick_length() value currently being
@@ -99,6 +97,10 @@ struct tk_read_base {
* @ntp_error_shift: Shift conversion between clock shifted nano seconds and
* ntp shifted nano seconds.
* @ntp_err_mult: Multiplication factor for scaled math conversion
+ * @cs_tick_adj: Per-second adjustment handed to NTP via ntp_clear()
+ * accounting for the difference between the nominal
+ * NTP interval and the real time taken by the
+ * clocksource's integer @cycle_interval (upscaled).
* @skip_second_overflow: Flag used to avoid updating NTP twice with same second
* @tai_offset: The current UTC to TAI offset in seconds
*
@@ -167,7 +169,7 @@ struct timekeeper {
u32 cs_ns_to_cyc_mult;
u32 cs_ns_to_cyc_shift;
u64 cs_ns_to_cyc_maxns;
- unsigned int clock_was_set_seq;
+ u32 clock_was_set_seq;
u8 cs_was_changed_seq;
u8 clock_valid;
@@ -178,7 +180,6 @@ struct timekeeper {
u64 cycle_interval;
u64 xtime_interval;
- s64 xtime_remainder;
u64 raw_interval;
ktime_t next_leap_ktime;
@@ -186,29 +187,10 @@ struct timekeeper {
s64 ntp_error;
u32 ntp_error_shift;
u32 ntp_err_mult;
+ s64 cs_tick_adj;
u32 skip_second_overflow;
+ s64 skew_delta;
s32 tai_offset;
};
-#ifdef CONFIG_GENERIC_GETTIMEOFDAY
-
-extern void update_vsyscall(struct timekeeper *tk);
-extern void update_vsyscall_tz(void);
-
-#else
-
-static inline void update_vsyscall(struct timekeeper *tk)
-{
-}
-static inline void update_vsyscall_tz(void)
-{
-}
-#endif
-
-#if defined(CONFIG_GENERIC_GETTIMEOFDAY) && defined(CONFIG_POSIX_AUX_CLOCKS)
-extern void vdso_time_update_aux(struct timekeeper *tk);
-#else
-static inline void vdso_time_update_aux(struct timekeeper *tk) { }
-#endif
-
#endif /* _LINUX_TIMEKEEPER_INTERNAL_H */
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 984a866d293b..efa9442aaeef 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -44,7 +44,6 @@ extern void ktime_get_ts64(struct timespec64 *ts);
extern void ktime_get_real_ts64(struct timespec64 *tv);
extern void ktime_get_coarse_ts64(struct timespec64 *ts);
extern void ktime_get_coarse_real_ts64(struct timespec64 *ts);
-extern void ktime_get_clock_ts64(clockid_t id, struct timespec64 *ts);
/* Multigrain timestamp interfaces */
extern void ktime_get_coarse_real_ts64_mg(struct timespec64 *ts);
@@ -268,15 +267,18 @@ extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta);
* Auxiliary clock interfaces
*/
#ifdef CONFIG_POSIX_AUX_CLOCKS
-extern bool ktime_get_aux(clockid_t id, ktime_t *kt);
-extern bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt);
+extern bool __must_check ktime_get_aux(clockid_t id, ktime_t *kt);
+extern bool __must_check ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt);
#else
-static inline bool ktime_get_aux(clockid_t id, ktime_t *kt) { return false; }
-static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { return false; }
+static inline bool __must_check ktime_get_aux(clockid_t id, ktime_t *kt) { return false; }
+static inline bool __must_check ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt)
+{
+ return false;
+}
#endif
/**
- * struct system_time_snapshot - Simultaneous time capture of CLOCK_MONOTONIC_RAW,
+ * struct system_time_snapshot - Simultaneous time capture of monotonic raw time,
* a selected CLOCK_* and the clocksource counter value
* @cycles: Clocksource counter value to produce the system times
* @hw_cycles: For derived clocksources, the hardware counter value from
@@ -289,6 +291,10 @@ static inline bool ktime_get_aux_ts64(clockid_t id, struct timespec64 *kt) { ret
* @clock_was_set_seq: The sequence number of clock-was-set events
* @cs_was_changed_seq: The sequence number of clocksource change events
* @valid: True if the snapshot is valid
+ *
+ * @monoraw is CLOCK_MONOTONIC_RAW for system time CLOCK ids. For CLOCK_AUX$N
+ * clock ids it's the monotonic raw time related to the AUX clock, which is
+ * CLOCK_MONOTONIC_RAW plus a AUX clock specific offset.
*/
struct system_time_snapshot {
u64 cycles;
@@ -297,7 +303,7 @@ struct system_time_snapshot {
ktime_t monoraw;
enum clocksource_ids cs_id;
enum clocksource_ids hw_csid;
- unsigned int clock_was_set_seq;
+ u32 clock_was_set_seq;
u8 cs_was_changed_seq;
u8 valid;
};
@@ -326,6 +332,10 @@ struct system_counterval_t {
* @sys_counter: Clocksource counter value simultaneous with device time
* @sys_systime: System time for @clock_id
* @sys_monoraw: Monotonic raw simultaneous with device time
+ *
+ * @sys_monoraw is CLOCK_MONOTONIC_RAW for system time CLOCK ids. For
+ * CLOCK_AUX$N clock ids it's the monotonic raw time related to the AUX clock,
+ * which is CLOCK_MONOTONIC_RAW plus a AUX clock specific offset.
*/
struct system_device_crosststamp {
clockid_t clock_id;
diff --git a/include/uapi/linux/time_types.h b/include/uapi/linux/time_types.h
index bcc0002115d3..03a0d8aaadca 100644
--- a/include/uapi/linux/time_types.h
+++ b/include/uapi/linux/time_types.h
@@ -30,7 +30,7 @@ struct __kernel_old_timeval {
struct __kernel_old_timespec {
__kernel_old_time_t tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
+ __kernel_long_t tv_nsec; /* nanoseconds */
};
struct __kernel_old_itimerval {
diff --git a/init/Kconfig b/init/Kconfig
index 10f2013b5321..5d884f0c213f 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -565,6 +565,7 @@ config VIRT_CPU_ACCOUNTING
choice
prompt "Cputime accounting"
+ default VIRT_CPU_ACCOUNTING_GEN if NO_HZ_FULL
default TICK_CPU_ACCOUNTING
# Kind of a stub config for the pure tick based cputime accounting
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 635f5775cc13..001140132a7d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -26,6 +26,8 @@
#include <linux/jiffies.h>
#include <linux/mm_api.h>
#include <linux/highmem.h>
+#include <linux/hrtimer.h>
+#include <linux/hrtimer_bases.h>
#include <linux/spinlock_api.h>
#include <linux/cpumask_api.h>
#include <linux/lockdep_api.h>
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index d098ac39bde4..ddfb6bee0745 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -133,7 +133,6 @@ config NO_HZ_FULL
depends on HAVE_VIRT_CPU_ACCOUNTING_GEN
select NO_HZ_COMMON
select RCU_NOCB_CPU
- select VIRT_CPU_ACCOUNTING_GEN
select IRQ_WORK
select CPU_ISOLATION
help
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index e48c4d379a7c..f1253f5795c6 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -123,7 +123,6 @@ static atomic_t watchdog_reset_pending;
/* Watchdog interval: 0.5sec. */
#define WATCHDOG_INTERVAL (HZ >> 1)
-#define WATCHDOG_INTERVAL_NS (WATCHDOG_INTERVAL * (NSEC_PER_SEC / HZ))
/* Maximum time between two reference watchdog readouts */
#define WATCHDOG_READOUT_MAX_NS (50U * NSEC_PER_USEC)
@@ -1566,8 +1565,12 @@ static int __init init_clocksource_sysfs(void)
{
int error = subsys_system_register(&clocksource_subsys, NULL);
- if (!error)
- error = device_register(&device_clocksource);
+ if (error)
+ return error;
+
+ error = device_register(&device_clocksource);
+ if (error)
+ bus_unregister(&clocksource_subsys);
return error;
}
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 313dcea127fe..530d61257b9a 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -26,6 +26,7 @@
#include <linux/export.h>
#include <linux/percpu.h>
#include <linux/hrtimer.h>
+#include <linux/hrtimer_bases.h>
#include <linux/notifier.h>
#include <linux/syscalls.h>
#include <linux/interrupt.h>
@@ -676,6 +677,8 @@ static ktime_t hrtimer_update_next_event(struct hrtimer_cpu_base *cpu_base)
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
{
+ lockdep_assert_held(&base->lock);
+
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
@@ -707,7 +710,7 @@ static inline void hrtimer_rearm_event(ktime_t expires_next, bool deferred)
tick_program_event(expires_next, 1);
}
-static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, struct hrtimer *next_timer,
+static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base,
ktime_t expires_next)
{
cpu_base->expires_next = expires_next;
@@ -743,7 +746,7 @@ static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, bool skip
if (skip_equal && expires_next == cpu_base->expires_next)
return;
- __hrtimer_reprogram(cpu_base, cpu_base->next_timer, expires_next);
+ __hrtimer_reprogram(cpu_base, expires_next);
}
/* High resolution timer related functions */
@@ -896,14 +899,14 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
cpu_base->next_timer = timer;
- __hrtimer_reprogram(cpu_base, timer, expires);
+ __hrtimer_reprogram(cpu_base, expires);
}
static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base, unsigned int active)
{
struct hrtimer_clock_base *base;
- unsigned int seq;
ktime_t expires;
+ u32 seq;
/*
* Update the base offsets unconditionally so the following
@@ -1040,6 +1043,30 @@ static inline void unlock_hrtimer_base(const struct hrtimer *timer, unsigned lon
}
/**
+ * hrtimer_update_function - Update the timer's callback function
+ * @timer: Timer to update
+ * @function: New callback function
+ *
+ * Only safe to call if the timer is not enqueued. Can be called in the callback function if the
+ * timer is not enqueued at the same time (see the comments above HRTIMER_STATE_ENQUEUED).
+ */
+void hrtimer_update_function(struct hrtimer *timer,
+ enum hrtimer_restart (*function)(struct hrtimer *))
+{
+#ifdef CONFIG_PROVE_LOCKING
+ guard(raw_spinlock_irqsave)(&timer->base->cpu_base->lock);
+
+ if (WARN_ON_ONCE(hrtimer_is_queued(timer)))
+ return;
+
+ if (WARN_ON_ONCE(!function))
+ return;
+#endif
+ ACCESS_PRIVATE(timer, function) = function;
+}
+EXPORT_SYMBOL_GPL(hrtimer_update_function);
+
+/**
* hrtimer_forward() - forward the timer expiry
* @timer: hrtimer to forward
* @now: forward past this time
@@ -1786,13 +1813,21 @@ EXPORT_SYMBOL_GPL(__hrtimer_get_remaining);
ktime_t hrtimer_get_next_event(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
- ktime_t expires = KTIME_MAX;
- guard(raw_spinlock_irqsave)(&cpu_base->lock);
- if (!hrtimer_hres_active(cpu_base))
- expires = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
+ /*
+ * When HRES is active cmp_next_hrtimer_event() expects KTIME_MAX.
+ *
+ * cpu_base->hres_active is written only by the local CPU in
+ * hrtimer_switch_to_hres() from hard interrupt context and in
+ * hrtimers_cpu_starting() during CPU bring-up, and all callers reach
+ * this with interrupts disabled on the same CPU, so an unlocked read is
+ * stable without holding the lock.
+ */
+ if (hrtimer_hres_active(cpu_base))
+ return KTIME_MAX;
- return expires;
+ guard(raw_spinlock_irqsave)(&cpu_base->lock);
+ return __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
}
/**
@@ -2060,13 +2095,6 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, struct hrtimer_cloc
base->running = NULL;
}
-static __always_inline struct hrtimer *clock_base_next_timer_safe(struct hrtimer_clock_base *base)
-{
- struct timerqueue_linked_node *next = timerqueue_linked_first(&base->active);
-
- return next ? hrtimer_from_timerqueue_node(next) : NULL;
-}
-
static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now,
unsigned long flags, unsigned int active_mask)
{
@@ -2228,8 +2256,10 @@ retry:
expires_next = hrtimer_update_next_event(cpu_base);
cpu_base->hang_detected = false;
if (expires_next < now) {
- if (++retries < 3)
+ if (++retries < 3) {
+ cpu_base->nr_retries++;
goto retry;
+ }
delta = ktime_sub(now, entry_time);
cpu_base->max_hang_time = max_t(unsigned int, cpu_base->max_hang_time, delta);
diff --git a/kernel/time/itimer.c b/kernel/time/itimer.c
index 7c6110e964e7..03a32dffc56c 100644
--- a/kernel/time/itimer.c
+++ b/kernel/time/itimer.c
@@ -100,7 +100,7 @@ static int do_getitimer(int which, struct itimerspec64 *value)
static int put_itimerval(struct __kernel_old_itimerval __user *o,
const struct itimerspec64 *i)
{
- struct __kernel_old_itimerval v;
+ struct __kernel_old_itimerval v = {};
v.it_interval.tv_sec = i->it_interval.tv_sec;
v.it_interval.tv_usec = i->it_interval.tv_nsec / NSEC_PER_USEC;
diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c
index 5fa0af66cf3f..3aff27bb0a15 100644
--- a/kernel/time/namespace.c
+++ b/kernel/time/namespace.c
@@ -293,10 +293,12 @@ int proc_timens_set_offset(struct file *file, struct task_struct *p,
return -EINVAL;
}
- if (off->val.tv_sec > KTIME_SEC_MAX ||
- off->val.tv_sec < -KTIME_SEC_MAX)
+ if (off->val.tv_sec > KTIME_SEC_MAX || off->val.tv_sec < -KTIME_SEC_MAX)
return -ERANGE;
+ if (off->val.tv_nsec < 0 || off->val.tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+
tp = timespec64_add(tp, off->val);
/*
* KTIME_SEC_MAX is divided by 2 to be sure that KTIME_MAX is
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 97fa99b96dd0..d22b532ec536 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -26,11 +26,13 @@
/**
* struct ntp_data - Structure holding all NTP related state
* @tick_usec: USER_HZ period in microseconds
- * @tick_length: Adjusted tick length
- * @tick_length_base: Base value for @tick_length
+ * @tick_length: Tick length in ns << NTP_SCALE_SHIFT
* @time_state: State of the clock synchronization
* @time_status: Clock status bits
* @time_offset: Time adjustment in nanoseconds
+ * @skew_delta: Per-tick phase slew rate for the coming second, in
+ * @time_offset units (shifted-ns / HZ). Set by
+ * second_overflow().
* @time_constant: PLL time constant
* @time_maxerror: Maximum error in microseconds holding the NTP sync distance
* (NTP dispersion + delay / 2)
@@ -38,7 +40,13 @@
* @time_freq: Frequency offset scaled nsecs/secs
* @time_reftime: Time at last adjustment in seconds
* @time_adjust: Adjustment value
+ * @time_adjust_frac: Sub-microsecond remainder of @time_adjust being
+ * delivered, in ns << NTP_SCALE_SHIFT (not divided by HZ).
* @ntp_tick_adj: Constant boot-param configurable NTP tick adjustment (upscaled)
+ * @cs_tick_adj: Fixed per-second adjustment compensating for the difference
+ * between the nominal NTP interval and the real time taken
+ * by the clocksource's integer @cycle_interval (upscaled).
+ * Set by the timekeeping core via ntp_clear().
* @ntp_next_leap_sec: Second value of the next pending leapsecond, or TIME64_MAX if no leap
*
* @pps_valid: PPS signal watchdog counter
@@ -59,17 +67,19 @@
struct ntp_data {
unsigned long tick_usec;
u64 tick_length;
- u64 tick_length_base;
int time_state;
int time_status;
s64 time_offset;
+ s64 skew_delta;
long time_constant;
long time_maxerror;
long time_esterror;
s64 time_freq;
time64_t time_reftime;
long time_adjust;
+ s64 time_adjust_frac;
s64 ntp_tick_adj;
+ s64 cs_tick_adj;
time64_t ntp_next_leap_sec;
#ifdef CONFIG_NTP_PPS
int pps_valid;
@@ -101,6 +111,9 @@ static struct ntp_data tk_ntp_data[TIMEKEEPERS_MAX] = {
#define SECS_PER_DAY 86400
#define MAX_TICKADJ 500LL /* usecs */
+/* One microsecond of phase, in plain shifted-ns (ns << NTP_SCALE_SHIFT) */
+#define ONE_US_NS ((s64)NSEC_PER_USEC << NTP_SCALE_SHIFT)
+/* Per-tick MAX_TICKADJ slew, in plain shifted-ns */
#define MAX_TICKADJ_SCALED \
(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
#define MAX_TAI_OFFSET 100000
@@ -245,8 +258,7 @@ static inline void pps_fill_timex(struct ntp_data *ntpdata, struct __kernel_time
#endif /* CONFIG_NTP_PPS */
/*
- * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and
- * time_freq:
+ * Update tick_length based on tick_usec, ntp_tick_adj and time_freq:
*/
static void ntp_update_frequency(struct ntp_data *ntpdata)
{
@@ -255,6 +267,7 @@ static void ntp_update_frequency(struct ntp_data *ntpdata)
second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << NTP_SCALE_SHIFT;
second_length += ntpdata->ntp_tick_adj;
+ second_length += ntpdata->cs_tick_adj;
second_length += ntpdata->time_freq;
new_base = div_u64(second_length, NTP_INTERVAL_FREQ);
@@ -263,8 +276,7 @@ static void ntp_update_frequency(struct ntp_data *ntpdata)
* Don't wait for the next second_overflow, apply the change to the
* tick length immediately:
*/
- ntpdata->tick_length += new_base - ntpdata->tick_length_base;
- ntpdata->tick_length_base = new_base;
+ ntpdata->tick_length = new_base;
}
static inline s64 ntp_update_offset_fll(struct ntp_data *ntpdata, s64 offset64, long secs)
@@ -335,14 +347,15 @@ static void __ntp_clear(struct ntp_data *ntpdata)
{
/* Stop active adjtime() */
ntpdata->time_adjust = 0;
+ ntpdata->time_adjust_frac = 0;
ntpdata->time_status |= STA_UNSYNC;
ntpdata->time_maxerror = NTP_PHASE_LIMIT;
ntpdata->time_esterror = NTP_PHASE_LIMIT;
ntp_update_frequency(ntpdata);
- ntpdata->tick_length = ntpdata->tick_length_base;
ntpdata->time_offset = 0;
+ ntpdata->skew_delta = 0;
ntpdata->ntp_next_leap_sec = TIME64_MAX;
/* Clear PPS state variables */
@@ -350,11 +363,26 @@ static void __ntp_clear(struct ntp_data *ntpdata)
}
/**
- * ntp_clear - Clears the NTP state variables
- * @tkid: Timekeeper ID to be able to select proper ntp data array member
+ * ntp_clear - Clear NTP state and set the clocksource quantisation adjustment
+ * @tkid: Timekeeper ID
+ * @cs_tick_adj: Per-second adjustment in ns << NTP_SCALE_SHIFT
+ *
+ * The timekeeping core uses an integer number of cycles (@cycle_interval)
+ * per NTP interval, so the real time that interval represents differs from
+ * the nominal NTP_INTERVAL_LENGTH by up to half a counter period. Folding
+ * this fixed offset into @cs_tick_adj makes it an explicit part of the NTP
+ * tick_length computation in ntp.c, instead of being applied during
+ * timekeeping accumulation where the NTP code never saw it. Like
+ * @ntp_tick_adj it stays internal to the kernel; userspace still sees the
+ * nominal tick via adjtimex. NTP retains its full symmetric ±MAXFREQ range
+ * around the corrected base rate.
+ *
+ * Called whenever the clocksource is (re)configured, which is also when the
+ * rest of the NTP state must be cleared, so the two are done together.
*/
-void ntp_clear(unsigned int tkid)
+void ntp_clear(unsigned int tkid, s64 cs_tick_adj)
{
+ tk_ntp_data[tkid].cs_tick_adj = cs_tick_adj;
__ntp_clear(&tk_ntp_data[tkid]);
}
@@ -364,6 +392,186 @@ u64 ntp_tick_length(unsigned int tkid)
return tk_ntp_data[tkid].tick_length;
}
+s64 ntp_get_skew_delta(unsigned int tkid)
+{
+ return tk_ntp_data[tkid].skew_delta;
+}
+
+/* Sign of @x as +1 or -1 (zero counts as positive; callers pass nonzero). */
+static inline int signof(s64 x)
+{
+ return x < 0 ? -1 : 1;
+}
+
+static s64 ntp_drain_time_offset(unsigned int tkid, s64 amount)
+{
+ struct ntp_data *ntpdata = &tk_ntp_data[tkid];
+
+ /* Only drain if amount and time_offset have the same sign */
+ if (!amount || signof(amount) != signof(ntpdata->time_offset))
+ return amount;
+
+ /* Clamp: don't overshoot zero */
+ if (abs(amount) > abs(ntpdata->time_offset)) {
+ s64 undrained = amount - ntpdata->time_offset;
+
+ ntpdata->time_offset = 0;
+ return undrained;
+ }
+
+ ntpdata->time_offset -= amount;
+ return 0;
+}
+
+/*
+ * Drain the legacy adjtime() correction (time_adjust) as it is delivered.
+ *
+ * @amount is the total intentional per-tick skew for this accumulation
+ * (skew_delta << shift), in time_offset units (shifted_ns / HZ); it covers
+ * both the exponential time_offset slew and the linear adjtime slew. This
+ * function claims only the adjtime share — capped at the MAX_TICKADJ rate —
+ * and returns the remainder for ntp_drain_time_offset().
+ *
+ * time_adjust is in whole µs. The sub-µs remainder being delivered lives in
+ * time_adjust_frac (plain shifted-ns, i.e. ns << NTP_SCALE_SHIFT -- unlike
+ * time_offset these are NOT pre-divided by HZ); we top it up by borrowing
+ * whole microseconds from time_adjust as the drain consumes it.
+ */
+static s64 ntp_drain_time_adjust(unsigned int tkid, s64 amount, unsigned int shift)
+{
+ struct ntp_data *ntpdata = &tk_ntp_data[tkid];
+ /* Sign reference: time_adjust if any whole us remain, else the drawer */
+ s64 ref = ntpdata->time_adjust ? (s64)ntpdata->time_adjust
+ : ntpdata->time_adjust_frac;
+ s64 deliver, deficit, claimed;
+
+ if (!amount || !ref || signof(amount) != signof(ref))
+ return amount;
+
+ /*
+ * Phase to deliver this accumulation, in plain shifted-ns. The drain
+ * @amount is in ÷HZ units, so multiply by HZ first, then clamp to the
+ * MAX_TICKADJ rate (MAX_TICKADJ_SCALED is the per-tick slew in
+ * shifted-ns). Multiply-then-clamp avoids an s64 divide for the cap.
+ */
+ deliver = min(abs(amount) * NTP_INTERVAL_FREQ,
+ (s64)MAX_TICKADJ_SCALED << shift);
+
+ /* Top up the sub-µs drawer from whole-µs time_adjust as needed */
+ deficit = deliver - abs(ntpdata->time_adjust_frac);
+ if (deficit > 0 && ntpdata->time_adjust) {
+ long borrow = div64_u64(deficit + ONE_US_NS - 1, ONE_US_NS);
+
+ if (ntpdata->time_adjust > 0) {
+ borrow = min(borrow, ntpdata->time_adjust);
+ ntpdata->time_adjust -= borrow;
+ ntpdata->time_adjust_frac += (s64)borrow * ONE_US_NS;
+ } else {
+ /* Clamp without negating time_adjust (UB for LONG_MIN) */
+ if (ntpdata->time_adjust > -borrow)
+ borrow = -ntpdata->time_adjust;
+ ntpdata->time_adjust += borrow;
+ ntpdata->time_adjust_frac -= (s64)borrow * ONE_US_NS;
+ }
+ }
+
+ /* Never deliver more than the drawer holds */
+ deliver = min(deliver, abs(ntpdata->time_adjust_frac));
+ if (ntpdata->time_adjust_frac > 0)
+ ntpdata->time_adjust_frac -= deliver;
+ else
+ ntpdata->time_adjust_frac += deliver;
+
+ /* Return the unclaimed remainder in ÷HZ drain units for time_offset */
+ claimed = div_s64(deliver, NTP_INTERVAL_FREQ);
+ return amount - signof(amount) * claimed;
+}
+
+/*
+ * Drain one accumulation's worth of intentional skew as it is delivered.
+ *
+ * @amount is the total intentional per-tick skew for this accumulation
+ * (skew_delta << shift), in time_offset units (shifted_ns / HZ). The
+ * adjtime() linear share is taken from time_adjust first (capped at the
+ * MAX_TICKADJ rate, hence @shift), then the exponential remainder from
+ * time_offset. Returns the amount actually claimed (same ÷HZ units).
+ */
+s64 ntp_drain_skew(unsigned int tkid, s64 amount, unsigned int shift)
+{
+ s64 unclaimed = ntp_drain_time_adjust(tkid, amount, shift);
+
+ unclaimed = ntp_drain_time_offset(tkid, unclaimed);
+
+ /*
+ * Return the amount actually drained from the intentional
+ * phase offset in time_offset and/or time_adjust.
+ */
+ return amount - unclaimed;
+}
+
+/*
+ * time_offset (drained exponentially) and time_adjust (drained linearly at the
+ * MAX_TICKADJ rate) can be asked to slew the clock in opposite directions.
+ * second_overflow() only folds their *net* into skew_delta, so the cancelling
+ * part would never be drained from either tracker via the per-tick code -- and
+ * if they cancel exactly, skew_delta is zero and neither converges at all.
+ *
+ * Settle that cancelling phase directly between the two here. No clock motion
+ * results (the opposing slews annihilate), but both move toward zero so neither
+ * stalls. @amount is the phase to take off time_offset, in its (÷HZ) units and
+ * with its sign; the same real magnitude comes off time_adjust in the opposite
+ * direction. Clamped so neither tracker is driven past zero.
+ */
+static void ntp_transfer_offset_adjust(struct ntp_data *ntpdata, s64 amount)
+{
+ s64 frac_delta, carry;
+
+ /*
+ * Don't drain time_offset past zero. @amount shares its sign and is
+ * normally bounded below it by ntp_offset_chunk(), but the ±1 skew_delta
+ * floor for a tiny time_offset can exceed it, so clamp.
+ */
+ if (abs(amount) > abs(ntpdata->time_offset))
+ amount = ntpdata->time_offset;
+ if (!amount)
+ return;
+
+ /*
+ * Remove the matching phase from time_adjust, in plain shifted-ns. No
+ * clamp against time_adjust's zero is needed: @amount is bounded by the
+ * adjtime chunk, which second_overflow() never lets exceed time_adjust's
+ * own pending phase, so this cannot overshoot.
+ */
+ frac_delta = amount * NTP_INTERVAL_FREQ;
+
+ ntpdata->time_offset -= amount;
+
+ /* Add the matching phase to time_adjust, carrying whole µs (O(1)). */
+ ntpdata->time_adjust_frac += frac_delta;
+ if (ntpdata->time_adjust_frac >= ONE_US_NS ||
+ ntpdata->time_adjust_frac <= -ONE_US_NS) {
+ carry = div64_s64(ntpdata->time_adjust_frac, ONE_US_NS);
+ ntpdata->time_adjust += carry;
+ ntpdata->time_adjust_frac -= carry * ONE_US_NS;
+ }
+
+ /*
+ * Keep time_adjust and its sub-µs remainder the same sign. The
+ * truncating carry above can leave them opposed (e.g. +4 µs paired
+ * with -250 ns), and ntp_drain_time_adjust() treats abs(time_adjust_frac)
+ * as same-direction drawer capacity -- an opposing remainder there makes
+ * it over-deliver phase that was never removed from the pile. Borrow or
+ * repay a single whole µs to realign; the total phase is unchanged.
+ */
+ if (ntpdata->time_adjust > 0 && ntpdata->time_adjust_frac < 0) {
+ ntpdata->time_adjust--;
+ ntpdata->time_adjust_frac += ONE_US_NS;
+ } else if (ntpdata->time_adjust < 0 && ntpdata->time_adjust_frac > 0) {
+ ntpdata->time_adjust++;
+ ntpdata->time_adjust_frac -= ONE_US_NS;
+ }
+}
+
/**
* ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime_t
* @tkid: Timekeeper ID
@@ -398,7 +606,6 @@ ktime_t ntp_get_next_leap(unsigned int tkid)
int second_overflow(unsigned int tkid, time64_t secs)
{
struct ntp_data *ntpdata = &tk_ntp_data[tkid];
- s64 delta;
int leap = 0;
s32 rem;
@@ -458,35 +665,70 @@ int second_overflow(unsigned int tkid, time64_t secs)
}
/* Compute the phase adjustment for the next second */
- ntpdata->tick_length = ntpdata->tick_length_base;
-
- delta = ntp_offset_chunk(ntpdata, ntpdata->time_offset);
- ntpdata->time_offset -= delta;
- ntpdata->tick_length += delta;
/* Check PPS signal */
pps_dec_valid(ntpdata);
- if (!ntpdata->time_adjust)
- goto out;
+ /*
+ * Set the per-tick skew rate for the next second. This is in
+ * the same units as time_offset: (ns << NTP_SCALE_SHIFT) / HZ.
+ * If the result is so low that the skew imparted would round
+ * to zero, pass the bare minimum ±1 to ensure that it *does*
+ * actually drain completely to zero. It won't overshoot because
+ * logarithmic_accumulation() only drains what it can from
+ * time_offset or time_adjust, and the rest ends up in ntp_error
+ * which drives the selection of 'mult' immediately each tick.
+ */
+ if (ntpdata->time_offset || ntpdata->time_adjust ||
+ ntpdata->time_adjust_frac) {
+ s64 off_chunk = ntp_offset_chunk(ntpdata, ntpdata->time_offset);
+ s64 adj_chunk = 0, net;
- if (ntpdata->time_adjust > MAX_TICKADJ) {
- ntpdata->time_adjust -= MAX_TICKADJ;
- ntpdata->tick_length += MAX_TICKADJ_SCALED;
- goto out;
- }
+ /*
+ * Once the exponential chunk rounds to zero, deliver the last
+ * remaining offset this second so it converges to zero instead
+ * of stalling just above it.
+ */
+ if (!off_chunk)
+ off_chunk = ntpdata->time_offset;
- if (ntpdata->time_adjust < -MAX_TICKADJ) {
- ntpdata->time_adjust += MAX_TICKADJ;
- ntpdata->tick_length -= MAX_TICKADJ_SCALED;
- goto out;
- }
+ if (ntpdata->time_adjust || ntpdata->time_adjust_frac) {
+ s64 adj;
- ntpdata->tick_length += (s64)(ntpdata->time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
- << NTP_SCALE_SHIFT;
- ntpdata->time_adjust = 0;
+ if (ntpdata->time_adjust >= MAX_TICKADJ)
+ adj = MAX_TICKADJ * ONE_US_NS;
+ else if (ntpdata->time_adjust <= -MAX_TICKADJ)
+ adj = -MAX_TICKADJ * ONE_US_NS;
+ else
+ adj = ntpdata->time_adjust * ONE_US_NS +
+ ntpdata->time_adjust_frac;
+
+ adj_chunk = div_s64(adj, NTP_INTERVAL_FREQ);
+ if (!adj_chunk)
+ adj_chunk = signof(ntpdata->time_adjust_frac);
+ }
+
+ /*
+ * If the two slews oppose, only their net would drive the
+ * per-tick drain, so the cancelling part would never drain from
+ * either tracker and an exact cancellation would stall both.
+ * Settle that overlap directly between them (no clock motion).
+ */
+ if (off_chunk && adj_chunk && signof(off_chunk) != signof(adj_chunk)) {
+ s64 conflict = min(abs(off_chunk), abs(adj_chunk));
+
+ ntp_transfer_offset_adjust(ntpdata, signof(off_chunk) * conflict);
+ }
+
+ /* Net is what the clock delivers; reduce to per-tick, then floor. */
+ net = off_chunk + adj_chunk;
+ ntpdata->skew_delta = div_s64(net, NTP_INTERVAL_FREQ);
+ if (!ntpdata->skew_delta && net)
+ ntpdata->skew_delta = signof(net);
+ } else {
+ ntpdata->skew_delta = 0;
+ }
-out:
return leap;
}
@@ -779,6 +1021,7 @@ int ntp_adjtimex(unsigned int tkid, struct __kernel_timex *txc, const struct tim
if (!(txc->modes & ADJ_OFFSET_READONLY)) {
/* adjtime() is independent from ntp_adjtime() */
ntpdata->time_adjust = txc->offset;
+ ntpdata->time_adjust_frac = 0;
ntp_update_frequency(ntpdata);
audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust);
@@ -1020,6 +1263,7 @@ static void hardpps_update_phase(struct ntp_data *ntpdata, long error)
NTP_INTERVAL_FREQ);
/* Cancel running adjtime() */
ntpdata->time_adjust = 0;
+ ntpdata->time_adjust_frac = 0;
}
/* Update jitter */
ntpdata->pps_jitter += (jitter - ntpdata->pps_jitter) >> PPS_INTMIN;
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h
index 7084d839c207..0474a761bafc 100644
--- a/kernel/time/ntp_internal.h
+++ b/kernel/time/ntp_internal.h
@@ -3,9 +3,11 @@
#define _LINUX_NTP_INTERNAL_H
extern void ntp_init(void);
-extern void ntp_clear(unsigned int tkid);
+extern void ntp_clear(unsigned int tkid, s64 cs_tick_adj);
/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
extern u64 ntp_tick_length(unsigned int tkid);
+extern s64 ntp_get_skew_delta(unsigned int tkid);
+extern s64 ntp_drain_skew(unsigned int tkid, s64 amount, unsigned int shift);
extern ktime_t ntp_get_next_leap(unsigned int tkid);
extern int second_overflow(unsigned int tkid, time64_t secs);
extern int ntp_adjtimex(unsigned int tkid, struct __kernel_timex *txc, const struct timespec64 *ts,
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index a7d3e8229c4b..d73d31c7994f 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1357,8 +1357,11 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
unsigned long flags, start;
LIST_HEAD(firing);
- if (!lock_task_sighand(tsk, &flags))
- return;
+ /*
+ * tsk is current and ->sighand is stable, see the
+ * tsk->exit_state check in run_posix_cpu_timers()
+ */
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
do {
/*
@@ -1418,7 +1421,7 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
* that gets the timer lock before we do will give it up and
* spin until we've taken care of that timer below.
*/
- unlock_task_sighand(tsk, &flags);
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
/*
* Now that all the timers on our list have the firing flag,
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 597d816d22e8..182974c4f21b 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -3,6 +3,7 @@
* tick internal variable and functions used by low/high res code
*/
#include <linux/hrtimer.h>
+#include <linux/hrtimer_bases.h>
#include <linux/tick.h>
#include "timekeeping.h"
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 0dd63a91e7c5..d1a7efd80bf5 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -42,6 +42,7 @@
#include <generated/timeconst.h>
#include "timekeeping.h"
+#include "timekeeping_internal.h"
/*
* The timezone where the local system is located. Used as a default by some
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index b1b5ec43c0f2..ea2e6e55f37b 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -339,7 +339,6 @@ static inline void clocksource_enable_inline_read(void) { }
static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
{
u64 interval;
- u64 tmp, ntpinterval;
struct clocksource *old_clock;
++tk->cs_was_changed_seq;
@@ -353,20 +352,16 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last;
/* Do the ns -> cycle conversion first, using original mult */
- tmp = NTP_INTERVAL_LENGTH;
- tmp <<= clock->shift;
- ntpinterval = tmp;
- tmp += clock->mult/2;
- do_div(tmp, clock->mult);
- if (tmp == 0)
- tmp = 1;
+ interval = (u64)NTP_INTERVAL_LENGTH << clock->shift;
+ interval += clock->mult / 2;
+ do_div(interval, clock->mult);
+ if (interval == 0)
+ interval = 1;
- interval = (u64) tmp;
tk->cycle_interval = interval;
/* Go back from cycles -> shifted ns */
tk->xtime_interval = interval * clock->mult;
- tk->xtime_remainder = ntpinterval - tk->xtime_interval;
tk->raw_interval = interval * clock->mult;
/* if changing clocks, convert xtime_nsec shift units */
@@ -386,7 +381,38 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->ntp_error = 0;
tk->ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
- tk->ntp_tick = ntpinterval << tk->ntp_error_shift;
+
+ /*
+ * ntp_tick is the tick length that NTP disciplines (its ±500 PPM
+ * scales only this part), in NTP-shifted ns: the real interval of
+ * a whole number of counter cycles. Because cycle_interval is
+ * rounded to an integer number of cycles, this ntp_tick differs
+ * from the true intended 1/HZ tick length by up to half a cycle
+ * period.
+ */
+ tk->ntp_tick = (u64)tk->xtime_interval << tk->ntp_error_shift;
+
+ /*
+ * cs_tick_adj is the constant difference between the disciplined
+ * ntp_tick above and the true 1/HZ tick, expressed per-second to
+ * match the ntp_update_frequency() addends and handed to NTP via
+ * ntp_clear() to be explicitly included in its tick_length.
+ *
+ * Worked example: HZ=1000, ACPI PM timer at 3.579545 MHz, which
+ * has 3579.545 cycles in 1ms, rounded to cycle_interval = 3580.
+ *
+ * So ntp_tick is actually 1.000127ms, as that is the amount of
+ * time that 3580 cycles will take at the nominal frequency. This
+ * is the part that NTP disciplines, causing each 3580 counts to
+ * advance the clock by up to NTP's ±500PPM of that amount.
+ *
+ * The "extra" 127ns/tick is what's stored in cs_tick_adj and
+ * applied as a constant correction by ntp_update_frequency() so
+ * that NTP *believes* it's disciplining a 1ms tick.
+ */
+ tk->cs_tick_adj = (s64)tk->ntp_tick -
+ ((s64)NTP_INTERVAL_LENGTH << NTP_SCALE_SHIFT);
+ tk->cs_tick_adj *= NTP_INTERVAL_FREQ;
/*
* The timekeeper keeps its own mult values for the currently
@@ -397,6 +423,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->tkr_raw.mult = clock->mult;
tk->ntp_err_mult = 0;
tk->skip_second_overflow = 0;
+ tk->skew_delta = 0;
tk->cs_id = clock->id;
@@ -803,7 +830,7 @@ static void timekeeping_update_from_shadow(struct tk_data *tkd, unsigned int act
if (action & TK_CLEAR_NTP) {
tk->ntp_error = 0;
- ntp_clear(tk->id);
+ ntp_clear(tk->id, tk->cs_tick_adj);
}
tk_update_leap_state(tk);
@@ -831,7 +858,11 @@ static void timekeeping_update_from_shadow(struct tk_data *tkd, unsigned int act
* the downside that the reader side does not longer benefit from
* the cacheline optimized data layout of the timekeeper and requires
* another indirection.
+ *
+ * Write xtime_sec first so that even if the memcpy() tears the store
+ * data integrity is provided for ktime_get_real_seconds().
*/
+ WRITE_ONCE(tkd->timekeeper.xtime_sec, tk->xtime_sec);
memcpy(&tkd->timekeeper, tk, sizeof(*tk));
write_seqcount_end(&tkd->seq);
}
@@ -1159,11 +1190,11 @@ time64_t ktime_get_real_seconds(void)
unsigned int seq;
if (IS_ENABLED(CONFIG_64BIT))
- return tk->xtime_sec;
+ return READ_ONCE(tk->xtime_sec);
do {
seq = read_seqcount_begin(&tk_core.seq);
- seconds = tk->xtime_sec;
+ seconds = READ_ONCE(tk->xtime_sec);
} while (read_seqcount_retry(&tk_core.seq, seq));
@@ -1185,7 +1216,7 @@ noinstr time64_t __ktime_get_real_seconds(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
- return tk->xtime_sec;
+ return READ_ONCE(tk->xtime_sec);
}
static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr,
@@ -1202,10 +1233,21 @@ static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr,
/**
* ktime_get_snapshot_id - Simultaneously snapshot a given clock ID with
- * CLOCK_MONOTONIC_RAW and the underlying
+ * the corresponding monotonic raw and the underlying
* clocksource counter value.
* @clock_id: The clock ID to snapshot
* @systime_snapshot: Pointer to struct receiving the system time snapshot
+ *
+ * For the system time keeping clocks (REALTIME, MONOTONIC and BOOTTIME) the
+ * monotonic raw clock is CLOCK_MONOTONIC_RAW. For AUX clocks this is the
+ * monotonic raw clock related to the AUX clock. These AUX clock related
+ * monotonic raw clocks have a strict linear offset to the system time
+ * CLOCK_MONOTONIC_RAW:
+ *
+ * MONOTONIC_RAW(AUX$N) = CLOCK_MONOTONIC_RAW(system) + offset(AUX$N)
+ *
+ * The offset is established when a AUX clock is initialized, but it is
+ * currently not accessible.
*/
void ktime_get_snapshot_id(clockid_t clock_id, struct system_time_snapshot *systime_snapshot)
{
@@ -1512,6 +1554,9 @@ EXPORT_SYMBOL_GPL(ktime_real_to_base_clock);
* @xtstamp: Receives simultaneously captured system and device time
*
* Reads a timestamp from a device and correlates it to system time
+ *
+ * See documentation for ktime_get_snapshot_id() for information about the raw
+ * monotonic time stamp which is used here.
*/
int get_device_system_crosststamp(int (*get_time_fn)
(ktime_t *device_time,
@@ -1522,10 +1567,11 @@ int get_device_system_crosststamp(int (*get_time_fn)
struct system_device_crosststamp *xtstamp)
{
u64 syscnt_cycles, cycles, now, interval_start;
- unsigned int seq, clock_was_set_seq = 0;
ktime_t base_sys, base_raw, *offs;
+ u32 clock_was_set_seq = 0;
u64 nsec_sys, nsec_raw;
u8 cs_was_changed_seq;
+ unsigned int seq;
bool do_interp;
struct timekeeper *tk;
struct tk_data *tkd;
@@ -1897,40 +1943,6 @@ void ktime_get_raw_ts64(struct timespec64 *ts)
EXPORT_SYMBOL(ktime_get_raw_ts64);
/**
- * ktime_get_clock_ts64 - Returns time of a clock in a timespec
- * @id: POSIX clock ID of the clock to read
- * @ts: Pointer to the timespec64 to be set
- *
- * The timestamp is invalidated (@ts->sec is set to -1) if the
- * clock @id is not available.
- */
-void ktime_get_clock_ts64(clockid_t id, struct timespec64 *ts)
-{
- /* Invalidate time stamp */
- ts->tv_sec = -1;
- ts->tv_nsec = 0;
-
- switch (id) {
- case CLOCK_REALTIME:
- ktime_get_real_ts64(ts);
- return;
- case CLOCK_MONOTONIC:
- ktime_get_ts64(ts);
- return;
- case CLOCK_MONOTONIC_RAW:
- ktime_get_raw_ts64(ts);
- return;
- case CLOCK_AUX ... CLOCK_AUX_LAST:
- if (IS_ENABLED(CONFIG_POSIX_AUX_CLOCKS))
- ktime_get_aux_ts64(id, ts);
- return;
- default:
- WARN_ON_ONCE(1);
- }
-}
-EXPORT_SYMBOL_GPL(ktime_get_clock_ts64);
-
-/**
* timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
*/
int timekeeping_valid_for_hres(void)
@@ -2076,7 +2088,12 @@ void __init timekeeping_init(void)
tk_set_wall_to_mono(tks, wall_to_mono);
- timekeeping_update_from_shadow(&tk_core, TK_CLOCK_WAS_SET);
+ /*
+ * Use TK_UPDATE_ALL so the NTP layer picks up the clocksource's
+ * cs_tick_adj via ntp_clear(). Clearing NTP here is otherwise
+ * redundant as ntp_init() already initialised it above.
+ */
+ timekeeping_update_from_shadow(&tk_core, TK_UPDATE_ALL);
}
/* time in seconds when suspend began for persistent clock */
@@ -2390,6 +2407,11 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
* xtime_nsec_2 = xtime_nsec_1 - offset
* Which simplifies to:
* xtime_nsec -= offset
+ *
+ * When subtracting offset from xtime_nsec, the same amount
+ * (in appropriate units) has to be added to ntp_error, in
+ * order to correctly track the delta between the time
+ * reported in xtime_nsec, and the intended time.
*/
if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
/* NTP adjustment caused clocksource mult overflow */
@@ -2400,6 +2422,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
tk->tkr_mono.mult += mult_adj;
tk->xtime_interval += interval;
tk->tkr_mono.xtime_nsec -= offset;
+ tk->ntp_error += offset << tk->ntp_error_shift;
}
/*
@@ -2409,18 +2432,27 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
{
u64 ntp_tl = ntp_tick_length(tk->id);
+ s64 skew = ntp_get_skew_delta(tk->id);
u32 mult;
/*
- * Determine the multiplier from the current NTP tick length.
- * Avoid expensive division when the tick length doesn't change.
+ * Determine the multiplier from the current NTP tick length plus
+ * skew_delta. The skew biases mult so that ±1 dithering can deliver
+ * the time_offset slew rate. Recompute when either changes.
*/
- if (likely(tk->ntp_tick == ntp_tl)) {
+ if (likely(tk->ntp_tick == ntp_tl && tk->skew_delta == skew)) {
+ /* Revert to the base mult rate. */
mult = tk->tkr_mono.mult - tk->ntp_err_mult;
} else {
tk->ntp_tick = ntp_tl;
- mult = div64_u64((tk->ntp_tick >> tk->ntp_error_shift) -
- tk->xtime_remainder, tk->cycle_interval);
+ tk->skew_delta = skew;
+ /*
+ * skew_delta is stored pre-divided by HZ (matching time_offset);
+ * scale it back up to the full per-tick rate for the mult bias.
+ */
+ skew *= NTP_INTERVAL_FREQ;
+ mult = div64_u64((tk->ntp_tick + skew) >> tk->ntp_error_shift,
+ tk->cycle_interval);
}
/*
@@ -2545,8 +2577,25 @@ static u64 logarithmic_accumulation(struct timekeeper *tk, u64 offset,
/* Accumulate error between NTP and clock interval */
tk->ntp_error += tk->ntp_tick << shift;
- tk->ntp_error -= (tk->xtime_interval + tk->xtime_remainder) <<
- (tk->ntp_error_shift + shift);
+ tk->ntp_error -= tk->xtime_interval << (tk->ntp_error_shift + shift);
+
+ /*
+ * When skewing, do so by adjusting ntp_error to impart an extra
+ * target delta into ntp_error per tick, limited to what can be
+ * drained from time_offset / time_adjust to avoid overshoot.
+ *
+ * The base 'mult' value was calculated with the skew taken into
+ * account, such that the per-tick choice of 'mult' vs. 'mult+1'
+ * allows for the desired effective rate and ntp_error does not
+ * grow unbounded.
+ *
+ * Once the full desired phase offset is delivered, any remaining
+ * skew imparted by the adjusted 'mult', accounted above, remains
+ * in ntp_error and will be compensated by the dithering over time.
+ */
+ if (tk->skew_delta)
+ tk->ntp_error += ntp_drain_skew(tk->id, tk->skew_delta << shift,
+ shift) * NTP_INTERVAL_FREQ;
return offset;
}
@@ -2795,7 +2844,7 @@ void do_timer(unsigned long ticks)
*
* Called from hrtimer_interrupt() or retrigger_next_event()
*/
-ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
+ktime_t ktime_get_update_offsets_now(u32 *cwsseq, ktime_t *offs_real,
ktime_t *offs_boot, ktime_t *offs_tai)
{
struct timekeeper *tk = &tk_core.timekeeper;
@@ -2943,10 +2992,12 @@ static int __do_adjtimex(struct tk_data *tkd, struct __kernel_timex *txc,
return ret;
add_device_randomness(txc, sizeof(*txc));
- if (!aux_clock)
+ if (!aux_clock) {
ktime_get_real_ts64(&ts);
- else
- tk_get_aux_ts64(tkd->timekeeper.id, &ts);
+ } else {
+ if (!tk_get_aux_ts64(tkd->timekeeper.id, &ts))
+ return -ENODEV;
+ }
add_device_randomness(&ts, sizeof(ts));
@@ -3051,7 +3102,7 @@ static inline unsigned int clockid_to_tkid(unsigned int id)
static inline struct tk_data *aux_get_tk_data(clockid_t id)
{
- if (!clockid_aux_valid(id))
+ if (!clockid_is_aux_clock(id))
return NULL;
return &timekeeper_data[clockid_to_tkid(id)];
}
@@ -3146,7 +3197,7 @@ EXPORT_SYMBOL_GPL(ktime_get_aux_ts64);
static int aux_get_res(clockid_t id, struct timespec64 *tp)
{
- if (!clockid_aux_valid(id))
+ if (!clockid_is_aux_clock(id))
return -ENODEV;
tp->tv_sec = aux_clock_resolution_ns() / NSEC_PER_SEC;
@@ -3313,7 +3364,9 @@ static const struct attribute_group aux_clock_enable_attr_group = {
static int __init tk_aux_sysfs_init(void)
{
struct kobject *auxo, *tko = kobject_create_and_add("time", kernel_kobj);
+ struct kobject *clks[MAX_AUX_CLOCKS];
int ret = -ENOMEM;
+ int i;
if (!tko)
return ret;
@@ -3322,21 +3375,28 @@ static int __init tk_aux_sysfs_init(void)
if (!auxo)
goto err_clean;
- for (int i = 0; i < MAX_AUX_CLOCKS; i++) {
+ for (i = 0; i < MAX_AUX_CLOCKS; i++) {
char id[2] = { [0] = '0' + i, };
- struct kobject *clk = kobject_create_and_add(id, auxo);
+ clks[i] = kobject_create_and_add(id, auxo);
- if (!clk) {
+ if (!clks[i]) {
ret = -ENOMEM;
- goto err_clean;
+ goto err_clks;
}
- ret = sysfs_create_group(clk, &aux_clock_enable_attr_group);
+ ret = sysfs_create_group(clks[i], &aux_clock_enable_attr_group);
if (ret)
- goto err_clean;
+ goto err_clk;
}
return 0;
+err_clk:
+ kobject_put(clks[i]);
+err_clks:
+ while (--i >= 0) {
+ sysfs_remove_group(clks[i], &aux_clock_enable_attr_group);
+ kobject_put(clks[i]);
+ }
err_clean:
kobject_put(auxo);
kobject_put(tko);
diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h
index 198d0608db74..4201f9e90813 100644
--- a/kernel/time/timekeeping.h
+++ b/kernel/time/timekeeping.h
@@ -4,7 +4,7 @@
/*
* Internal interfaces for kernel/time/
*/
-extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq,
+extern ktime_t ktime_get_update_offsets_now(u32 *cwsseq,
ktime_t *offs_real,
ktime_t *offs_boot,
ktime_t *offs_tai);
diff --git a/kernel/time/timekeeping_internal.h b/kernel/time/timekeeping_internal.h
index 973ede670a36..6d719b8e5ea2 100644
--- a/kernel/time/timekeeping_internal.h
+++ b/kernel/time/timekeeping_internal.h
@@ -6,6 +6,8 @@
#include <linux/spinlock.h>
#include <linux/time.h>
+struct timekeeper;
+
/*
* timekeeping debug functions
*/
@@ -48,4 +50,23 @@ void timekeeper_unlock_irqrestore(unsigned long flags);
/* NTP specific interface to access the current seconds value */
long ktime_get_ntp_seconds(unsigned int id);
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
+
+extern void update_vsyscall(struct timekeeper *tk);
+extern void update_vsyscall_tz(void);
+extern void vdso_time_update_aux(struct timekeeper *tk);
+
+#else
+
+static inline void update_vsyscall(struct timekeeper *tk)
+{
+}
+static inline void update_vsyscall_tz(void)
+{
+}
+static inline void vdso_time_update_aux(struct timekeeper *tk)
+{
+}
+#endif
+
#endif /* _TIMEKEEPING_INTERNAL_H */
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 514802def1e0..0406bf4488e9 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -20,7 +20,7 @@
struct timer_list_iter {
int cpu;
bool second_pass;
- u64 now;
+ ktime_t now;
};
/*
@@ -44,19 +44,19 @@ static void SEQ_printf(struct seq_file *m, const char *fmt, ...)
static void
print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer,
- int idx, u64 now)
+ int idx, ktime_t now)
{
SEQ_printf(m, " #%d: <%p>, %ps", idx, taddr, ACCESS_PRIVATE(timer, function));
SEQ_printf(m, ", S:%02x", timer->is_queued);
SEQ_printf(m, "\n");
- SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n",
- (unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)),
- (unsigned long long)ktime_to_ns(hrtimer_get_expires(timer)),
- (long long)(ktime_to_ns(hrtimer_get_softexpires(timer)) - now),
- (long long)(ktime_to_ns(hrtimer_get_expires(timer)) - now));
+ SEQ_printf(m, " # expires at %lld-%lld nsecs [in %lld to %lld nsecs]\n",
+ (long long)hrtimer_get_softexpires(timer),
+ (long long)hrtimer_get_expires(timer),
+ (long long)ktime_sub(hrtimer_get_softexpires(timer), now),
+ (long long)ktime_sub(hrtimer_get_expires(timer), now));
}
-static void print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
+static void print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, ktime_t now)
{
struct timerqueue_linked_node *curr;
struct hrtimer *timer, tmp;
@@ -94,21 +94,21 @@ next_one:
}
static void
-print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
+print_base(struct seq_file *m, struct hrtimer_clock_base *base, ktime_t now)
{
SEQ_printf(m, " .base: %p\n", base);
SEQ_printf(m, " .index: %d\n", base->index);
SEQ_printf(m, " .resolution: %u nsecs\n", hrtimer_resolution);
#ifdef CONFIG_HIGH_RES_TIMERS
- SEQ_printf(m, " .offset: %Ld nsecs\n",
+ SEQ_printf(m, " .offset: %lld nsecs\n",
(long long) base->offset);
#endif
SEQ_printf(m, "active timers:\n");
- print_active_timers(m, base, now + ktime_to_ns(base->offset));
+ print_active_timers(m, base, ktime_add(now, base->offset));
}
-static void print_cpu(struct seq_file *m, int cpu, u64 now)
+static void print_cpu(struct seq_file *m, int cpu, ktime_t now)
{
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
@@ -118,15 +118,17 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
SEQ_printf(m, " clock %d:\n", i);
print_base(m, cpu_base->clock_base + i, now);
}
-#define P(x) \
- SEQ_printf(m, " .%-15s: %Lu\n", #x, \
- (unsigned long long)(cpu_base->x))
-#define P_ns(x) \
- SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \
- (unsigned long long)(ktime_to_ns(cpu_base->x)))
+
+#define DIAG_READ(x) data_race(READ_ONCE(x))
+
+#define P(x) \
+ SEQ_printf(m, " .%-15s: %llu\n", #x, \
+ (unsigned long long)DIAG_READ(cpu_base->x))
+#define P_ktime(x) \
+ SEQ_printf(m, " .%-15s: %lld nsecs\n", #x, (long long)DIAG_READ(cpu_base->x))
#ifdef CONFIG_HIGH_RES_TIMERS
- P_ns(expires_next);
+ P_ktime(expires_next);
P(hres_active);
P(nr_events);
P(nr_retries);
@@ -134,38 +136,39 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P(max_hang_time);
#endif
#undef P
-#undef P_ns
+#undef P_ktime
#ifdef CONFIG_TICK_ONESHOT
# define P(x) \
- SEQ_printf(m, " .%-15s: %Lu\n", #x, \
- (unsigned long long)(ts->x))
-# define P_ns(x) \
- SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \
- (unsigned long long)(ktime_to_ns(ts->x)))
+ SEQ_printf(m, " .%-15s: %llu\n", #x, \
+ (unsigned long long)DIAG_READ(ts->x))
+# define P_ktime(x) \
+ SEQ_printf(m, " .%-15s: %lld nsecs\n", #x, (long long)DIAG_READ(ts->x))
# define P_flag(x, f) \
- SEQ_printf(m, " .%-15s: %d\n", #x, !!(ts->flags & (f)))
+ SEQ_printf(m, " .%-15s: %d\n", #x, !!(DIAG_READ(ts->flags) & (f)))
{
struct tick_sched *ts = tick_get_tick_sched(cpu);
P_flag(nohz, TS_FLAG_NOHZ);
P_flag(highres, TS_FLAG_HIGHRES);
- P_ns(last_tick);
+ P_ktime(last_tick);
P_flag(tick_stopped, TS_FLAG_STOPPED);
P(idle_calls);
P(idle_sleeps);
- P_ns(idle_entrytime);
- P_ns(idle_waketime);
+ P_ktime(idle_entrytime);
+ P_ktime(idle_waketime);
P(last_jiffies);
P(next_timer);
- P_ns(idle_expires);
- SEQ_printf(m, "jiffies: %Lu\n",
+ P_ktime(idle_expires);
+ SEQ_printf(m, "jiffies: %llu\n",
(unsigned long long)jiffies);
}
#endif
#undef P
-#undef P_ns
+#undef P_ktime
+#undef P_flag
+#undef DIAG_READ
SEQ_printf(m, "\n");
}
@@ -196,8 +199,7 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
SEQ_printf(m, " mult: %u\n", dev->mult);
SEQ_printf(m, " shift: %u\n", dev->shift);
SEQ_printf(m, " mode: %d\n", clockevent_get_state(dev));
- SEQ_printf(m, " next_event: %Ld nsecs\n",
- (unsigned long long) ktime_to_ns(dev->next_event));
+ SEQ_printf(m, " next_event: %lld nsecs\n", (long long)dev->next_event);
SEQ_printf(m, " set_next_event: %ps\n", dev->set_next_event);
@@ -250,17 +252,17 @@ static void timer_list_show_tickdevices_header(struct seq_file *m)
}
#endif
-static inline void timer_list_header(struct seq_file *m, u64 now)
+static inline void timer_list_header(struct seq_file *m, ktime_t now)
{
SEQ_printf(m, "Timer List Version: v0.11\n");
SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
- SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
+ SEQ_printf(m, "now at %lld nsecs\n", (long long)now);
SEQ_printf(m, "\n");
}
void sysrq_timer_list_show(void)
{
- u64 now = ktime_to_ns(ktime_get());
+ ktime_t now = ktime_get();
int cpu;
timer_list_header(NULL, now);
@@ -318,7 +320,7 @@ static void *timer_list_start(struct seq_file *file, loff_t *offset)
struct timer_list_iter *iter = file->private;
if (!*offset)
- iter->now = ktime_to_ns(ktime_get());
+ iter->now = ktime_get();
iter->cpu = -1;
iter->second_pass = false;
return move_iter(iter, *offset);
diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
index 806c23cf71fc..059d43355e65 100644
--- a/kernel/time/timer_migration.c
+++ b/kernel/time/timer_migration.c
@@ -1847,8 +1847,10 @@ static int tmigr_setup_groups(struct tmigr_hierarchy *hier, unsigned int cpu,
}
/* Assert single root without parent */
- if (WARN_ON_ONCE(i >= tmigr_hierarchy_levels))
+ if (WARN_ON_ONCE(i >= tmigr_hierarchy_levels)) {
+ kfree(stack);
return -EINVAL;
+ }
for (; i >= start_lvl; i--) {
group = stack[i];
diff --git a/kernel/time/timer_migration.h b/kernel/time/timer_migration.h
index 31735dd52327..c9c1c29f011d 100644
--- a/kernel/time/timer_migration.h
+++ b/kernel/time/timer_migration.h
@@ -103,7 +103,7 @@ struct tmigr_group {
* before the timer migration hierarchy hotplug callback is
* reached. During this phase, the CPU has to handle the
* global timers on its own and must not act as a migrator.
-
+ *
* @idle: Indicates whether the CPU is idle in the timer migration
* hierarchy
* @remote: Is set when timers of the CPU are expired remotely
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 7283f0f18813..ce7ab986dee6 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -13,6 +13,7 @@
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/hrtimer.h>
+#include <linux/hrtimer_bases.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <sound/core.h>
diff --git a/tools/testing/selftests/clock-helpers.h b/tools/testing/selftests/clock-helpers.h
new file mode 100644
index 000000000000..01451f538e71
--- /dev/null
+++ b/tools/testing/selftests/clock-helpers.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __CLOCK_HELPERS_H
+#define __CLOCK_HELPERS_H
+
+#include <sys/types.h>
+#include <time.h>
+
+#define MSEC_PER_SEC 1000LL
+#define USEC_PER_MSEC 1000LL
+#define NSEC_PER_USEC 1000LL
+#define NSEC_PER_MSEC 1000000LL
+#define USEC_PER_SEC 1000000LL
+#define NSEC_PER_SEC 1000000000LL
+#define PSEC_PER_SEC 1000000000000LL
+#define FSEC_PER_SEC 1000000000000000LL
+
+#ifndef CLOCK_AUX
+#define CLOCK_AUX 16
+#endif
+
+#ifndef MAX_AUX_CLOCKS
+#define MAX_AUX_CLOCKS 8
+#endif
+
+#ifndef CLOCK_AUX_LAST
+#define CLOCK_AUX_LAST (CLOCK_AUX + MAX_AUX_CLOCKS - 1)
+#endif
+
+__attribute__((unused))
+static inline const char *clock_name(clockid_t clockid)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ return "CLOCK_REALTIME";
+ case CLOCK_MONOTONIC:
+ return "CLOCK_MONOTONIC";
+ case CLOCK_PROCESS_CPUTIME_ID:
+ return "CLOCK_PROCESS_CPUTIME_ID";
+ case CLOCK_THREAD_CPUTIME_ID:
+ return "CLOCK_THREAD_CPUTIME_ID";
+ case CLOCK_MONOTONIC_RAW:
+ return "CLOCK_MONOTONIC_RAW";
+ case CLOCK_REALTIME_COARSE:
+ return "CLOCK_REALTIME_COARSE";
+ case CLOCK_MONOTONIC_COARSE:
+ return "CLOCK_MONOTONIC_COARSE";
+ case CLOCK_BOOTTIME:
+ return "CLOCK_BOOTTIME";
+ case CLOCK_REALTIME_ALARM:
+ return "CLOCK_REALTIME_ALARM";
+ case CLOCK_BOOTTIME_ALARM:
+ return "CLOCK_BOOTTIME_ALARM";
+ case CLOCK_TAI:
+ return "CLOCK_TAI";
+ case CLOCK_AUX + 0:
+ return "CLOCK_AUX0";
+ case CLOCK_AUX + 1:
+ return "CLOCK_AUX1";
+ case CLOCK_AUX + 2:
+ return "CLOCK_AUX2";
+ case CLOCK_AUX + 3:
+ return "CLOCK_AUX3";
+ case CLOCK_AUX + 4:
+ return "CLOCK_AUX4";
+ case CLOCK_AUX + 5:
+ return "CLOCK_AUX5";
+ case CLOCK_AUX + 6:
+ return "CLOCK_AUX6";
+ case CLOCK_AUX + 7:
+ return "CLOCK_AUX7";
+ };
+ return "UNKNOWN_CLOCKID";
+}
+
+#endif /* __CLOCK_HELPERS_H */
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile
index 32203593c62e..0e73a16874c4 100644
--- a/tools/testing/selftests/timers/Makefile
+++ b/tools/testing/selftests/timers/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-CFLAGS += -O3 -Wl,-no-as-needed -Wall -I $(top_srcdir)
+CFLAGS += -O3 -Wl,-no-as-needed -Wall
LDLIBS += -lrt -lpthread -lm
# these are all "safe" tests that don't modify
diff --git a/tools/testing/selftests/timers/adjtick.c b/tools/testing/selftests/timers/adjtick.c
index 5b3ef708d6e9..68009a6d6de8 100644
--- a/tools/testing/selftests/timers/adjtick.c
+++ b/tools/testing/selftests/timers/adjtick.c
@@ -22,8 +22,8 @@
#include <sys/time.h>
#include <sys/timex.h>
#include <time.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define MILLION 1000000
diff --git a/tools/testing/selftests/timers/alarmtimer-suspend.c b/tools/testing/selftests/timers/alarmtimer-suspend.c
index aa66c805f6a4..120b3ce8b39e 100644
--- a/tools/testing/selftests/timers/alarmtimer-suspend.c
+++ b/tools/testing/selftests/timers/alarmtimer-suspend.c
@@ -28,8 +28,8 @@
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
-#include <include/vdso/time64.h>
#include <errno.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */
@@ -39,37 +39,6 @@ int alarmcount;
int alarm_clock_id;
struct timespec start_time;
-
-char *clockstring(int clockid)
-{
- switch (clockid) {
- case CLOCK_REALTIME:
- return "CLOCK_REALTIME";
- case CLOCK_MONOTONIC:
- return "CLOCK_MONOTONIC";
- case CLOCK_PROCESS_CPUTIME_ID:
- return "CLOCK_PROCESS_CPUTIME_ID";
- case CLOCK_THREAD_CPUTIME_ID:
- return "CLOCK_THREAD_CPUTIME_ID";
- case CLOCK_MONOTONIC_RAW:
- return "CLOCK_MONOTONIC_RAW";
- case CLOCK_REALTIME_COARSE:
- return "CLOCK_REALTIME_COARSE";
- case CLOCK_MONOTONIC_COARSE:
- return "CLOCK_MONOTONIC_COARSE";
- case CLOCK_BOOTTIME:
- return "CLOCK_BOOTTIME";
- case CLOCK_REALTIME_ALARM:
- return "CLOCK_REALTIME_ALARM";
- case CLOCK_BOOTTIME_ALARM:
- return "CLOCK_BOOTTIME_ALARM";
- case CLOCK_TAI:
- return "CLOCK_TAI";
- }
- return "UNKNOWN_CLOCKID";
-}
-
-
long long timespec_sub(struct timespec a, struct timespec b)
{
long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
@@ -129,12 +98,12 @@ int main(void)
alarmcount = 0;
if (timer_create(alarm_clock_id, &se, &tm1) == -1) {
printf("timer_create failed, %s unsupported?: %s\n",
- clockstring(alarm_clock_id), strerror(errno));
+ clock_name(alarm_clock_id), strerror(errno));
break;
}
clock_gettime(alarm_clock_id, &start_time);
- printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id),
+ printf("Start time (%s): %ld:%ld\n", clock_name(alarm_clock_id),
start_time.tv_sec, start_time.tv_nsec);
printf("Setting alarm for every %i seconds\n", SUSPEND_SECS);
its1.it_value = start_time;
diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c
index e53e63e18683..d7982ac4bd18 100644
--- a/tools/testing/selftests/timers/inconsistency-check.c
+++ b/tools/testing/selftests/timers/inconsistency-check.c
@@ -28,7 +28,7 @@
#include <sys/timex.h>
#include <string.h>
#include <signal.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
@@ -36,35 +36,6 @@
#define CALLS_PER_LOOP 64
-char *clockstring(int clockid)
-{
- switch (clockid) {
- case CLOCK_REALTIME:
- return "CLOCK_REALTIME";
- case CLOCK_MONOTONIC:
- return "CLOCK_MONOTONIC";
- case CLOCK_PROCESS_CPUTIME_ID:
- return "CLOCK_PROCESS_CPUTIME_ID";
- case CLOCK_THREAD_CPUTIME_ID:
- return "CLOCK_THREAD_CPUTIME_ID";
- case CLOCK_MONOTONIC_RAW:
- return "CLOCK_MONOTONIC_RAW";
- case CLOCK_REALTIME_COARSE:
- return "CLOCK_REALTIME_COARSE";
- case CLOCK_MONOTONIC_COARSE:
- return "CLOCK_MONOTONIC_COARSE";
- case CLOCK_BOOTTIME:
- return "CLOCK_BOOTTIME";
- case CLOCK_REALTIME_ALARM:
- return "CLOCK_REALTIME_ALARM";
- case CLOCK_BOOTTIME_ALARM:
- return "CLOCK_BOOTTIME_ALARM";
- case CLOCK_TAI:
- return "CLOCK_TAI";
- }
- return "UNKNOWN_CLOCKID";
-}
-
/* returns 1 if a <= b, 0 otherwise */
static inline int in_order(struct timespec a, struct timespec b)
{
@@ -171,15 +142,15 @@ int main(int argc, char *argv[])
for (clockid = userclock; clockid < maxclocks; clockid++) {
if (clockid == CLOCK_HWSPECIFIC || clock_gettime(clockid, &ts)) {
- ksft_test_result_skip("%-31s\n", clockstring(clockid));
+ ksft_test_result_skip("%-31s\n", clock_name(clockid));
continue;
}
if (consistency_test(clockid, runtime)) {
- ksft_test_result_fail("%-31s\n", clockstring(clockid));
+ ksft_test_result_fail("%-31s\n", clock_name(clockid));
ksft_exit_fail();
} else {
- ksft_test_result_pass("%-31s\n", clockstring(clockid));
+ ksft_test_result_pass("%-31s\n", clock_name(clockid));
}
}
ksft_exit_pass();
diff --git a/tools/testing/selftests/timers/leap-a-day.c b/tools/testing/selftests/timers/leap-a-day.c
index 3568cfb3e815..b93cb5714b37 100644
--- a/tools/testing/selftests/timers/leap-a-day.c
+++ b/tools/testing/selftests/timers/leap-a-day.c
@@ -9,16 +9,19 @@
* kernel's leap-second behavior, as well as how well applications
* handle the leap-second discontinuity.
*
- * Usage: leap-a-day [-s] [-i <num>]
+ * Usage: leap-a-day [-w] [-i <num>] [-t]
*
* Options:
- * -s: Each iteration, set the date to 10 seconds before midnight GMT.
- * This speeds up the number of leapsecond transitions tested,
- * but because it calls settimeofday frequently, advancing the
- * time by 24 hours every ~16 seconds, it may cause application
- * disruption.
+ * -w: Only set the leap-second flag and wait for the leap second
+ * each iteration, instead of advancing the time. By default the
+ * date is set to 10 seconds before midnight GMT, which speeds up
+ * the number of leapsecond transitions tested, but because it
+ * calls settimeofday frequently, advancing the time by 24 hours
+ * every ~16 seconds, it may cause application disruption.
*
- * -i: Number of iterations to run (default: infinite)
+ * -i: Number of iterations to run (-1 = infinite, default: 10)
+ *
+ * -t: Print TAI time.
*
* Other notes: Disabling NTP prior to running this is advised, as the two
* may conflict in their commands to the kernel.
@@ -48,7 +51,7 @@
#include <string.h>
#include <signal.h>
#include <unistd.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define CLOCK_TAI 11
@@ -186,7 +189,7 @@ int main(int argc, char **argv)
int opt;
/* Process arguments */
- while ((opt = getopt(argc, argv, "sti:")) != -1) {
+ while ((opt = getopt(argc, argv, "wti:")) != -1) {
switch (opt) {
case 'w':
printf("Only setting leap-flag, not changing time. It could take up to a day for leap to trigger.\n");
diff --git a/tools/testing/selftests/timers/mqueue-lat.c b/tools/testing/selftests/timers/mqueue-lat.c
index c0d9368e4fca..fa4c3e3f58fe 100644
--- a/tools/testing/selftests/timers/mqueue-lat.c
+++ b/tools/testing/selftests/timers/mqueue-lat.c
@@ -29,7 +29,7 @@
#include <signal.h>
#include <errno.h>
#include <mqueue.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
diff --git a/tools/testing/selftests/timers/nanosleep.c b/tools/testing/selftests/timers/nanosleep.c
index a054680b3372..b45e4c855259 100644
--- a/tools/testing/selftests/timers/nanosleep.c
+++ b/tools/testing/selftests/timers/nanosleep.c
@@ -27,43 +27,9 @@
#include <sys/timex.h>
#include <string.h>
#include <signal.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
-/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
-#define CLOCK_HWSPECIFIC 10
-
-#define UNSUPPORTED 0xf00f
-
-char *clockstring(int clockid)
-{
- switch (clockid) {
- case CLOCK_REALTIME:
- return "CLOCK_REALTIME";
- case CLOCK_MONOTONIC:
- return "CLOCK_MONOTONIC";
- case CLOCK_PROCESS_CPUTIME_ID:
- return "CLOCK_PROCESS_CPUTIME_ID";
- case CLOCK_THREAD_CPUTIME_ID:
- return "CLOCK_THREAD_CPUTIME_ID";
- case CLOCK_MONOTONIC_RAW:
- return "CLOCK_MONOTONIC_RAW";
- case CLOCK_REALTIME_COARSE:
- return "CLOCK_REALTIME_COARSE";
- case CLOCK_MONOTONIC_COARSE:
- return "CLOCK_MONOTONIC_COARSE";
- case CLOCK_BOOTTIME:
- return "CLOCK_BOOTTIME";
- case CLOCK_REALTIME_ALARM:
- return "CLOCK_REALTIME_ALARM";
- case CLOCK_BOOTTIME_ALARM:
- return "CLOCK_BOOTTIME_ALARM";
- case CLOCK_TAI:
- return "CLOCK_TAI";
- };
- return "UNKNOWN_CLOCKID";
-}
-
/* returns 1 if a <= b, 0 otherwise */
static inline int in_order(struct timespec a, struct timespec b)
{
@@ -92,15 +58,15 @@ int nanosleep_test(int clockid, long long ns)
/* First check abs time */
if (clock_gettime(clockid, &now))
- return UNSUPPORTED;
+ return KSFT_SKIP;
target = timespec_add(now, ns);
if (clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL))
- return UNSUPPORTED;
+ return KSFT_SKIP;
clock_gettime(clockid, &now);
if (!in_order(target, now))
- return -1;
+ return KSFT_FAIL;
/* Second check reltime */
clock_gettime(clockid, &now);
@@ -112,8 +78,8 @@ int nanosleep_test(int clockid, long long ns)
clock_gettime(clockid, &now);
if (!in_order(target, now))
- return -1;
- return 0;
+ return KSFT_FAIL;
+ return KSFT_PASS;
}
static void dummy_event_handler(int val)
@@ -132,82 +98,86 @@ static int nanosleep_test_remaining(int clockid)
sa.sa_handler = dummy_event_handler;
ret = sigaction(SIGALRM, &sa, NULL);
if (ret)
- return -1;
+ return KSFT_FAIL;
ret = timer_create(clockid, NULL, &timer);
if (ret)
- return -1;
+ return KSFT_FAIL;
itimer.it_value.tv_nsec = NSEC_PER_SEC / 4;
ret = timer_settime(timer, 0, &itimer, NULL);
if (ret)
- return -1;
+ return KSFT_FAIL;
rqtp.tv_nsec = NSEC_PER_SEC / 2;
ret = clock_nanosleep(clockid, 0, &rqtp, &rmtp);
- if (ret != EINTR)
- return -1;
- ret = timer_delete(timer);
- if (ret)
- return -1;
+ if (timer_delete(timer)) {
+ ksft_exit_fail_msg("Unable to delete the timeout timer for %s. "
+ "This might interfere with following testcases.\n",
+ clock_name(clockid));
+ }
+
+ if (ret != EINTR)
+ return KSFT_FAIL;
sa.sa_handler = SIG_DFL;
ret = sigaction(SIGALRM, &sa, NULL);
if (ret)
- return -1;
+ return KSFT_FAIL;
if (!in_order((struct timespec) {}, rmtp))
- return -1;
+ return KSFT_FAIL;
if (!in_order(rmtp, rqtp))
- return -1;
+ return KSFT_FAIL;
+
+ return KSFT_PASS;
+}
- return 0;
+static void nanosleep_test_clock(clockid_t clockid)
+{
+ long long length = 10;
+ int ret;
+
+ while (length <= (NSEC_PER_SEC * 10)) {
+ ret = nanosleep_test(clockid, length);
+ if (ret != KSFT_PASS) {
+ ksft_test_result_report(ret, "%s\n", clock_name(clockid));
+ ksft_test_result_skip("%s (remaining)\n", clock_name(clockid));
+ return;
+ }
+
+ length *= 100;
+ }
+ ksft_test_result_pass("%s\n", clock_name(clockid));
+
+ ret = nanosleep_test_remaining(clockid);
+ ksft_test_result_report(ret, "%s (remaining)\n", clock_name(clockid));
}
int main(int argc, char **argv)
{
- long long length;
- int clockid, ret;
- int max_clocks = CLOCK_TAI + 1;
+ int clockid;
- ksft_print_header();
- ksft_set_plan(max_clocks);
+ static const clockid_t tested_clocks[] = {
+ CLOCK_REALTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_BOOTTIME,
+ CLOCK_BOOTTIME_ALARM,
+ CLOCK_REALTIME_ALARM,
+ CLOCK_TAI,
+ };
- for (clockid = CLOCK_REALTIME; clockid < max_clocks; clockid++) {
+ ksft_print_header();
+ ksft_set_plan(ARRAY_SIZE(tested_clocks) * 2);
- /* Skip cputime clockids since nanosleep won't increment cputime */
- if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
- clockid == CLOCK_THREAD_CPUTIME_ID ||
- clockid == CLOCK_HWSPECIFIC) {
- ksft_test_result_skip("%-31s\n", clockstring(clockid));
- continue;
- }
+ for (size_t clock_index = 0; clock_index < ARRAY_SIZE(tested_clocks); clock_index++) {
+ clockid = tested_clocks[clock_index];
fflush(stdout);
- length = 10;
- while (length <= (NSEC_PER_SEC * 10)) {
- ret = nanosleep_test(clockid, length);
- if (ret == UNSUPPORTED) {
- ksft_test_result_skip("%-31s\n", clockstring(clockid));
- goto next;
- }
- if (ret < 0) {
- ksft_test_result_fail("%-31s\n", clockstring(clockid));
- ksft_exit_fail();
- }
- length *= 100;
- }
- ret = nanosleep_test_remaining(clockid);
- if (ret < 0) {
- ksft_test_result_fail("%-31s\n", clockstring(clockid));
- ksft_exit_fail();
- }
- ksft_test_result_pass("%-31s\n", clockstring(clockid));
-next:
- ret = 0;
+ nanosleep_test_clock(clockid);
}
- ksft_exit_pass();
+ ksft_finished();
}
diff --git a/tools/testing/selftests/timers/nsleep-lat.c b/tools/testing/selftests/timers/nsleep-lat.c
index a7ba1eb1e21b..5de0051ac8e3 100644
--- a/tools/testing/selftests/timers/nsleep-lat.c
+++ b/tools/testing/selftests/timers/nsleep-lat.c
@@ -24,44 +24,10 @@
#include <sys/timex.h>
#include <string.h>
#include <signal.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
-#define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */
-
-/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
-#define CLOCK_HWSPECIFIC 10
-
-#define UNSUPPORTED 0xf00f
-
-char *clockstring(int clockid)
-{
- switch (clockid) {
- case CLOCK_REALTIME:
- return "CLOCK_REALTIME";
- case CLOCK_MONOTONIC:
- return "CLOCK_MONOTONIC";
- case CLOCK_PROCESS_CPUTIME_ID:
- return "CLOCK_PROCESS_CPUTIME_ID";
- case CLOCK_THREAD_CPUTIME_ID:
- return "CLOCK_THREAD_CPUTIME_ID";
- case CLOCK_MONOTONIC_RAW:
- return "CLOCK_MONOTONIC_RAW";
- case CLOCK_REALTIME_COARSE:
- return "CLOCK_REALTIME_COARSE";
- case CLOCK_MONOTONIC_COARSE:
- return "CLOCK_MONOTONIC_COARSE";
- case CLOCK_BOOTTIME:
- return "CLOCK_BOOTTIME";
- case CLOCK_REALTIME_ALARM:
- return "CLOCK_REALTIME_ALARM";
- case CLOCK_BOOTTIME_ALARM:
- return "CLOCK_BOOTTIME_ALARM";
- case CLOCK_TAI:
- return "CLOCK_TAI";
- };
- return "UNKNOWN_CLOCKID";
-}
+#define UNRESONABLE_LATENCY (40 * NSEC_PER_MSEC)
struct timespec timespec_add(struct timespec ts, unsigned long long ns)
{
@@ -92,58 +58,68 @@ int nanosleep_lat_test(int clockid, long long ns)
target.tv_nsec = ns%NSEC_PER_SEC;
if (clock_gettime(clockid, &start))
- return UNSUPPORTED;
+ return KSFT_SKIP;
if (clock_nanosleep(clockid, 0, &target, NULL))
- return UNSUPPORTED;
+ return KSFT_SKIP;
count = 10;
/* First check relative latency */
- clock_gettime(clockid, &start);
- for (i = 0; i < count; i++)
- clock_nanosleep(clockid, 0, &target, NULL);
- clock_gettime(clockid, &end);
+ if (clock_gettime(clockid, &start))
+ return KSFT_FAIL;
+
+ for (i = 0; i < count; i++) {
+ if (clock_nanosleep(clockid, 0, &target, NULL))
+ return KSFT_FAIL;
+ }
+
+ if (clock_gettime(clockid, &end))
+ return KSFT_FAIL;
if (((timespec_sub(start, end)/count)-ns) > UNRESONABLE_LATENCY) {
ksft_print_msg("Large rel latency: %lld ns :", (timespec_sub(start, end)/count)-ns);
- return -1;
+ return KSFT_FAIL;
}
/* Next check absolute latency */
for (i = 0; i < count; i++) {
- clock_gettime(clockid, &start);
+ if (clock_gettime(clockid, &start))
+ return KSFT_FAIL;
target = timespec_add(start, ns);
- clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL);
- clock_gettime(clockid, &end);
+ if (clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL))
+ return KSFT_FAIL;
+ if (clock_gettime(clockid, &end))
+ return KSFT_FAIL;
latency += timespec_sub(target, end);
}
if (latency/count > UNRESONABLE_LATENCY) {
ksft_print_msg("Large abs latency: %lld ns :", latency/count);
- return -1;
+ return KSFT_FAIL;
}
- return 0;
+ return KSFT_PASS;
}
-#define SKIPPED_CLOCK_COUNT 3
-
int main(int argc, char **argv)
{
long long length;
int clockid, ret;
- int max_clocks = CLOCK_TAI + 1;
- ksft_print_header();
- ksft_set_plan(max_clocks - CLOCK_REALTIME - SKIPPED_CLOCK_COUNT);
+ static const clockid_t tested_clocks[] = {
+ CLOCK_REALTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_BOOTTIME,
+ CLOCK_BOOTTIME_ALARM,
+ CLOCK_REALTIME_ALARM,
+ CLOCK_TAI,
+ };
- for (clockid = CLOCK_REALTIME; clockid < max_clocks; clockid++) {
+ ksft_print_header();
+ ksft_set_plan(ARRAY_SIZE(tested_clocks));
- /* Skip cputime clockids since nanosleep won't increment cputime */
- if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
- clockid == CLOCK_THREAD_CPUTIME_ID ||
- clockid == CLOCK_HWSPECIFIC)
- continue;
+ for (size_t clock_index = 0; clock_index < ARRAY_SIZE(tested_clocks); clock_index++) {
+ clockid = tested_clocks[clock_index];
length = 10;
while (length <= (NSEC_PER_SEC * 10)) {
@@ -154,12 +130,7 @@ int main(int argc, char **argv)
}
- if (ret == UNSUPPORTED) {
- ksft_test_result_skip("%s\n", clockstring(clockid));
- } else {
- ksft_test_result(ret >= 0, "%s\n",
- clockstring(clockid));
- }
+ ksft_test_result_report(ret, "%s\n", clock_name(clockid));
}
ksft_finished();
diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c
index 2f3bac9fc6e8..a92d4b957747 100644
--- a/tools/testing/selftests/timers/posix_timers.c
+++ b/tools/testing/selftests/timers/posix_timers.c
@@ -16,10 +16,10 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
-#include <include/vdso/time64.h>
#include <pthread.h>
#include <stdbool.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define DELAY 2
@@ -141,8 +141,9 @@ static void check_itimer(int which, const char *name)
ksft_test_result(check_diff(start, end) == 0, "%s\n", name);
}
-static void check_timer_create(int which, const char *name)
+static void check_timer_create(int which)
{
+ const char *name = clock_name(which);
struct timespec start, end;
struct itimerspec val = {
.it_value.tv_sec = DELAY,
@@ -455,8 +456,9 @@ static void check_delete(void)
ksft_test_result(!tsig.signals, "check_delete\n");
}
-static void check_sigev_none(int which, const char *name)
+static void check_sigev_none(int which)
{
+ const char *name = clock_name(which);
struct timespec start, now;
struct itimerspec its;
struct sigevent sev;
@@ -493,8 +495,9 @@ static void check_sigev_none(int which, const char *name)
"check_sigev_none %s\n", name);
}
-static void check_gettime(int which, const char *name)
+static void check_gettime(int which)
{
+ const char *name = clock_name(which);
struct itimerspec its, prev;
struct timespec start, now;
struct sigevent sev;
@@ -546,8 +549,9 @@ static void check_gettime(int which, const char *name)
ksft_test_result(wraps > 1, "check_gettime %s\n", name);
}
-static void check_overrun(int which, const char *name)
+static void check_overrun(int which)
{
+ const char *name = clock_name(which);
struct timespec start, now;
struct tmrsig tsig = { };
struct itimerspec its;
@@ -689,7 +693,7 @@ int main(int argc, char **argv)
check_itimer(ITIMER_VIRTUAL, "ITIMER_VIRTUAL");
check_itimer(ITIMER_PROF, "ITIMER_PROF");
check_itimer(ITIMER_REAL, "ITIMER_REAL");
- check_timer_create(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
+ check_timer_create(CLOCK_THREAD_CPUTIME_ID);
/*
* It's unfortunately hard to reliably test a timer expiration
@@ -700,7 +704,7 @@ int main(int argc, char **argv)
* to ensure true parallelism. So test only one thread until we
* find a better solution.
*/
- check_timer_create(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
+ check_timer_create(CLOCK_PROCESS_CPUTIME_ID);
check_timer_distribution();
if (run_sig_ign_tests) {
@@ -708,18 +712,18 @@ int main(int argc, char **argv)
check_sig_ign(1);
check_rearm();
check_delete();
- check_sigev_none(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
- check_sigev_none(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
- check_gettime(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
- check_gettime(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
- check_gettime(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
+ check_sigev_none(CLOCK_MONOTONIC);
+ check_sigev_none(CLOCK_PROCESS_CPUTIME_ID);
+ check_gettime(CLOCK_MONOTONIC);
+ check_gettime(CLOCK_PROCESS_CPUTIME_ID);
+ check_gettime(CLOCK_THREAD_CPUTIME_ID);
} else {
ksft_print_msg("Skipping SIG_IGN tests on kernel < 6.13\n");
}
- check_overrun(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
- check_overrun(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
- check_overrun(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
+ check_overrun(CLOCK_MONOTONIC);
+ check_overrun(CLOCK_PROCESS_CPUTIME_ID);
+ check_overrun(CLOCK_THREAD_CPUTIME_ID);
ksft_finished();
}
diff --git a/tools/testing/selftests/timers/raw_skew.c b/tools/testing/selftests/timers/raw_skew.c
index a7bae7d80916..0c87a8fb0d7f 100644
--- a/tools/testing/selftests/timers/raw_skew.c
+++ b/tools/testing/selftests/timers/raw_skew.c
@@ -25,7 +25,7 @@
#include <sys/time.h>
#include <sys/timex.h>
#include <time.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define shift_right(x, s) ({ \
diff --git a/tools/testing/selftests/timers/set-2038.c b/tools/testing/selftests/timers/set-2038.c
index ecc171de4728..f522a3035ec6 100644
--- a/tools/testing/selftests/timers/set-2038.c
+++ b/tools/testing/selftests/timers/set-2038.c
@@ -27,7 +27,7 @@
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define KTIME_MAX ((long long)~((unsigned long long)1 << 63))
diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c
index 44d2e3614fa5..79ddba25d314 100644
--- a/tools/testing/selftests/timers/set-timer-lat.c
+++ b/tools/testing/selftests/timers/set-timer-lat.c
@@ -28,7 +28,7 @@
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
/* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */
@@ -43,36 +43,6 @@ struct timespec start_time;
long long max_latency_ns;
int timer_fired_early;
-char *clockstring(int clockid)
-{
- switch (clockid) {
- case CLOCK_REALTIME:
- return "CLOCK_REALTIME";
- case CLOCK_MONOTONIC:
- return "CLOCK_MONOTONIC";
- case CLOCK_PROCESS_CPUTIME_ID:
- return "CLOCK_PROCESS_CPUTIME_ID";
- case CLOCK_THREAD_CPUTIME_ID:
- return "CLOCK_THREAD_CPUTIME_ID";
- case CLOCK_MONOTONIC_RAW:
- return "CLOCK_MONOTONIC_RAW";
- case CLOCK_REALTIME_COARSE:
- return "CLOCK_REALTIME_COARSE";
- case CLOCK_MONOTONIC_COARSE:
- return "CLOCK_MONOTONIC_COARSE";
- case CLOCK_BOOTTIME:
- return "CLOCK_BOOTTIME";
- case CLOCK_REALTIME_ALARM:
- return "CLOCK_REALTIME_ALARM";
- case CLOCK_BOOTTIME_ALARM:
- return "CLOCK_BOOTTIME_ALARM";
- case CLOCK_TAI:
- return "CLOCK_TAI";
- }
- return "UNKNOWN_CLOCKID";
-}
-
-
long long timespec_sub(struct timespec a, struct timespec b)
{
long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
@@ -103,7 +73,7 @@ void sigalarm(int signo)
void describe_timer(int flags, int interval)
{
printf("%-22s %s %s ",
- clockstring(clock_id),
+ clock_name(clock_id),
flags ? "ABSTIME":"RELTIME",
interval ? "PERIODIC":"ONE-SHOT");
}
@@ -129,12 +99,12 @@ int setup_timer(int clock_id, int flags, int interval, timer_t *tm1)
if ((clock_id == CLOCK_REALTIME_ALARM) ||
(clock_id == CLOCK_BOOTTIME_ALARM)) {
printf("%-22s %s missing CAP_WAKE_ALARM? : [UNSUPPORTED]\n",
- clockstring(clock_id),
+ clock_name(clock_id),
flags ? "ABSTIME":"RELTIME");
/* Indicate timer isn't set, so caller doesn't wait */
return 1;
}
- printf("%s - timer_create() failed\n", clockstring(clock_id));
+ printf("%s - timer_create() failed\n", clock_name(clock_id));
return -1;
}
@@ -151,7 +121,7 @@ int setup_timer(int clock_id, int flags, int interval, timer_t *tm1)
err = timer_settime(*tm1, flags, &its1, &its2);
if (err) {
- printf("%s - timer_settime() failed\n", clockstring(clock_id));
+ printf("%s - timer_settime() failed\n", clock_name(clock_id));
return -1;
}
diff --git a/tools/testing/selftests/timers/valid-adjtimex.c b/tools/testing/selftests/timers/valid-adjtimex.c
index e1e56d3097d6..f641d5fb0902 100644
--- a/tools/testing/selftests/timers/valid-adjtimex.c
+++ b/tools/testing/selftests/timers/valid-adjtimex.c
@@ -29,7 +29,7 @@
#include <string.h>
#include <signal.h>
#include <unistd.h>
-#include <include/vdso/time64.h>
+#include "clock-helpers.h"
#include "kselftest.h"
#define ADJ_SETOFFSET 0x0100