All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boqun Feng <boqun.feng@gmail.com>
To: Oliver Mangold <oliver.mangold@pm.me>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Asahi Lina" <lina@asahilina.net>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v8 1/4] rust: types: Add Ownable/Owned types
Date: Fri, 21 Mar 2025 09:08:25 -0700	[thread overview]
Message-ID: <67dd8efb.050a0220.11e64e.7506@mx.google.com> (raw)
In-Reply-To: <20250313-unique-ref-v8-1-3082ffc67a31@pm.me>

On Thu, Mar 13, 2025 at 07:00:04AM +0000, Oliver Mangold wrote:
> From: Asahi Lina <lina@asahilina.net>
> 
> 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.
> 
> Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net/
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> [ om: make from_raw() and into_raw() public, small fixes to documentation ]
> Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
> ---
>  rust/kernel/types.rs | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 109 insertions(+)
> 
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index 55ddd50e8aaa075ac33d5f1088a7f72df05f74f4..65f6d0721f5f23c8db79c6735dc7d5e1ac984ea7 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -551,6 +551,115 @@ fn drop(&mut self) {
>      }
>  }
>  
> +/// Types that may be owned by Rust code or borrowed, but have a lifetime managed by C code.
> +///
> +/// It allows such types to define their own custom destructor function to be called when
> +/// a Rust-owned reference is dropped.
> +///
> +/// This is usually implemented by wrappers to existing structures on the C side of the code.
> +///
> +/// # Safety
> +///
> +/// Implementers must ensure that any objects borrowed directly as `&T` stay alive for the duration

It may be more clear to use `&Ownable` instead of `&T`, but I will wait
and see if others have better ideas.

> +/// of the lifetime, and that any objects owned by Rust as [`Owned<T>`] stay alive while that owned
> +/// reference exists, until the [`Ownable::release()`] trait method is called.
> +pub unsafe trait Ownable {
> +    /// Releases the object (frees it or returns it to foreign ownership).
> +    ///
> +    /// # Safety
> +    ///
> +    /// Callers must ensure that the object is no longer referenced after this call.
> +    unsafe fn release(this: NonNull<Self>);
> +}
> +
> +/// A subtrait of Ownable that asserts that an [`Owned<T>`] Rust reference is not only unique
> +/// within Rust and keeps the `T` alive, but also guarantees that the C code follows the
> +/// usual mutable reference requirements. That is, the kernel will never mutate the
> +/// `T` (excluding internal mutability that follows the usual rules) while Rust owns it.
> +///
> +/// When this type is implemented for an [`Ownable`] type, it allows [`Owned<T>`] to be
> +/// dereferenced into a &mut T.
> +///
> +/// # Safety
> +///
> +/// Implementers must ensure that the kernel never mutates the underlying type while
> +/// Rust owns it.
> +pub unsafe trait OwnableMut: Ownable {}
> +
> +/// An owned reference to an ownable kernel object.
> +///
> +/// The object is automatically freed or released when an instance of [`Owned`] is
> +/// dropped.
> +///
> +/// # Invariants
> +///
> +/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`Owned`] instance.
> +pub struct Owned<T: Ownable> {

This can be:

	pub struct Owned<T: Ownable + ?Sized>

right? Hmm.. but `ARef` doesn't support trait objects yet. Maybe it
makes sense to support for both `Owned` and `ARef` later?

> +    ptr: NonNull<T>,
> +    _p: PhantomData<T>,
> +}
> +
> +// SAFETY: It is safe to send `Owned<T>` to another thread when the underlying `T` is `Send` because
> +// it effectively means sending a unique `&mut T` pointer (which is safe because `T` is `Send`).
> +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 it effectively means sharing `&T` (which is safe because `T` is `Sync`).
> +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 the underlying object is acquired and can be considered owned by
> +    /// Rust.
> +    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
> +        // INVARIANT: The safety requirements guarantee that the new instance now owns the
> +        // reference.
> +        Self {
> +            ptr,
> +            _p: PhantomData,
> +        }
> +    }
> +
> +    /// Consumes the [`Owned`], returning a raw pointer.
> +    ///
> +    /// This function does not actually relinquish ownership of the object.
> +    /// After calling this function, the caller is responsible for ownership previously managed
> +    /// by the [`Owned`].
> +    pub fn into_raw(me: Self) -> NonNull<T> {
> +        ManuallyDrop::new(me).ptr
> +    }
> +}
> +
> +impl<T: Ownable> Deref for Owned<T> {
> +    type Target = T;
> +
> +    fn deref(&self) -> &Self::Target {
> +        // SAFETY: The type invariants guarantee that the object is valid.
> +        unsafe { self.ptr.as_ref() }
> +    }
> +}
> +
> +impl<T: OwnableMut> DerefMut for Owned<T> {
> +    fn deref_mut(&mut self) -> &mut Self::Target {
> +        // SAFETY: The type invariants guarantee that the object is valid,
> +        // and that we can safely return a mutable reference to it.
> +        unsafe { self.ptr.as_mut() }
> +    }
> +}
> +
> +impl<T: Ownable> Drop for Owned<T> {
> +    fn drop(&mut self) {
> +        // SAFETY: The type invariants guarantee that the `Owned` owns the object we're about to
> +        // release.
> +        unsafe { T::release(self.ptr) };
> +    }
> +}
> +

Reviewed-by: Boqun Feng <boqun.feng@gmail.com>

Regards,
Boqun

>  /// A sum type that always holds either a value of type `L` or `R`.
>  ///
>  /// # Examples
> 
> -- 
> 2.48.1
> 
> 

  reply	other threads:[~2025-03-21 16:08 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <GwULoA3hxsCsNdxJ4lw7WqNC5bhCMacx5xMre9hZV2GWDdYmQx9rYVzHadna4KGiko3Glypv-AeXUsoECQB-EA==@protonmail.internalid>
2025-03-13  6:59 ` [PATCH v8 0/4] New trait OwnableRefCounted for ARef<->Owned conversion Oliver Mangold
2025-03-13  7:00   ` [PATCH v8 1/4] rust: types: Add Ownable/Owned types Oliver Mangold
2025-03-21 16:08     ` Boqun Feng [this message]
2025-03-25 12:00       ` Oliver Mangold
2025-03-23 20:46     ` Andreas Hindborg
2025-03-13  7:00   ` [PATCH v8 2/4] rust: rename AlwaysRefCounted to RefCounted Oliver Mangold
2025-03-21 16:20     ` Boqun Feng
2025-03-24  7:32       ` Oliver Mangold
2025-03-13  7:00   ` [PATCH v8 3/4] rust: kbuild: provide `RUSTC_HAS_DO_NOT_RECOMMEND` symbol Oliver Mangold
2025-03-13  7:00   ` [PATCH v8 4/4] rust: adding OwnableRefCounted and SimpleOwnableRefCounted Oliver Mangold
2025-03-21 16:37     ` Boqun Feng
2025-03-24  7:59       ` Oliver Mangold
2025-03-23 20:19   ` [PATCH v8 0/4] New trait OwnableRefCounted for ARef<->Owned conversion Andreas Hindborg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=67dd8efb.050a0220.11e64e.7506@mx.google.com \
    --to=boqun.feng@gmail.com \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=gary@garyguo.net \
    --cc=lina@asahilina.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=oliver.mangold@pm.me \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.