* FAILED: patch "[PATCH] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers" failed to apply to 6.18-stable tree
@ 2026-11-07 10:14 Sasha Levin
2026-11-11 16:04 ` [PATCH 6.18.y 1/2] posix-timers: Handle the timer_[re]arm() return value Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-07 10:14 UTC (permalink / raw)
To: alex.lin.programmer, tglx; +Cc: stable
The patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 141a27750ec3d91ad9d1ad1764ebb5e51b963478
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107051445-failed-6.18-141a27750ec3@kernel.org' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 141a27750ec3d91ad9d1ad1764ebb5e51b963478 Mon Sep 17 00:00:00 2001
From: Hung-Jui Lin <alex.lin.programmer@gmail.com>
Date: Fri, 23 Oct 2026 23:14:10 +0800
Subject: [PATCH] posix-timers: Report zero remaining time for disarmed
SIGEV_NONE timers
SIGEV_NONE timers are never queued. common_timer_get() emulates their
expiry by computing the remaining time from the stored expiry value.
Because an armed SIGEV_NONE oneshot timer is not queued, its it_status
stays POSIX_TIMER_DISARMED. So common_timer_get() cannot use it_status to
skip a disarmed SIGEV_NONE timer and evaluates the stored expiry value for
all SIGEV_NONE timers.
Disarming a timer with timer_settime() and a zero it_value cancels the
timer and sets it_status to POSIX_TIMER_DISARMED, but leaves the expiry
value unchanged. As a consequence, timer_gettime() on a disarmed SIGEV_NONE
timer reports the remaining time of the previous arming until that time has
passed, instead of zero as POSIX requires for a disarmed timer. Example
with a CLOCK_MONOTONIC timer armed with it_value = 10ms and it_interval =
100ms, then disarmed with an all-zero itimerspec:
armed: it_value = 0.009999000 it_interval = 0.100000000
disarmed: it_value = 0.008700792 it_interval = 0.000000000
SIGEV_SIGNAL timers and SIGEV_NONE CPU timers report zero in the same
situation. All clocks which use common_timer_get() are affected, including
the alarm timer clocks.
Mark SIGEV_NONE timers as POSIX_TIMER_ARMED when they are armed, so that
common_timer_get() returns early for every disarmed timer. Forward
SIGEV_NONE interval timers in common_timer_get() regardless of it_status,
as they are never queued and therefore never forwarded by the expiry code.
After the change the disarmed timer above reports zero. Armed SIGEV_NONE
oneshot and interval timers on CLOCK_MONOTONIC, CLOCK_REALTIME,
CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM still report their remaining time,
and the posix_timers selftest passes.
Fixes: becf8b5d00f4 ("[PATCH] hrtimer: convert posix timers completely")
Signed-off-by: Hung-Jui Lin <alex.lin.programmer@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261023151411.28685-1-alex.lin.programmer@gmail.com
---
kernel/time/posix-timers.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 436ba794cc0b5..4c80c2dada9d3 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -694,16 +694,8 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
if (iv) {
cur_setting->it_interval = ktime_to_timespec64(iv);
} else if (timr->it_status == POSIX_TIMER_DISARMED) {
- /*
- * SIGEV_NONE oneshot timers are never queued and therefore
- * timr->it_status is always DISARMED. The check below
- * vs. remaining time will handle this case.
- *
- * For all other timers there is nothing to update here, so
- * return.
- */
- if (!sig_none)
- return;
+ /* Nothing to update for a disarmed timer */
+ return;
}
now = kc->clock_get_ktime(timr->it_clock);
@@ -713,7 +705,7 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
* is a SIGEV_NONE timer move the expiry time forward by intervals,
* so expiry is > now.
*/
- if (iv && timr->it_status != POSIX_TIMER_ARMED)
+ if (iv && (sig_none || timr->it_status != POSIX_TIMER_ARMED))
timr->it_overrun += kc->timer_forward(timr, now);
remaining = kc->timer_remaining(timr, now);
@@ -915,8 +907,15 @@ int common_timer_set(struct k_itimer *timr, int flags,
sigev_none = timr->it_sigev_notify == SIGEV_NONE;
if (kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none)) {
- if (!sigev_none)
- timr->it_status = POSIX_TIMER_ARMED;
+ /*
+ * SIGEV_NONE timers are not queued, but mark them armed
+ * so that common_timer_get() can tell them apart from
+ * disarmed timers. An expired SIGEV_NONE timer stays
+ * armed, which is harmless: common_timer_get() reports
+ * zero remaining time for it and it never reaches the
+ * signal delivery code.
+ */
+ timr->it_status = POSIX_TIMER_ARMED;
} else {
/* Timer was already expired, queue the signal */
posix_timer_queue_signal(timr);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 6.18.y 1/2] posix-timers: Handle the timer_[re]arm() return value
2026-11-07 10:14 FAILED: patch "[PATCH] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers" failed to apply to 6.18-stable tree Sasha Levin
@ 2026-11-11 16:04 ` Sasha Levin
2026-11-11 16:04 ` [PATCH 6.18.y 2/2] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-11 16:04 UTC (permalink / raw)
To: stable
Cc: Thomas Gleixner, Frederic Weisbecker, Peter Zijlstra (Intel),
Sasha Levin
From: Thomas Gleixner <tglx@kernel.org>
[ Upstream commit cfb7fe3fdd4ca1d37da1ed15a1897d4a27c47a8a ]
The [re]arm callbacks will return true when the timer was queued and false
if it was already expired at enqueue time.
In both cases the call sites can trivially queue the signal right there,
when the timer was already expired. That avoids a full round trip through
the hrtimer interrupt.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260408114952.198028466@kernel.org
Stable-dep-of: 141a27750ec3 ("posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/time/posix-timers.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 3082129d836c2..3d39f77423afb 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -306,6 +306,8 @@ static bool common_hrtimer_rearm(struct k_itimer *timr)
static bool __posixtimer_deliver_signal(struct kernel_siginfo *info, struct k_itimer *timr)
{
+ bool queued;
+
guard(spinlock)(&timr->it_lock);
/*
@@ -319,12 +321,18 @@ static bool __posixtimer_deliver_signal(struct kernel_siginfo *info, struct k_it
if (!timr->it_interval || WARN_ON_ONCE(timr->it_status != POSIX_TIMER_REQUEUE_PENDING))
return true;
- timr->kclock->timer_rearm(timr);
- timr->it_status = POSIX_TIMER_ARMED;
+ /* timer_rearm() updates timr::it_overrun */
+ queued = timr->kclock->timer_rearm(timr);
+
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1LL;
++timr->it_signal_seq;
info->si_overrun = timer_overrun_to_int(timr);
+
+ if (queued)
+ timr->it_status = POSIX_TIMER_ARMED;
+ else
+ posix_timer_queue_signal(timr);
return true;
}
@@ -912,9 +920,13 @@ int common_timer_set(struct k_itimer *timr, int flags,
expires = timens_ktime_to_host(timr->it_clock, expires);
sigev_none = timr->it_sigev_notify == SIGEV_NONE;
- kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
- if (!sigev_none)
- timr->it_status = POSIX_TIMER_ARMED;
+ if (kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none)) {
+ if (!sigev_none)
+ timr->it_status = POSIX_TIMER_ARMED;
+ } else {
+ /* Timer was already expired, queue the signal */
+ posix_timer_queue_signal(timr);
+ }
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 6.18.y 2/2] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers
2026-11-11 16:04 ` [PATCH 6.18.y 1/2] posix-timers: Handle the timer_[re]arm() return value Sasha Levin
@ 2026-11-11 16:04 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-11-11 16:04 UTC (permalink / raw)
To: stable; +Cc: Hung-Jui Lin, Thomas Gleixner, Sasha Levin
From: Hung-Jui Lin <alex.lin.programmer@gmail.com>
[ Upstream commit 141a27750ec3d91ad9d1ad1764ebb5e51b963478 ]
SIGEV_NONE timers are never queued. common_timer_get() emulates their
expiry by computing the remaining time from the stored expiry value.
Because an armed SIGEV_NONE oneshot timer is not queued, its it_status
stays POSIX_TIMER_DISARMED. So common_timer_get() cannot use it_status to
skip a disarmed SIGEV_NONE timer and evaluates the stored expiry value for
all SIGEV_NONE timers.
Disarming a timer with timer_settime() and a zero it_value cancels the
timer and sets it_status to POSIX_TIMER_DISARMED, but leaves the expiry
value unchanged. As a consequence, timer_gettime() on a disarmed SIGEV_NONE
timer reports the remaining time of the previous arming until that time has
passed, instead of zero as POSIX requires for a disarmed timer. Example
with a CLOCK_MONOTONIC timer armed with it_value = 10ms and it_interval =
100ms, then disarmed with an all-zero itimerspec:
armed: it_value = 0.009999000 it_interval = 0.100000000
disarmed: it_value = 0.008700792 it_interval = 0.000000000
SIGEV_SIGNAL timers and SIGEV_NONE CPU timers report zero in the same
situation. All clocks which use common_timer_get() are affected, including
the alarm timer clocks.
Mark SIGEV_NONE timers as POSIX_TIMER_ARMED when they are armed, so that
common_timer_get() returns early for every disarmed timer. Forward
SIGEV_NONE interval timers in common_timer_get() regardless of it_status,
as they are never queued and therefore never forwarded by the expiry code.
After the change the disarmed timer above reports zero. Armed SIGEV_NONE
oneshot and interval timers on CLOCK_MONOTONIC, CLOCK_REALTIME,
CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM still report their remaining time,
and the posix_timers selftest passes.
Fixes: becf8b5d00f4 ("[PATCH] hrtimer: convert posix timers completely")
Signed-off-by: Hung-Jui Lin <alex.lin.programmer@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261023151411.28685-1-alex.lin.programmer@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/time/posix-timers.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 3d39f77423afb..03bf012fae539 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -702,16 +702,8 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
if (iv) {
cur_setting->it_interval = ktime_to_timespec64(iv);
} else if (timr->it_status == POSIX_TIMER_DISARMED) {
- /*
- * SIGEV_NONE oneshot timers are never queued and therefore
- * timr->it_status is always DISARMED. The check below
- * vs. remaining time will handle this case.
- *
- * For all other timers there is nothing to update here, so
- * return.
- */
- if (!sig_none)
- return;
+ /* Nothing to update for a disarmed timer */
+ return;
}
now = kc->clock_get_ktime(timr->it_clock);
@@ -721,7 +713,7 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
* is a SIGEV_NONE timer move the expiry time forward by intervals,
* so expiry is > now.
*/
- if (iv && timr->it_status != POSIX_TIMER_ARMED)
+ if (iv && (sig_none || timr->it_status != POSIX_TIMER_ARMED))
timr->it_overrun += kc->timer_forward(timr, now);
remaining = kc->timer_remaining(timr, now);
@@ -921,8 +913,15 @@ int common_timer_set(struct k_itimer *timr, int flags,
sigev_none = timr->it_sigev_notify == SIGEV_NONE;
if (kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none)) {
- if (!sigev_none)
- timr->it_status = POSIX_TIMER_ARMED;
+ /*
+ * SIGEV_NONE timers are not queued, but mark them armed
+ * so that common_timer_get() can tell them apart from
+ * disarmed timers. An expired SIGEV_NONE timer stays
+ * armed, which is harmless: common_timer_get() reports
+ * zero remaining time for it and it never reaches the
+ * signal delivery code.
+ */
+ timr->it_status = POSIX_TIMER_ARMED;
} else {
/* Timer was already expired, queue the signal */
posix_timer_queue_signal(timr);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-11 16:05 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 10:14 FAILED: patch "[PATCH] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers" failed to apply to 6.18-stable tree Sasha Levin
2026-11-11 16:04 ` [PATCH 6.18.y 1/2] posix-timers: Handle the timer_[re]arm() return value Sasha Levin
2026-11-11 16:04 ` [PATCH 6.18.y 2/2] posix-timers: Report zero remaining time for disarmed SIGEV_NONE timers Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox