Skip to content

Commit d59e0ca

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]> Co-developed-by: Sky <[email protected]> Signed-off-by: Sky <[email protected]> Signed-off-by: Christian Schrefl <[email protected]>
1 parent 277a2ed commit d59e0ca

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed

init/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ config LD_CAN_USE_KEEP_IN_OVERLAY
140140
config RUSTC_HAS_COERCE_POINTEE
141141
def_bool RUSTC_VERSION >= 108400
142142

143+
config RUSTC_HAS_UNSAFE_PINNED
144+
def_bool RUSTC_VERSION >= 108800
145+
143146
config PAHOLE_VERSION
144147
int
145148
default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE))

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))]
1818
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))]
1919
#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))]
20+
#![cfg_attr(CONFIG_RUSTC_HAS_UNSAFE_PINNED, feature(unsafe_pinned))]
2021
#![feature(inline_const)]
2122
#![feature(lint_reasons)]
2223
// Stable in Rust 1.82

rust/kernel/types.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
253253
///
254254
/// [`Opaque<T>`] is meant to be used with FFI objects that are never interpreted by Rust code.
255255
///
256+
/// In cases where the contained data is only used by Rust, is not allowed to be
257+
/// uninitialized and automatic [`Drop`] is desired [`UnsafePinned`] should be used instead.
258+
///
256259
/// It is used to wrap structs from the C side, like for example `Opaque<bindings::mutex>`.
257260
/// It gets rid of all the usual assumptions that Rust has for a value:
258261
///
@@ -578,3 +581,6 @@ pub type NotThreadSafe = PhantomData<*mut ()>;
578581
/// [`NotThreadSafe`]: type@NotThreadSafe
579582
#[allow(non_upper_case_globals)]
580583
pub const NotThreadSafe: NotThreadSafe = PhantomData;
584+
585+
mod unsafe_pinned;
586+
pub use unsafe_pinned::UnsafePinned;

rust/kernel/types/unsafe_pinned.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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.
10+
11+
use core::{cell::UnsafeCell, marker::PhantomPinned};
12+
use pin_init::{cast_pin_init, PinInit, Wrapper};
13+
14+
/// This type provides a way to opt-out of typical aliasing rules;
15+
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
16+
///
17+
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
18+
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
19+
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
20+
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
21+
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
22+
/// control! Techniques such as pinning via [`Pin`](core::pin::Pin) are needed to ensure soundness.
23+
///
24+
/// Similar to [`UnsafeCell`], [`UnsafePinned`] will not usually show up in
25+
/// the public API of a library. It is an internal implementation detail of libraries that need to
26+
/// support aliasing mutable references.
27+
///
28+
/// Further note that this does *not* lift the requirement that shared references must be read-only!
29+
/// Use [`UnsafeCell`] for that.
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+
/// In order to disable niche optimizations this implementation uses [`UnsafeCell`] internally,
42+
/// the upstream version however will not. So the fact that [`UnsafePinned`] contains an
43+
/// [`UnsafeCell`] must not be relied on (Other than the niche blocking).
44+
// As opposed to the upstream Rust type this contains a `PhantomPinned`` and `UnsafeCell<T>`
45+
// - `PhantomPinned` to avoid needing a `impl<T> !Unpin for UnsafePinned<T>`
46+
// Required to use the `!Unpin hack`.
47+
// - `UnsafeCell<T>` instead of T to disallow niche optimizations,
48+
// which is handled in the compiler in upstream Rust
49+
#[repr(transparent)]
50+
pub struct UnsafePinned<T: ?Sized> {
51+
_ph: PhantomPinned,
52+
value: UnsafeCell<T>,
53+
}
54+
55+
impl<T> UnsafePinned<T> {
56+
/// Constructs a new instance of [`UnsafePinned`] which will wrap the specified value.
57+
///
58+
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
59+
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
60+
#[inline(always)]
61+
#[must_use]
62+
pub const fn new(value: T) -> Self {
63+
UnsafePinned {
64+
value: UnsafeCell::new(value),
65+
_ph: PhantomPinned,
66+
}
67+
}
68+
}
69+
impl<T: ?Sized> UnsafePinned<T> {
70+
/// Get read-only access to the contents of a shared `UnsafePinned`.
71+
///
72+
/// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
73+
/// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
74+
/// [`UnsafeCell`] if you also need interior mutability.
75+
///
76+
/// [`UnsafeCell`]: core::cell::UnsafeCell
77+
///
78+
/// ```rust,no_build
79+
/// use kernel::types::UnsafePinned;
80+
///
81+
/// unsafe {
82+
/// let mut x = UnsafePinned::new(0);
83+
/// let ptr = x.get(); // read-only pointer, assumes immutability
84+
/// x.get_mut_unchecked().write(1);
85+
/// ptr.read(); // UB!
86+
/// }
87+
/// ```
88+
///
89+
/// Note that the `get_mut_unchecked` function used by this example is
90+
/// currently not implemented in the kernel implementation.
91+
#[inline(always)]
92+
#[must_use]
93+
pub const fn get(&self) -> *const T {
94+
self.value.get()
95+
}
96+
97+
/// Gets a mutable pointer to the wrapped value.
98+
///
99+
/// The difference from `get_mut_pinned` and `get_mut_unchecked` is that this function
100+
/// accepts a raw pointer, which is useful to avoid the creation of temporary references.
101+
///
102+
/// These functions mentioned here are currently not implemented in the kernel.
103+
#[inline(always)]
104+
#[must_use]
105+
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
106+
this as *mut T
107+
}
108+
}
109+
110+
impl<T> Wrapper<T> for UnsafePinned<T> {
111+
fn pin_init<E>(init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
112+
// SAFETY: `UnsafePinned<T>` has a compatible layout to `T`.
113+
unsafe { cast_pin_init(init) }
114+
}
115+
}

0 commit comments

Comments
 (0)