From: FUJITA Tomonori <tomo@flapping.org>
To: a.hindborg@kernel.org, ojeda@kernel.org
Cc: acourbot@nvidia.com, aliceryhl@google.com,
anna-maria@linutronix.de, bjorn3_gh@protonmail.com,
boqun@kernel.org, dakr@kernel.org, daniel.almeida@collabora.com,
frederic@kernel.org, gary@garyguo.net, jstultz@google.com,
lossin@kernel.org, lyude@redhat.com, sboyd@kernel.org,
tamird@kernel.org, tglx@kernel.org, tmgross@umich.edu,
work@onurozkan.dev, rust-for-linux@vger.kernel.org,
FUJITA Tomonori <fujita.tomonori@gmail.com>
Subject: [PATCH 0/4] Fix forward()/expires() racing with concurrent arming
Date: Thu, 13 Aug 2026 22:48:30 +0900 [thread overview]
Message-ID: <20260813134834.1562995-1-tomo@flapping.org> (raw)
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
This series started from the review of patches 3 and 4 [1]: a hrtimer
can be armed from any CPU at any time, including while its callback
runs, so restricting HrTimer::expires() to the callback context is not
by itself enough to remove the race.
It turned out that expires() is not the only problem. A callback may
also change its expiry time with hrtimer_forward(), which is sound
only because __run_hrtimer() dequeues the timer for the duration of
the callback. Arming the same timer from another CPU puts it back into
the rbtree while the callback runs, so hrtimer_forward() then changes
the expiry of a timer that is queued, without the base lock and
without re-checking the ordering, which leaves the tree unsorted.
Two of the four pointer types cannot construct that
situation. Starting a Pin<Box<T, A>> moves the box into the handle,
and starting a Pin<&mut T> consumes the exclusive borrow, so in both
cases nothing is left to arm the timer with. Arc<T> is Clone and
Pin<&T> is Copy, and both of their start functions are reachable from
safe code, so safe Rust could arm a timer whose callback was running.
"No arming while the callback runs" cannot be expressed in the type
system, because the callback begins when the timer expires rather than
at any point in the Rust program, so patches 1 and 2 use the stronger
"no arming while armed" instead. hrtimer_cancel() waits for the
handler to return, which makes that the point where the right to arm
can be handed back. The right to arm is split out of Arc<T> into
HrTimerArc<T> and out of Pin<&T> into HrTimerPin<'a, T>, both
non-clonable and consumed by start, modelled on ListArc; the object
itself stays shareable through plain Arc references and shared pinned
references respectively.
Patches 3 and 4 are the previously posted expires() and
repr(transparent) patches, unchanged. With patches 1 and 2 in place,
the callback context has no concurrent writer of node.expires. So
HrTimerCallbackContext::expires() is sound.
[1]: https://lore.kernel.org/rust-for-linux/20260807233039.1091842-1-tomo@flapping.org/
FUJITA Tomonori (4):
rust: hrtimer: Introduce HrTimerArc to make arming exclusive
rust: hrtimer: Introduce HrTimerPin to make arming exclusive
rust: hrtimer: Restrict expires() to safe contexts
rust: hrtimer: Make HrTimer repr(transparent)
rust/helpers/time.c | 6 ++
rust/kernel/time/hrtimer.rs | 135 ++++++++++++++++------------
rust/kernel/time/hrtimer/arc.rs | 113 +++++++++++++++++------
rust/kernel/time/hrtimer/pin.rs | 107 +++++++++++++++-------
rust/kernel/time/hrtimer/pin_mut.rs | 2 +-
rust/kernel/time/hrtimer/tbox.rs | 2 +-
6 files changed, 249 insertions(+), 116 deletions(-)
base-commit: 643a7c306b8ce32743d4f94dd700c8588be37e66
--
2.43.0
next reply other threads:[~2026-08-13 13:48 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 13:48 FUJITA Tomonori [this message]
2026-08-13 13:48 ` [PATCH v1 1/4] rust: hrtimer: Introduce HrTimerArc to make arming exclusive FUJITA Tomonori
2026-08-13 13:48 ` [PATCH v1 2/4] rust: hrtimer: Introduce HrTimerPin " FUJITA Tomonori
2026-08-13 13:48 ` [PATCH v1 3/4] rust: hrtimer: Restrict expires() to safe contexts FUJITA Tomonori
2026-08-13 13:48 ` [PATCH v1 4/4] rust: hrtimer: Make HrTimer repr(transparent) FUJITA Tomonori
2026-08-13 14:16 ` [PATCH 0/4] Fix forward()/expires() racing with concurrent arming Gary Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260813134834.1562995-1-tomo@flapping.org \
--to=tomo@flapping.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=anna-maria@linutronix.de \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=frederic@kernel.org \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=jstultz@google.com \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sboyd@kernel.org \
--cc=tamird@kernel.org \
--cc=tglx@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.