Skip to content

Commit 0d44553

Browse files
onestackedintel-lab-lkp
authored andcommitted
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] as a unstable feature, therefore this patch implements the subset required for additional data in `MiscDeviceRegistration` on older rust versions and using the upstream type on new rust versions which include this feature. 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 a comment on the `UnsafePinned` type. The documentation on is based on the upstream rust documentation with minor modifications. 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]> Signed-off-by: Christian Schrefl <[email protected]>
1 parent 0af2f6b commit 0d44553

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

Diff for: init/Kconfig

+3
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))

Diff for: rust/kernel/lib.rs

+1
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

Diff for: rust/kernel/types.rs

+34
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,34 @@ pub type NotThreadSafe = PhantomData<*mut ()>;
578581
/// [`NotThreadSafe`]: type@NotThreadSafe
579582
#[allow(non_upper_case_globals)]
580583
pub const NotThreadSafe: NotThreadSafe = PhantomData;
584+
585+
// When available use the upstream `UnsafePinned` type
586+
#[cfg(CONFIG_RUSTC_HAS_UNSAFE_PINNED)]
587+
pub use core::pin::UnsafePinned;
588+
589+
// Otherwise us the kernel implementation of `UnsafePinned`
590+
#[cfg(not(CONFIG_RUSTC_HAS_UNSAFE_PINNED))]
591+
mod unsafe_pinned;
592+
#[cfg(not(CONFIG_RUSTC_HAS_UNSAFE_PINNED))]
593+
pub use unsafe_pinned::UnsafePinned;
594+
595+
/// Trait for creating a [`PinInit`]ialized wrapper containing `T`.
596+
// Needs to be defined in kernel crate to get around the Orphan Rule when upstream `UnsafePinned`
597+
// is used.
598+
pub trait TryPinInitWrapper<T: ?Sized> {
599+
/// Create an [`Self`] pin-initializer which contains `T`
600+
fn try_pin_init<E>(value: impl PinInit<T, E>) -> impl PinInit<Self, E>;
601+
}
602+
impl<T: ?Sized> TryPinInitWrapper<T> for UnsafePinned<T> {
603+
fn try_pin_init<E>(value: impl PinInit<T, E>) -> impl PinInit<Self, E> {
604+
// SAFETY:
605+
// - In case of an error in `value` the error is returned, otherwise `slot` is fully
606+
// initialized, since `self.value` is initialized and `_pin` is a zero sized type.
607+
// - The `Pin` invariants of `self.value` are upheld, since no moving occurs.
608+
unsafe {
609+
pin_init::pin_init_from_closure(move |slot| {
610+
value.__pinned_init(Self::raw_get_mut(slot))
611+
})
612+
}
613+
}
614+
}

Diff for: rust/kernel/types/unsafe_pinned.rs

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! This file provides a implementation of a subset of the upstream rust `UnsafePinned` type
4+
//! for rust versions that don't include this type.
5+
6+
use core::{cell::UnsafeCell, marker::PhantomPinned};
7+
8+
/// This type provides a way to opt-out of typical aliasing rules;
9+
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
10+
///
11+
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
12+
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
13+
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
14+
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
15+
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
16+
/// control! Techniques such as pinning via [`Pin`](core::pin::Pin) are needed to ensure soundness.
17+
///
18+
/// Similar to [`UnsafeCell`], [`UnsafePinned`] will not usually show up in
19+
/// the public API of a library. It is an internal implementation detail of libraries that need to
20+
/// support aliasing mutable references.
21+
///
22+
/// Further note that this does *not* lift the requirement that shared references must be read-only!
23+
/// Use [`UnsafeCell`] for that.
24+
///
25+
/// This type blocks niches the same way [`UnsafeCell`] does.
26+
//
27+
// As opposed to the upstream Rust type this contains a `PhantomPinned`` and `UnsafeCell<T>`
28+
// - `PhantomPinned` to avoid needing a `impl<T> !Unpin for UnsafePinned<T>`
29+
// - `UnsafeCell<T>` instead of T to disallow niche optimizations,
30+
// which is handled in the compiler in upstream Rust
31+
#[repr(transparent)]
32+
pub struct UnsafePinned<T: ?Sized> {
33+
_ph: PhantomPinned,
34+
value: UnsafeCell<T>,
35+
}
36+
37+
impl<T> UnsafePinned<T> {
38+
/// Constructs a new instance of [`UnsafePinned`] which will wrap the specified value.
39+
///
40+
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
41+
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
42+
#[inline(always)]
43+
#[must_use]
44+
pub const fn new(value: T) -> Self {
45+
UnsafePinned {
46+
value: UnsafeCell::new(value),
47+
_ph: PhantomPinned,
48+
}
49+
}
50+
}
51+
impl<T: ?Sized> UnsafePinned<T> {
52+
/// Get read-only access to the contents of a shared `UnsafePinned`.
53+
///
54+
/// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
55+
/// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
56+
/// [`UnsafeCell`] if you also need interior mutability.
57+
///
58+
/// [`UnsafeCell`]: core::cell::UnsafeCell
59+
///
60+
/// ```rust,no_build
61+
/// use kernel::types::UnsafePinned;
62+
///
63+
/// unsafe {
64+
/// let mut x = UnsafePinned::new(0);
65+
/// let ptr = x.get(); // read-only pointer, assumes immutability
66+
/// x.get_mut_unchecked().write(1);
67+
/// ptr.read(); // UB!
68+
/// }
69+
/// ```
70+
///
71+
/// Note that the `get_mut_unchecked` function used by this example is
72+
/// currently not implemented in the kernel implementation.
73+
#[inline(always)]
74+
#[must_use]
75+
pub const fn get(&self) -> *const T {
76+
self.value.get()
77+
}
78+
79+
/// Gets a mutable pointer to the wrapped value.
80+
///
81+
/// The difference from `get_mut_pinned` and `get_mut_unchecked` is that this function
82+
/// accepts a raw pointer, which is useful to avoid the creation of temporary references.
83+
///
84+
/// These functions mentioned here are currently not implemented in the kernel.
85+
#[inline(always)]
86+
#[must_use]
87+
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
88+
this as *mut T
89+
}
90+
}

0 commit comments

Comments
 (0)