From da123f0ee40f0e5a3791bbaf58a1db1744c59f72 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Fri, 19 Sep 2025 11:12:39 +0200 Subject: rust: lock: guard: Add T: Unpin bound to DerefMut A core property of pinned types is not handing a mutable reference to the inner data in safe code, as this trivially allows that data to be moved. Enforce this condition by adding a bound on lock::Guard's DerefMut implementation, so that it's only implemented for pinning-agnostic types. Suggested-by: Benno Lossin Suggested-by: Boqun Feng Signed-off-by: Daniel Almeida Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/linux/issues/1181 --- rust/kernel/sync/lock.rs | 5 ++++- rust/kernel/sync/lock/global.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 27202beef90c..b482f34bf0ce 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -251,7 +251,10 @@ impl core::ops::Deref for Guard<'_, T, B> { } } -impl core::ops::DerefMut for Guard<'_, T, B> { +impl core::ops::DerefMut for Guard<'_, T, B> +where + T: Unpin, +{ fn deref_mut(&mut self) -> &mut Self::Target { // SAFETY: The caller owns the lock, so it is safe to deref the protected data. unsafe { &mut *self.lock.data.get() } diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs index d65f94b5caf2..38b448032799 100644 --- a/rust/kernel/sync/lock/global.rs +++ b/rust/kernel/sync/lock/global.rs @@ -106,7 +106,10 @@ impl core::ops::Deref for GlobalGuard { } } -impl core::ops::DerefMut for GlobalGuard { +impl core::ops::DerefMut for GlobalGuard +where + B::Item: Unpin, +{ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } -- cgit v1.2.3 From 2497a7116ff9a051d0e78885a27a52213bc2841d Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Fri, 19 Sep 2025 11:12:40 +0200 Subject: rust: lock: Pin the inner data In preparation to support Lock where T is pinned, the first thing that needs to be done is to structurally pin the 'data' member. This switches the 't' parameter in Lock::new() to take in an impl PinInit instead of a plain T. This in turn uses the blanket implementation "impl PinInit for T". Subsequent patches will touch on Guard. Suggested-by: Benno Lossin Suggested-by: Boqun Feng Signed-off-by: Daniel Almeida Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/linux/issues/1181 --- rust/kernel/sync/lock.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'rust') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index b482f34bf0ce..9242790d15db 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -11,7 +11,7 @@ use crate::{ types::{NotThreadSafe, Opaque, ScopeGuard}, }; use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; -use pin_init::{pin_data, pin_init, PinInit}; +use pin_init::{pin_data, pin_init, PinInit, Wrapper}; pub mod mutex; pub mod spinlock; @@ -115,6 +115,7 @@ pub struct Lock { _pin: PhantomPinned, /// The data protected by the lock. + #[pin] pub(crate) data: UnsafeCell, } @@ -127,9 +128,13 @@ unsafe impl Sync for Lock {} impl Lock { /// Constructs a new lock initialiser. - pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit { + pub fn new( + t: impl PinInit, + name: &'static CStr, + key: Pin<&'static LockClassKey>, + ) -> impl PinInit { pin_init!(Self { - data: UnsafeCell::new(t), + data <- UnsafeCell::pin_init(t), _pin: PhantomPinned, // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have // static lifetimes so they live indefinitely. -- cgit v1.2.3 From 66f1ea83d9f8346324fc50779944297d778cac95 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Fri, 19 Sep 2025 11:12:41 +0200 Subject: rust: lock: Add a Pin<&mut T> accessor In order for callers to be able to access the inner T safely if T: !Unpin, there needs to be a way to get a Pin<&mut T>. Add this accessor and a corresponding example to tell users how it works. This requires the pin projection functionality [1] for better ergonomic. [boqun: Apply Daniel's fix to the code example, add the reference to pin projection patch and remove out-of-date part in the commit log] Suggested-by: Benno Lossin Suggested-by: Boqun Feng Signed-off-by: Daniel Almeida Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Link: https://github.com/Rust-for-Linux/linux/issues/1181 Link: https://lore.kernel.org/rust-for-linux/20250912174148.373530-1-lossin@kernel.org/ [1] --- rust/kernel/sync/lock.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'rust') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 9242790d15db..cb00fdb94ffd 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -245,6 +245,31 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { cb() } + + /// Returns a pinned mutable reference to the protected data. + /// + /// The guard implements [`DerefMut`] when `T: Unpin`, so for [`Unpin`] + /// types [`DerefMut`] should be used instead of this function. + /// + /// [`DerefMut`]: core::ops::DerefMut + /// [`Unpin`]: core::marker::Unpin + /// + /// # Examples + /// + /// ``` + /// # use kernel::sync::{Mutex, MutexGuard}; + /// # use core::{pin::Pin, marker::PhantomPinned}; + /// struct Data(PhantomPinned); + /// + /// fn example(mutex: &Mutex) { + /// let mut data: MutexGuard<'_, Data> = mutex.lock(); + /// let mut data: Pin<&mut Data> = data.as_mut(); + /// } + /// ``` + pub fn as_mut(&mut self) -> Pin<&mut T> { + // SAFETY: `self.lock.data` is structurally pinned. + unsafe { Pin::new_unchecked(&mut *self.lock.data.get()) } + } } impl core::ops::Deref for Guard<'_, T, B> { -- cgit v1.2.3 From 37d0472c8ac441af8bc10fc4959ad9d62dd5fa4c Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Tue, 21 Oct 2025 23:42:37 -0400 Subject: rust: debugfs: Implement Reader for Mutex only when T is Unpin Since we are going to make `Mutex` structurally pin the data (i.e. `T`), therefore `.lock()` function only returns a `Guard` that can dereference a mutable reference to `T` if only `T` is `Unpin`, therefore restrict the impl `Reader` block of `Mutex` to that. Signed-off-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Acked-by: Danilo Krummrich Link: https://patch.msgid.link/20251022034237.70431-1-boqun.feng@gmail.com --- rust/kernel/debugfs/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index ab009eb254b3..ba7ec5a900b8 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -50,7 +50,7 @@ pub trait Reader { fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result; } -impl Reader for Mutex { +impl Reader for Mutex { fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { let mut buf = [0u8; 128]; if reader.len() > buf.len() { -- cgit v1.2.3 From 14e9a18b07ec463a85094cc8942788336164319f Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Tue, 21 Oct 2025 23:53:22 -0400 Subject: rust: sync: atomic: Make Atomic*Ops pub(crate) In order to write code over a generate Atomic we need to make Atomic*Ops public so that functions like `.load()` and `.store()` are available. Make these pub(crate) at the beginning so the usage in kernel crate is supported. Tested-by: David Gow Acked-by: Greg Kroah-Hartman Signed-off-by: Boqun Feng Link: https://patch.msgid.link/20251022035324.70785-2-boqun.feng@gmail.com --- rust/kernel/sync/atomic.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs index 016a6bcaf080..0bc6e7b04d67 100644 --- a/rust/kernel/sync/atomic.rs +++ b/rust/kernel/sync/atomic.rs @@ -22,9 +22,10 @@ mod predefine; pub use internal::AtomicImpl; pub use ordering::{Acquire, Full, Relaxed, Release}; +pub(crate) use internal::{AtomicArithmeticOps, AtomicBasicOps, AtomicExchangeOps}; use crate::build_error; -use internal::{AtomicArithmeticOps, AtomicBasicOps, AtomicExchangeOps, AtomicRepr}; +use internal::AtomicRepr; use ordering::OrderingType; /// A memory location which can be safely modified from multiple execution contexts. -- cgit v1.2.3 From 013f912eb5fa7c06b3648ca630acfc4ff26456fa Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Tue, 21 Oct 2025 23:53:23 -0400 Subject: rust: sync: atomic: Implement Debug for Atomic If `Atomic` is `Debug` then it's a `debugfs::Writer`, therefore make it so since 1) debugfs needs to support `Atomic` and 2) it's rather trivial to implement `Debug` for `Atomic`. Tested-by: David Gow Acked-by: Greg Kroah-Hartman Signed-off-by: Boqun Feng Link: https://patch.msgid.link/20251022035324.70785-3-boqun.feng@gmail.com --- rust/kernel/sync/atomic.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'rust') diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs index 0bc6e7b04d67..3afc376be42d 100644 --- a/rust/kernel/sync/atomic.rs +++ b/rust/kernel/sync/atomic.rs @@ -307,6 +307,15 @@ where } } +impl core::fmt::Debug for Atomic +where + T::Repr: AtomicBasicOps, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.load(Relaxed), f) + } +} + impl Atomic where T::Repr: AtomicExchangeOps, -- cgit v1.2.3 From f74cf399e02e24c544b0bd4b1fe8fa2c5ae30b18 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Tue, 21 Oct 2025 23:53:24 -0400 Subject: rust: debugfs: Replace the usage of Rust native atomics Rust native atomics are not allowed to use in kernel due to the mismatch of memory model with Linux kernel memory model, hence remove the usage of Rust native atomics in debufs. Reviewed-by: Matthew Maurer Acked-by: Danilo Krummrich Tested-by: David Gow Acked-by: Greg Kroah-Hartman Signed-off-by: Boqun Feng Link: https://patch.msgid.link/20251022035324.70785-4-boqun.feng@gmail.com --- rust/kernel/debugfs/traits.rs | 53 ++++++++++++------------------------- samples/rust/rust_debugfs.rs | 12 ++++----- samples/rust/rust_debugfs_scoped.rs | 6 ++--- 3 files changed, 25 insertions(+), 46 deletions(-) (limited to 'rust') diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs index ba7ec5a900b8..92054fed2136 100644 --- a/rust/kernel/debugfs/traits.rs +++ b/rust/kernel/debugfs/traits.rs @@ -4,14 +4,11 @@ //! Traits for rendering or updating values exported to DebugFS. use crate::prelude::*; +use crate::sync::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed}; use crate::sync::Mutex; use crate::uaccess::UserSliceReader; use core::fmt::{self, Debug, Formatter}; use core::str::FromStr; -use core::sync::atomic::{ - AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, - AtomicU8, AtomicUsize, Ordering, -}; /// A trait for types that can be written into a string. /// @@ -66,37 +63,21 @@ impl Reader for Mutex { } } -macro_rules! impl_reader_for_atomic { - ($(($atomic_type:ty, $int_type:ty)),*) => { - $( - impl Reader for $atomic_type { - fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { - let mut buf = [0u8; 21]; // Enough for a 64-bit number. - if reader.len() > buf.len() { - return Err(EINVAL); - } - let n = reader.len(); - reader.read_slice(&mut buf[..n])?; +impl Reader for Atomic +where + T::Repr: AtomicBasicOps, +{ + fn read_from_slice(&self, reader: &mut UserSliceReader) -> Result { + let mut buf = [0u8; 21]; // Enough for a 64-bit number. + if reader.len() > buf.len() { + return Err(EINVAL); + } + let n = reader.len(); + reader.read_slice(&mut buf[..n])?; - let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; - let val = s.trim().parse::<$int_type>().map_err(|_| EINVAL)?; - self.store(val, Ordering::Relaxed); - Ok(()) - } - } - )* - }; + let s = core::str::from_utf8(&buf[..n]).map_err(|_| EINVAL)?; + let val = s.trim().parse::().map_err(|_| EINVAL)?; + self.store(val, Relaxed); + Ok(()) + } } - -impl_reader_for_atomic!( - (AtomicI16, i16), - (AtomicI32, i32), - (AtomicI64, i64), - (AtomicI8, i8), - (AtomicIsize, isize), - (AtomicU16, u16), - (AtomicU32, u32), - (AtomicU64, u64), - (AtomicU8, u8), - (AtomicUsize, usize) -); diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 82b61a15a34b..711faa07bece 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -32,14 +32,12 @@ //! ``` use core::str::FromStr; -use core::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering; use kernel::c_str; use kernel::debugfs::{Dir, File}; use kernel::new_mutex; use kernel::prelude::*; +use kernel::sync::atomic::{Atomic, Relaxed}; use kernel::sync::Mutex; - use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; kernel::module_platform_driver! { @@ -59,7 +57,7 @@ struct RustDebugFs { #[pin] _compatible: File, #[pin] - counter: File, + counter: File>, #[pin] inner: File>, } @@ -109,7 +107,7 @@ impl platform::Driver for RustDebugFs { ) -> Result>> { let result = KBox::try_pin_init(RustDebugFs::new(pdev), GFP_KERNEL)?; // We can still mutate fields through the files which are atomic or mutexed: - result.counter.store(91, Ordering::Relaxed); + result.counter.store(91, Relaxed); { let mut guard = result.inner.lock(); guard.x = guard.y; @@ -120,8 +118,8 @@ impl platform::Driver for RustDebugFs { } impl RustDebugFs { - fn build_counter(dir: &Dir) -> impl PinInit> + '_ { - dir.read_write_file(c_str!("counter"), AtomicUsize::new(0)) + fn build_counter(dir: &Dir) -> impl PinInit>> + '_ { + dir.read_write_file(c_str!("counter"), Atomic::::new(0)) } fn build_inner(dir: &Dir) -> impl PinInit>> + '_ { diff --git a/samples/rust/rust_debugfs_scoped.rs b/samples/rust/rust_debugfs_scoped.rs index b0c4e76b123e..9f0ec5f24cda 100644 --- a/samples/rust/rust_debugfs_scoped.rs +++ b/samples/rust/rust_debugfs_scoped.rs @@ -6,9 +6,9 @@ //! `Scope::dir` to create a variety of files without the need to separately //! track them all. -use core::sync::atomic::AtomicUsize; use kernel::debugfs::{Dir, Scope}; use kernel::prelude::*; +use kernel::sync::atomic::Atomic; use kernel::sync::Mutex; use kernel::{c_str, new_mutex, str::CString}; @@ -62,7 +62,7 @@ fn create_file_write( let file_name = CString::try_from_fmt(fmt!("{name_str}"))?; for sub in items { nums.push( - AtomicUsize::new(sub.parse().map_err(|_| EINVAL)?), + Atomic::::new(sub.parse().map_err(|_| EINVAL)?), GFP_KERNEL, )?; } @@ -109,7 +109,7 @@ impl ModuleData { struct DeviceData { name: CString, - nums: KVec, + nums: KVec>, } fn init_control(base_dir: &Dir, dyn_dirs: Dir) -> impl PinInit> + '_ { -- cgit v1.2.3