Skip to content

Commit 7c271c9

Browse files
committed
rust: add UnsafePinned type
`UnsafePinned<T>` is useful for cases where a value might be shared with C code but not directly used by it. In particular this is added for storing additional data in the `MiscDeviceRegistration` which will be shared between `fops->open` and the containing struct. Similar to `Opaque` but guarantees that the value is always initialized and that the inner value is dropped when `UnsafePinned` is dropped. This was originally proposed for the IRQ abstractions [0] and is also useful for other where the inner data may be aliased, but is always valid and automatic `Drop` is desired. Since then the `UnsafePinned` type was added to upstream Rust [1] by Sky as a unstable feature, therefore this patch implements the subset of the upstream API for the `UnsafePinned` type required for additional data in `MiscDeviceRegistration` and in the implementation of the `Opaque` type. Some differences to the upstream type definition are required in the kernel implementation, because upstream type uses some compiler changes to opt out of certain optimizations, this is documented in the documentation and a comment on the `UnsafePinned` type. The documentation on is based on the upstream rust documentation with minor modifications for the kernel implementation. Link: https://lore.kernel.org/rust-for-linux/CAH5fLgiOASgjoYKFz6kWwzLaH07DqP2ph+3YyCDh2+gYqGpABA@mail.gmail.com [0] Link: rust-lang/rust#137043 [1] Suggested-by: Alice Ryhl <[email protected]> Reviewed-by: Gerald Wisböck <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Co-developed-by: Sky <[email protected]> Signed-off-by: Sky <[email protected]> Signed-off-by: Christian Schrefl <[email protected]>
1 parent 5afc8e8 commit 7c271c9

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

rust/kernel/types.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
269269
///
270270
/// [`Opaque<T>`] is meant to be used with FFI objects that are never interpreted by Rust code.
271271
///
272+
/// In cases where the contained data is only used by Rust, is not allowed to be
273+
/// uninitialized and automatic [`Drop`] is desired [`UnsafePinned`] should be used instead.
274+
///
272275
/// It is used to wrap structs from the C side, like for example `Opaque<bindings::mutex>`.
273276
/// It gets rid of all the usual assumptions that Rust has for a value:
274277
///
@@ -594,3 +597,6 @@ pub type NotThreadSafe = PhantomData<*mut ()>;
594597
/// [`NotThreadSafe`]: type@NotThreadSafe
595598
#[allow(non_upper_case_globals)]
596599
pub const NotThreadSafe: NotThreadSafe = PhantomData;
600+
601+
mod unsafe_pinned;
602+
pub use unsafe_pinned::UnsafePinned;

rust/kernel/types/unsafe_pinned.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
3+
//! The contents of this file partially come from the Rust standard library, hosted in
4+
//! the <https://github.com/rust-lang/rust> repository, licensed under
5+
//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
6+
//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
7+
//!
8+
//! This file provides a implementation / polyfill of a subset of the upstream
9+
//! rust `UnsafePinned` type. For details on the difference to the upstream
10+
//! implementation see the comment on the [`UnsafePinned`] struct definition.
11+
12+
use core::{cell::UnsafeCell, marker::PhantomPinned};
13+
use pin_init::{cast_pin_init, PinInit, Wrapper};
14+
15+
/// This type provides a way to entirely opt-out of typical aliasing rules;
16+
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
17+
/// This also subsumes the effects of `UnsafeCell`, i.e., `&UnsafePinned<T>` may point to data
18+
/// that is being mutated.
19+
///
20+
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
21+
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
22+
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
23+
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
24+
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
25+
/// control! Techniques such as pinning via [`Pin`](core::pin::Pin) are needed to ensure soundness.
26+
///
27+
/// Similar to [`UnsafeCell`], [`UnsafePinned`] will not usually show up in
28+
/// the public API of a library. It is an internal implementation detail of libraries that need to
29+
/// support aliasing mutable references.
30+
///
31+
/// This type blocks niches the same way [`UnsafeCell`] does.
32+
///
33+
/// # Kernel implementation notes
34+
///
35+
/// This implementation works because of the "`!Unpin` hack" in rustc, which allows (some kinds of)
36+
/// mutual aliasing of `!Unpin` types. This hack might be removed at some point, after which only
37+
/// the `core::pin::UnsafePinned` type will allow this behavior. In order to simplify the migration
38+
/// to future rust versions only this polyfill of this type should be used when this behavior is
39+
/// required.
40+
//
41+
// As opposed to the upstream Rust type this contains a `PhantomPinned` to ensure the struct always
42+
// is `!Unpin` the upstream type has a explicit impl `impl !Unpin for UnsafePinned`.
43+
#[repr(transparent)]
44+
pub struct UnsafePinned<T: ?Sized> {
45+
_ph: PhantomPinned,
46+
value: UnsafeCell<T>,
47+
}
48+
49+
impl<T> UnsafePinned<T> {
50+
/// Constructs a new instance of [`UnsafePinned`] which will wrap the specified value.
51+
///
52+
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
53+
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
54+
#[inline(always)]
55+
#[must_use]
56+
pub const fn new(value: T) -> Self {
57+
UnsafePinned {
58+
value: UnsafeCell::new(value),
59+
_ph: PhantomPinned,
60+
}
61+
}
62+
}
63+
impl<T: ?Sized> UnsafePinned<T> {
64+
/// Get mutable access to the contents of a shared `UnsafePinned`.
65+
///
66+
/// This can be cast to a pointer of any kind. When creating references, you must uphold the
67+
/// aliasing rules; see [`UnsafeCell`] for more discussion and caveats.
68+
///
69+
/// [`UnsafeCell`]: core::cell::UnsafeCell#aliasing-rules
70+
///
71+
/// ```rust,no_run
72+
/// use kernel::types::UnsafePinned;
73+
///
74+
/// unsafe {
75+
/// let mut x = UnsafePinned::new(0);
76+
/// let ptr = x.get();
77+
/// UnsafePinned::raw_get_mut(&raw mut x).write(1);
78+
/// assert_eq!(ptr.read(), 1);
79+
/// }
80+
/// ```
81+
#[inline(always)]
82+
#[must_use]
83+
pub const fn get(&self) -> *mut T {
84+
self.value.get()
85+
}
86+
87+
/// Gets a mutable pointer to the wrapped value.
88+
#[inline(always)]
89+
#[must_use]
90+
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
91+
this as *mut T
92+
}
93+
}
94+
95+
impl<T> Wrapper<T> for UnsafePinned<T> {
96+
fn pin_init<E>(init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
97+
// SAFETY: `UnsafePinned<T>` has a compatible layout to `T`.
98+
unsafe { cast_pin_init(init) }
99+
}
100+
}

0 commit comments

Comments
 (0)