Skip to content

Commit

Permalink
Merge pull request torvalds#386 from wedsonaf/borrowed
Browse files Browse the repository at this point in the history
rust: enhance `PointerWrapper`.
  • Loading branch information
wedsonaf authored Jun 23, 2021
2 parents c93f25f + 20bf0d4 commit 3c47616
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 6 deletions.
8 changes: 8 additions & 0 deletions rust/kernel/of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ impl OfMatchTable {
}

impl PointerWrapper for OfMatchTable {
type Borrowed = <InnerTable as PointerWrapper>::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
Expand All @@ -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) })
Expand Down
99 changes: 93 additions & 6 deletions rust/kernel/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -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
Expand All @@ -49,46 +61,121 @@ pub trait PointerWrapper {
}

impl<T> PointerWrapper for Box<T> {
type Borrowed = UnsafeReference<T>;

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 _) }
}
}

impl<T: RefCounted> PointerWrapper for Ref<T> {
type Borrowed = UnsafeReference<T>;

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 _) }
}
}

impl<T> PointerWrapper for Arc<T> {
type Borrowed = UnsafeReference<T>;

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<T: ?Sized> {
ptr: NonNull<T>,
}

impl<T: ?Sized> UnsafeReference<T> {
/// 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<T: ?Sized> Deref for UnsafeReference<T> {
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<T: PointerWrapper + Deref> PointerWrapper for Pin<T> {
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.
let inner = unsafe { Pin::into_inner_unchecked(self) };
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()`.
Expand Down

0 comments on commit 3c47616

Please sign in to comment.