On Mon, 17 Nov 2025 10:07:40 +0000 Oliver Mangold <[email protected]> wrote:
> From: Asahi Lina <[email protected]> > > By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a > (typically C FFI) type that *may* be owned by Rust, but need not be. Unlike > `AlwaysRefCounted`, this mechanism expects the reference to be unique > within Rust, and does not allow cloning. > > Conceptually, this is similar to a `KBox<T>`, except that it delegates > resource management to the `T` instead of using a generic allocator. > > [ om: > - Split code into separate file and `pub use` it from types.rs. > - Make from_raw() and into_raw() public. > - Remove OwnableMut, and make DerefMut dependent on Unpin instead. > - Usage example/doctest for Ownable/Owned. > - Fixes to documentation and commit message. > ] > > Link: > https://lore.kernel.org/all/[email protected]/ > Signed-off-by: Asahi Lina <[email protected]> > Co-developed-by: Oliver Mangold <[email protected]> > Signed-off-by: Oliver Mangold <[email protected]> > Co-developed-by: Andreas Hindborg <[email protected]> > Signed-off-by: Andreas Hindborg <[email protected]> > Reviewed-by: Boqun Feng <[email protected]> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/owned.rs | 195 > +++++++++++++++++++++++++++++++++++++++++++++++ > rust/kernel/sync/aref.rs | 5 ++ > rust/kernel/types.rs | 2 + > 4 files changed, 203 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index 3dd7bebe7888..e0ee04330dd0 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -112,6 +112,7 @@ > pub mod of; > #[cfg(CONFIG_PM_OPP)] > pub mod opp; > +pub mod owned; > pub mod page; > #[cfg(CONFIG_PCI)] > pub mod pci; > diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs > new file mode 100644 > index 000000000000..a2cdd2cb8a10 > --- /dev/null > +++ b/rust/kernel/owned.rs > @@ -0,0 +1,195 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! Unique owned pointer types for objects with custom drop logic. > +//! > +//! These pointer types are useful for C-allocated objects which by > API-contract > +//! are owned by Rust, but need to be freed through the C API. > + > +use core::{ > + mem::ManuallyDrop, > + ops::{Deref, DerefMut}, > + pin::Pin, > + ptr::NonNull, > +}; > + > +/// Type allocated and destroyed on the C side, but owned by Rust. The example given in the documentation below shows a valid way of defining a type that's handled on the Rust side, so I think this message is somewhat inaccurate. Perhaps something like Types that specify their own way of performing allocation and destruction. Typically, this trait is implemented on types from the C side. ? > +/// > +/// Implementing this trait allows types to be referenced via the > [`Owned<Self>`] pointer type. This > +/// is useful when it is desirable to tie the lifetime of the reference to > an owned object, rather > +/// than pass around a bare reference. [`Ownable`] types can define custom > drop logic that is > +/// executed when the owned reference [`Owned<Self>`] pointing to the object > is dropped. > +/// > +/// Note: The underlying object is not required to provide internal > reference counting, because it > +/// represents a unique, owned reference. If reference counting (on the Rust > side) is required, > +/// [`AlwaysRefCounted`](crate::types::AlwaysRefCounted) should be > implemented. > +/// > +/// # Safety > +/// > +/// Implementers must ensure that the [`release()`](Self::release) function > frees the underlying > +/// object in the correct way for a valid, owned object of this type. > +/// > +/// # Examples > +/// > +/// A minimal example implementation of [`Ownable`] and its usage with > [`Owned`] looks like this: > +/// > +/// ``` > +/// # #![expect(clippy::disallowed_names)] > +/// # use core::cell::Cell; > +/// # use core::ptr::NonNull; > +/// # use kernel::sync::global_lock; > +/// # use kernel::alloc::{flags, kbox::KBox, AllocError}; > +/// # use kernel::types::{Owned, Ownable}; > +/// > +/// // Let's count the allocations to see if freeing works. > +/// kernel::sync::global_lock! { > +/// // SAFETY: we call `init()` right below, before doing anything else. > +/// unsafe(uninit) static FOO_ALLOC_COUNT: Mutex<usize> = 0; > +/// } > +/// // SAFETY: We call `init()` only once, here. > +/// unsafe { FOO_ALLOC_COUNT.init() }; > +/// > +/// struct Foo { > +/// } > +/// > +/// impl Foo { > +/// fn new() -> Result<Owned<Self>, AllocError> { > +/// // We are just using a `KBox` here to handle the actual > allocation, as our `Foo` is > +/// // not actually a C-allocated object. > +/// let result = KBox::new( > +/// Foo {}, > +/// flags::GFP_KERNEL, > +/// )?; > +/// let result = NonNull::new(KBox::into_raw(result)) > +/// .expect("Raw pointer to newly allocation KBox is null, this > should never happen."); > +/// // Count new allocation > +/// *FOO_ALLOC_COUNT.lock() += 1; > +/// // SAFETY: We just allocated the `Self`, thus it is valid and > there cannot be any other > +/// // Rust references. Calling `into_raw()` makes us responsible > for ownership and we won't > +/// // use the raw pointer anymore. Thus we can transfer ownership > to the `Owned`. > +/// Ok(unsafe { Owned::from_raw(result) }) > +/// } > +/// } > +/// > +/// // SAFETY: What out `release()` function does is safe of any valid > `Self`. I can't parse this sentence. Is "out" supposed to be a different word? > +/// unsafe impl Ownable for Foo { > +/// unsafe fn release(this: NonNull<Self>) { > +/// // The `Foo` will be dropped when `KBox` goes out of scope. I would just write `drop(unsafe { ... })` to make drop explicit instead of commenting about the implicit drop. > +/// // SAFETY: The [`KBox<Self>`] is still alive. We can pass > ownership to the [`KBox`], as > +/// // by requirement on calling this function, the `Self` will no > longer be used by the > +/// // caller. > +/// unsafe { KBox::from_raw(this.as_ptr()) }; > +/// // Count released allocation > +/// *FOO_ALLOC_COUNT.lock() -= 1; > +/// } > +/// } > +/// > +/// { > +/// let foo = Foo::new().expect("Failed to allocate a Foo. This shouldn't > happen"); > +/// assert!(*FOO_ALLOC_COUNT.lock() == 1); > +/// } > +/// // `foo` is out of scope now, so we expect no live allocations. > +/// assert!(*FOO_ALLOC_COUNT.lock() == 0); > +/// ``` > +pub unsafe trait Ownable { > + /// Releases the object. > + /// > + /// # Safety > + /// > + /// Callers must ensure that: > + /// - `this` points to a valid `Self`. > + /// - `*this` is no longer used after this call. > + unsafe fn release(this: NonNull<Self>); > +} > + > +/// An owned reference to an owned `T`. > +/// > +/// The [`Ownable`] is automatically freed or released when an instance of > [`Owned`] is > +/// dropped. > +/// > +/// # Invariants > +/// > +/// - The [`Owned<T>`] has exclusive access to the instance of `T`. > +/// - The instance of `T` will stay alive at least as long as the > [`Owned<T>`] is alive. > +pub struct Owned<T: Ownable> { > + ptr: NonNull<T>, > +} > + > +// SAFETY: It is safe to send an [`Owned<T>`] to another thread when the > underlying `T` is [`Send`], > +// because of the ownership invariant. Sending an [`Owned<T>`] is equivalent > to sending the `T`. > +unsafe impl<T: Ownable + Send> Send for Owned<T> {} > + > +// SAFETY: It is safe to send [`&Owned<T>`] to another thread when the > underlying `T` is [`Sync`], > +// because of the ownership invariant. Sending an [`&Owned<T>`] is > equivalent to sending the `&T`. > +unsafe impl<T: Ownable + Sync> Sync for Owned<T> {} > + > +impl<T: Ownable> Owned<T> { > + /// Creates a new instance of [`Owned`]. > + /// > + /// It takes over ownership of the underlying object. > + /// > + /// # Safety > + /// > + /// Callers must ensure that: > + /// - `ptr` points to a valid instance of `T`. > + /// - Ownership of the underlying `T` can be transferred to the > `Self<T>` (i.e. operations > + /// which require ownership will be safe). > + /// - No other Rust references to the underlying object exist. This > implies that the underlying > + /// object is not accessed through `ptr` anymore after the function > call (at least until the > + /// the `Self<T>` is dropped. Is this correct? If `Self<T>` is dropped then `T::release` is called so the pointer should also not be accessed further? > + /// - The C code follows the usual shared reference requirements. That > is, the kernel will never > + /// mutate or free the underlying object (excluding interior > mutability that follows the usual > + /// rules) while Rust owns it. The concept "interior mutability" doesn't really exist on the C side. Also, use of interior mutability (by UnsafeCell) would be incorrect if the type is implemented in the rust side (as this requires a UnsafePinned). Interior mutability means things can be mutated behind a shared reference -- however in this case, we have a mutable reference (either `Pin<&mut Self>` or `&mut Self`)! Perhaps together with the next line, they could be just phrased like this? - The underlying object must not be accessed (read or mutated) through any pointer other than the created `Owned<T>`. Opt-out is still possbile similar to a mutable reference (e.g. by using p`Opaque`]). I think we should just tell the user "this is just a unique reference similar to &mut". They should be able to deduce that all the `!Unpin` that opts out from uniqueness of mutable reference applies here too. > + /// - In case `T` implements [`Unpin`] the previous requirement is > extended from shared to > + /// mutable reference requirements. That is, the kernel will not > mutate or free the underlying > + /// object and is okay with it being modified by Rust code. - If `T` implements [`Unpin`], the structure must not be mutated for the entire lifetime of `Owned<T>`. > + pub unsafe fn from_raw(ptr: NonNull<T>) -> Self { This needs a (rather trivial) INVARIANT comment. > + Self { > + ptr, > + } > + } > + > + /// Consumes the [`Owned`], returning a raw pointer. > + /// > + /// This function does not actually relinquish ownership of the object. > After calling this Perhaps "relinquish" isn't the best word here? In my mental model this function is pretty much relinquishing ownership as `Owned<T>` no longer exists. It just doesn't release the object. > + /// function, the caller is responsible for ownership previously managed > + /// by the [`Owned`]. > + pub fn into_raw(me: Self) -> NonNull<T> { > + ManuallyDrop::new(me).ptr > + } > + > + /// Get a pinned mutable reference to the data owned by this `Owned<T>`. > + pub fn get_pin_mut(&mut self) -> Pin<&mut T> { > + // SAFETY: The type invariants guarantee that the object is valid, > and that we can safely > + // return a mutable reference to it. > + let unpinned = unsafe { self.ptr.as_mut() }; > + > + // SAFETY: We never hand out unpinned mutable references to the data > in > + // `Self`, unless the contained type is `Unpin`. > + unsafe { Pin::new_unchecked(unpinned) } > + } > +} Best, Gary
