aboutsummaryrefslogtreecommitdiff
path: root/kernel/time
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-25 17:54:02 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-25 17:54:02 -1000
commited2bc044a7c8c9759bbe1165b8e487d07dd53b73 (patch)
treecd6b916bcfcc9f5dae6b2586a312f31a34d84f78 /kernel/time
parent6e723c4f9417663c318d898fa113af211f48a6da (diff)
parent6541fbc942f3b63bb8bd44e34eee6223e0abe719 (diff)
Merge tag 'timers-urgent-2026-10-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fixes from Ingo Molnar: - Clear timer_base::pending_map on CPU hot-unplug, that can cause temporal timeout processing anomalous on the next hot-replug (Liang Hao) - Fix PID refcount leak in the posix-cpu-timers do_cpu_nanosleep() signal path (Cen Zhang) - Require (CAP_SYS_TIME) permission to set auxiliary clocks via aux_clock_set() (Daehyeon Ko) - Update offsets on sequence counter retry in ktime_get_update_offsets_now() (Thomas Weißschuh) * tag 'timers-urgent-2026-10-25' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: timekeeping: Update offsets on sequence counter retry in ktime_get_update_offsets_now() timekeeping: Require permission to set auxiliary clocks posix-cpu-timers: Fix pid refcount leak in do_cpu_nanosleep() signal path timers: Clear pending_map on CPU hotplug
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/posix-cpu-timers.c4
-rw-r--r--kernel/time/timekeeping.c8
-rw-r--r--kernel/time/timer.c2
3 files changed, 11 insertions, 3 deletions
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index cd75d4bb5b64..2f23d62ad446 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1687,8 +1687,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
*/
expires = cpu_timer_getexpires(&timer.it.cpu);
error = posix_cpu_timer_set(&timer, 0, &zero_it, &it);
- if (!error) {
- /* Timer is now unarmed, deletion can not fail. */
+ if (error != TIMER_RETRY) {
+ /* Unarmed or target gone (-ESRCH), deletion can not fail. */
posix_cpu_timer_del(&timer);
} else {
while (error == TIMER_RETRY) {
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d54c4d303db6..dcf47f1ffdcf 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -14,6 +14,7 @@
#include <linux/random.h>
#include <linux/sched/clock.h>
#include <linux/sched/loadavg.h>
+#include <linux/security.h>
#include <linux/static_key.h>
#include <linux/stop_machine.h>
#include <linux/syscore_ops.h>
@@ -2850,6 +2851,7 @@ 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;
+ u32 cwsseq_orig = *cwsseq;
unsigned int seq;
ktime_t base;
u64 nsecs;
@@ -2861,7 +2863,7 @@ ktime_t ktime_get_update_offsets_now(u32 *cwsseq, ktime_t *offs_real,
nsecs = timekeeping_get_ns(&tk->tkr_mono);
base = ktime_add_ns(base, nsecs);
- if (*cwsseq != tk->clock_was_set_seq) {
+ if (cwsseq_orig != tk->clock_was_set_seq) {
*cwsseq = tk->clock_was_set_seq;
*offs_real = tk->offs_real;
*offs_boot = tk->offs_boot;
@@ -3217,11 +3219,15 @@ static int aux_clock_set(const clockid_t id, const struct timespec64 *tnew)
struct tk_data *aux_tkd = aux_get_tk_data(id);
struct timekeeper *aux_tks;
ktime_t tnow, nsecs;
+ int ret;
if (!timespec64_valid_settod(tnew))
return -EINVAL;
if (!aux_tkd)
return -ENODEV;
+ ret = security_settime64(tnew, NULL);
+ if (ret)
+ return ret;
aux_tks = &aux_tkd->shadow_timekeeper;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 42afdcb229d8..a3c4e20a4e36 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -44,6 +44,7 @@
#include <linux/compat.h>
#include <linux/random.h>
#include <linux/sysctl.h>
+#include <linux/bitmap.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
@@ -2541,6 +2542,7 @@ int timers_dead_cpu(unsigned int cpu)
for (i = 0; i < WHEEL_SIZE; i++)
migrate_timer_list(new_base, old_base->vectors + i);
+ bitmap_zero(old_base->pending_map, WHEEL_SIZE);
raw_spin_unlock(&old_base->lock);
raw_spin_unlock_irq(&new_base->lock);
put_cpu_ptr(&timer_bases);