mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] hrtimer: Use hard expiry when updating timers on the same base
@ 2026-09-09 10:27 Andrea Parri
  2026-09-09 16:03 ` Thomas Gleixner
  0 siblings, 1 reply; 3+ messages in thread
From: Andrea Parri @ 2026-09-09 10:27 UTC (permalink / raw)
  To: Anna-Maria Behnsen, Frederic Weisbecker, Thomas Gleixner, Peter Zijlstra
  Cc: linux-kernel, Andrea Parri, stable

Rearming a queued timer with nonzero slack can leave the timerqueue out
of order. remove_and_enqueue_same_base() checks the new soft expiry
against its neighbours' hard expiries, then stores the new hard expiry
in the node without requeueing it.

For example, with A at 10 and B at 20, rearming A at 11 with slack 30
passes the neighbour check but leaves A's hard expiry of 41 before B's
20. The same function also caches the soft expiry in base->expires_next
when updating or inserting the first timer, giving next-event selection
an earlier deadline than the queue head's hard expiry.

Set the timer expiry before handling the queue. Use its stored hard
expiry for the in-place ordering check and both updates to
base->expires_next.

The early update should be safe because remove_and_enqueue_same_base()
runs with base->cpu_base->lock held. The lock keeps the queue stable
while hrtimer_can_update_in_place() checks the new expiry against both
neighbours.  If the check fails, timerqueue_linked_del() removes the
node without comparing expiry values before it is reinserted.

Fixes: eddffab8282e3 ("hrtimer: Keep track of first expiring timer per clock base")
Fixes: 343f2f4dc5425 ("hrtimer: Try to modify timers in place")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
---
Changes in v2:
- Set the timer expiry before handling the queue and reuse its stored
  hard expiry, as suggested by Peter Zijlstra.

Link to v1: https://lore.kernel.org/r/20260907211134.3854-1-parri.andrea@gmail.com/
---
 kernel/time/hrtimer.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 530d61257b9a0..af22a2fec4904 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1263,13 +1263,16 @@ remove_and_enqueue_same_base(struct hrtimer *timer, struct hrtimer_clock_base *b
 {
 	bool was_first = false;
 
+	/* Set the new expiry time */
+	hrtimer_set_expires_range_ns(timer, expires, delta_ns);
+	expires = hrtimer_get_expires(timer);
+
 	/* Remove it from the timer queue if active */
 	if (timer->is_queued) {
 		was_first = !timerqueue_linked_prev(&timer->node);
 
 		/* Try to update in place to avoid the de/enqueue dance */
 		if (hrtimer_can_update_in_place(timer, base, expires)) {
-			hrtimer_set_expires_range_ns(timer, expires, delta_ns);
 			trace_hrtimer_start(timer, mode, true);
 			if (was_first)
 				base->expires_next = expires;
@@ -1280,9 +1283,6 @@ remove_and_enqueue_same_base(struct hrtimer *timer, struct hrtimer_clock_base *b
 		timerqueue_linked_del(&base->active, &timer->node);
 	}
 
-	/* Set the new expiry time */
-	hrtimer_set_expires_range_ns(timer, expires, delta_ns);
-
 	debug_activate(timer, mode, timer->is_queued);
 	base->cpu_base->active_bases |= 1 << base->index;
 
-- 
2.53.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] hrtimer: Use hard expiry when updating timers on the same base
  2026-09-09 10:27 [PATCH v2] hrtimer: Use hard expiry when updating timers on the same base Andrea Parri
@ 2026-09-09 16:03 ` Thomas Gleixner
  2026-09-10  7:21   ` Andrea Parri
  0 siblings, 1 reply; 3+ messages in thread
From: Thomas Gleixner @ 2026-09-09 16:03 UTC (permalink / raw)
  To: Andrea Parri, Anna-Maria Behnsen, Frederic Weisbecker, Peter Zijlstra
  Cc: linux-kernel, Andrea Parri, stable

On Wed, Sep 09 2026 at 12:27, Andrea Parri wrote:
> @@ -1263,13 +1263,16 @@ remove_and_enqueue_same_base(struct hrtimer *timer, struct hrtimer_clock_base *b
>  {
>  	bool was_first = false;
>  
> +	/* Set the new expiry time */
> +	hrtimer_set_expires_range_ns(timer, expires, delta_ns);
> +	expires = hrtimer_get_expires(timer);

My knee jerk reaction when reading this the first time was something
non-printable because the obvious rule is that you can't change the sort
key of a tree entry when that can make the tree inconsistent.

As the base lock is held and nothing can observe the potentially
resulting inconsistency at that point and the timer either stays in
place or is dequeued, this is safe, but non obvious.

So this really wants to have a big fat comment explaining why this is
safe to do.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] hrtimer: Use hard expiry when updating timers on the same base
  2026-09-09 16:03 ` Thomas Gleixner
@ 2026-09-10  7:21   ` Andrea Parri
  0 siblings, 0 replies; 3+ messages in thread
From: Andrea Parri @ 2026-09-10  7:21 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Anna-Maria Behnsen, Frederic Weisbecker, Peter Zijlstra,
	linux-kernel, stable

> So this really wants to have a big fat comment explaining why this is
> safe to do.

Agreed. The existing comment only describes the update and misses the
temporary tree inconsistency. I'll spell out that the base lock excludes
other queue operations, that the neighbour check proves the node can
remain in place, and that removal does not consult the expiry otherwise.

Thanks,
Andrea

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-10  7:21 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-09 10:27 [PATCH v2] hrtimer: Use hard expiry when updating timers on the same base Andrea Parri
2026-09-09 16:03 ` Thomas Gleixner
2026-09-10  7:21   ` Andrea Parri

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®