* [PATCH v2 0/2] rust: sync: Add AtomicFlag type
@ 2026-01-29 12:26 FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw)
To: boqun, ojeda, peterz, will
Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin,
mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
This series adds AtomicFlag and switches the list atomic tracker to
use it.
Unlike the previous design, we avoid exposing Atomic<Flag> and always
use AtomicFlag.
v2:
- Drop Atomic<u8> alias; Define Flag on all architectures
- Place padding first on big endian archs
v1: https://lore.kernel.org/rust-for-linux/20260128115200.3820113-1-tomo@aliasing.net/
FUJITA Tomonori (2):
rust: sync: atomic: Add perfromance-optimal Flag type for atomic
booleans
rust: list: Use AtomicFlag in AtomicTracker
rust/kernel/list/arc.rs | 8 +-
rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
rust/kernel/sync/atomic/predefine.rs | 17 ++++
3 files changed, 146 insertions(+), 4 deletions(-)
base-commit: 6583920e15fc567109e1c64ca58c917f52f40736
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans
2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori
@ 2026-01-29 12:26 ` FUJITA Tomonori
2026-01-29 14:15 ` Gary Guo
2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori
2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng
2 siblings, 1 reply; 7+ messages in thread
From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw)
To: boqun, ojeda, peterz, will
Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin,
mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
Add AtomicFlag type for boolean flags.
Document when AtomicFlag is generally preferable to Atomic<bool>: in
particular, when RMW operations such as xchg()/cmpxchg() may be used
and minimizing memory usage is not the top priority. On some
architectures without byte-sized RMW instructions, Atomic<bool> can be
slower for RMW operations.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
rust/kernel/sync/atomic/predefine.rs | 17 ++++
2 files changed, 142 insertions(+)
diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
index 4aebeacb961a..bfc393d98aa9 100644
--- a/rust/kernel/sync/atomic.rs
+++ b/rust/kernel/sync/atomic.rs
@@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering)
unsafe { from_repr(ret) }
}
}
+
+#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
+#[repr(C)]
+#[derive(Clone, Copy)]
+struct Flag {
+ bool_field: bool,
+}
+
+/// # Invariants
+///
+/// `padding` must be all zeroes.
+#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
+#[repr(C, align(4))]
+#[derive(Clone, Copy)]
+struct Flag {
+ #[cfg(target_endian = "big")]
+ padding: [u8; 3],
+ bool_field: bool,
+ #[cfg(target_endian = "little")]
+ padding: [u8; 3],
+}
+
+impl Flag {
+ #[inline(always)]
+ const fn new(b: bool) -> Self {
+ // INVARIANT: `padding` is all zeroes.
+ Self {
+ bool_field: b,
+ #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
+ padding: [0; 3],
+ }
+ }
+}
+
+// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip
+// transmutable to the selected representation (`i8` or `i32`).
+unsafe impl AtomicType for Flag {
+ #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
+ type Repr = i8;
+ #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
+ type Repr = i32;
+}
+
+/// An atomic flag type intended to be backed by performance-optimal integer type.
+///
+/// The backing integer type is an implementation detail; it may vary by architecture and change
+/// in the future.
+///
+/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write
+/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does
+/// not save memory due to padding. On some architectures that do not support byte-sized atomic
+/// RMW operations, RMW operations on [`Atomic<bool>`] are slower.
+///
+/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::sync::atomic::{AtomicFlag, Relaxed};
+///
+/// let flag = AtomicFlag::new(false);
+/// assert_eq!(false, flag.load(Relaxed));
+/// flag.store(true, Relaxed);
+/// assert_eq!(true, flag.load(Relaxed));
+/// ```
+pub struct AtomicFlag(Atomic<Flag>);
+
+impl AtomicFlag {
+ /// Creates a new atomic flag.
+ #[inline(always)]
+ pub const fn new(b: bool) -> Self {
+ Self(Atomic::new(Flag::new(b)))
+ }
+
+ /// Returns a mutable reference to the underlying flag as a [`bool`].
+ ///
+ /// This is safe because the mutable reference of the atomic flag guarantees exclusive access.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::sync::atomic::{AtomicFlag, Relaxed};
+ ///
+ /// let mut atomic_flag = AtomicFlag::new(false);
+ /// assert_eq!(false, atomic_flag.load(Relaxed));
+ /// *atomic_flag.get_mut() = true;
+ /// assert_eq!(true, atomic_flag.load(Relaxed));
+ /// ```
+ #[inline(always)]
+ pub fn get_mut(&mut self) -> &mut bool {
+ &mut self.0.get_mut().bool_field
+ }
+
+ /// Loads the value from the atomic flag.
+ #[inline(always)]
+ pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool {
+ self.0.load(o).bool_field
+ }
+
+ /// Stores a value to the atomic flag.
+ #[inline(always)]
+ pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) {
+ self.0.store(Flag::new(v), o);
+ }
+
+ /// Stores a value to the atomic flag and returns the previous value.
+ #[inline(always)]
+ pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool {
+ self.0.xchg(Flag::new(new), o).bool_field
+ }
+
+ /// Store a value to the atomic flag if the current value is equal to `old`.
+ #[inline(always)]
+ pub fn cmpxchg<Ordering: ordering::Ordering>(
+ &self,
+ old: bool,
+ new: bool,
+ o: Ordering,
+ ) -> Result<bool, bool> {
+ match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) {
+ Ok(_) => Ok(old),
+ Err(f) => Err(f.bool_field),
+ }
+ }
+}
diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
index 42067c6a266c..d14e10544dcf 100644
--- a/rust/kernel/sync/atomic/predefine.rs
+++ b/rust/kernel/sync/atomic/predefine.rs
@@ -215,4 +215,21 @@ fn atomic_bool_tests() {
assert_eq!(false, x.load(Relaxed));
assert_eq!(Ok(false), x.cmpxchg(false, true, Full));
}
+
+ #[test]
+ fn atomic_flag_tests() {
+ let mut flag = AtomicFlag::new(false);
+
+ assert_eq!(false, flag.load(Relaxed));
+
+ *flag.get_mut() = true;
+ assert_eq!(true, flag.load(Relaxed));
+
+ assert_eq!(true, flag.xchg(false, Relaxed));
+ assert_eq!(false, flag.load(Relaxed));
+
+ *flag.get_mut() = true;
+ assert_eq!(Ok(true), flag.cmpxchg(true, false, Full));
+ assert_eq!(false, flag.load(Relaxed));
+ }
}
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker
2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
@ 2026-01-29 12:26 ` FUJITA Tomonori
2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng
2 siblings, 0 replies; 7+ messages in thread
From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw)
To: boqun, ojeda, peterz, will
Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin,
mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
Make AtomicTracker use AtomicFlag instead of Atomic<bool> to avoid
slow byte-sized RMWs on architectures that don't support them.
Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/kernel/list/arc.rs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs
index 2282f33913ee..5e84f500a3fe 100644
--- a/rust/kernel/list/arc.rs
+++ b/rust/kernel/list/arc.rs
@@ -6,7 +6,7 @@
use crate::alloc::{AllocError, Flags};
use crate::prelude::*;
-use crate::sync::atomic::{ordering, Atomic};
+use crate::sync::atomic::{ordering, AtomicFlag};
use crate::sync::{Arc, ArcBorrow, UniqueArc};
use core::marker::PhantomPinned;
use core::ops::Deref;
@@ -469,7 +469,7 @@ impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc
/// If the boolean is `false`, then there is no [`ListArc`] for this value.
#[repr(transparent)]
pub struct AtomicTracker<const ID: u64 = 0> {
- inner: Atomic<bool>,
+ inner: AtomicFlag,
// This value needs to be pinned to justify the INVARIANT: comment in `AtomicTracker::new`.
_pin: PhantomPinned,
}
@@ -480,12 +480,12 @@ pub fn new() -> impl PinInit<Self> {
// INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will
// not be constructed in an `Arc` that already has a `ListArc`.
Self {
- inner: Atomic::new(false),
+ inner: AtomicFlag::new(false),
_pin: PhantomPinned,
}
}
- fn project_inner(self: Pin<&mut Self>) -> &mut Atomic<bool> {
+ fn project_inner(self: Pin<&mut Self>) -> &mut AtomicFlag {
// SAFETY: The `inner` field is not structurally pinned, so we may obtain a mutable
// reference to it even if we only have a pinned reference to `self`.
unsafe { &mut Pin::into_inner_unchecked(self).inner }
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
@ 2026-01-29 14:15 ` Gary Guo
2026-01-29 15:33 ` Boqun Feng
0 siblings, 1 reply; 7+ messages in thread
From: Gary Guo @ 2026-01-29 14:15 UTC (permalink / raw)
To: FUJITA Tomonori, boqun, ojeda, peterz, will
Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin,
mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote:
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> Add AtomicFlag type for boolean flags.
>
> Document when AtomicFlag is generally preferable to Atomic<bool>: in
> particular, when RMW operations such as xchg()/cmpxchg() may be used
> and minimizing memory usage is not the top priority. On some
> architectures without byte-sized RMW instructions, Atomic<bool> can be
> slower for RMW operations.
>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Hi Fujita,
Thanks for the patch. I think this looks nice, so from design point of view:
Reviewed-by: Gary Guo <gary@garyguo.net>
However, Boqun reported that the codegen of `.bool_field` may involve a bit
masking instruction.
Best,
Gary
> ---
> rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
> rust/kernel/sync/atomic/predefine.rs | 17 ++++
> 2 files changed, 142 insertions(+)
>
> diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
> index 4aebeacb961a..bfc393d98aa9 100644
> --- a/rust/kernel/sync/atomic.rs
> +++ b/rust/kernel/sync/atomic.rs
> @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering)
> unsafe { from_repr(ret) }
> }
> }
> +
> +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
> +#[repr(C)]
> +#[derive(Clone, Copy)]
> +struct Flag {
> + bool_field: bool,
> +}
> +
> +/// # Invariants
> +///
> +/// `padding` must be all zeroes.
> +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> +#[repr(C, align(4))]
> +#[derive(Clone, Copy)]
> +struct Flag {
> + #[cfg(target_endian = "big")]
> + padding: [u8; 3],
> + bool_field: bool,
> + #[cfg(target_endian = "little")]
> + padding: [u8; 3],
> +}
> +
> +impl Flag {
> + #[inline(always)]
> + const fn new(b: bool) -> Self {
> + // INVARIANT: `padding` is all zeroes.
> + Self {
> + bool_field: b,
> + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> + padding: [0; 3],
> + }
> + }
> +}
> +
> +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip
> +// transmutable to the selected representation (`i8` or `i32`).
> +unsafe impl AtomicType for Flag {
> + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
> + type Repr = i8;
> + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> + type Repr = i32;
> +}
> +
> +/// An atomic flag type intended to be backed by performance-optimal integer type.
> +///
> +/// The backing integer type is an implementation detail; it may vary by architecture and change
> +/// in the future.
> +///
> +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write
> +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does
> +/// not save memory due to padding. On some architectures that do not support byte-sized atomic
> +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower.
> +///
> +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::sync::atomic::{AtomicFlag, Relaxed};
> +///
> +/// let flag = AtomicFlag::new(false);
> +/// assert_eq!(false, flag.load(Relaxed));
> +/// flag.store(true, Relaxed);
> +/// assert_eq!(true, flag.load(Relaxed));
> +/// ```
> +pub struct AtomicFlag(Atomic<Flag>);
> +
> +impl AtomicFlag {
> + /// Creates a new atomic flag.
> + #[inline(always)]
> + pub const fn new(b: bool) -> Self {
> + Self(Atomic::new(Flag::new(b)))
> + }
> +
> + /// Returns a mutable reference to the underlying flag as a [`bool`].
> + ///
> + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access.
> + ///
> + /// # Examples
> + ///
> + /// ```
> + /// use kernel::sync::atomic::{AtomicFlag, Relaxed};
> + ///
> + /// let mut atomic_flag = AtomicFlag::new(false);
> + /// assert_eq!(false, atomic_flag.load(Relaxed));
> + /// *atomic_flag.get_mut() = true;
> + /// assert_eq!(true, atomic_flag.load(Relaxed));
> + /// ```
> + #[inline(always)]
> + pub fn get_mut(&mut self) -> &mut bool {
> + &mut self.0.get_mut().bool_field
> + }
> +
> + /// Loads the value from the atomic flag.
> + #[inline(always)]
> + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool {
> + self.0.load(o).bool_field
> + }
> +
> + /// Stores a value to the atomic flag.
> + #[inline(always)]
> + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) {
> + self.0.store(Flag::new(v), o);
> + }
> +
> + /// Stores a value to the atomic flag and returns the previous value.
> + #[inline(always)]
> + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool {
> + self.0.xchg(Flag::new(new), o).bool_field
> + }
> +
> + /// Store a value to the atomic flag if the current value is equal to `old`.
> + #[inline(always)]
> + pub fn cmpxchg<Ordering: ordering::Ordering>(
> + &self,
> + old: bool,
> + new: bool,
> + o: Ordering,
> + ) -> Result<bool, bool> {
> + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) {
> + Ok(_) => Ok(old),
> + Err(f) => Err(f.bool_field),
> + }
> + }
> +}
> diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
> index 42067c6a266c..d14e10544dcf 100644
> --- a/rust/kernel/sync/atomic/predefine.rs
> +++ b/rust/kernel/sync/atomic/predefine.rs
> @@ -215,4 +215,21 @@ fn atomic_bool_tests() {
> assert_eq!(false, x.load(Relaxed));
> assert_eq!(Ok(false), x.cmpxchg(false, true, Full));
> }
> +
> + #[test]
> + fn atomic_flag_tests() {
> + let mut flag = AtomicFlag::new(false);
> +
> + assert_eq!(false, flag.load(Relaxed));
> +
> + *flag.get_mut() = true;
> + assert_eq!(true, flag.load(Relaxed));
> +
> + assert_eq!(true, flag.xchg(false, Relaxed));
> + assert_eq!(false, flag.load(Relaxed));
> +
> + *flag.get_mut() = true;
> + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full));
> + assert_eq!(false, flag.load(Relaxed));
> + }
> }
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans
2026-01-29 14:15 ` Gary Guo
@ 2026-01-29 15:33 ` Boqun Feng
2026-01-29 15:45 ` Gary Guo
0 siblings, 1 reply; 7+ messages in thread
From: Boqun Feng @ 2026-01-29 15:33 UTC (permalink / raw)
To: Gary Guo
Cc: FUJITA Tomonori, ojeda, peterz, will, a.hindborg, aliceryhl,
bjorn3_gh, dakr, lossin, mark.rutland, tmgross, rust-for-linux,
FUJITA Tomonori
On Thu, Jan 29, 2026 at 02:15:10PM +0000, Gary Guo wrote:
> On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote:
> > From: FUJITA Tomonori <fujita.tomonori@gmail.com>
> >
> > Add AtomicFlag type for boolean flags.
> >
> > Document when AtomicFlag is generally preferable to Atomic<bool>: in
> > particular, when RMW operations such as xchg()/cmpxchg() may be used
> > and minimizing memory usage is not the top priority. On some
> > architectures without byte-sized RMW instructions, Atomic<bool> can be
> > slower for RMW operations.
> >
> > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> Hi Fujita,
>
> Thanks for the patch. I think this looks nice, so from design point of view:
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
>
> However, Boqun reported that the codegen of `.bool_field` may involve a bit
> masking instruction.
>
Yeah, but at the moment, I haven't found any elegant way to reduce that
see [1], plus I've tried to transmute the 32-bit Flag struct into a
32-bit enum, but for example on riscv64 an `sext.w` instruction is still
generated [2]. That's a sign to me that the micro-optimization here may
not bring actual performance gain. But of course, open to any
improvement, let's ship what we have now and improve the codegen later.
[1]: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/A.20.60AlwaysZero.60.20type.20for.20padding.3F/near/570631532
[2]: https://godbolt.org/z/3PMK3EK1r
Regards,
Boqun
> Best,
> Gary
>
> > ---
> > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
> > rust/kernel/sync/atomic/predefine.rs | 17 ++++
> > 2 files changed, 142 insertions(+)
> >
> > diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
> > index 4aebeacb961a..bfc393d98aa9 100644
> > --- a/rust/kernel/sync/atomic.rs
> > +++ b/rust/kernel/sync/atomic.rs
> > @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering)
> > unsafe { from_repr(ret) }
> > }
> > }
> > +
> > +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
> > +#[repr(C)]
> > +#[derive(Clone, Copy)]
> > +struct Flag {
> > + bool_field: bool,
> > +}
> > +
> > +/// # Invariants
> > +///
> > +/// `padding` must be all zeroes.
> > +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> > +#[repr(C, align(4))]
> > +#[derive(Clone, Copy)]
> > +struct Flag {
> > + #[cfg(target_endian = "big")]
> > + padding: [u8; 3],
> > + bool_field: bool,
> > + #[cfg(target_endian = "little")]
> > + padding: [u8; 3],
> > +}
> > +
> > +impl Flag {
> > + #[inline(always)]
> > + const fn new(b: bool) -> Self {
> > + // INVARIANT: `padding` is all zeroes.
> > + Self {
> > + bool_field: b,
> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> > + padding: [0; 3],
> > + }
> > + }
> > +}
> > +
> > +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip
> > +// transmutable to the selected representation (`i8` or `i32`).
> > +unsafe impl AtomicType for Flag {
> > + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
> > + type Repr = i8;
> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
> > + type Repr = i32;
> > +}
> > +
> > +/// An atomic flag type intended to be backed by performance-optimal integer type.
> > +///
> > +/// The backing integer type is an implementation detail; it may vary by architecture and change
> > +/// in the future.
> > +///
> > +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write
> > +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does
> > +/// not save memory due to padding. On some architectures that do not support byte-sized atomic
> > +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower.
> > +///
> > +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine.
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// use kernel::sync::atomic::{AtomicFlag, Relaxed};
> > +///
> > +/// let flag = AtomicFlag::new(false);
> > +/// assert_eq!(false, flag.load(Relaxed));
> > +/// flag.store(true, Relaxed);
> > +/// assert_eq!(true, flag.load(Relaxed));
> > +/// ```
> > +pub struct AtomicFlag(Atomic<Flag>);
> > +
> > +impl AtomicFlag {
> > + /// Creates a new atomic flag.
> > + #[inline(always)]
> > + pub const fn new(b: bool) -> Self {
> > + Self(Atomic::new(Flag::new(b)))
> > + }
> > +
> > + /// Returns a mutable reference to the underlying flag as a [`bool`].
> > + ///
> > + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access.
> > + ///
> > + /// # Examples
> > + ///
> > + /// ```
> > + /// use kernel::sync::atomic::{AtomicFlag, Relaxed};
> > + ///
> > + /// let mut atomic_flag = AtomicFlag::new(false);
> > + /// assert_eq!(false, atomic_flag.load(Relaxed));
> > + /// *atomic_flag.get_mut() = true;
> > + /// assert_eq!(true, atomic_flag.load(Relaxed));
> > + /// ```
> > + #[inline(always)]
> > + pub fn get_mut(&mut self) -> &mut bool {
> > + &mut self.0.get_mut().bool_field
> > + }
> > +
> > + /// Loads the value from the atomic flag.
> > + #[inline(always)]
> > + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool {
> > + self.0.load(o).bool_field
> > + }
> > +
> > + /// Stores a value to the atomic flag.
> > + #[inline(always)]
> > + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) {
> > + self.0.store(Flag::new(v), o);
> > + }
> > +
> > + /// Stores a value to the atomic flag and returns the previous value.
> > + #[inline(always)]
> > + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool {
> > + self.0.xchg(Flag::new(new), o).bool_field
> > + }
> > +
> > + /// Store a value to the atomic flag if the current value is equal to `old`.
> > + #[inline(always)]
> > + pub fn cmpxchg<Ordering: ordering::Ordering>(
> > + &self,
> > + old: bool,
> > + new: bool,
> > + o: Ordering,
> > + ) -> Result<bool, bool> {
> > + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) {
> > + Ok(_) => Ok(old),
> > + Err(f) => Err(f.bool_field),
> > + }
> > + }
> > +}
> > diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
> > index 42067c6a266c..d14e10544dcf 100644
> > --- a/rust/kernel/sync/atomic/predefine.rs
> > +++ b/rust/kernel/sync/atomic/predefine.rs
> > @@ -215,4 +215,21 @@ fn atomic_bool_tests() {
> > assert_eq!(false, x.load(Relaxed));
> > assert_eq!(Ok(false), x.cmpxchg(false, true, Full));
> > }
> > +
> > + #[test]
> > + fn atomic_flag_tests() {
> > + let mut flag = AtomicFlag::new(false);
> > +
> > + assert_eq!(false, flag.load(Relaxed));
> > +
> > + *flag.get_mut() = true;
> > + assert_eq!(true, flag.load(Relaxed));
> > +
> > + assert_eq!(true, flag.xchg(false, Relaxed));
> > + assert_eq!(false, flag.load(Relaxed));
> > +
> > + *flag.get_mut() = true;
> > + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full));
> > + assert_eq!(false, flag.load(Relaxed));
> > + }
> > }
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans
2026-01-29 15:33 ` Boqun Feng
@ 2026-01-29 15:45 ` Gary Guo
0 siblings, 0 replies; 7+ messages in thread
From: Gary Guo @ 2026-01-29 15:45 UTC (permalink / raw)
To: Boqun Feng, Gary Guo
Cc: FUJITA Tomonori, ojeda, peterz, will, a.hindborg, aliceryhl,
bjorn3_gh, dakr, lossin, mark.rutland, tmgross, rust-for-linux,
FUJITA Tomonori
On Thu Jan 29, 2026 at 3:33 PM GMT, Boqun Feng wrote:
> On Thu, Jan 29, 2026 at 02:15:10PM +0000, Gary Guo wrote:
>> On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote:
>> > From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>> >
>> > Add AtomicFlag type for boolean flags.
>> >
>> > Document when AtomicFlag is generally preferable to Atomic<bool>: in
>> > particular, when RMW operations such as xchg()/cmpxchg() may be used
>> > and minimizing memory usage is not the top priority. On some
>> > architectures without byte-sized RMW instructions, Atomic<bool> can be
>> > slower for RMW operations.
>> >
>> > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
>>
>> Hi Fujita,
>>
>> Thanks for the patch. I think this looks nice, so from design point of view:
>>
>> Reviewed-by: Gary Guo <gary@garyguo.net>
>>
>> However, Boqun reported that the codegen of `.bool_field` may involve a bit
>> masking instruction.
>>
>
> Yeah, but at the moment, I haven't found any elegant way to reduce that
> see [1], plus I've tried to transmute the 32-bit Flag struct into a
> 32-bit enum, but for example on riscv64 an `sext.w` instruction is still
> generated [2]. That's a sign to me that the micro-optimization here may
> not bring actual performance gain. But of course, open to any
> improvement, let's ship what we have now and improve the codegen later.
>
> [1]: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/A.20.60AlwaysZero.60.20type.20for.20padding.3F/near/570631532
> [2]: https://godbolt.org/z/3PMK3EK1r
Interesting! In this case, disabling MIR optimization generates better code for
test2 (-Zmir-opt-level=0). Although, it still has an `andi a0, a0, 1` remaining.
Testing with `-Cno-prepopulate-passes --emit=llvm-ir` it looks like Rust is not
telling LLVM about the fact that `v` can only be 0 or 1... Although, I recall
that previously seeing LLVM codegen issues when Rust does give LLVM additional
unreachable paths.. So the fix isn't going to be straightforward.
With this background I agree we should ship this as is. It's much better than a
LL/SC loop anyway.
Best,
Gary
>
>>
>> > ---
>> > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
>> > rust/kernel/sync/atomic/predefine.rs | 17 ++++
>> > 2 files changed, 142 insertions(+)
>> >
>> > diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
>> > index 4aebeacb961a..bfc393d98aa9 100644
>> > --- a/rust/kernel/sync/atomic.rs
>> > +++ b/rust/kernel/sync/atomic.rs
>> > @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering)
>> > unsafe { from_repr(ret) }
>> > }
>> > }
>> > +
>> > +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
>> > +#[repr(C)]
>> > +#[derive(Clone, Copy)]
>> > +struct Flag {
>> > + bool_field: bool,
>> > +}
>> > +
>> > +/// # Invariants
>> > +///
>> > +/// `padding` must be all zeroes.
>> > +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
>> > +#[repr(C, align(4))]
>> > +#[derive(Clone, Copy)]
>> > +struct Flag {
>> > + #[cfg(target_endian = "big")]
>> > + padding: [u8; 3],
>> > + bool_field: bool,
>> > + #[cfg(target_endian = "little")]
>> > + padding: [u8; 3],
>> > +}
>> > +
>> > +impl Flag {
>> > + #[inline(always)]
>> > + const fn new(b: bool) -> Self {
>> > + // INVARIANT: `padding` is all zeroes.
>> > + Self {
>> > + bool_field: b,
>> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
>> > + padding: [0; 3],
>> > + }
>> > + }
>> > +}
>> > +
>> > +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip
>> > +// transmutable to the selected representation (`i8` or `i32`).
>> > +unsafe impl AtomicType for Flag {
>> > + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))]
>> > + type Repr = i8;
>> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))]
>> > + type Repr = i32;
>> > +}
>> > +
>> > +/// An atomic flag type intended to be backed by performance-optimal integer type.
>> > +///
>> > +/// The backing integer type is an implementation detail; it may vary by architecture and change
>> > +/// in the future.
>> > +///
>> > +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write
>> > +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does
>> > +/// not save memory due to padding. On some architectures that do not support byte-sized atomic
>> > +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower.
>> > +///
>> > +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine.
>> > +///
>> > +/// # Examples
>> > +///
>> > +/// ```
>> > +/// use kernel::sync::atomic::{AtomicFlag, Relaxed};
>> > +///
>> > +/// let flag = AtomicFlag::new(false);
>> > +/// assert_eq!(false, flag.load(Relaxed));
>> > +/// flag.store(true, Relaxed);
>> > +/// assert_eq!(true, flag.load(Relaxed));
>> > +/// ```
>> > +pub struct AtomicFlag(Atomic<Flag>);
>> > +
>> > +impl AtomicFlag {
>> > + /// Creates a new atomic flag.
>> > + #[inline(always)]
>> > + pub const fn new(b: bool) -> Self {
>> > + Self(Atomic::new(Flag::new(b)))
>> > + }
>> > +
>> > + /// Returns a mutable reference to the underlying flag as a [`bool`].
>> > + ///
>> > + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access.
>> > + ///
>> > + /// # Examples
>> > + ///
>> > + /// ```
>> > + /// use kernel::sync::atomic::{AtomicFlag, Relaxed};
>> > + ///
>> > + /// let mut atomic_flag = AtomicFlag::new(false);
>> > + /// assert_eq!(false, atomic_flag.load(Relaxed));
>> > + /// *atomic_flag.get_mut() = true;
>> > + /// assert_eq!(true, atomic_flag.load(Relaxed));
>> > + /// ```
>> > + #[inline(always)]
>> > + pub fn get_mut(&mut self) -> &mut bool {
>> > + &mut self.0.get_mut().bool_field
>> > + }
>> > +
>> > + /// Loads the value from the atomic flag.
>> > + #[inline(always)]
>> > + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool {
>> > + self.0.load(o).bool_field
>> > + }
>> > +
>> > + /// Stores a value to the atomic flag.
>> > + #[inline(always)]
>> > + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) {
>> > + self.0.store(Flag::new(v), o);
>> > + }
>> > +
>> > + /// Stores a value to the atomic flag and returns the previous value.
>> > + #[inline(always)]
>> > + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool {
>> > + self.0.xchg(Flag::new(new), o).bool_field
>> > + }
>> > +
>> > + /// Store a value to the atomic flag if the current value is equal to `old`.
>> > + #[inline(always)]
>> > + pub fn cmpxchg<Ordering: ordering::Ordering>(
>> > + &self,
>> > + old: bool,
>> > + new: bool,
>> > + o: Ordering,
>> > + ) -> Result<bool, bool> {
>> > + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) {
>> > + Ok(_) => Ok(old),
>> > + Err(f) => Err(f.bool_field),
>> > + }
>> > + }
>> > +}
>> > diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
>> > index 42067c6a266c..d14e10544dcf 100644
>> > --- a/rust/kernel/sync/atomic/predefine.rs
>> > +++ b/rust/kernel/sync/atomic/predefine.rs
>> > @@ -215,4 +215,21 @@ fn atomic_bool_tests() {
>> > assert_eq!(false, x.load(Relaxed));
>> > assert_eq!(Ok(false), x.cmpxchg(false, true, Full));
>> > }
>> > +
>> > + #[test]
>> > + fn atomic_flag_tests() {
>> > + let mut flag = AtomicFlag::new(false);
>> > +
>> > + assert_eq!(false, flag.load(Relaxed));
>> > +
>> > + *flag.get_mut() = true;
>> > + assert_eq!(true, flag.load(Relaxed));
>> > +
>> > + assert_eq!(true, flag.xchg(false, Relaxed));
>> > + assert_eq!(false, flag.load(Relaxed));
>> > +
>> > + *flag.get_mut() = true;
>> > + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full));
>> > + assert_eq!(false, flag.load(Relaxed));
>> > + }
>> > }
>>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/2] rust: sync: Add AtomicFlag type
2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori
@ 2026-01-29 16:00 ` Boqun Feng
2 siblings, 0 replies; 7+ messages in thread
From: Boqun Feng @ 2026-01-29 16:00 UTC (permalink / raw)
To: FUJITA Tomonori
Cc: ojeda, peterz, will, a.hindborg, aliceryhl, bjorn3_gh, dakr, gary,
lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
On Thu, Jan 29, 2026 at 09:26:20PM +0900, FUJITA Tomonori wrote:
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> This series adds AtomicFlag and switches the list atomic tracker to
> use it.
>
> Unlike the previous design, we avoid exposing Atomic<Flag> and always
> use AtomicFlag.
>
> v2:
> - Drop Atomic<u8> alias; Define Flag on all architectures
> - Place padding first on big endian archs
> v1: https://lore.kernel.org/rust-for-linux/20260128115200.3820113-1-tomo@aliasing.net/
>
Queued in rust-sync for more tests and reviews, thank you!
Regards,
Boqun
>
> FUJITA Tomonori (2):
> rust: sync: atomic: Add perfromance-optimal Flag type for atomic
> booleans
> rust: list: Use AtomicFlag in AtomicTracker
>
> rust/kernel/list/arc.rs | 8 +-
> rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
> rust/kernel/sync/atomic/predefine.rs | 17 ++++
> 3 files changed, 146 insertions(+), 4 deletions(-)
>
>
> base-commit: 6583920e15fc567109e1c64ca58c917f52f40736
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-01-29 16:01 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
2026-01-29 14:15 ` Gary Guo
2026-01-29 15:33 ` Boqun Feng
2026-01-29 15:45 ` Gary Guo
2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori
2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox