1

rust: init: update init module to take allocation flags

This is the last component in the conversion for allocators to take
allocation flags as parameters.

Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
Link: https://lore.kernel.org/r/20240328013603.206764-10-wedsonaf@gmail.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Wedson Almeida Filho 2024-03-27 22:36:02 -03:00 committed by Miguel Ojeda
parent cc41670e06
commit c34aa00d1d
6 changed files with 50 additions and 41 deletions

View File

@ -68,7 +68,7 @@
//! # a <- new_mutex!(42, "Foo::a"),
//! # b: 24,
//! # });
//! let foo: Result<Pin<Box<Foo>>> = Box::pin_init(foo);
//! let foo: Result<Pin<Box<Foo>>> = Box::pin_init(foo, GFP_KERNEL);
//! ```
//!
//! For more information see the [`pin_init!`] macro.
@ -80,7 +80,8 @@
//!
//! ```rust
//! # use kernel::sync::{new_mutex, Arc, Mutex};
//! let mtx: Result<Arc<Mutex<usize>>> = Arc::pin_init(new_mutex!(42, "example::mtx"));
//! let mtx: Result<Arc<Mutex<usize>>> =
//! Arc::pin_init(new_mutex!(42, "example::mtx"), GFP_KERNEL);
//! ```
//!
//! To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
@ -99,7 +100,7 @@
//! fn new() -> impl PinInit<Self, Error> {
//! try_pin_init!(Self {
//! status <- new_mutex!(0, "DriverData::status"),
//! buffer: Box::init(kernel::init::zeroed())?,
//! buffer: Box::init(kernel::init::zeroed(), GFP_KERNEL)?,
//! })
//! }
//! }
@ -210,7 +211,7 @@
//! [`pin_init!`]: crate::pin_init!
use crate::{
alloc::{box_ext::BoxExt, flags::*},
alloc::{box_ext::BoxExt, Flags},
error::{self, Error},
sync::UniqueArc,
types::{Opaque, ScopeGuard},
@ -391,7 +392,7 @@ macro_rules! stack_try_pin_init {
/// },
/// });
/// # initializer }
/// # Box::pin_init(demo()).unwrap();
/// # Box::pin_init(demo(), GFP_KERNEL).unwrap();
/// ```
///
/// Arbitrary Rust expressions can be used to set the value of a variable.
@ -461,7 +462,7 @@ macro_rules! stack_try_pin_init {
/// # })
/// # }
/// # }
/// let foo = Box::pin_init(Foo::new());
/// let foo = Box::pin_init(Foo::new(), GFP_KERNEL);
/// ```
///
/// They can also easily embed it into their own `struct`s:
@ -601,7 +602,7 @@ macro_rules! pin_init {
/// impl BigBuf {
/// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self {
/// big: Box::init(init::zeroed())?,
/// big: Box::init(init::zeroed(), GFP_KERNEL)?,
/// small: [0; 1024 * 1024],
/// ptr: core::ptr::null_mut(),
/// }? Error)
@ -702,7 +703,7 @@ macro_rules! init {
/// impl BigBuf {
/// fn new() -> impl Init<Self, Error> {
/// try_init!(Self {
/// big: Box::init(zeroed())?,
/// big: Box::init(zeroed(), GFP_KERNEL)?,
/// small: [0; 1024 * 1024],
/// }? Error)
/// }
@ -1014,7 +1015,7 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
///
/// ```rust
/// use kernel::{error::Error, init::init_array_from_fn};
/// let array: Box<[usize; 1_000]> = Box::init::<Error>(init_array_from_fn(|i| i)).unwrap();
/// let array: Box<[usize; 1_000]> = Box::init::<Error>(init_array_from_fn(|i| i), GFP_KERNEL).unwrap();
/// assert_eq!(array.len(), 1_000);
/// ```
pub fn init_array_from_fn<I, const N: usize, T, E>(
@ -1058,7 +1059,7 @@ where
/// ```rust
/// 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))).unwrap();
/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i)), GFP_KERNEL).unwrap();
/// assert_eq!(array.len(), 1_000);
/// ```
pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
@ -1116,7 +1117,7 @@ pub trait InPlaceInit<T>: Sized {
/// type.
///
/// If `T: !Unpin` it will not be able to move afterwards.
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
where
E: From<AllocError>;
@ -1124,7 +1125,7 @@ pub trait InPlaceInit<T>: Sized {
/// type.
///
/// If `T: !Unpin` it will not be able to move afterwards.
fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>>
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Pin<Self>>
where
Error: From<E>,
{
@ -1132,16 +1133,16 @@ pub trait InPlaceInit<T>: Sized {
let init = unsafe {
pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
};
Self::try_pin_init(init)
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>) -> Result<Self, E>
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>) -> error::Result<Self>
fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
where
Error: From<E>,
{
@ -1149,17 +1150,17 @@ pub trait InPlaceInit<T>: Sized {
let init = unsafe {
init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
};
Self::try_init(init)
Self::try_init(init, flags)
}
}
impl<T> InPlaceInit<T> for Box<T> {
#[inline]
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
where
E: From<AllocError>,
{
let mut this = <Box<_> as BoxExt<_>>::new_uninit(GFP_KERNEL)?;
let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
let slot = this.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
// slot is valid and will not be moved, because we pin it later.
@ -1169,11 +1170,11 @@ impl<T> InPlaceInit<T> for Box<T> {
}
#[inline]
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
where
E: From<AllocError>,
{
let mut this = <Box<_> as BoxExt<_>>::new_uninit(GFP_KERNEL)?;
let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
let slot = this.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
// slot is valid.
@ -1185,11 +1186,11 @@ impl<T> InPlaceInit<T> for Box<T> {
impl<T> InPlaceInit<T> for UniqueArc<T> {
#[inline]
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
where
E: From<AllocError>,
{
let mut this = UniqueArc::new_uninit(GFP_KERNEL)?;
let mut this = UniqueArc::new_uninit(flags)?;
let slot = this.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
// slot is valid and will not be moved, because we pin it later.
@ -1199,11 +1200,11 @@ impl<T> InPlaceInit<T> for UniqueArc<T> {
}
#[inline]
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
where
E: From<AllocError>,
{
let mut this = UniqueArc::new_uninit(GFP_KERNEL)?;
let mut this = UniqueArc::new_uninit(flags)?;
let slot = this.as_mut_ptr();
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
// slot is valid.

View File

@ -182,22 +182,22 @@ impl<T> Arc<T> {
///
/// If `T: !Unpin` it will not be able to move afterwards.
#[inline]
pub fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Self>
pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self>
where
Error: From<E>,
{
UniqueArc::pin_init(init).map(|u| u.into())
UniqueArc::pin_init(init, flags).map(|u| u.into())
}
/// Use the given initializer to in-place initialize a `T`.
///
/// This is equivalent to [`Arc<T>::pin_init`], since an [`Arc`] is always pinned.
#[inline]
pub fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
where
Error: From<E>,
{
UniqueArc::init(init).map(|u| u.into())
UniqueArc::init(init, flags).map(|u| u.into())
}
}
@ -565,13 +565,16 @@ impl<T> UniqueArc<T> {
}
/// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet.
pub fn new_uninit(_flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {
pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {
// INVARIANT: The refcount is initialised to a non-zero value.
let inner = Box::try_init::<AllocError>(try_init!(ArcInner {
let inner = Box::try_init::<AllocError>(
try_init!(ArcInner {
// SAFETY: There are no safety requirements for this FFI call.
refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
data <- init::uninit::<T, AllocError>(),
}? AllocError))?;
}? AllocError),
flags,
)?;
Ok(UniqueArc {
// INVARIANT: The newly-created object has a refcount of 1.
// SAFETY: The pointer from the `Box` is valid.

View File

@ -75,7 +75,7 @@ pub use new_condvar;
/// Box::pin_init(pin_init!(Example {
/// value <- new_mutex!(0),
/// value_changed <- new_condvar!(),
/// }))
/// }), GFP_KERNEL)
/// }
/// ```
///

View File

@ -60,7 +60,7 @@ pub use new_mutex;
/// }
///
/// // Allocate a boxed `Example`.
/// let e = Box::pin_init(Example::new())?;
/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?;
/// assert_eq!(e.c, 10);
/// assert_eq!(e.d.lock().a, 20);
/// assert_eq!(e.d.lock().b, 30);

View File

@ -58,7 +58,7 @@ pub use new_spinlock;
/// }
///
/// // Allocate a boxed `Example`.
/// let e = Box::pin_init(Example::new())?;
/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?;
/// assert_eq!(e.c, 10);
/// assert_eq!(e.d.lock().a, 20);
/// assert_eq!(e.d.lock().b, 30);

View File

@ -53,7 +53,7 @@
//! Arc::pin_init(pin_init!(MyStruct {
//! value,
//! work <- new_work!("MyStruct::work"),
//! }))
//! }), GFP_KERNEL)
//! }
//! }
//!
@ -101,7 +101,7 @@
//! value_2,
//! work_1 <- new_work!("MyStruct::work_1"),
//! work_2 <- new_work!("MyStruct::work_2"),
//! }))
//! }), GFP_KERNEL)
//! }
//! }
//!
@ -132,6 +132,7 @@
//!
//! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h)
use crate::alloc::Flags;
use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
use alloc::alloc::AllocError;
use alloc::boxed::Box;
@ -210,13 +211,17 @@ impl Queue {
/// Tries to spawn the given function or closure as a work item.
///
/// This method can fail because it allocates memory to store the work item.
pub fn try_spawn<T: 'static + Send + FnOnce()>(&self, func: T) -> Result<(), AllocError> {
pub fn try_spawn<T: 'static + Send + FnOnce()>(
&self,
flags: Flags,
func: T,
) -> Result<(), AllocError> {
let init = pin_init!(ClosureWork {
work <- new_work!("Queue::try_spawn"),
func: Some(func),
});
self.enqueue(Box::pin_init(init).map_err(|_| AllocError)?);
self.enqueue(Box::pin_init(init, flags).map_err(|_| AllocError)?);
Ok(())
}
}