mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-23 07:23:12 +02:00
Toolchain and infrastructure:
- Extract the 'pin-init' API from the 'kernel' crate and make it into
a standalone crate.
In order to do this, the contents are rearranged so that they can
easily be kept in sync with the version maintained out-of-tree that
other projects have started to use too (or plan to, like QEMU).
This will reduce the maintenance burden for Benno, who will now have
his own sub-tree, and will simplify future expected changes like the
move to use 'syn' to simplify the implementation.
- Add '#[test]'-like support based on KUnit.
We already had doctests support based on KUnit, which takes the
examples in our Rust documentation and runs them under KUnit.
Now, we are adding the beginning of the support for "normal" tests,
similar to those the '#[test]' tests in userspace Rust. For instance:
#[kunit_tests(my_suite)]
mod tests {
#[test]
fn my_test() {
assert_eq!(1 + 1, 2);
}
}
Unlike with doctests, the 'assert*!'s do not map to the KUnit
assertion APIs yet.
- Check Rust signatures at compile time for functions called from C by
name.
In particular, introduce a new '#[export]' macro that can be placed
in the Rust function definition. It will ensure that the function
declaration on the C side matches the signature on the Rust function:
#[export]
pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize {
// ...
}
The macro essentially forces the compiler to compare the types of
the actual Rust function and the 'bindgen'-processed C signature.
These cases are rare so far. In the future, we may consider
introducing another tool, 'cbindgen', to generate C headers
automatically. Even then, having these functions explicitly marked
may be a good idea anyway.
- Enable the 'raw_ref_op' Rust feature: it is already stable, and
allows us to use the new '&raw' syntax, avoiding a couple macros.
After everyone has migrated, we will disallow the macros.
- Pass the correct target to 'bindgen' on Usermode Linux.
- Fix 'rusttest' build in macOS.
'kernel' crate:
- New 'hrtimer' module: add support for setting up intrusive timers
without allocating when starting the timer. Add support for
'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer types
for use with timer callbacks. Add support for setting clock source
and timer mode.
- New 'dma' module: add a simple DMA coherent allocator abstraction and
a test sample driver.
- 'list' module: make the linked list 'Cursor' point between elements,
rather than at an element, which is more convenient to us and allows
for cursors to empty lists; and document it with examples of how to
perform common operations with the provided methods.
- 'str' module: implement a few traits for 'BStr' as well as the
'strip_prefix()' method.
- 'sync' module: add 'Arc::as_ptr'.
- 'alloc' module: add 'Box::into_pin'.
- 'error' module: extend the 'Result' documentation, including a few
examples on different ways of handling errors, a warning about using
methods that may panic, and links to external documentation.
'macros' crate:
- 'module' macro: add the 'authors' key to support multiple authors.
The original key will be kept until everyone has migrated.
Documentation:
- Add error handling sections.
MAINTAINERS:
- Add Danilo Krummrich as reviewer of the Rust "subsystem".
- Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has
its own sub-tree.
- Add sub-tree for 'RUST [ALLOC]'.
- Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with Abdiel
Janulgue as primary maintainer. It will go through the sub-tree of
the 'RUST [ALLOC]' entry.
- Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as
maintainer. It has its own sub-tree.
And a few other cleanups and improvements.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEPjU5OPd5QIZ9jqqOGXyLc2htIW0FAmfpQgAACgkQGXyLc2ht
IW35CQ//VOIFKtG6qgHVMIxrmpT7YFsrAU41h+cHT2lzy5KiTqSYlCgd18SJ+Iyy
vi1ylfdyqOpH5EoO+opPN2H4E+VUlRJg7BkZrT4p1lgGDEKg1mtR/825TxquLNFM
A653f3FvK/scMb6X43kWNKGK/jnxlfxBGmUwIY4/p7+adIuZzXnNbPkV9XYGLx3r
8KIBKJ9gM52eXoCoF8XJpg6Vg/0rYWIet32OzYF0PvzSAOqUlH4keu15jeUo+59V
tgCzAkc2yV3oSo721KYlpPeCPKI5iVCzIcwT0n8fqraXtgGnaFPe5XF16U9Qvrjv
vRp5/dePAHwsOcj5ErzOgLMqGa1sqY76lxDI05PNcBJ8fBAhNEV/rpCTXs/wRagQ
xUZOdsQyEn0V/BOtV+dnwu410dElEeJdOAeojSYFm1gUay43a0e6yIboxn3Ylnfx
8jONSokZ/UFHX3wOFNqHeXsY+REB8Qq8OZXjNBZVFpKHNsICWA0G3BcCRnB1815k
0v7seSdrST78EJ/A5nM0a9gghuLzYgAN04SDx0FzKjb2mHs3PiVfXDvrNMCJ0pBW
zbF9RlvszKZStY5tpxdZ5Zh+f7rfYcnJHYhNpoP7DJr136iWP+NnHbk1lK6+o4WY
lPVdMMgUSUlEXIHgK2ebcb/I1KBrDYiPktmvKAFLrH3qVzhkLAU=
=PCxf
-----END PGP SIGNATURE-----
Merge tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda:
"Toolchain and infrastructure:
- Extract the 'pin-init' API from the 'kernel' crate and make it into
a standalone crate.
In order to do this, the contents are rearranged so that they can
easily be kept in sync with the version maintained out-of-tree that
other projects have started to use too (or plan to, like QEMU).
This will reduce the maintenance burden for Benno, who will now
have his own sub-tree, and will simplify future expected changes
like the move to use 'syn' to simplify the implementation.
- Add '#[test]'-like support based on KUnit.
We already had doctests support based on KUnit, which takes the
examples in our Rust documentation and runs them under KUnit.
Now, we are adding the beginning of the support for "normal" tests,
similar to those the '#[test]' tests in userspace Rust. For
instance:
#[kunit_tests(my_suite)]
mod tests {
#[test]
fn my_test() {
assert_eq!(1 + 1, 2);
}
}
Unlike with doctests, the 'assert*!'s do not map to the KUnit
assertion APIs yet.
- Check Rust signatures at compile time for functions called from C
by name.
In particular, introduce a new '#[export]' macro that can be placed
in the Rust function definition. It will ensure that the function
declaration on the C side matches the signature on the Rust
function:
#[export]
pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize {
// ...
}
The macro essentially forces the compiler to compare the types of
the actual Rust function and the 'bindgen'-processed C signature.
These cases are rare so far. In the future, we may consider
introducing another tool, 'cbindgen', to generate C headers
automatically. Even then, having these functions explicitly marked
may be a good idea anyway.
- Enable the 'raw_ref_op' Rust feature: it is already stable, and
allows us to use the new '&raw' syntax, avoiding a couple macros.
After everyone has migrated, we will disallow the macros.
- Pass the correct target to 'bindgen' on Usermode Linux.
- Fix 'rusttest' build in macOS.
'kernel' crate:
- New 'hrtimer' module: add support for setting up intrusive timers
without allocating when starting the timer. Add support for
'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer
types for use with timer callbacks. Add support for setting clock
source and timer mode.
- New 'dma' module: add a simple DMA coherent allocator abstraction
and a test sample driver.
- 'list' module: make the linked list 'Cursor' point between
elements, rather than at an element, which is more convenient to us
and allows for cursors to empty lists; and document it with
examples of how to perform common operations with the provided
methods.
- 'str' module: implement a few traits for 'BStr' as well as the
'strip_prefix()' method.
- 'sync' module: add 'Arc::as_ptr'.
- 'alloc' module: add 'Box::into_pin'.
- 'error' module: extend the 'Result' documentation, including a few
examples on different ways of handling errors, a warning about
using methods that may panic, and links to external documentation.
'macros' crate:
- 'module' macro: add the 'authors' key to support multiple authors.
The original key will be kept until everyone has migrated.
Documentation:
- Add error handling sections.
MAINTAINERS:
- Add Danilo Krummrich as reviewer of the Rust "subsystem".
- Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has
its own sub-tree.
- Add sub-tree for 'RUST [ALLOC]'.
- Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with
Abdiel Janulgue as primary maintainer. It will go through the
sub-tree of the 'RUST [ALLOC]' entry.
- Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as
maintainer. It has its own sub-tree.
And a few other cleanups and improvements"
* tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (71 commits)
rust: dma: add `Send` implementation for `CoherentAllocation`
rust: macros: fix `make rusttest` build on macOS
rust: block: refactor to use `&raw mut`
rust: enable `raw_ref_op` feature
rust: uaccess: name the correct function
rust: rbtree: fix comments referring to Box instead of KBox
rust: hrtimer: add maintainer entry
rust: hrtimer: add clocksource selection through `ClockId`
rust: hrtimer: add `HrTimerMode`
rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>`
rust: alloc: add `Box::into_pin`
rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>`
rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>`
rust: hrtimer: add `hrtimer::ScopedHrTimerPointer`
rust: hrtimer: add `UnsafeHrTimerPointer`
rust: hrtimer: allow timer restart from timer handler
rust: str: implement `strip_prefix` for `BStr`
rust: str: implement `AsRef<BStr>` for `[u8]` and `BStr`
rust: str: implement `Index` for `BStr`
rust: str: implement `PartialEq` for `BStr`
...
306 lines
10 KiB
Rust
306 lines
10 KiB
Rust
// 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!`]: pin_init::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\n");
|
|
//! }
|
|
//! }
|
|
//!
|
|
//! 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()) };
|
|
//! }
|
|
//! }
|
|
//! ```
|
|
|
|
use crate::{
|
|
alloc::{AllocError, Flags},
|
|
error::{self, Error},
|
|
};
|
|
use pin_init::{init_from_closure, pin_init_from_closure, Init, PinInit};
|
|
|
|
/// Smart pointer that can initialize memory in-place.
|
|
pub trait InPlaceInit<T>: Sized {
|
|
/// Pinned version of `Self`.
|
|
///
|
|
/// If a type already implicitly pins its pointee, `Pin<Self>` is unnecessary. In this case use
|
|
/// `Self`, otherwise just use `Pin<Self>`.
|
|
type PinnedSelf;
|
|
|
|
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
|
/// type.
|
|
///
|
|
/// If `T: !Unpin` it will not be able to move afterwards.
|
|
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
|
where
|
|
E: From<AllocError>;
|
|
|
|
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
|
/// type.
|
|
///
|
|
/// If `T: !Unpin` it will not be able to move afterwards.
|
|
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
|
|
where
|
|
Error: From<E>,
|
|
{
|
|
// SAFETY: We delegate to `init` and only change the error type.
|
|
let init = unsafe {
|
|
pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
|
|
};
|
|
Self::try_pin_init(init, flags)
|
|
}
|
|
|
|
/// Use the given initializer to in-place initialize a `T`.
|
|
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
|
|
where
|
|
E: From<AllocError>;
|
|
|
|
/// Use the given initializer to in-place initialize a `T`.
|
|
fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
|
|
where
|
|
Error: From<E>,
|
|
{
|
|
// SAFETY: We delegate to `init` and only change the error type.
|
|
let init = unsafe {
|
|
init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
|
|
};
|
|
Self::try_init(init, flags)
|
|
}
|
|
}
|
|
|
|
/// Construct an in-place fallible initializer for `struct`s.
|
|
///
|
|
/// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use
|
|
/// [`init!`].
|
|
///
|
|
/// The syntax is identical to [`try_pin_init!`]. If you want to specify a custom error,
|
|
/// append `? $type` after the `struct` initializer.
|
|
/// The safety caveats from [`try_pin_init!`] also apply:
|
|
/// - `unsafe` code must guarantee either full initialization or return an error and allow
|
|
/// deallocation of the memory.
|
|
/// - the fields are initialized in the order given in the initializer.
|
|
/// - no references to fields are allowed to be created inside of the initializer.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// use kernel::error::Error;
|
|
/// use pin_init::zeroed;
|
|
/// struct BigBuf {
|
|
/// big: KBox<[u8; 1024 * 1024 * 1024]>,
|
|
/// small: [u8; 1024 * 1024],
|
|
/// }
|
|
///
|
|
/// impl BigBuf {
|
|
/// fn new() -> impl Init<Self, Error> {
|
|
/// try_init!(Self {
|
|
/// big: KBox::init(zeroed(), GFP_KERNEL)?,
|
|
/// small: [0; 1024 * 1024],
|
|
/// }? Error)
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// [`Infallible`]: core::convert::Infallible
|
|
/// [`init!`]: pin_init::init
|
|
/// [`try_pin_init!`]: crate::try_pin_init!
|
|
/// [`Error`]: crate::error::Error
|
|
#[macro_export]
|
|
macro_rules! try_init {
|
|
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
|
$($fields:tt)*
|
|
}) => {
|
|
::pin_init::try_init!($(&$this in)? $t $(::<$($generics),* $(,)?>)? {
|
|
$($fields)*
|
|
}? $crate::error::Error)
|
|
};
|
|
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
|
$($fields:tt)*
|
|
}? $err:ty) => {
|
|
::pin_init::try_init!($(&$this in)? $t $(::<$($generics),* $(,)?>)? {
|
|
$($fields)*
|
|
}? $err)
|
|
};
|
|
}
|
|
|
|
/// Construct an in-place, fallible pinned initializer for `struct`s.
|
|
///
|
|
/// If the initialization can complete without error (or [`Infallible`]), then use [`pin_init!`].
|
|
///
|
|
/// You can use the `?` operator or use `return Err(err)` inside the initializer to stop
|
|
/// initialization and return the error.
|
|
///
|
|
/// IMPORTANT: if you have `unsafe` code inside of the initializer you have to ensure that when
|
|
/// initialization fails, the memory can be safely deallocated without any further modifications.
|
|
///
|
|
/// This macro defaults the error to [`Error`].
|
|
///
|
|
/// The syntax is identical to [`pin_init!`] with the following exception: you can append `? $type`
|
|
/// after the `struct` initializer to specify the error type you want to use.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// # #![feature(new_uninit)]
|
|
/// use kernel::error::Error;
|
|
/// use pin_init::zeroed;
|
|
/// #[pin_data]
|
|
/// struct BigBuf {
|
|
/// big: KBox<[u8; 1024 * 1024 * 1024]>,
|
|
/// small: [u8; 1024 * 1024],
|
|
/// ptr: *mut u8,
|
|
/// }
|
|
///
|
|
/// impl BigBuf {
|
|
/// fn new() -> impl PinInit<Self, Error> {
|
|
/// try_pin_init!(Self {
|
|
/// big: KBox::init(zeroed(), GFP_KERNEL)?,
|
|
/// small: [0; 1024 * 1024],
|
|
/// ptr: core::ptr::null_mut(),
|
|
/// }? Error)
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// [`Infallible`]: core::convert::Infallible
|
|
/// [`pin_init!`]: pin_init::pin_init
|
|
/// [`Error`]: crate::error::Error
|
|
#[macro_export]
|
|
macro_rules! try_pin_init {
|
|
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
|
$($fields:tt)*
|
|
}) => {
|
|
::pin_init::try_pin_init!($(&$this in)? $t $(::<$($generics),* $(,)?>)? {
|
|
$($fields)*
|
|
}? $crate::error::Error)
|
|
};
|
|
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
|
$($fields:tt)*
|
|
}? $err:ty) => {
|
|
::pin_init::try_pin_init!($(&$this in)? $t $(::<$($generics),* $(,)?>)? {
|
|
$($fields)*
|
|
}? $err)
|
|
};
|
|
}
|