Message ID | 20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | rust: page: Support borrowing `struct page` and physaddr conversion | expand |
On Sun, Feb 2, 2025 at 2:06 PM Asahi Lina <lina@asahilina.net> wrote: > > 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. > > Signed-off-by: Asahi Lina <lina@asahilina.net> Overall LGTM. > +/// 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 {} Giving out mutable references allows users to call core::mem::swap on the object. We must require that this is allowed. > +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(crate) 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`. > + #[allow(dead_code)] > + pub(crate) fn into_raw(me: Self) -> NonNull<T> { I would just make these methods public, like the ARef ones. Then you can drop the #[allow(dead_code)] annotation. Alice
On 2/3/25 6:13 PM, Alice Ryhl wrote: > On Sun, Feb 2, 2025 at 2:06 PM Asahi Lina <lina@asahilina.net> wrote: >> >> 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. >> >> Signed-off-by: Asahi Lina <lina@asahilina.net> > > Overall LGTM. > >> +/// 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 {} > > Giving out mutable references allows users to call core::mem::swap on > the object. We must require that this is allowed. Hmm, yeah. I don't use this yet, and I'm not sure if it makes much sense with that caveat. I'll drop it for v2. > >> +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(crate) 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`. >> + #[allow(dead_code)] >> + pub(crate) fn into_raw(me: Self) -> NonNull<T> { > > I would just make these methods public, like the ARef ones. Then you > can drop the #[allow(dead_code)] annotation. Does it make sense to ever have drivers doing this? I feel like these methods should be limited to the kernel crate. ~~ Lina
On Mon, Feb 3, 2025 at 3:17 PM Asahi Lina <lina@asahilina.net> wrote: > > > > On 2/3/25 6:13 PM, Alice Ryhl wrote: > > On Sun, Feb 2, 2025 at 2:06 PM Asahi Lina <lina@asahilina.net> wrote: > >> + /// 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`. > >> + #[allow(dead_code)] > >> + pub(crate) fn into_raw(me: Self) -> NonNull<T> { > > > > I would just make these methods public, like the ARef ones. Then you > > can drop the #[allow(dead_code)] annotation. > > Does it make sense to ever have drivers doing this? I feel like these > methods should be limited to the kernel crate. Not having drivers use this is the ideal, but I don't think we should always expect it to be possible. The Binder driver has a C component for the binderfs component, and it also has some code that's essentially an abstraction inside the driver that I was asked to move into Binder because it's so specific to Binder that it's not useful for anyone else. Alice
On 2/4/25 3:17 AM, Alice Ryhl wrote: > On Mon, Feb 3, 2025 at 3:17 PM Asahi Lina <lina@asahilina.net> wrote: >> >> >> >> On 2/3/25 6:13 PM, Alice Ryhl wrote: >>> On Sun, Feb 2, 2025 at 2:06 PM Asahi Lina <lina@asahilina.net> wrote: >>>> + /// 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`. >>>> + #[allow(dead_code)] >>>> + pub(crate) fn into_raw(me: Self) -> NonNull<T> { >>> >>> I would just make these methods public, like the ARef ones. Then you >>> can drop the #[allow(dead_code)] annotation. >> >> Does it make sense to ever have drivers doing this? I feel like these >> methods should be limited to the kernel crate. > > Not having drivers use this is the ideal, but I don't think we should > always expect it to be possible. The Binder driver has a C component > for the binderfs component, and it also has some code that's > essentially an abstraction inside the driver that I was asked to move > into Binder because it's so specific to Binder that it's not useful > for anyone else. That's fair, I'll make it pub. ~~ Lina
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index ec6457bb3084ae327c38ba4ba79b1601aef38244..0bee56153dcea47fb1321162df6b8765b5436e9f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -479,6 +479,116 @@ 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 +/// 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> { + 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(crate) 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`. + #[allow(dead_code)] + pub(crate) 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: Ownable + 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) }; + } +} + /// A sum type that always holds either a value of type `L` or `R`. /// /// # Examples
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. Signed-off-by: Asahi Lina <lina@asahilina.net> --- rust/kernel/types.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+)