diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs index 06d1bd4a796a81..949a7d9206297a 100644 --- a/rust/kernel/of.rs +++ b/rust/kernel/of.rs @@ -60,6 +60,8 @@ impl OfMatchTable { } impl PointerWrapper for OfMatchTable { + type Borrowed = ::Borrowed; + fn into_pointer(self) -> *const c_types::c_void { // Per the invariant above, the generated pointer points to an // array of `bindings::of_device_id`, where the final element is @@ -68,6 +70,12 @@ impl PointerWrapper for OfMatchTable { self.0.into_pointer() } + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { + // SAFETY: The safety requirements for this function are the same as the ones for + // `InnerTable::borrow`. + unsafe { InnerTable::borrow(ptr) } + } + unsafe fn from_pointer(p: *const c_types::c_void) -> Self { // SAFETY: The passed pointer comes from a previous call to [`InnerTable::into_pointer()`]. Self(unsafe { InnerTable::from_pointer(p) }) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 027a91812c7b0c..821ccd4b571f4a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -4,13 +4,12 @@ //! //! C header: [`include/linux/types.h`](../../../../include/linux/types.h) -use core::{ops::Deref, pin::Pin}; - +use crate::{ + bindings, c_types, + sync::{Ref, RefCounted}, +}; use alloc::{boxed::Box, sync::Arc}; - -use crate::bindings; -use crate::c_types; -use crate::sync::{Ref, RefCounted}; +use core::{ops::Deref, pin::Pin, ptr::NonNull}; /// Permissions. /// @@ -37,9 +36,22 @@ impl Mode { /// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct /// file::private_data`. pub trait PointerWrapper { + /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and + /// [`PointerWrapper::from_pointer`]. + type Borrowed: Deref; + /// Returns the raw pointer. fn into_pointer(self) -> *const c_types::c_void; + /// Returns a borrowed value. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`PointerWrapper::into_pointer`]. + /// Additionally, [`PointerWrapper::from_pointer`] can only be called after *all* values + /// returned by [`PointerWrapper::borrow`] have been dropped. + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed; + /// Returns the instance back from the raw pointer. /// /// # Safety @@ -49,10 +61,20 @@ pub trait PointerWrapper { } impl PointerWrapper for Box { + type Borrowed = UnsafeReference; + fn into_pointer(self) -> *const c_types::c_void { Box::into_raw(self) as _ } + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { + // 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 also ensure that the object remains alive for the lifetime of + // the returned value. + unsafe { UnsafeReference::new(&*ptr.cast()) } + } + unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. unsafe { Box::from_raw(ptr as _) } @@ -60,10 +82,20 @@ impl PointerWrapper for Box { } impl PointerWrapper for Ref { + type Borrowed = UnsafeReference; + fn into_pointer(self) -> *const c_types::c_void { Ref::into_raw(self) as _ } + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { + // 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 also ensure that the object remains alive for the lifetime of + // the returned value. + unsafe { UnsafeReference::new(&*ptr.cast()) } + } + unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. unsafe { Ref::from_raw(ptr as _) } @@ -71,17 +103,66 @@ impl PointerWrapper for Ref { } impl PointerWrapper for Arc { + type Borrowed = UnsafeReference; + fn into_pointer(self) -> *const c_types::c_void { Arc::into_raw(self) as _ } + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { + // 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 also ensure that the object remains alive for the lifetime of + // the returned value. + unsafe { UnsafeReference::new(&*ptr.cast()) } + } + unsafe fn from_pointer(ptr: *const c_types::c_void) -> Self { // SAFETY: The passed pointer comes from a previous call to [`Self::into_pointer()`]. unsafe { Arc::from_raw(ptr as _) } } } +/// A reference with manually-managed lifetime. +/// +/// # Invariants +/// +/// There are no mutable references to the underlying object, and it remains valid for the lifetime +/// of the [`UnsafeReference`] instance. +pub struct UnsafeReference { + ptr: NonNull, +} + +impl UnsafeReference { + /// Creates a new [`UnsafeReference`] instance. + /// + /// # Safety + /// + /// Callers must ensure the following for the lifetime of the returned [`UnsafeReference`] + /// instance: + /// 1. That `obj` remains valid; + /// 2. That no mutable references to `obj` are created. + unsafe fn new(obj: &T) -> Self { + // INVARIANT: The safety requirements of this function ensure that the invariants hold. + Self { + ptr: NonNull::from(obj), + } + } +} + +impl Deref for UnsafeReference { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: By the type invariant, the object is still valid and alive, and there are no + // mutable references to it. + unsafe { self.ptr.as_ref() } + } +} + impl PointerWrapper for Pin { + type Borrowed = T::Borrowed; + fn into_pointer(self) -> *const c_types::c_void { // SAFETY: We continue to treat the pointer as pinned by returning just a pointer to it to // the caller. @@ -89,6 +170,12 @@ impl PointerWrapper for Pin { inner.into_pointer() } + unsafe fn borrow(ptr: *const c_types::c_void) -> Self::Borrowed { + // SAFETY: The safety requirements for this function are the same as the ones for + // `T::borrow`. + unsafe { T::borrow(ptr) } + } + unsafe fn from_pointer(p: *const c_types::c_void) -> Self { // SAFETY: The object was originally pinned. // The passed pointer comes from a previous call to `inner::into_pointer()`.