* [PATCH v2 01/22] rust: init: disable doctests
[not found] <20250308110339.2997091-1-benno.lossin@proton.me>
@ 2025-03-08 11:03 ` Benno Lossin
2025-03-08 11:04 ` [PATCH v2 02/22] rust: move pin-init API into its own directory Benno Lossin
` (20 subsequent siblings)
21 siblings, 0 replies; 31+ messages in thread
From: Benno Lossin @ 2025-03-08 11:03 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross
Cc: Fiona Behrens, rust-for-linux, linux-kernel
The build system cannot handle doctests in the kernel crate in files
outside of `rust/kernel/`. Subsequent commits will move files out of
that directory, but will still compile them as part of the kernel crate.
Thus ignore all doctests in the to-be-moved files.
Leave tests disabled until they are separated into their own crate and
they stop causing breakage.
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/init.rs | 40 ++++++++++++++++++++--------------------
rust/macros/lib.rs | 8 ++++----
2 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 7fd1ea8265a5..aa8df0595585 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -34,7 +34,7 @@
//! [`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is
//! that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
//!
-//! ```rust
+//! ```rust,ignore
//! # #![expect(clippy::disallowed_names)]
//! use kernel::sync::{new_mutex, Mutex};
//! # use core::pin::Pin;
@@ -54,7 +54,7 @@
//! `foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like
//! (or just the stack) to actually initialize a `Foo`:
//!
-//! ```rust
+//! ```rust,ignore
//! # #![expect(clippy::disallowed_names)]
//! # use kernel::sync::{new_mutex, Mutex};
//! # use core::pin::Pin;
@@ -78,7 +78,7 @@
//! Many types from the kernel supply a function/macro that returns an initializer, because the
//! above method only works for types where you can access the fields.
//!
-//! ```rust
+//! ```rust,ignore
//! # use kernel::sync::{new_mutex, Arc, Mutex};
//! let mtx: Result<Arc<Mutex<usize>>> =
//! Arc::pin_init(new_mutex!(42, "example::mtx"), GFP_KERNEL);
@@ -86,7 +86,7 @@
//!
//! To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
//!
-//! ```rust
+//! ```rust,ignore
//! # use kernel::{sync::Mutex, new_mutex, init::PinInit, try_pin_init};
//! #[pin_data]
//! struct DriverData {
@@ -119,7 +119,7 @@
//! - you may assume that `slot` will stay pinned even after the closure returns until `drop` of
//! `slot` gets called.
//!
-//! ```rust
+//! ```rust,ignore
//! # #![expect(unreachable_pub, clippy::disallowed_names)]
//! use kernel::{init, types::Opaque};
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
@@ -236,7 +236,7 @@
///
/// # Examples
///
-/// ```rust
+/// ```rust,ignore
/// # #![expect(clippy::disallowed_names)]
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
/// # use core::pin::Pin;
@@ -382,7 +382,7 @@ macro_rules! stack_try_pin_init {
///
/// The syntax is almost identical to that of a normal `struct` initializer:
///
-/// ```rust
+/// ```rust,ignore
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin;
/// #[pin_data]
@@ -426,7 +426,7 @@ macro_rules! stack_try_pin_init {
///
/// To create an initializer function, simply declare it like this:
///
-/// ```rust
+/// ```rust,ignore
/// # use kernel::{init, pin_init, init::*};
/// # use core::pin::Pin;
/// # #[pin_data]
@@ -452,7 +452,7 @@ macro_rules! stack_try_pin_init {
///
/// Users of `Foo` can now create it like this:
///
-/// ```rust
+/// ```rust,ignore
/// # #![expect(clippy::disallowed_names)]
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin;
@@ -480,7 +480,7 @@ macro_rules! stack_try_pin_init {
///
/// They can also easily embed it into their own `struct`s:
///
-/// ```rust
+/// ```rust,ignore
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
/// # use core::pin::Pin;
/// # #[pin_data]
@@ -539,7 +539,7 @@ macro_rules! stack_try_pin_init {
///
/// For instance:
///
-/// ```rust
+/// ```rust,ignore
/// # use kernel::{macros::{Zeroable, pin_data}, pin_init};
/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
/// #[pin_data]
@@ -602,7 +602,7 @@ macro_rules! pin_init {
///
/// # Examples
///
-/// ```rust
+/// ```rust,ignore
/// use kernel::{init::{self, PinInit}, error::Error};
/// #[pin_data]
/// struct BigBuf {
@@ -705,7 +705,7 @@ macro_rules! init {
///
/// # Examples
///
-/// ```rust
+/// ```rust,ignore
/// use kernel::{alloc::KBox, init::{PinInit, zeroed}, error::Error};
/// struct BigBuf {
/// big: KBox<[u8; 1024 * 1024 * 1024]>,
@@ -761,7 +761,7 @@ macro_rules! try_init {
/// # Example
///
/// This will succeed:
-/// ```
+/// ```ignore
/// use kernel::assert_pinned;
/// #[pin_data]
/// struct MyStruct {
@@ -787,7 +787,7 @@ macro_rules! try_init {
/// 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.
-/// ```
+/// ```ignore
/// use kernel::assert_pinned;
/// #[pin_data]
/// struct Foo<T> {
@@ -865,7 +865,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
///
/// # Examples
///
- /// ```rust
+ /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)]
/// use kernel::{types::Opaque, init::pin_init_from_closure};
/// #[repr(C)]
@@ -977,7 +977,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
///
/// # Examples
///
- /// ```rust
+ /// ```rust,ignore
/// # #![expect(clippy::disallowed_names)]
/// use kernel::{types::Opaque, init::{self, init_from_closure}};
/// struct Foo {
@@ -1089,7 +1089,7 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
///
/// # Examples
///
-/// ```rust
+/// ```rust,ignore
/// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn};
/// let array: KBox<[usize; 1_000]> =
/// KBox::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL)?;
@@ -1134,7 +1134,7 @@ pub fn init_array_from_fn<I, const N: usize, T, E>(
///
/// # Examples
///
-/// ```rust
+/// ```rust,ignore
/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex};
/// let array: Arc<[Mutex<usize>; 1_000]> =
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL)?;
@@ -1323,7 +1323,7 @@ fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Ini
///
/// Use [`pinned_drop`] to implement this trait safely:
///
-/// ```rust
+/// ```rust,ignore
/// # use kernel::sync::Mutex;
/// use kernel::macros::pinned_drop;
/// use core::pin::Pin;
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index d61bc6a56425..60a0226bad42 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -248,7 +248,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
///
/// # Examples
///
-/// ```
+/// ```ignore
/// # #![feature(lint_reasons)]
/// # use kernel::prelude::*;
/// # use std::{sync::Mutex, process::Command};
@@ -261,7 +261,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
/// }
/// ```
///
-/// ```
+/// ```ignore
/// # #![feature(lint_reasons)]
/// # use kernel::prelude::*;
/// # use std::{sync::Mutex, process::Command};
@@ -302,7 +302,7 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
///
/// # Examples
///
-/// ```
+/// ```ignore
/// # #![feature(lint_reasons)]
/// # use kernel::prelude::*;
/// # use macros::{pin_data, pinned_drop};
@@ -478,7 +478,7 @@ pub fn paste(input: TokenStream) -> TokenStream {
///
/// # Examples
///
-/// ```
+/// ```ignore
/// use kernel::macros::Zeroable;
///
/// #[derive(Zeroable)]
--
2.47.2
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 02/22] rust: move pin-init API into its own directory
[not found] <20250308110339.2997091-1-benno.lossin@proton.me>
2025-03-08 11:03 ` [PATCH v2 01/22] rust: init: disable doctests Benno Lossin
@ 2025-03-08 11:04 ` Benno Lossin
2025-03-08 11:04 ` [PATCH v2 03/22] rust: add extensions to the pin-init crate and move relevant documentation there Benno Lossin
` (19 subsequent siblings)
21 siblings, 0 replies; 31+ messages in thread
From: Benno Lossin @ 2025-03-08 11:04 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross
Cc: Fiona Behrens, linux-kernel, rust-for-linux
In preparation of splitting off the pin-init crate from the kernel
crate, move all pin-init API code (including proc-macros) into
`rust/pin-init`.
Moved modules have their import path adjusted via the `#[path = "..."]`
attribute. This allows the files to still be imported in the kernel
crate even though the files are in different directories.
Code that is moved out of files (but the file itself stays where it is)
is imported via the `include!` macro. This also allows the code to be
moved while still being part of the kernel crate.
Note that this commit moves the generics parsing code out of the GPL-2.0
file `rust/macros/helpers.rs` into the Apache-2.0 OR MIT file
`rust/pin_init/internal/src/helpers.rs`. I am the sole author of that
code and it already is available with that license at [1].
The same is true for the entry-points of the proc-macros `pin_data`,
`pinned_drop` and `derive_zeroable` in `rust/macros/lib.rs` that are
moved to `rust/pin_data/internal/src/lib.rs`. Although there are some
smaller patches that fix the doctests.
Link: https://github.com/Rust-for-Linux/pinned-init [1]
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/lib.rs | 1 +
rust/macros/helpers.rs | 146 +----------------
rust/macros/lib.rs | 124 +--------------
rust/pin-init/internal/src/helpers.rs | 147 ++++++++++++++++++
rust/pin-init/internal/src/lib.rs | 122 +++++++++++++++
.../internal/src}/pin_data.rs | 0
.../internal/src}/pinned_drop.rs | 0
.../internal/src}/zeroable.rs | 0
.../init => pin-init/src}/__internal.rs | 0
rust/{kernel/init.rs => pin-init/src/lib.rs} | 0
rust/{kernel/init => pin-init/src}/macros.rs | 0
11 files changed, 275 insertions(+), 265 deletions(-)
create mode 100644 rust/pin-init/internal/src/helpers.rs
create mode 100644 rust/pin-init/internal/src/lib.rs
rename rust/{macros => pin-init/internal/src}/pin_data.rs (100%)
rename rust/{macros => pin-init/internal/src}/pinned_drop.rs (100%)
rename rust/{macros => pin-init/internal/src}/zeroable.rs (100%)
rename rust/{kernel/init => pin-init/src}/__internal.rs (100%)
rename rust/{kernel/init.rs => pin-init/src/lib.rs} (100%)
rename rust/{kernel/init => pin-init/src}/macros.rs (100%)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 398242f92a96..c1b781371ba3 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -50,6 +50,7 @@
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
pub mod firmware;
pub mod fs;
+#[path = "../pin-init/src/lib.rs"]
pub mod init;
pub mod io;
pub mod ioctl;
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index 563dcd2b7ace..8e07703fcc16 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -70,148 +70,4 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
}
}
-/// Parsed generics.
-///
-/// See the field documentation for an explanation what each of the fields represents.
-///
-/// # Examples
-///
-/// ```rust,ignore
-/// # let input = todo!();
-/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input);
-/// quote! {
-/// struct Foo<$($decl_generics)*> {
-/// // ...
-/// }
-///
-/// impl<$impl_generics> Foo<$ty_generics> {
-/// fn foo() {
-/// // ...
-/// }
-/// }
-/// }
-/// ```
-pub(crate) struct Generics {
- /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`).
- ///
- /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`).
- pub(crate) decl_generics: Vec<TokenTree>,
- /// The generics with bounds (e.g. `T: Clone, const N: usize`).
- ///
- /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.
- pub(crate) impl_generics: Vec<TokenTree>,
- /// The generics without bounds and without default values (e.g. `T, N`).
- ///
- /// Use this when you use the type that is declared with these generics e.g.
- /// `Foo<$ty_generics>`.
- pub(crate) ty_generics: Vec<TokenTree>,
-}
-
-/// Parses the given `TokenStream` into `Generics` and the rest.
-///
-/// The generics are not present in the rest, but a where clause might remain.
-pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
- // The generics with bounds and default values.
- let mut decl_generics = vec![];
- // `impl_generics`, the declared generics with their bounds.
- let mut impl_generics = vec![];
- // Only the names of the generics, without any bounds.
- let mut ty_generics = vec![];
- // Tokens not related to the generics e.g. the `where` token and definition.
- let mut rest = vec![];
- // The current level of `<`.
- let mut nesting = 0;
- let mut toks = input.into_iter();
- // If we are at the beginning of a generic parameter.
- let mut at_start = true;
- let mut skip_until_comma = false;
- while let Some(tt) = toks.next() {
- if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') {
- // Found the end of the generics.
- break;
- } else if nesting >= 1 {
- decl_generics.push(tt.clone());
- }
- match tt.clone() {
- TokenTree::Punct(p) if p.as_char() == '<' => {
- if nesting >= 1 && !skip_until_comma {
- // This is inside of the generics and part of some bound.
- impl_generics.push(tt);
- }
- nesting += 1;
- }
- TokenTree::Punct(p) if p.as_char() == '>' => {
- // This is a parsing error, so we just end it here.
- if nesting == 0 {
- break;
- } else {
- nesting -= 1;
- if nesting >= 1 && !skip_until_comma {
- // We are still inside of the generics and part of some bound.
- impl_generics.push(tt);
- }
- }
- }
- TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {
- if nesting == 1 {
- impl_generics.push(tt.clone());
- impl_generics.push(tt);
- skip_until_comma = false;
- }
- }
- _ if !skip_until_comma => {
- match nesting {
- // If we haven't entered the generics yet, we still want to keep these tokens.
- 0 => rest.push(tt),
- 1 => {
- // Here depending on the token, it might be a generic variable name.
- match tt.clone() {
- TokenTree::Ident(i) if at_start && i.to_string() == "const" => {
- let Some(name) = toks.next() else {
- // Parsing error.
- break;
- };
- impl_generics.push(tt);
- impl_generics.push(name.clone());
- ty_generics.push(name.clone());
- decl_generics.push(name);
- at_start = false;
- }
- TokenTree::Ident(_) if at_start => {
- impl_generics.push(tt.clone());
- ty_generics.push(tt);
- at_start = false;
- }
- TokenTree::Punct(p) if p.as_char() == ',' => {
- impl_generics.push(tt.clone());
- ty_generics.push(tt);
- at_start = true;
- }
- // Lifetimes begin with `'`.
- TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
- impl_generics.push(tt.clone());
- ty_generics.push(tt);
- }
- // Generics can have default values, we skip these.
- TokenTree::Punct(p) if p.as_char() == '=' => {
- skip_until_comma = true;
- }
- _ => impl_generics.push(tt),
- }
- }
- _ => impl_generics.push(tt),
- }
- }
- _ => {}
- }
- }
- rest.extend(toks);
- (
- Generics {
- impl_generics,
- decl_generics,
- ty_generics,
- },
- rest,
- )
-}
+include!("../pin-init/internal/src/helpers.rs");
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 60a0226bad42..7ff82c82ce0c 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -12,9 +12,12 @@
mod helpers;
mod module;
mod paste;
+#[path = "../pin-init/internal/src/pin_data.rs"]
mod pin_data;
+#[path = "../pin-init/internal/src/pinned_drop.rs"]
mod pinned_drop;
mod vtable;
+#[path = "../pin-init/internal/src/zeroable.rs"]
mod zeroable;
use proc_macro::TokenStream;
@@ -232,106 +235,6 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream {
concat_idents::concat_idents(ts)
}
-/// Used to specify the pinning information of the fields of a struct.
-///
-/// This is somewhat similar in purpose as
-/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
-/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
-/// field you want to structurally pin.
-///
-/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
-/// then `#[pin]` directs the type of initializer that is required.
-///
-/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this
-/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with
-/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care.
-///
-/// # Examples
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use std::{sync::Mutex, process::Command};
-/// # use kernel::macros::pin_data;
-/// #[pin_data]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// }
-/// ```
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use std::{sync::Mutex, process::Command};
-/// # use core::pin::Pin;
-/// # pub struct Info;
-/// # mod bindings {
-/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {}
-/// # }
-/// use kernel::macros::{pin_data, pinned_drop};
-///
-/// #[pin_data(PinnedDrop)]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// raw_info: *mut Info,
-/// }
-///
-/// #[pinned_drop]
-/// impl PinnedDrop for DriverData {
-/// fn drop(self: Pin<&mut Self>) {
-/// unsafe { bindings::destroy_info(self.raw_info) };
-/// }
-/// }
-/// # fn main() {}
-/// ```
-///
-/// [`pin_init!`]: ../kernel/macro.pin_init.html
-// ^ cannot use direct link, since `kernel` is not a dependency of `macros`.
-#[proc_macro_attribute]
-pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
- pin_data::pin_data(inner, item)
-}
-
-/// Used to implement `PinnedDrop` safely.
-///
-/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`.
-///
-/// # Examples
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use macros::{pin_data, pinned_drop};
-/// # use std::{sync::Mutex, process::Command};
-/// # use core::pin::Pin;
-/// # mod bindings {
-/// # pub struct Info;
-/// # pub unsafe fn destroy_info(_ptr: *mut Info) {}
-/// # }
-/// #[pin_data(PinnedDrop)]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// raw_info: *mut bindings::Info,
-/// }
-///
-/// #[pinned_drop]
-/// impl PinnedDrop for DriverData {
-/// fn drop(self: Pin<&mut Self>) {
-/// unsafe { bindings::destroy_info(self.raw_info) };
-/// }
-/// }
-/// ```
-#[proc_macro_attribute]
-pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
- pinned_drop::pinned_drop(args, input)
-}
-
/// Paste identifiers together.
///
/// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a
@@ -472,23 +375,4 @@ pub fn paste(input: TokenStream) -> TokenStream {
tokens.into_iter().collect()
}
-/// Derives the [`Zeroable`] trait for the given struct.
-///
-/// This can only be used for structs where every field implements the [`Zeroable`] trait.
-///
-/// # Examples
-///
-/// ```ignore
-/// use kernel::macros::Zeroable;
-///
-/// #[derive(Zeroable)]
-/// pub struct DriverData {
-/// id: i64,
-/// buf_ptr: *mut u8,
-/// len: usize,
-/// }
-/// ```
-#[proc_macro_derive(Zeroable)]
-pub fn derive_zeroable(input: TokenStream) -> TokenStream {
- zeroable::derive(input)
-}
+include!("../pin-init/internal/src/lib.rs");
diff --git a/rust/pin-init/internal/src/helpers.rs b/rust/pin-init/internal/src/helpers.rs
new file mode 100644
index 000000000000..2f4fc75c014e
--- /dev/null
+++ b/rust/pin-init/internal/src/helpers.rs
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+/// Parsed generics.
+///
+/// See the field documentation for an explanation what each of the fields represents.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// # let input = todo!();
+/// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input);
+/// quote! {
+/// struct Foo<$($decl_generics)*> {
+/// // ...
+/// }
+///
+/// impl<$impl_generics> Foo<$ty_generics> {
+/// fn foo() {
+/// // ...
+/// }
+/// }
+/// }
+/// ```
+pub(crate) struct Generics {
+ /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`).
+ ///
+ /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`).
+ pub(crate) decl_generics: Vec<TokenTree>,
+ /// The generics with bounds (e.g. `T: Clone, const N: usize`).
+ ///
+ /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`.
+ pub(crate) impl_generics: Vec<TokenTree>,
+ /// The generics without bounds and without default values (e.g. `T, N`).
+ ///
+ /// Use this when you use the type that is declared with these generics e.g.
+ /// `Foo<$ty_generics>`.
+ pub(crate) ty_generics: Vec<TokenTree>,
+}
+
+/// Parses the given `TokenStream` into `Generics` and the rest.
+///
+/// The generics are not present in the rest, but a where clause might remain.
+pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) {
+ // The generics with bounds and default values.
+ let mut decl_generics = vec![];
+ // `impl_generics`, the declared generics with their bounds.
+ let mut impl_generics = vec![];
+ // Only the names of the generics, without any bounds.
+ let mut ty_generics = vec![];
+ // Tokens not related to the generics e.g. the `where` token and definition.
+ let mut rest = vec![];
+ // The current level of `<`.
+ let mut nesting = 0;
+ let mut toks = input.into_iter();
+ // If we are at the beginning of a generic parameter.
+ let mut at_start = true;
+ let mut skip_until_comma = false;
+ while let Some(tt) = toks.next() {
+ if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') {
+ // Found the end of the generics.
+ break;
+ } else if nesting >= 1 {
+ decl_generics.push(tt.clone());
+ }
+ match tt.clone() {
+ TokenTree::Punct(p) if p.as_char() == '<' => {
+ if nesting >= 1 && !skip_until_comma {
+ // This is inside of the generics and part of some bound.
+ impl_generics.push(tt);
+ }
+ nesting += 1;
+ }
+ TokenTree::Punct(p) if p.as_char() == '>' => {
+ // This is a parsing error, so we just end it here.
+ if nesting == 0 {
+ break;
+ } else {
+ nesting -= 1;
+ if nesting >= 1 && !skip_until_comma {
+ // We are still inside of the generics and part of some bound.
+ impl_generics.push(tt);
+ }
+ }
+ }
+ TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => {
+ if nesting == 1 {
+ impl_generics.push(tt.clone());
+ impl_generics.push(tt);
+ skip_until_comma = false;
+ }
+ }
+ _ if !skip_until_comma => {
+ match nesting {
+ // If we haven't entered the generics yet, we still want to keep these tokens.
+ 0 => rest.push(tt),
+ 1 => {
+ // Here depending on the token, it might be a generic variable name.
+ match tt.clone() {
+ TokenTree::Ident(i) if at_start && i.to_string() == "const" => {
+ let Some(name) = toks.next() else {
+ // Parsing error.
+ break;
+ };
+ impl_generics.push(tt);
+ impl_generics.push(name.clone());
+ ty_generics.push(name.clone());
+ decl_generics.push(name);
+ at_start = false;
+ }
+ TokenTree::Ident(_) if at_start => {
+ impl_generics.push(tt.clone());
+ ty_generics.push(tt);
+ at_start = false;
+ }
+ TokenTree::Punct(p) if p.as_char() == ',' => {
+ impl_generics.push(tt.clone());
+ ty_generics.push(tt);
+ at_start = true;
+ }
+ // Lifetimes begin with `'`.
+ TokenTree::Punct(p) if p.as_char() == '\'' && at_start => {
+ impl_generics.push(tt.clone());
+ ty_generics.push(tt);
+ }
+ // Generics can have default values, we skip these.
+ TokenTree::Punct(p) if p.as_char() == '=' => {
+ skip_until_comma = true;
+ }
+ _ => impl_generics.push(tt),
+ }
+ }
+ _ => impl_generics.push(tt),
+ }
+ }
+ _ => {}
+ }
+ }
+ rest.extend(toks);
+ (
+ Generics {
+ impl_generics,
+ decl_generics,
+ ty_generics,
+ },
+ rest,
+ )
+}
diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs
new file mode 100644
index 000000000000..0a2761cc793c
--- /dev/null
+++ b/rust/pin-init/internal/src/lib.rs
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+/// Used to specify the pinning information of the fields of a struct.
+///
+/// This is somewhat similar in purpose as
+/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
+/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
+/// field you want to structurally pin.
+///
+/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
+/// then `#[pin]` directs the type of initializer that is required.
+///
+/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this
+/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with
+/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care.
+///
+/// # Examples
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use std::{sync::Mutex, process::Command};
+/// # use kernel::macros::pin_data;
+/// #[pin_data]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// }
+/// ```
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use std::{sync::Mutex, process::Command};
+/// # use core::pin::Pin;
+/// # pub struct Info;
+/// # mod bindings {
+/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {}
+/// # }
+/// use kernel::macros::{pin_data, pinned_drop};
+///
+/// #[pin_data(PinnedDrop)]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// raw_info: *mut Info,
+/// }
+///
+/// #[pinned_drop]
+/// impl PinnedDrop for DriverData {
+/// fn drop(self: Pin<&mut Self>) {
+/// unsafe { bindings::destroy_info(self.raw_info) };
+/// }
+/// }
+/// # fn main() {}
+/// ```
+///
+/// [`pin_init!`]: ../kernel/macro.pin_init.html
+// ^ cannot use direct link, since `kernel` is not a dependency of `macros`.
+#[proc_macro_attribute]
+pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
+ pin_data::pin_data(inner, item)
+}
+
+/// Used to implement `PinnedDrop` safely.
+///
+/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use macros::{pin_data, pinned_drop};
+/// # use std::{sync::Mutex, process::Command};
+/// # use core::pin::Pin;
+/// # mod bindings {
+/// # pub struct Info;
+/// # pub unsafe fn destroy_info(_ptr: *mut Info) {}
+/// # }
+/// #[pin_data(PinnedDrop)]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// raw_info: *mut bindings::Info,
+/// }
+///
+/// #[pinned_drop]
+/// impl PinnedDrop for DriverData {
+/// fn drop(self: Pin<&mut Self>) {
+/// unsafe { bindings::destroy_info(self.raw_info) };
+/// }
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
+ pinned_drop::pinned_drop(args, input)
+}
+
+/// Derives the [`Zeroable`] trait for the given struct.
+///
+/// This can only be used for structs where every field implements the [`Zeroable`] trait.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::macros::Zeroable;
+///
+/// #[derive(Zeroable)]
+/// pub struct DriverData {
+/// id: i64,
+/// buf_ptr: *mut u8,
+/// len: usize,
+/// }
+/// ```
+#[proc_macro_derive(Zeroable)]
+pub fn derive_zeroable(input: TokenStream) -> TokenStream {
+ zeroable::derive(input)
+}
diff --git a/rust/macros/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs
similarity index 100%
rename from rust/macros/pin_data.rs
rename to rust/pin-init/internal/src/pin_data.rs
diff --git a/rust/macros/pinned_drop.rs b/rust/pin-init/internal/src/pinned_drop.rs
similarity index 100%
rename from rust/macros/pinned_drop.rs
rename to rust/pin-init/internal/src/pinned_drop.rs
diff --git a/rust/macros/zeroable.rs b/rust/pin-init/internal/src/zeroable.rs
similarity index 100%
rename from rust/macros/zeroable.rs
rename to rust/pin-init/internal/src/zeroable.rs
diff --git a/rust/kernel/init/__internal.rs b/rust/pin-init/src/__internal.rs
similarity index 100%
rename from rust/kernel/init/__internal.rs
rename to rust/pin-init/src/__internal.rs
diff --git a/rust/kernel/init.rs b/rust/pin-init/src/lib.rs
similarity index 100%
rename from rust/kernel/init.rs
rename to rust/pin-init/src/lib.rs
diff --git a/rust/kernel/init/macros.rs b/rust/pin-init/src/macros.rs
similarity index 100%
rename from rust/kernel/init/macros.rs
rename to rust/pin-init/src/macros.rs
--
2.47.2
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v2 03/22] rust: add extensions to the pin-init crate and move relevant documentation there
[not found] <20250308110339.2997091-1-benno.lossin@proton.me>
2025-03-08 11:03 ` [PATCH v2 01/22] rust: init: disable doctests Benno Lossin
2025-03-08 11:04 ` [PATCH v2 02/22] rust: move pin-init API into its own directory Benno Lossin
@ 2025-03-08 11:04 ` Benno Lossin
2025-03-18 11:32 ` Andreas Hindborg
2025-03-08 11:04 ` [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate Benno Lossin
` (18 subsequent siblings)
21 siblings, 1 reply; 31+ messages in thread
From: Benno Lossin @ 2025-03-08 11:04 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross
Cc: Fiona Behrens, linux-kernel, rust-for-linux
In preparation of splitting off the pin-init crate from the kernel
crate, move all kernel-specific documentation from pin-init back into
the kernel crate.
Also include an example from the user-space version [1] adapted to the
kernel.
The new `init.rs` file will also be populated by kernel-specific
extensions to the pin-init crate by the next commits.
Link: https://github.com/Rust-for-Linux/pin-init/blob/c1417c64c71229f0fd444d75e88f33e3c547c829/src/lib.rs#L161 [1]
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/init.rs | 135 +++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 3 +
rust/pin-init/src/lib.rs | 14 ----
3 files changed, 138 insertions(+), 14 deletions(-)
create mode 100644 rust/kernel/init.rs
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
new file mode 100644
index 000000000000..322dfd9ec347
--- /dev/null
+++ b/rust/kernel/init.rs
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Extensions to the [`pin-init`] crate.
+//!
+//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential
+//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move.
+//!
+//! The [`pin-init`] crate is the way such structs are initialized on the Rust side. Please refer
+//! to its documentation to better understand how to use it. Additionally, there are many examples
+//! throughout the kernel, such as the types from the [`sync`] module. And the ones presented
+//! below.
+//!
+//! [`sync`]: crate::sync
+//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
+//! [`pin-init`]: https://rust.docs.kernel.org/pin_init/
+//!
+//! # [`Opaque<T>`]
+//!
+//! For the special case where initializing a field is a single FFI-function call that cannot fail,
+//! there exist the helper function [`Opaque::ffi_init`]. This function initialize a single
+//! [`Opaque<T>`] field by just delegating to the supplied closure. You can use these in
+//! combination with [`pin_init!`].
+//!
+//! [`Opaque<T>`]: crate::types::Opaque
+//! [`Opaque::ffi_init`]: crate::types::Opaque::ffi_init
+//! [`pin_init!`]: crate::pin_init
+//!
+//! # Examples
+//!
+//! ## General Examples
+//!
+//! ```rust,ignore
+//! # #![allow(clippy::disallowed_names)]
+//! use kernel::types::Opaque;
+//! use pin_init::pin_init_from_closure;
+//!
+//! // assume we have some `raw_foo` type in C:
+//! #[repr(C)]
+//! struct RawFoo([u8; 16]);
+//! extern {
+//! fn init_foo(_: *mut RawFoo);
+//! }
+//!
+//! #[pin_data]
+//! struct Foo {
+//! #[pin]
+//! raw: Opaque<RawFoo>,
+//! }
+//!
+//! impl Foo {
+//! fn setup(self: Pin<&mut Self>) {
+//! pr_info!("Setting up foo");
+//! }
+//! }
+//!
+//! let foo = pin_init!(Foo {
+//! raw <- unsafe {
+//! Opaque::ffi_init(|s| {
+//! // note that this cannot fail.
+//! init_foo(s);
+//! })
+//! },
+//! }).pin_chain(|foo| {
+//! foo.setup();
+//! Ok(())
+//! });
+//! ```
+//!
+//! ```rust,ignore
+//! # #![allow(unreachable_pub, clippy::disallowed_names)]
+//! use kernel::{prelude::*, types::Opaque};
+//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
+//! # mod bindings {
+//! # #![allow(non_camel_case_types)]
+//! # pub struct foo;
+//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
+//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
+//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 }
+//! # }
+//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround.
+//! # trait FromErrno {
+//! # fn from_errno(errno: core::ffi::c_int) -> Error {
+//! # // Dummy error that can be constructed outside the `kernel` crate.
+//! # Error::from(core::fmt::Error)
+//! # }
+//! # }
+//! # impl FromErrno for Error {}
+//! /// # Invariants
+//! ///
+//! /// `foo` is always initialized
+//! #[pin_data(PinnedDrop)]
+//! pub struct RawFoo {
+//! #[pin]
+//! foo: Opaque<bindings::foo>,
+//! #[pin]
+//! _p: PhantomPinned,
+//! }
+//!
+//! impl RawFoo {
+//! pub fn new(flags: u32) -> impl PinInit<Self, Error> {
+//! // SAFETY:
+//! // - when the closure returns `Ok(())`, then it has successfully initialized and
+//! // enabled `foo`,
+//! // - when it returns `Err(e)`, then it has cleaned up before
+//! unsafe {
+//! pin_init::pin_init_from_closure(move |slot: *mut Self| {
+//! // `slot` contains uninit memory, avoid creating a reference.
+//! let foo = addr_of_mut!((*slot).foo);
+//!
+//! // Initialize the `foo`
+//! bindings::init_foo(Opaque::raw_get(foo));
+//!
+//! // Try to enable it.
+//! let err = bindings::enable_foo(Opaque::raw_get(foo), flags);
+//! if err != 0 {
+//! // Enabling has failed, first clean up the foo and then return the error.
+//! bindings::destroy_foo(Opaque::raw_get(foo));
+//! return Err(Error::from_errno(err));
+//! }
+//!
+//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
+//! Ok(())
+//! })
+//! }
+//! }
+//! }
+//!
+//! #[pinned_drop]
+//! impl PinnedDrop for RawFoo {
+//! fn drop(self: Pin<&mut Self>) {
+//! // SAFETY: Since `foo` is initialized, destroying is safe.
+//! unsafe { bindings::destroy_foo(self.foo.get()) };
+//! }
+//! }
+//! ```
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index c1b781371ba3..e3933f3dfc0b 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -52,6 +52,9 @@
pub mod fs;
#[path = "../pin-init/src/lib.rs"]
pub mod init;
+// momentarily use the name `init_ext` and set the path manually
+#[path = "init.rs"]
+pub mod init_ext;
pub mod io;
pub mod ioctl;
pub mod jump_label;
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index aa8df0595585..0307a08ccee9 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -5,9 +5,6 @@
//! It also allows in-place initialization of big `struct`s that would otherwise produce a stack
//! overflow.
//!
-//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential
-//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move.
-//!
//! # Overview
//!
//! To initialize a `struct` with an in-place constructor you will need two things:
@@ -188,15 +185,6 @@
//! }
//! ```
//!
-//! For the special case where initializing a field is a single FFI-function call that cannot fail,
-//! there exist the helper function [`Opaque::ffi_init`]. This function initialize a single
-//! [`Opaque`] field by just delegating to the supplied closure. You can use these in combination
-//! with [`pin_init!`].
-//!
-//! For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
-//! the `kernel` crate. The [`sync`] module is a good starting point.
-//!
-//! [`sync`]: kernel::sync
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
//! [structurally pinned fields]:
//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
@@ -205,8 +193,6 @@
//! [`impl PinInit<Foo>`]: PinInit
//! [`impl PinInit<T, E>`]: PinInit
//! [`impl Init<T, E>`]: Init
-//! [`Opaque`]: kernel::types::Opaque
-//! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init
//! [`pin_data`]: ::macros::pin_data
//! [`pin_init!`]: crate::pin_init!
--
2.47.2
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 03/22] rust: add extensions to the pin-init crate and move relevant documentation there
2025-03-08 11:04 ` [PATCH v2 03/22] rust: add extensions to the pin-init crate and move relevant documentation there Benno Lossin
@ 2025-03-18 11:32 ` Andreas Hindborg
0 siblings, 0 replies; 31+ messages in thread
From: Andreas Hindborg @ 2025-03-18 11:32 UTC (permalink / raw)
To: Benno Lossin
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Alice Ryhl, Trevor Gross, Fiona Behrens,
linux-kernel, rust-for-linux
"Benno Lossin" <benno.lossin@proton.me> writes:
> In preparation of splitting off the pin-init crate from the kernel
> crate, move all kernel-specific documentation from pin-init back into
> the kernel crate.
>
> Also include an example from the user-space version [1] adapted to the
> kernel.
>
> The new `init.rs` file will also be populated by kernel-specific
> extensions to the pin-init crate by the next commits.
>
> Link: https://github.com/Rust-for-Linux/pin-init/blob/c1417c64c71229f0fd444d75e88f33e3c547c829/src/lib.rs#L161 [1]
> Signed-off-by: Benno Lossin <benno.lossin@proton.me>
> Reviewed-by: Fiona Behrens <me@kloenk.dev>
> Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate
[not found] <20250308110339.2997091-1-benno.lossin@proton.me>
` (2 preceding siblings ...)
2025-03-08 11:04 ` [PATCH v2 03/22] rust: add extensions to the pin-init crate and move relevant documentation there Benno Lossin
@ 2025-03-08 11:04 ` Benno Lossin
2025-03-18 11:33 ` Andreas Hindborg
2025-03-08 11:04 ` [PATCH v2 05/22] rust: pin-init: change examples to the user-space version Benno Lossin
` (17 subsequent siblings)
21 siblings, 1 reply; 31+ messages in thread
From: Benno Lossin @ 2025-03-08 11:04 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross
Cc: Fiona Behrens, rust-for-linux, linux-kernel
Move the documentation of proc-macros from pin-init-internal into
pin-init. This is because documentation can only reference types from
dependencies and pin-init-internal cannot have pin-init as a dependency,
as that would be cyclic.
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/pin-init/internal/src/lib.rs | 109 +----------------------------
rust/pin-init/src/lib.rs | 111 ++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+), 106 deletions(-)
diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs
index 0a2761cc793c..bf66cbee2531 100644
--- a/rust/pin-init/internal/src/lib.rs
+++ b/rust/pin-init/internal/src/lib.rs
@@ -1,121 +1,18 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
-/// Used to specify the pinning information of the fields of a struct.
-///
-/// This is somewhat similar in purpose as
-/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
-/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
-/// field you want to structurally pin.
-///
-/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
-/// then `#[pin]` directs the type of initializer that is required.
-///
-/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this
-/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with
-/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care.
-///
-/// # Examples
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use std::{sync::Mutex, process::Command};
-/// # use kernel::macros::pin_data;
-/// #[pin_data]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// }
-/// ```
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use std::{sync::Mutex, process::Command};
-/// # use core::pin::Pin;
-/// # pub struct Info;
-/// # mod bindings {
-/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {}
-/// # }
-/// use kernel::macros::{pin_data, pinned_drop};
-///
-/// #[pin_data(PinnedDrop)]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// raw_info: *mut Info,
-/// }
-///
-/// #[pinned_drop]
-/// impl PinnedDrop for DriverData {
-/// fn drop(self: Pin<&mut Self>) {
-/// unsafe { bindings::destroy_info(self.raw_info) };
-/// }
-/// }
-/// # fn main() {}
-/// ```
-///
-/// [`pin_init!`]: ../kernel/macro.pin_init.html
-// ^ cannot use direct link, since `kernel` is not a dependency of `macros`.
+#[allow(missing_docs)]
#[proc_macro_attribute]
pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream {
pin_data::pin_data(inner, item)
}
-/// Used to implement `PinnedDrop` safely.
-///
-/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`.
-///
-/// # Examples
-///
-/// ```ignore
-/// # #![feature(lint_reasons)]
-/// # use kernel::prelude::*;
-/// # use macros::{pin_data, pinned_drop};
-/// # use std::{sync::Mutex, process::Command};
-/// # use core::pin::Pin;
-/// # mod bindings {
-/// # pub struct Info;
-/// # pub unsafe fn destroy_info(_ptr: *mut Info) {}
-/// # }
-/// #[pin_data(PinnedDrop)]
-/// struct DriverData {
-/// #[pin]
-/// queue: Mutex<KVec<Command>>,
-/// buf: KBox<[u8; 1024 * 1024]>,
-/// raw_info: *mut bindings::Info,
-/// }
-///
-/// #[pinned_drop]
-/// impl PinnedDrop for DriverData {
-/// fn drop(self: Pin<&mut Self>) {
-/// unsafe { bindings::destroy_info(self.raw_info) };
-/// }
-/// }
-/// ```
+#[allow(missing_docs)]
#[proc_macro_attribute]
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
pinned_drop::pinned_drop(args, input)
}
-/// Derives the [`Zeroable`] trait for the given struct.
-///
-/// This can only be used for structs where every field implements the [`Zeroable`] trait.
-///
-/// # Examples
-///
-/// ```ignore
-/// use kernel::macros::Zeroable;
-///
-/// #[derive(Zeroable)]
-/// pub struct DriverData {
-/// id: i64,
-/// buf_ptr: *mut u8,
-/// len: usize,
-/// }
-/// ```
+#[allow(missing_docs)]
#[proc_macro_derive(Zeroable)]
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
zeroable::derive(input)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 0307a08ccee9..df6962460874 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -218,6 +218,117 @@
#[doc(hidden)]
pub mod macros;
+/// Used to specify the pinning information of the fields of a struct.
+///
+/// This is somewhat similar in purpose as
+/// [pin-project-lite](https://crates.io/crates/pin-project-lite).
+/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each
+/// field you want to structurally pin.
+///
+/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`,
+/// then `#[pin]` directs the type of initializer that is required.
+///
+/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this
+/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with
+/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care.
+///
+/// # Examples
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use std::{sync::Mutex, process::Command};
+/// # use kernel::macros::pin_data;
+/// #[pin_data]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// }
+/// ```
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use std::{sync::Mutex, process::Command};
+/// # use core::pin::Pin;
+/// # pub struct Info;
+/// # mod bindings {
+/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {}
+/// # }
+/// use kernel::macros::{pin_data, pinned_drop};
+///
+/// #[pin_data(PinnedDrop)]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// raw_info: *mut Info,
+/// }
+///
+/// #[pinned_drop]
+/// impl PinnedDrop for DriverData {
+/// fn drop(self: Pin<&mut Self>) {
+/// unsafe { bindings::destroy_info(self.raw_info) };
+/// }
+/// }
+/// # fn main() {}
+/// ```
+///
+/// [`pin_init!`]: crate::pin_init
+pub use ::macros::pin_data;
+
+/// Used to implement `PinnedDrop` safely.
+///
+/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`.
+///
+/// # Examples
+///
+/// ```ignore
+/// # #![feature(lint_reasons)]
+/// # use kernel::prelude::*;
+/// # use macros::{pin_data, pinned_drop};
+/// # use std::{sync::Mutex, process::Command};
+/// # use core::pin::Pin;
+/// # mod bindings {
+/// # pub struct Info;
+/// # pub unsafe fn destroy_info(_ptr: *mut Info) {}
+/// # }
+/// #[pin_data(PinnedDrop)]
+/// struct DriverData {
+/// #[pin]
+/// queue: Mutex<KVec<Command>>,
+/// buf: KBox<[u8; 1024 * 1024]>,
+/// raw_info: *mut bindings::Info,
+/// }
+///
+/// #[pinned_drop]
+/// impl PinnedDrop for DriverData {
+/// fn drop(self: Pin<&mut Self>) {
+/// unsafe { bindings::destroy_info(self.raw_info) };
+/// }
+/// }
+/// ```
+pub use ::macros::pinned_drop;
+
+/// Derives the [`Zeroable`] trait for the given struct.
+///
+/// This can only be used for structs where every field implements the [`Zeroable`] trait.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::macros::Zeroable;
+///
+/// #[derive(Zeroable)]
+/// pub struct DriverData {
+/// id: i64,
+/// buf_ptr: *mut u8,
+/// len: usize,
+/// }
+/// ```
+pub use ::macros::Zeroable;
+
/// Initialize and pin a type directly on the stack.
///
/// # Examples
--
2.47.2
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate
2025-03-08 11:04 ` [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate Benno Lossin
@ 2025-03-18 11:33 ` Andreas Hindborg
2025-03-19 13:14 ` Miguel Ojeda
0 siblings, 1 reply; 31+ messages in thread
From: Andreas Hindborg @ 2025-03-18 11:33 UTC (permalink / raw)
To: Benno Lossin
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Alice Ryhl, Trevor Gross, Fiona Behrens,
rust-for-linux, linux-kernel
"Benno Lossin" <benno.lossin@proton.me> writes:
> Move the documentation of proc-macros from pin-init-internal into
> pin-init. This is because documentation can only reference types from
> dependencies and pin-init-internal cannot have pin-init as a dependency,
> as that would be cyclic.
>
> Signed-off-by: Benno Lossin <benno.lossin@proton.me>
> Reviewed-by: Fiona Behrens <me@kloenk.dev>
> Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate
2025-03-18 11:33 ` Andreas Hindborg
@ 2025-03-19 13:14 ` Miguel Ojeda
0 siblings, 0 replies; 31+ messages in thread
From: Miguel Ojeda @ 2025-03-19 13:14 UTC (permalink / raw)
To: Andreas Hindborg
Cc: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Alice Ryhl, Trevor Gross, Fiona Behrens,
rust-for-linux, linux-kernel
On Tue, Mar 18, 2025 at 12:35 PM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
I already applied this on Sunday:
https://lore.kernel.org/rust-for-linux/CANiq72kg2-5PC4T_ieFTN9dqeMnZ0H5TqqPhW+GxB7fPV0COVQ@mail.gmail.com/
and we went through fixing the conflicts in -next, so unless I have to
rebase for something else, I don't think I will take these tags,
sorry.
But thanks a lot for providing them!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 05/22] rust: pin-init: change examples to the user-space version
[not found] <20250308110339.2997091-1-benno.lossin@proton.me>
` (3 preceding siblings ...)
2025-03-08 11:04 ` [PATCH v2 04/22] rust: pin-init: move proc-macro documentation into pin-init crate Benno Lossin
@ 2025-03-08 11:04 ` Benno Lossin
2025-03-08 11:04 ` [PATCH v2 06/22] rust: pin-init: call `try_[pin_]init!` from `[pin_]init!` instead of `__init_internal!` Benno Lossin
` (16 subsequent siblings)
21 siblings, 0 replies; 31+ messages in thread
From: Benno Lossin @ 2025-03-08 11:04 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross
Cc: Fiona Behrens, linux-kernel, rust-for-linux
Replace the examples in the documentation by the ones from the
user-space version and introduce the standalone examples from the
user-space version such as the `CMutex<T>` type.
The `CMutex<T>` example from the pinned-init repository [1] is used in
several documentation examples in the user-space version instead of the
kernel `Mutex<T>` type (as it's not available). In order to split off
the pin-init crate, all examples need to be free of kernel-specific
types.
Link: https://github.com/rust-for-Linux/pinned-init [1]
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/pin-init/examples/big_struct_in_place.rs | 39 ++
rust/pin-init/examples/error.rs | 27 ++
rust/pin-init/examples/linked_list.rs | 161 ++++++++
rust/pin-init/examples/mutex.rs | 209 ++++++++++
rust/pin-init/examples/pthread_mutex.rs | 178 +++++++++
rust/pin-init/examples/static_init.rs | 122 ++++++
rust/pin-init/src/lib.rs | 365 +++++++++---------
7 files changed, 915 insertions(+), 186 deletions(-)
create mode 100644 rust/pin-init/examples/big_struct_in_place.rs
create mode 100644 rust/pin-init/examples/error.rs
create mode 100644 rust/pin-init/examples/linked_list.rs
create mode 100644 rust/pin-init/examples/mutex.rs
create mode 100644 rust/pin-init/examples/pthread_mutex.rs
create mode 100644 rust/pin-init/examples/static_init.rs
diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs
new file mode 100644
index 000000000000..30d44a334ffd
--- /dev/null
+++ b/rust/pin-init/examples/big_struct_in_place.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+use pin_init::*;
+
+// Struct with size over 1GiB
+#[derive(Debug)]
+pub struct BigStruct {
+ buf: [u8; 1024 * 1024 * 1024],
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+ managed_buf: ManagedBuf,
+}
+
+#[derive(Debug)]
+pub struct ManagedBuf {
+ buf: [u8; 1024 * 1024],
+}
+
+impl ManagedBuf {
+ pub fn new() -> impl Init<Self> {
+ init!(ManagedBuf { buf <- zeroed() })
+ }
+}
+
+fn main() {
+ // we want to initialize the struct in-place, otherwise we would get a stackoverflow
+ let buf: Box<BigStruct> = Box::init(init!(BigStruct {
+ buf <- zeroed(),
+ a: 7,
+ b: 186,
+ c: 7789,
+ d: 34,
+ managed_buf <- ManagedBuf::new(),
+ }))
+ .unwrap();
+ println!("{}", core::mem::size_of_val(&*buf));
+}
diff --git a/rust/pin-init/examples/error.rs b/rust/pin-init/examples/error.rs
new file mode 100644
index 000000000000..e0cc258746ce
--- /dev/null
+++ b/rust/pin-init/examples/error.rs
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+#![cfg_attr(feature = "alloc", feature(allocator_api))]
+
+use core::convert::Infallible;
+
+#[cfg(feature = "alloc")]
+use std::alloc::AllocError;
+
+#[derive(Debug)]
+pub struct Error;
+
+impl From<Infallible> for Error {
+ fn from(e: Infallible) -> Self {
+ match e {}
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl From<AllocError> for Error {
+ fn from(_: AllocError) -> Self {
+ Self
+ }
+}
+
+#[allow(dead_code)]
+fn main() {}
diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs
new file mode 100644
index 000000000000..6d7eb0a0ec0d
--- /dev/null
+++ b/rust/pin-init/examples/linked_list.rs
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+#![allow(clippy::undocumented_unsafe_blocks)]
+#![cfg_attr(feature = "alloc", feature(allocator_api))]
+
+use core::{
+ cell::Cell,
+ convert::Infallible,
+ marker::PhantomPinned,
+ pin::Pin,
+ ptr::{self, NonNull},
+};
+
+use pin_init::*;
+
+#[expect(unused_attributes)]
+mod error;
+use error::Error;
+
+#[pin_data(PinnedDrop)]
+#[repr(C)]
+#[derive(Debug)]
+pub struct ListHead {
+ next: Link,
+ prev: Link,
+ #[pin]
+ pin: PhantomPinned,
+}
+
+impl ListHead {
+ #[inline]
+ pub fn new() -> impl PinInit<Self, Infallible> {
+ try_pin_init!(&this in Self {
+ next: unsafe { Link::new_unchecked(this) },
+ prev: unsafe { Link::new_unchecked(this) },
+ pin: PhantomPinned,
+ }? Infallible)
+ }
+
+ #[inline]
+ pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
+ try_pin_init!(&this in Self {
+ prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),
+ next: list.next.replace(unsafe { Link::new_unchecked(this)}),
+ pin: PhantomPinned,
+ }? Infallible)
+ }
+
+ #[inline]
+ pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
+ try_pin_init!(&this in Self {
+ next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}),
+ prev: list.prev.replace(unsafe { Link::new_unchecked(this)}),
+ pin: PhantomPinned,
+ }? Infallible)
+ }
+
+ #[inline]
+ pub fn next(&self) -> Option<NonNull<Self>> {
+ if ptr::eq(self.next.as_ptr(), self) {
+ None
+ } else {
+ Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) })
+ }
+ }
+
+ #[allow(dead_code)]
+ pub fn size(&self) -> usize {
+ let mut size = 1;
+ let mut cur = self.next.clone();
+ while !ptr::eq(self, cur.cur()) {
+ cur = cur.next().clone();
+ size += 1;
+ }
+ size
+ }
+}
+
+#[pinned_drop]
+impl PinnedDrop for ListHead {
+ //#[inline]
+ fn drop(self: Pin<&mut Self>) {
+ if !ptr::eq(self.next.as_ptr(), &*self) {
+ let next = unsafe { &*self.next.as_ptr() };
+ let prev = unsafe { &*self.prev.as_ptr() };
+ next.prev.set(&self.prev);
+ prev.next.set(&self.next);
+ }
+ }
+}
+
+#[repr(transparent)]
+#[derive(Clone, Debug)]
+struct Link(Cell<NonNull<ListHead>>);
+
+impl Link {
+ /// # Safety
+ ///
+ /// The contents of the pointer should form a consistent circular
+ /// linked list; for example, a "next" link should be pointed back
+ /// by the target `ListHead`'s "prev" link and a "prev" link should be
+ /// pointed back by the target `ListHead`'s "next" link.
+ #[inline]
+ unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {
+ Self(Cell::new(ptr))
+ }
+
+ #[inline]
+ fn next(&self) -> &Link {
+ unsafe