diff options
author | Benno Lossin <benno.lossin@proton.me> | 2025-03-08 11:04:07 +0000 |
---|---|---|
committer | Miguel Ojeda <ojeda@kernel.org> | 2025-03-16 21:59:18 +0100 |
commit | 86f7dacadeecb9e6cc3e79571fed790b5147652a (patch) | |
tree | 81ac00cd7f736b02d178d3468026b4c6c88e62ea /rust | |
parent | fbf8fb328d1bfe3bd17d5c5626cb485a1ca1a50d (diff) |
rust: add extensions to the pin-init crate and move relevant documentation there
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>
Link: https://lore.kernel.org/r/20250308110339.2997091-4-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'rust')
-rw-r--r-- | rust/kernel/init.rs | 135 | ||||
-rw-r--r-- | rust/kernel/lib.rs | 3 | ||||
-rw-r--r-- | rust/pin-init/src/lib.rs | 14 |
3 files changed, 138 insertions, 14 deletions
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 firmware; 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! |