From 2dde1c8b04a5c415912bc3ffa8b677eb364dbcb7 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 7 Nov 2024 05:36:46 -0500 Subject: rust: sync: document `PhantomData` in `Arc` Add a comment explaining the relevant semantics of `PhantomData`. This should help future readers who may, as I did, assume that this field is redundant at first glance. Signed-off-by: Tamir Duberstein Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20241107-simplify-arc-v2-1-7256e638aac1@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index fa4509406ee9..9f0b04400e8e 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -127,6 +127,14 @@ mod std_vendor; /// ``` pub struct Arc { ptr: NonNull>, + // NB: this informs dropck that objects of type `ArcInner` may be used in ` as + // Drop>::drop`. Note that dropck already assumes that objects of type `T` may be used in + // ` as Drop>::drop` and the distinction between `T` and `ArcInner` is not presently + // meaningful with respect to dropck - but this may change in the future so this is left here + // out of an abundance of caution. + // + // See https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking + // for more detail on the semantics of dropck in the presence of `PhantomData`. _p: PhantomData>, } -- cgit v1.2.3 From 15abc88057eeec052aefde897df277eca2340ac6 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 19 Nov 2024 18:11:03 -0500 Subject: rust: sync: Add Lock::from_raw() for Lock<(), B> The KMS bindings [1] have a few bindings that require manually acquiring specific locks before calling certain functions. At the moment though, the only way of acquiring these locks in bindings is to simply call the C locking functions directly - since said locks are not initialized on the Rust side of things. However - if we add `#[repr(C)]` to `Lock<(), B>`, then given `()` is a ZST - `Lock<(), B>` becomes equivalent in data layout to its inner `B::State` type. Since locks in C don't have data explicitly associated with them anyway, we can take advantage of this to add a `Lock::from_raw()` function that can translate a raw pointer to `B::State` into its proper `Lock<(), B>` equivalent. This lets us simply acquire a reference to the lock in question and work with it like it was initialized on the Rust side of things, allowing us to use less unsafe code to implement bindings with lock requirements. [Boqun: Use "Link:" instead of a URL and format the commit log] Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Link: https://patchwork.freedesktop.org/series/131522/ [1] Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241119231146.2298971-2-lyude@redhat.com --- rust/kernel/sync/lock.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 41dcddac69e2..57dc2e90e504 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -96,6 +96,7 @@ pub unsafe trait Backend { /// /// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock /// [`Backend`] specified as the generic parameter `B`. +#[repr(C)] #[pin_data] pub struct Lock { /// The kernel lock object. @@ -134,6 +135,28 @@ impl Lock { } } +impl Lock<(), B> { + /// Constructs a [`Lock`] from a raw pointer. + /// + /// This can be useful for interacting with a lock which was initialised outside of Rust. + /// + /// # Safety + /// + /// The caller promises that `ptr` points to a valid initialised instance of [`State`] during + /// the whole lifetime of `'a`. + /// + /// [`State`]: Backend::State + pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a Self { + // SAFETY: + // - By the safety contract `ptr` must point to a valid initialised instance of `B::State` + // - Since the lock data type is `()` which is a ZST, `state` is the only non-ZST member of + // the struct + // - Combined with `#[repr(C)]`, this guarantees `Self` has an equivalent data layout to + // `B::State`. + unsafe { &*ptr.cast() } + } +} + impl Lock { /// Acquires the lock and gives the caller access to the data protected by it. pub fn lock(&self) -> Guard<'_, T, B> { -- cgit v1.2.3 From daa03fe50ec376aeadd63a264c471c56af194e83 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 19 Nov 2024 18:11:04 -0500 Subject: rust: sync: Make Guard::new() public Since we added a `Lock::from_raw()` function previously, it makes sense to also introduce an interface for creating a `Guard` from a reference to a `Lock` for instances where we've derived the `Lock` from a raw pointer and know that the lock is already acquired, there are such usages in KMS API. [Boqun: Add backquotes to type names, reformat the commit log, reword a bit on the usage of KMS API] Signed-off-by: Lyude Paul Reviewed-by: Filipe Xavier Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241119231146.2298971-3-lyude@redhat.com --- rust/kernel/sync/lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 57dc2e90e504..72dbf3fbb259 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -234,7 +234,7 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// # Safety /// /// The caller must ensure that it owns the lock. - pub(crate) unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { + pub unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { Self { lock, state, -- cgit v1.2.3 From 37624dde4768ec25d2f9798aa75bf32e18c0eae2 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Wed, 20 Nov 2024 17:26:28 -0500 Subject: rust: sync: Add MutexGuard type alias A simple helper alias for code that needs to deal with Guard types returned from Mutexes. Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241120222742.2490495-2-lyude@redhat.com --- rust/kernel/sync.rs | 2 +- rust/kernel/sync/lock/mutex.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 1eab7ebf25fd..2721b5c8deda 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -16,7 +16,7 @@ pub mod poll; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; -pub use lock::mutex::{new_mutex, Mutex}; +pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; pub use lock::spinlock::{new_spinlock, SpinLock}; pub use locked_by::LockedBy; diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 0e946ebefce1..10a70c07268d 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -86,6 +86,14 @@ pub use new_mutex; /// [`struct mutex`]: srctree/include/linux/mutex.h pub type Mutex = super::Lock; +/// A [`Guard`] acquired from locking a [`Mutex`]. +/// +/// This is simply a type alias for a [`Guard`] returned from locking a [`Mutex`]. It will unlock +/// the [`Mutex`] upon being dropped. +/// +/// [`Guard`]: super::Guard +pub type MutexGuard<'a, T> = super::Guard<'a, T, MutexBackend>; + /// A kernel `struct mutex` lock backend. pub struct MutexBackend; -- cgit v1.2.3 From eb5ccb038284dc0e69822d71aafcbf7b57394aad Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Wed, 20 Nov 2024 17:26:29 -0500 Subject: rust: sync: Add SpinLockGuard type alias A simple helper alias for code that needs to deal with Guard types returned from SpinLocks. Signed-off-by: Lyude Paul Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241120222742.2490495-3-lyude@redhat.com --- rust/kernel/sync.rs | 2 +- rust/kernel/sync/lock/spinlock.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 2721b5c8deda..dffdaad972ce 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -17,7 +17,7 @@ pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; -pub use lock::spinlock::{new_spinlock, SpinLock}; +pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; pub use locked_by::LockedBy; /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 9f4d128bed98..081c0220013b 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -87,6 +87,14 @@ pub type SpinLock = super::Lock; /// A kernel `spinlock_t` lock backend. pub struct SpinLockBackend; +/// A [`Guard`] acquired from locking a [`SpinLock`]. +/// +/// This is simply a type alias for a [`Guard`] returned from locking a [`SpinLock`]. It will unlock +/// the [`SpinLock`] upon being dropped. +/// +/// [`Guard`]: super::Guard +pub type SpinLockGuard<'a, T> = super::Guard<'a, T, SpinLockBackend>; + // SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. `relock` uses the // default implementation that always calls the same locking method. unsafe impl super::Backend for SpinLockBackend { -- cgit v1.2.3 From fbd7a5a0359bc770e898d918d84977ea61163aad Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Mon, 25 Nov 2024 15:40:58 -0500 Subject: rust: sync: Add lock::Backend::assert_is_held() Since we've exposed Lock::from_raw() and Guard::new() publically, we want to be able to make sure that we assert that a lock is actually held when constructing a Guard for it to handle instances of unsafe Guard::new() calls outside of our lock module. Hence add a new method assert_is_held() to Backend, which uses lockdep to check whether or not a lock has been acquired. When lockdep is disabled, this has no overhead. [Boqun: Resolve the conflicts with exposing Guard::new(), reword the commit log a bit and format "unsafe { ; }" into "unsafe { }" for the consistency. ] Signed-off-by: Lyude Paul Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20241125204139.656801-1-lyude@redhat.com --- rust/helpers/mutex.c | 5 +++++ rust/helpers/spinlock.c | 5 +++++ rust/kernel/sync/lock.rs | 10 ++++++++++ rust/kernel/sync/lock/mutex.rs | 5 +++++ rust/kernel/sync/lock/spinlock.rs | 5 +++++ 5 files changed, 30 insertions(+) (limited to 'rust/kernel/sync') diff --git a/rust/helpers/mutex.c b/rust/helpers/mutex.c index 7e00680958ef..06575553eda5 100644 --- a/rust/helpers/mutex.c +++ b/rust/helpers/mutex.c @@ -12,3 +12,8 @@ void rust_helper___mutex_init(struct mutex *mutex, const char *name, { __mutex_init(mutex, name, key); } + +void rust_helper_mutex_assert_is_held(struct mutex *mutex) +{ + lockdep_assert_held(mutex); +} diff --git a/rust/helpers/spinlock.c b/rust/helpers/spinlock.c index 5971fdf6f755..42c4bf01a23e 100644 --- a/rust/helpers/spinlock.c +++ b/rust/helpers/spinlock.c @@ -30,3 +30,8 @@ int rust_helper_spin_trylock(spinlock_t *lock) { return spin_trylock(lock); } + +void rust_helper_spin_assert_is_held(spinlock_t *lock) +{ + lockdep_assert_held(lock); +} diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index 72dbf3fbb259..eb80048e0110 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -90,6 +90,13 @@ pub unsafe trait Backend { // SAFETY: The safety requirements ensure that the lock is initialised. *guard_state = unsafe { Self::lock(ptr) }; } + + /// Asserts that the lock is held using lockdep. + /// + /// # Safety + /// + /// Callers must ensure that [`Backend::init`] has been previously called. + unsafe fn assert_is_held(ptr: *mut Self::State); } /// A mutual exclusion primitive. @@ -235,6 +242,9 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> { /// /// The caller must ensure that it owns the lock. pub unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { + // SAFETY: The caller can only hold the lock if `Backend::init` has already been called. + unsafe { B::assert_is_held(lock.state.get()) }; + Self { lock, state, diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 10a70c07268d..70cadbc2e8e2 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -134,4 +134,9 @@ unsafe impl super::Backend for MutexBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::mutex_assert_is_held(ptr) } + } } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index 081c0220013b..ab2f8d075311 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -133,4 +133,9 @@ unsafe impl super::Backend for SpinLockBackend { None } } + + unsafe fn assert_is_held(ptr: *mut Self::State) { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + unsafe { bindings::spin_assert_is_held(ptr) } + } } -- cgit v1.2.3 From 51158207294108898e5b72bb78fa51a7e848844f Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Thu, 19 Dec 2024 18:04:06 +0100 Subject: rust: add rcu abstraction Add a simple abstraction to guard critical code sections with an rcu read lock. Reviewed-by: Boqun Feng Signed-off-by: Wedson Almeida Filho Co-developed-by: Danilo Krummrich Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme Tested-by: Fabien Parent Link: https://lore.kernel.org/r/20241219170425.12036-5-dakr@kernel.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + rust/helpers/helpers.c | 1 + rust/helpers/rcu.c | 13 +++++++++++++ rust/kernel/sync.rs | 1 + rust/kernel/sync/rcu.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 rust/helpers/rcu.c create mode 100644 rust/kernel/sync/rcu.rs (limited to 'rust/kernel/sync') diff --git a/MAINTAINERS b/MAINTAINERS index f330a08cd293..8e02ab45184a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19691,6 +19691,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev F: Documentation/RCU/ F: include/linux/rcu* F: kernel/rcu/ +F: rust/kernel/sync/rcu.rs X: Documentation/RCU/torture.rst X: include/linux/srcu*.h X: kernel/rcu/srcu*.c diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index dcf827a61b52..060750af6524 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -20,6 +20,7 @@ #include "page.c" #include "pid_namespace.c" #include "rbtree.c" +#include "rcu.c" #include "refcount.c" #include "security.c" #include "signal.c" diff --git a/rust/helpers/rcu.c b/rust/helpers/rcu.c new file mode 100644 index 000000000000..f1cec6583513 --- /dev/null +++ b/rust/helpers/rcu.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_rcu_read_lock(void) +{ + rcu_read_lock(); +} + +void rust_helper_rcu_read_unlock(void) +{ + rcu_read_unlock(); +} diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 1eab7ebf25fd..0654008198b2 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -12,6 +12,7 @@ mod condvar; pub mod lock; mod locked_by; pub mod poll; +pub mod rcu; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs new file mode 100644 index 000000000000..b51d9150ffe2 --- /dev/null +++ b/rust/kernel/sync/rcu.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! RCU support. +//! +//! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h) + +use crate::{bindings, types::NotThreadSafe}; + +/// Evidence that the RCU read side lock is held on the current thread/CPU. +/// +/// The type is explicitly not `Send` because this property is per-thread/CPU. +/// +/// # Invariants +/// +/// The RCU read side lock is actually held while instances of this guard exist. +pub struct Guard(NotThreadSafe); + +impl Guard { + /// Acquires the RCU read side lock and returns a guard. + pub fn new() -> Self { + // SAFETY: An FFI call with no additional requirements. + unsafe { bindings::rcu_read_lock() }; + // INVARIANT: The RCU read side lock was just acquired above. + Self(NotThreadSafe) + } + + /// Explicitly releases the RCU read side lock. + pub fn unlock(self) {} +} + +impl Default for Guard { + fn default() -> Self { + Self::new() + } +} + +impl Drop for Guard { + fn drop(&mut self) { + // SAFETY: By the type invariants, the RCU read side is locked, so it is ok to unlock it. + unsafe { bindings::rcu_read_unlock() }; + } +} + +/// Acquires the RCU read side lock. +pub fn read_lock() -> Guard { + Guard::new() +} -- cgit v1.2.3 From 47cb6bf7860ce33bdd000198f8b65cf9fb3324b4 Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Wed, 4 Dec 2024 04:47:49 +0800 Subject: rust: use derive(CoercePointee) on rustc >= 1.84.0 The `kernel` crate relies on both `coerce_unsized` and `dispatch_from_dyn` unstable features. Alice Ryhl has proposed [1] the introduction of the unstable macro `SmartPointer` to reduce such dependence, along with a RFC patch [2]. Since Rust 1.81.0 this macro, later renamed to `CoercePointee` in Rust 1.84.0 [3], has been fully implemented with the naming discussion resolved. This feature is now on track to stabilization in the language. In order to do so, we shall start using this macro in the `kernel` crate to prove the functionality and utility of the macro as the justification of its stabilization. This patch makes this switch in such a way that the crate remains backward compatible with older Rust compiler versions, via the new Kconfig option `RUSTC_HAS_COERCE_POINTEE`. A minimal demonstration example is added to the `samples/rust/rust_print_main.rs` module. Link: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html [1] Link: https://lore.kernel.org/all/20240823-derive-smart-pointer-v1-1-53769cd37239@google.com/ [2] Link: https://github.com/rust-lang/rust/pull/131284 [3] Signed-off-by: Xiangfei Ding Reviewed-by: Fiona Behrens Reviewed-by: Alice Ryhl Link: https://lore.kernel.org/r/20241203205050.679106-2-dingxiangfei2009@gmail.com [ Fixed version to 1.84. Renamed option to `RUSTC_HAS_COERCE_POINTEE` to match `CC_HAS_*` ones. Moved up new config option, closer to the `CC_HAS_*` ones. Simplified Kconfig line. Fixed typos and slightly reworded example and commit. Added Link to PR. - Miguel ] Signed-off-by: Miguel Ojeda --- init/Kconfig | 3 +++ rust/kernel/alloc.rs | 2 +- rust/kernel/lib.rs | 7 ++++--- rust/kernel/list/arc.rs | 9 ++++++--- rust/kernel/sync/arc.rs | 15 +++++++++++---- samples/rust/rust_print_main.rs | 18 ++++++++++++++++++ 6 files changed, 43 insertions(+), 11 deletions(-) (limited to 'rust/kernel/sync') diff --git a/init/Kconfig b/init/Kconfig index e8d2b5128f87..868ffa922b2c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -129,6 +129,9 @@ config CC_HAS_COUNTED_BY # https://github.com/llvm/llvm-project/pull/112636 depends on !(CC_IS_CLANG && CLANG_VERSION < 190103) +config RUSTC_HAS_COERCE_POINTEE + def_bool RUSTC_VERSION >= 108400 + config PAHOLE_VERSION int default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE)) diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs index f2f7f3a53d29..fc9c9c41cd79 100644 --- a/rust/kernel/alloc.rs +++ b/rust/kernel/alloc.rs @@ -123,7 +123,7 @@ pub mod flags { /// [`Allocator`] is designed to be implemented as a ZST; [`Allocator`] functions do not operate on /// an object instance. /// -/// In order to be able to support `#[derive(SmartPointer)]` later on, we need to avoid a design +/// In order to be able to support `#[derive(CoercePointee)]` later on, we need to avoid a design /// that requires an `Allocator` to be instantiated, hence its functions must not contain any kind /// of `self` parameter. /// diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6063f4a3d9c0..545d1170ee63 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -13,11 +13,12 @@ #![no_std] #![feature(arbitrary_self_types)] -#![feature(coerce_unsized)] -#![feature(dispatch_from_dyn)] +#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))] +#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))] #![feature(inline_const)] #![feature(lint_reasons)] -#![feature(unsize)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 3483d8c232c4..13c50df37b89 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -7,7 +7,7 @@ use crate::alloc::{AllocError, Flags}; use crate::prelude::*; use crate::sync::{Arc, ArcBorrow, UniqueArc}; -use core::marker::{PhantomPinned, Unsize}; +use core::marker::PhantomPinned; use core::ops::Deref; use core::pin::Pin; use core::sync::atomic::{AtomicBool, Ordering}; @@ -159,6 +159,7 @@ pub use impl_list_arc_safe; /// /// [`List`]: crate::list::List #[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct ListArc where T: ListArcSafe + ?Sized, @@ -443,18 +444,20 @@ where // This is to allow coercion from `ListArc` to `ListArc` if `T` can be converted to the // dynamically-sized type (DST) `U`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl core::ops::CoerceUnsized> for ListArc where - T: ListArcSafe + Unsize + ?Sized, + T: ListArcSafe + core::marker::Unsize + ?Sized, U: ListArcSafe + ?Sized, { } // This is to allow `ListArc` to be dispatched on when `ListArc` can be coerced into // `ListArc`. +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] impl core::ops::DispatchFromDyn> for ListArc where - T: ListArcSafe + Unsize + ?Sized, + T: ListArcSafe + core::marker::Unsize + ?Sized, U: ListArcSafe + ?Sized, { } diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 9f0b04400e8e..25d2185df4cb 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -26,7 +26,7 @@ use crate::{ use core::{ alloc::Layout, fmt, - marker::{PhantomData, Unsize}, + marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, @@ -125,6 +125,8 @@ mod std_vendor; /// let coerced: Arc = obj; /// # Ok::<(), Error>(()) /// ``` +#[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct Arc { ptr: NonNull>, // NB: this informs dropck that objects of type `ArcInner` may be used in ` as @@ -180,10 +182,12 @@ impl ArcInner { // This is to allow coercion from `Arc` to `Arc` if `T` can be converted to the // dynamically-sized type (DST) `U`. -impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} // This is to allow `Arc` to be dispatched on when `Arc` can be coerced into `Arc`. -impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> for Arc {} // SAFETY: It is safe to send `Arc` to another thread when the underlying `T` is `Sync` because // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs @@ -479,6 +483,8 @@ impl From>> for Arc { /// obj.as_arc_borrow().use_reference(); /// # Ok::<(), Error>(()) /// ``` +#[repr(transparent)] +#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))] pub struct ArcBorrow<'a, T: ?Sized + 'a> { inner: NonNull>, _p: PhantomData<&'a ()>, @@ -486,7 +492,8 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> { // This is to allow `ArcBorrow` to be dispatched on when `ArcBorrow` can be coerced into // `ArcBorrow`. -impl, U: ?Sized> core::ops::DispatchFromDyn> +#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))] +impl, U: ?Sized> core::ops::DispatchFromDyn> for ArcBorrow<'_, T> { } diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs index 7935b4772ec6..7e8af5f176a3 100644 --- a/samples/rust/rust_print_main.rs +++ b/samples/rust/rust_print_main.rs @@ -34,6 +34,24 @@ fn arc_print() -> Result { // Uses `dbg` to print, will move `c` (for temporary debugging purposes). dbg!(c); + { + // `Arc` can be used to delegate dynamic dispatch and the following is an example. + // Both `i32` and `&str` implement `Display`. This enables us to express a unified + // behaviour, contract or protocol on both `i32` and `&str` into a single `Arc` of + // type `Arc`. + + use core::fmt::Display; + fn arc_dyn_print(arc: &Arc) { + pr_info!("Arc says {arc}"); + } + + let a_i32_display: Arc = Arc::new(42i32, GFP_KERNEL)?; + let a_str_display: Arc = a.clone(); + + arc_dyn_print(&a_i32_display); + arc_dyn_print(&a_str_display); + } + // Pretty-prints the debug formatting with lower-case hexadecimal integers. pr_info!("{:#x?}", a); -- cgit v1.2.3 From c6340da3d254ee491fc113d4dc5566bea7bebdf3 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 20 Nov 2024 06:46:00 -0500 Subject: rust: arc: use `NonNull::new_unchecked` There is no need to check (and panic on violations of) the safety requirements on `ForeignOwnable` functions. Avoiding the check is consistent with the implementation of `ForeignOwnable` for `Box`. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-1-80dbadd00951@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 25d2185df4cb..2f3156b6aacf 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -349,9 +349,9 @@ impl ForeignOwnable for Arc { } unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { - // By the safety requirement of this function, we know that `ptr` came from - // a previous call to `Arc::into_foreign`. - let inner = NonNull::new(ptr as *mut ArcInner).unwrap(); + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. @@ -359,10 +359,14 @@ impl ForeignOwnable for Arc { } unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner) }; + // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and // holds a reference count increment that is transferrable to us. - unsafe { Self::from_inner(NonNull::new(ptr as _).unwrap()) } + unsafe { Self::from_inner(inner) } } } -- cgit v1.2.3 From aa991a2a819535a0014e1159b455b64e3db87510 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 20 Nov 2024 06:46:01 -0500 Subject: rust: types: avoid `as` casts Replace `as` casts with `cast{,_mut}` calls which are a bit safer. In one instance, remove an unnecessary `as` cast without replacement. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Acked-by: Danilo Krummrich Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-2-80dbadd00951@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/kbox.rs | 8 ++++---- rust/kernel/sync/arc.rs | 9 +++++---- rust/kernel/types.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 19e227351918..05dd45c4b604 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -356,13 +356,13 @@ where type Borrowed<'a> = &'a T; fn into_foreign(self) -> *const crate::ffi::c_void { - Box::into_raw(self) as _ + Box::into_raw(self).cast() } unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr as _) } + unsafe { Box::from_raw(ptr.cast_mut().cast()) } } unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T { @@ -380,13 +380,13 @@ where fn into_foreign(self) -> *const crate::ffi::c_void { // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() } unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast_mut().cast())) } } unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 2f3156b6aacf..378925e553ec 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -213,10 +213,11 @@ impl Arc { }; let inner = KBox::new(value, flags)?; + let inner = KBox::leak(inner).into(); // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new // `Arc` object. - Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) }) + Ok(unsafe { Self::from_inner(inner) }) } } @@ -345,13 +346,13 @@ impl ForeignOwnable for Arc { type Borrowed<'a> = ArcBorrow<'a, T>; fn into_foreign(self) -> *const crate::ffi::c_void { - ManuallyDrop::new(self).ptr.as_ptr() as _ + ManuallyDrop::new(self).ptr.as_ptr().cast() } unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner) }; + let inner = unsafe { NonNull::new_unchecked(ptr.cast_mut().cast::>()) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. @@ -361,7 +362,7 @@ impl ForeignOwnable for Arc { unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner) }; + let inner = unsafe { NonNull::new_unchecked(ptr.cast_mut().cast::>()) }; // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index ec6457bb3084..318d2140470a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -434,7 +434,7 @@ impl ARef { /// } /// /// let mut data = Empty {}; - /// let ptr = NonNull::::new(&mut data as *mut _).unwrap(); + /// let ptr = NonNull::::new(&mut data).unwrap(); /// # // SAFETY: TODO. /// let data_ref: ARef = unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull = ARef::into_raw(data_ref); -- cgit v1.2.3 From 5d385a356f628bd4a1d9f403588272d9626e3245 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 20 Nov 2024 06:46:02 -0500 Subject: rust: arc: split unsafe block, add missing comment The new SAFETY comment style is taken from existing comments in `deref` and `drop. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-3-80dbadd00951@gmail.com Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 378925e553ec..93eac650146a 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -389,10 +389,14 @@ impl AsRef for Arc { impl Clone for Arc { fn clone(&self) -> Self { + // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is + // safe to dereference it. + let refcount = unsafe { self.ptr.as_ref() }.refcount.get(); + // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero. // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is // safe to increment the refcount. - unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) }; + unsafe { bindings::refcount_inc(refcount) }; // SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`. unsafe { Self::from_inner(self.ptr) } -- cgit v1.2.3 From 14686571a914833e38eef0f907202f58df4ffcd2 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 20 Nov 2024 06:46:03 -0500 Subject: rust: kernel: change `ForeignOwnable` pointer to mut It is slightly more convenient to operate on mut pointers, and this also properly conveys the desired ownership semantics of the trait. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Acked-by: Danilo Krummrich Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-4-80dbadd00951@gmail.com [ Reworded title slightly. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/kbox.rs | 16 ++++++++-------- rust/kernel/miscdevice.rs | 2 +- rust/kernel/sync/arc.rs | 10 +++++----- rust/kernel/types.rs | 14 +++++++------- 4 files changed, 21 insertions(+), 21 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 05dd45c4b604..d811edbf9b3b 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -355,17 +355,17 @@ where { type Borrowed<'a> = &'a T; - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { Box::into_raw(self).cast() } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr.cast_mut().cast()) } + unsafe { Box::from_raw(ptr.cast()) } } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T { // SAFETY: The safety requirements of this method ensure that the object remains alive and // immutable for the duration of 'a. unsafe { &*ptr.cast() } @@ -378,18 +378,18 @@ where { type Borrowed<'a> = Pin<&'a T>; - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { // SAFETY: We are still treating the box as pinned. Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast_mut().cast())) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index 9e1b9c0fae9d..b3a6cc50b240 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -189,7 +189,7 @@ unsafe extern "C" fn fops_open( }; // SAFETY: The open call of a file owns the private data. - unsafe { (*file).private_data = ptr.into_foreign().cast_mut() }; + unsafe { (*file).private_data = ptr.into_foreign() }; 0 } diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 93eac650146a..fe334394c328 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -345,24 +345,24 @@ impl Arc { impl ForeignOwnable for Arc { type Borrowed<'a> = ArcBorrow<'a, T>; - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { ManuallyDrop::new(self).ptr.as_ptr().cast() } - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast_mut().cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast_mut().cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 318d2140470a..f9b398ee31fd 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -29,7 +29,7 @@ pub trait ForeignOwnable: Sized { /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in /// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. - fn into_foreign(self) -> *const crate::ffi::c_void; + fn into_foreign(self) -> *mut crate::ffi::c_void; /// Borrows a foreign-owned object. /// @@ -37,7 +37,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Self::Borrowed<'a>; + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; /// Converts a foreign-owned object back to a Rust-owned one. /// @@ -47,7 +47,7 @@ pub trait ForeignOwnable: Sized { /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for /// this object must have been dropped. - unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -58,7 +58,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must either be null or satisfy the safety requirements for /// [`ForeignOwnable::from_foreign`]. - unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option { + unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { if ptr.is_null() { None } else { @@ -72,13 +72,13 @@ pub trait ForeignOwnable: Sized { impl ForeignOwnable for () { type Borrowed<'a> = (); - fn into_foreign(self) -> *const crate::ffi::c_void { + fn into_foreign(self) -> *mut crate::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn borrow<'a>(_: *const crate::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} - unsafe fn from_foreign(_: *const crate::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} } /// Runs a cleanup function/closure when dropped. -- cgit v1.2.3 From c6b97538c2c0f4de5902b5bb78eb89bd34219df9 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 20 Nov 2024 06:46:04 -0500 Subject: rust: kernel: reorder `ForeignOwnable` items `{into,from}_foreign` before `borrow` is slightly more logical. This removes an inconsistency with `kbox.rs` which already uses this ordering. Reviewed-by: Alice Ryhl Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-5-80dbadd00951@gmail.com [ Reworded title slightly. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/sync/arc.rs | 18 +++++++++--------- rust/kernel/types.rs | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index fe334394c328..e351c701c166 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -349,25 +349,25 @@ impl ForeignOwnable for Arc { ManuallyDrop::new(self).ptr.as_ptr().cast() } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; - // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive - // for the lifetime of the returned value. - unsafe { ArcBorrow::new(inner) } + // SAFETY: By the safety requirement of this function, we know that `ptr` came from + // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and + // holds a reference count increment that is transferrable to us. + unsafe { Self::from_inner(inner) } } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; - // SAFETY: By the safety requirement of this function, we know that `ptr` came from - // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and - // holds a reference count increment that is transferrable to us. - unsafe { Self::from_inner(inner) } + // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive + // for the lifetime of the returned value. + unsafe { ArcBorrow::new(inner) } } } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index f9b398ee31fd..af316e291908 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -31,14 +31,6 @@ pub trait ForeignOwnable: Sized { /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. fn into_foreign(self) -> *mut crate::ffi::c_void; - /// Borrows a foreign-owned object. - /// - /// # Safety - /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; - /// Converts a foreign-owned object back to a Rust-owned one. /// /// # Safety @@ -67,6 +59,14 @@ pub trait ForeignOwnable: Sized { unsafe { Some(Self::from_foreign(ptr)) } } } + + /// Borrows a foreign-owned object. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for + /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. + unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; } impl ForeignOwnable for () { @@ -76,9 +76,9 @@ impl ForeignOwnable for () { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} - unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} + + unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} } /// Runs a cleanup function/closure when dropped. -- cgit v1.2.3 From c27e705cb2b71769dbb4bb1bee1920d2fa01a597 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 20 Nov 2024 06:46:05 -0500 Subject: rust: kernel: add improved version of `ForeignOwnable::borrow_mut` Previously, the `ForeignOwnable` trait had a method called `borrow_mut` that was intended to provide mutable access to the inner value. However, the method accidentally made it possible to change the address of the object being modified, which usually isn't what we want. (And when we want that, it can be done by calling `from_foreign` and `into_foreign`, like how the old `borrow_mut` was implemented.) In this patch, we introduce an alternate definition of `borrow_mut` that solves the previous problem. Conceptually, given a pointer type `P` that implements `ForeignOwnable`, the `borrow_mut` method gives you the same kind of access as an `&mut P` would, except that it does not let you change the pointer `P` itself. This is analogous to how the existing `borrow` method provides the same kind of access to the inner value as an `&P`. Note that for types like `Arc`, having an `&mut Arc` only gives you immutable access to the inner `T`. This is because mutable references assume exclusive access, but there might be other handles to the same reference counted value, so the access isn't exclusive. The `Arc` type implements this by making `borrow_mut` return the same type as `borrow`. Signed-off-by: Alice Ryhl Reviewed-by: Boqun Feng Reviewed-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein Acked-by: Danilo Krummrich Link: https://lore.kernel.org/r/20241120-borrow-mut-v6-6-80dbadd00951@gmail.com [ Updated to `crate::ffi::`. Reworded title slightly. - Miguel ] Signed-off-by: Miguel Ojeda --- rust/kernel/alloc/kbox.rs | 21 ++++++++++++++ rust/kernel/sync/arc.rs | 7 +++++ rust/kernel/types.rs | 71 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 86 insertions(+), 13 deletions(-) (limited to 'rust/kernel/sync') diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index d811edbf9b3b..cb4ebea3b074 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -354,6 +354,7 @@ where A: Allocator, { type Borrowed<'a> = &'a T; + type BorrowedMut<'a> = &'a mut T; fn into_foreign(self) -> *mut crate::ffi::c_void { Box::into_raw(self).cast() @@ -370,6 +371,13 @@ where // immutable for the duration of 'a. unsafe { &*ptr.cast() } } + + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T { + let ptr = ptr.cast(); + // SAFETY: The safety requirements of this method ensure that the pointer is valid and that + // nothing else will access the value for the duration of 'a. + unsafe { &mut *ptr } + } } impl ForeignOwnable for Pin> @@ -377,6 +385,7 @@ where A: Allocator, { type Borrowed<'a> = Pin<&'a T>; + type BorrowedMut<'a> = Pin<&'a mut T>; fn into_foreign(self) -> *mut crate::ffi::c_void { // SAFETY: We are still treating the box as pinned. @@ -399,6 +408,18 @@ where // SAFETY: This pointer originates from a `Pin>`. unsafe { Pin::new_unchecked(r) } } + + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> { + let ptr = ptr.cast(); + // SAFETY: The safety requirements for this function ensure that the object is still alive, + // so it is safe to dereference the raw pointer. + // The safety requirements of `from_foreign` also ensure that the object remains alive for + // the lifetime of the returned value. + let r = unsafe { &mut *ptr }; + + // SAFETY: This pointer originates from a `Pin>`. + unsafe { Pin::new_unchecked(r) } + } } impl Deref for Box diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index e351c701c166..3cefda7a4372 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -344,6 +344,7 @@ impl Arc { impl ForeignOwnable for Arc { type Borrowed<'a> = ArcBorrow<'a, T>; + type BorrowedMut<'a> = Self::Borrowed<'a>; fn into_foreign(self) -> *mut crate::ffi::c_void { ManuallyDrop::new(self).ptr.as_ptr().cast() @@ -369,6 +370,12 @@ impl ForeignOwnable for Arc { // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } + + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety + // requirements for `borrow`. + unsafe { Self::borrow(ptr) } + } } impl Deref for Arc { diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index af316e291908..0dfaf45a755c 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -19,26 +19,33 @@ use core::{ /// This trait is meant to be used in cases when Rust objects are stored in C objects and /// eventually "freed" back to Rust. pub trait ForeignOwnable: Sized { - /// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and - /// [`ForeignOwnable::from_foreign`]. + /// Type used to immutably borrow a value that is currently foreign-owned. type Borrowed<'a>; + /// Type used to mutably borrow a value that is currently foreign-owned. + type BorrowedMut<'a>; + /// Converts a Rust-owned object to a foreign-owned one. /// /// The foreign representation is a pointer to void. There are no guarantees for this pointer. /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in - /// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], - /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. + /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can + /// result in undefined behavior. + /// + /// [`from_foreign`]: Self::from_foreign + /// [`try_from_foreign`]: Self::try_from_foreign + /// [`borrow`]: Self::borrow + /// [`borrow_mut`]: Self::borrow_mut fn into_foreign(self) -> *mut crate::ffi::c_void; /// Converts a foreign-owned object back to a Rust-owned one. /// /// # Safety /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for - /// this object must have been dropped. + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and it + /// must not be passed to `from_foreign` more than once. + /// + /// [`into_foreign`]: Self::into_foreign unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. @@ -48,8 +55,9 @@ pub trait ForeignOwnable: Sized { /// /// # Safety /// - /// `ptr` must either be null or satisfy the safety requirements for - /// [`ForeignOwnable::from_foreign`]. + /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. + /// + /// [`from_foreign`]: Self::from_foreign unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { if ptr.is_null() { None @@ -60,17 +68,53 @@ pub trait ForeignOwnable: Sized { } } - /// Borrows a foreign-owned object. + /// Borrows a foreign-owned object immutably. + /// + /// This method provides a way to access a foreign-owned value from Rust immutably. It provides + /// you with exactly the same abilities as an `&Self` when the value is Rust-owned. /// /// # Safety /// - /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for - /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and if + /// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of + /// the lifetime 'a. + /// + /// [`into_foreign`]: Self::into_foreign + /// [`from_foreign`]: Self::from_foreign unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; + + /// Borrows a foreign-owned object mutably. + /// + /// This method provides a way to access a foreign-owned value from Rust mutably. It provides + /// you with exactly the same abilities as an `&mut Self` when the value is Rust-owned, except + /// that the address of the object must not be changed. + /// + /// Note that for types like [`Arc`], an `&mut Arc` only gives you immutable access to the + /// inner value, so this method also only provides immutable access in that case. + /// + /// In the case of `Box`, this method gives you the ability to modify the inner `T`, but it + /// does not let you change the box itself. That is, you cannot change which allocation the box + /// points at. + /// + /// # Safety + /// + /// The provided pointer must have been returned by a previous call to [`into_foreign`], and if + /// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of + /// the lifetime 'a. + /// + /// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or + /// `borrow_mut` on the same object. + /// + /// [`into_foreign`]: Self::into_foreign + /// [`from_foreign`]: Self::from_foreign + /// [`borrow`]: Self::borrow + /// [`Arc`]: crate::sync::Arc + unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>; } impl ForeignOwnable for () { type Borrowed<'a> = (); + type BorrowedMut<'a> = (); fn into_foreign(self) -> *mut crate::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() @@ -79,6 +123,7 @@ impl ForeignOwnable for () { unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {} } /// Runs a cleanup function/closure when dropped. -- cgit v1.2.3