Rust for Linux List
 help / color / mirror / Atom feed
* [PATCH 0/6] hrtimer: add an expiry injecting callback variant
@ 2026-08-25 12:16 Andreas Hindborg
  2026-08-25 12:16 ` [PATCH 1/6] hrtimer: add " Andreas Hindborg
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Andreas Hindborg @ 2026-08-25 12:16 UTC (permalink / raw)
  To: Anna-Maria Behnsen, Frederic Weisbecker, Thomas Gleixner,
	Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Jani Nikula, Joonas Lahtinen,
	Rodrigo Vivi, Tvrtko Ursulin, David Airlie, Simona Vetter,
	Lyude Paul, John Stultz, Stephen Boyd
  Cc: Miguel Ojeda, Boqun Feng, Gary Guo, FUJITA Tomonori, linux-kernel,
	rust-for-linux, intel-gfx, dri-devel, Andreas Hindborg

An hrtimer callback runs after __run_hrtimer() has dropped the
cpu_base->lock, and a timer can be armed from any CPU at any time,
including while its callback is running. A callback that adjusts its
own expiry with hrtimer_forward() therefore races with a concurrent
hrtimer_start_range_ns():

- The read-modify-write of node.expires in hrtimer_forward() is
  unsynchronized against the write in the start path, which happens
  under the base lock.

- The is_queued check in hrtimer_forward() is a
  time-of-check-to-time-of-use bug. A concurrent start can enqueue
  the timer right after the check, and forwarding a queued timer
  changes the expiry of a node inside the timerqueue without
  re-sorting it, leaving the tree unordered.

Users that both forward from the callback and arm the timer from
other contexts have to serialize the two themselves, as perf does
with cpc->hrtimer_lock and the hrtimer_active flag, see 4cfafd3082af
("sched,perf: Fix periodic timers"). The requirement is subtle. i915_pmu
and taprio do not honor it today.

For the Rust hrtimer abstraction this is a soundness problem rather than
a documentation problem: safe Rust code can arm a timer whose callback
is running, because Arc<T> is Clone and Pin<&T> is Copy, so a callback
context forward() cannot be offered as safe API at all. Making arming
exclusive in the Rust type system was tried [1] and abandoned. It adds
complexity to the Arc based API, and it leaves the C interface as the
same trap for C users.

Gary suggested [2] removing the race structurally instead: snapshot
the expiry under the base lock, hand it to the callback by value, and
have the callback request the forward and the requeue instead of
performing them itself. This series implements that suggestion.

Patch 1 adds the expiry injecting callback variant to the hrtimer core.
Such a callback is installed with hrtimer_setup_ext() and receives
the expiry snapshotted under the base lock. To restart the timer it
fills a struct hrtimer_forward_args and returns HRTIMER_RESTART, and
__run_hrtimer() then applies the forward and the enqueue with the base
lock held. The callback never touches live timer state. If a concurrent
start enqueued the timer while the callback ran, the restart request
is discarded and the start wins, which matches how we already treat a
restart of a timer that was requeued behind the callback's back. The
new callback pointer shares storage with the classic one in an anonymous
union and is discriminated by a flag placed in existing padding, so
struct hrtimer does not grow and the classic callback path is untouched.

Patch 2 converts i915_pmu, which forwards from its sampling callback
while gt park/unpark can start the timer from another CPU. The
conversion closes that window without adding locking to the sampling
path, and demonstrates that the new variant is not Rust-only
plumbing.

Patches 3 to 6 are the Rust side. Patch 3 moves the abstraction to
the new callback variant: HrTimerCallback::run() receives the expiry
snapshot and returns HrTimerRestart::Forward { now, interval }, and
HrTimerCallbackContext with its forward()/forward_now() methods is
removed. Patch 4 is Tomonori's expires() fix rebased on top, now
justified by exclusive access rather than by callback context. Patch
5 documents the pre-existing hazard that starting a timer from within
its own handler self-deadlocks when the returned handle is dropped
there.

The i915 patch is compile tested only, I have no hardware for it.

[1]: https://lore.kernel.org/rust-for-linux/20260813134834.1562995-1-tomo@flapping.org/
[2]: https://lore.kernel.org/rust-for-linux/DKNVOU9JC15P.3DEBNZ56QK20E@garyguo.net/

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
Andreas Hindborg (4):
      hrtimer: add expiry injecting callback variant
      drm/i915/pmu: use the expiry injecting hrtimer callback
      rust: hrtimer: use the expiry injecting callback variant
      rust: hrtimer: document deadlock when starting a timer in its handler

FUJITA Tomonori (2):
      rust: hrtimer: restrict expires() to exclusive access
      rust: hrtimer: Make HrTimer repr(transparent)

 drivers/gpu/drm/i915/i915_pmu.c     |   8 +-
 include/linux/hrtimer.h             |   7 +
 include/linux/hrtimer_types.h       |  34 ++++-
 kernel/time/hrtimer.c               | 112 +++++++++++++++-
 rust/helpers/time.c                 |   6 +
 rust/kernel/time/hrtimer.rs         | 257 +++++++++++++++++++-----------------
 rust/kernel/time/hrtimer/arc.rs     |  23 ++--
 rust/kernel/time/hrtimer/pin.rs     |  23 ++--
 rust/kernel/time/hrtimer/pin_mut.rs |  26 ++--
 rust/kernel/time/hrtimer/tbox.rs    |  23 ++--
 10 files changed, 352 insertions(+), 167 deletions(-)
---
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
change-id: 20260825-expires-v2-0764adf4c466

Best regards,
--  
Andreas Hindborg <a.hindborg@kernel.org>



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

end of thread, other threads:[~2026-08-26  9:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-25 12:16 [PATCH 0/6] hrtimer: add an expiry injecting callback variant Andreas Hindborg
2026-08-25 12:16 ` [PATCH 1/6] hrtimer: add " Andreas Hindborg
2026-08-25 12:16 ` [PATCH 2/6] drm/i915/pmu: use the expiry injecting hrtimer callback Andreas Hindborg
2026-08-25 12:16 ` [PATCH 3/6] rust: hrtimer: use the expiry injecting callback variant Andreas Hindborg
2026-08-25 12:16 ` [PATCH 4/6] rust: hrtimer: restrict expires() to exclusive access Andreas Hindborg
2026-08-25 12:16 ` [PATCH 5/6] rust: hrtimer: document deadlock when starting a timer in its handler Andreas Hindborg
     [not found]   ` <DKY292V0LWJN.1L3HG02NBW6K5@garyguo.net>
2026-08-26  9:31     ` Andreas Hindborg
2026-08-25 12:16 ` [PATCH 6/6] rust: hrtimer: Make HrTimer repr(transparent) Andreas Hindborg
     [not found]   ` <DKY2AIA7ELLI.1REFFZGXL78Q5@garyguo.net>
2026-08-26  9:30     ` Andreas Hindborg

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