Rust for Linux List
 help / color / mirror / Atom feed
* [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