mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
rust: introduce InPlaceModule
This allows modules to be initialised in-place in pinned memory, which enables the usage of pinned types (e.g., mutexes, spinlocks, driver registrations, etc.) in modules without any extra allocations. Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> Signed-off-by: Danilo Krummrich <dakr@kernel.org> Acked-by: Miguel Ojeda <ojeda@kernel.org> Link: https://lore.kernel.org/r/20241022213221.2383-3-dakr@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
77e8355046
commit
7f15c46a57
@ -82,6 +82,29 @@ pub trait Module: Sized + Sync + Send {
|
||||
fn init(module: &'static ThisModule) -> error::Result<Self>;
|
||||
}
|
||||
|
||||
/// A module that is pinned and initialised in-place.
|
||||
pub trait InPlaceModule: Sync + Send {
|
||||
/// Creates an initialiser for the module.
|
||||
///
|
||||
/// It is called when the module is loaded.
|
||||
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error>;
|
||||
}
|
||||
|
||||
impl<T: Module> InPlaceModule for T {
|
||||
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error> {
|
||||
let initer = move |slot: *mut Self| {
|
||||
let m = <Self as Module>::init(module)?;
|
||||
|
||||
// SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
|
||||
unsafe { slot.write(m) };
|
||||
Ok(())
|
||||
};
|
||||
|
||||
// SAFETY: On success, `initer` always fully initialises an instance of `Self`.
|
||||
unsafe { init::pin_init_from_closure(initer) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent to `THIS_MODULE` in the C API.
|
||||
///
|
||||
/// C header: [`include/linux/export.h`](srctree/include/linux/export.h)
|
||||
|
@ -232,6 +232,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
|
||||
mod __module_init {{
|
||||
mod __module_init {{
|
||||
use super::super::{type_};
|
||||
use kernel::init::PinInit;
|
||||
|
||||
/// The \"Rust loadable module\" mark.
|
||||
//
|
||||
@ -242,7 +243,8 @@ mod __module_init {{
|
||||
#[used]
|
||||
static __IS_RUST_MODULE: () = ();
|
||||
|
||||
static mut __MOD: Option<{type_}> = None;
|
||||
static mut __MOD: core::mem::MaybeUninit<{type_}> =
|
||||
core::mem::MaybeUninit::uninit();
|
||||
|
||||
// Loadable modules need to export the `{{init,cleanup}}_module` identifiers.
|
||||
/// # Safety
|
||||
@ -331,20 +333,14 @@ mod __module_init {{
|
||||
///
|
||||
/// This function must only be called once.
|
||||
unsafe fn __init() -> core::ffi::c_int {{
|
||||
match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{
|
||||
Ok(m) => {{
|
||||
// SAFETY: No data race, since `__MOD` can only be accessed by this
|
||||
// module and there only `__init` and `__exit` access it. These
|
||||
// functions are only called once and `__exit` cannot be called
|
||||
// before or during `__init`.
|
||||
unsafe {{
|
||||
__MOD = Some(m);
|
||||
}}
|
||||
return 0;
|
||||
}}
|
||||
Err(e) => {{
|
||||
return e.to_errno();
|
||||
}}
|
||||
let initer =
|
||||
<{type_} as kernel::InPlaceModule>::init(&super::super::THIS_MODULE);
|
||||
// SAFETY: No data race, since `__MOD` can only be accessed by this module
|
||||
// and there only `__init` and `__exit` access it. These functions are only
|
||||
// called once and `__exit` cannot be called before or during `__init`.
|
||||
match unsafe {{ initer.__pinned_init(__MOD.as_mut_ptr()) }} {{
|
||||
Ok(m) => 0,
|
||||
Err(e) => e.to_errno(),
|
||||
}}
|
||||
}}
|
||||
|
||||
@ -359,7 +355,7 @@ unsafe fn __exit() {{
|
||||
// called once and `__init` was already called.
|
||||
unsafe {{
|
||||
// Invokes `drop()` on `__MOD`, which should be used for cleanup.
|
||||
__MOD = None;
|
||||
__MOD.assume_init_drop();
|
||||
}}
|
||||
}}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user