From: Alice Ryhl <aliceryhl@google.com>
To: Miguel Ojeda <ojeda@kernel.org>,
Andrew Morton <akpm@linux-foundation.org>
Cc: "Alex Gaynor" <alex.gaynor@gmail.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
"Andreas Hindborg" <a.hindborg@samsung.com>,
"Marco Elver" <elver@google.com>, "Coly Li" <colyli@suse.de>,
"Paolo Abeni" <pabeni@redhat.com>,
"Pierre Gondois" <pierre.gondois@arm.com>,
"Ingo Molnar" <mingo@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Wei Yang" <richard.weiyang@gmail.com>,
"Matthew Wilcox" <willy@infradead.org>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
"Alice Ryhl" <aliceryhl@google.com>,
"Kees Cook" <kees@kernel.org>
Subject: [PATCH v3 01/10] rust: init: add `assert_pinned` macro
Date: Tue, 23 Jul 2024 08:22:02 +0000 [thread overview]
Message-ID: <20240723-linked-list-v3-1-89db92c7dbf4@google.com> (raw)
In-Reply-To: <20240723-linked-list-v3-0-89db92c7dbf4@google.com>
From: Benno Lossin <benno.lossin@proton.me>
Add a macro to statically check if a field of a struct is marked with
`#[pin]` ie that it is structurally pinned. This can be used when
`unsafe` code needs to rely on fields being structurally pinned.
The macro has a special "inline" mode for the case where the type
depends on generic parameters from the surrounding scope.
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
rust/kernel/init.rs | 67 ++++++++++++++++++++++++++++++++++++++++++
rust/kernel/init/__internal.rs | 29 ++++++++++++++++++
2 files changed, 96 insertions(+)
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 495c09ebe3a3..1263f486abc4 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -742,6 +742,73 @@ macro_rules! try_init {
};
}
+/// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is
+/// structurally pinned.
+///
+/// # Example
+///
+/// This will succeed:
+/// ```
+/// use kernel::assert_pinned;
+/// #[pin_data]
+/// struct MyStruct {
+/// #[pin]
+/// some_field: u64,
+/// }
+///
+/// assert_pinned!(MyStruct, some_field, u64);
+/// ```
+///
+/// This will fail:
+/// ```compile_fail
+/// use kernel::assert_pinned;
+/// #[pin_data]
+/// struct MyStruct {
+/// some_field: u64,
+/// }
+///
+/// assert_pinned!(MyStruct, some_field, u64);
+/// ```
+///
+/// Some uses of the macro may trigger the `can't use generic parameters from outer item` error. To
+/// work around this, you may pass the `inline` parameter to the macro. The `inline` parameter can
+/// only be used when the macro is invoked from a function body.
+/// ```
+/// use kernel::assert_pinned;
+/// #[pin_data]
+/// struct Foo<T> {
+/// #[pin]
+/// elem: T,
+/// }
+///
+/// impl<T> Foo<T> {
+/// pub fn project(self: Pin<&mut Self>) -> Pin<&mut T> {
+/// assert_pinned!(Foo<T>, elem, T, inline);
+///
+/// // SAFETY: The field is structurally pinned.
+/// unsafe { self.map_unchecked_mut(|me| &mut me.elem) }
+/// }
+/// }
+/// ```
+#[macro_export]
+macro_rules! assert_pinned {
+ ($ty:ty, $field:ident, $field_ty:ty, inline) => {
+ let _ = move |ptr: *mut $field_ty| {
+ // SAFETY: This code is unreachable.
+ let data = unsafe { <$ty as $crate::init::__internal::HasPinData>::__pin_data() };
+ let init = $crate::init::__internal::AlwaysFail::<$field_ty>::new();
+ // SAFETY: This code is unreachable.
+ unsafe { data.$field(ptr, init) }.ok();
+ };
+ };
+
+ ($ty:ty, $field:ident, $field_ty:ty) => {
+ const _: () = {
+ $crate::assert_pinned!($ty, $field, $field_ty, inline);
+ };
+ };
+}
+
/// A pin-initializer for the type `T`.
///
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs
index db3372619ecd..13cefd37512f 100644
--- a/rust/kernel/init/__internal.rs
+++ b/rust/kernel/init/__internal.rs
@@ -228,3 +228,32 @@ pub unsafe fn new() -> Self {
Self(())
}
}
+
+/// Initializer that always fails.
+///
+/// Used by [`assert_pinned!`].
+///
+/// [`assert_pinned!`]: crate::assert_pinned
+pub struct AlwaysFail<T: ?Sized> {
+ _t: PhantomData<T>,
+}
+
+impl<T: ?Sized> AlwaysFail<T> {
+ /// Creates a new initializer that always fails.
+ pub fn new() -> Self {
+ Self { _t: PhantomData }
+ }
+}
+
+impl<T: ?Sized> Default for AlwaysFail<T> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+// SAFETY: `__pinned_init` always fails, which is always okay.
+unsafe impl<T: ?Sized> PinInit<T, ()> for AlwaysFail<T> {
+ unsafe fn __pinned_init(self, _slot: *mut T) -> Result<(), ()> {
+ Err(())
+ }
+}
--
2.45.2.1089.g2a221341d9-goog
next prev parent reply other threads:[~2024-07-23 8:22 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-23 8:22 [PATCH v3 00/10] Add Rust linked list for reference counted values Alice Ryhl
2024-07-23 8:22 ` Alice Ryhl [this message]
2024-07-23 8:22 ` [PATCH v3 02/10] rust: list: add ListArc Alice Ryhl
2024-07-31 16:47 ` Benno Lossin
2024-08-06 13:16 ` Alice Ryhl
2024-08-06 14:11 ` Benno Lossin
2024-08-06 14:14 ` Miguel Ojeda
2024-07-23 8:22 ` [PATCH v3 03/10] rust: list: add tracking for ListArc Alice Ryhl
2024-07-31 17:17 ` Benno Lossin
2024-07-23 8:22 ` [PATCH v3 04/10] rust: list: add struct with prev/next pointers Alice Ryhl
2024-07-31 18:41 ` Benno Lossin
2024-08-01 9:42 ` Alice Ryhl
2024-08-01 10:45 ` Benno Lossin
2024-08-01 12:51 ` Alice Ryhl
2024-08-01 13:46 ` Benno Lossin
2024-08-01 13:47 ` Alice Ryhl
2024-07-23 8:22 ` [PATCH v3 05/10] rust: list: add macro for implementing ListItem Alice Ryhl
2024-07-31 13:03 ` Alice Ryhl
2024-07-31 20:17 ` Benno Lossin
2024-07-23 8:22 ` [PATCH v3 06/10] rust: list: add List Alice Ryhl
2024-08-01 9:11 ` Benno Lossin
2024-08-01 9:40 ` Alice Ryhl
2024-08-01 10:48 ` Benno Lossin
2024-07-23 8:22 ` [PATCH v3 07/10] rust: list: add iterators Alice Ryhl
2024-07-23 8:22 ` [PATCH v3 08/10] rust: list: add cursor Alice Ryhl
2024-07-23 8:22 ` [PATCH v3 09/10] rust: list: support heterogeneous lists Alice Ryhl
2024-08-01 9:24 ` Benno Lossin
2024-08-01 9:38 ` Alice Ryhl
2024-08-01 10:50 ` Benno Lossin
2024-08-01 12:33 ` Alice Ryhl
2024-07-23 8:22 ` [PATCH v3 10/10] rust: list: add ListArcField Alice Ryhl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240723-linked-list-v3-1-89db92c7dbf4@google.com \
--to=aliceryhl@google.com \
--cc=a.hindborg@samsung.com \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=colyli@suse.de \
--cc=elver@google.com \
--cc=gary@garyguo.net \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=ojeda@kernel.org \
--cc=pabeni@redhat.com \
--cc=pierre.gondois@arm.com \
--cc=richard.weiyang@gmail.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).