diff options
author | Wedson Almeida Filho <walmeida@microsoft.com> | 2023-09-29 17:58:08 -0300 |
---|---|---|
committer | Danilo Krummrich <dakr@kernel.org> | 2024-08-13 15:53:39 +0200 |
commit | df05774306e2b987ed823855d13f8208e9f29250 (patch) | |
tree | 84f1ba5d66734468e21a015fc488286c5d085080 | |
parent | 6e14443091639269f9866cac0c9d82d44335eee5 (diff) |
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.
Drivers that don't need this may continue to implement `Module` without
any changes.
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
-rw-r--r-- | rust/kernel/lib.rs | 23 | ||||
-rw-r--r-- | rust/macros/module.rs | 26 |
2 files changed, 33 insertions, 16 deletions
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 274bdc1b0a82..35c8aa0e714d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -78,6 +78,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) diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 411dc103d82e..f9be425e0b74 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -228,6 +228,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. // @@ -238,7 +239,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { #[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 @@ -315,20 +316,13 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { /// /// 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(), }} }} @@ -343,7 +337,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { // called once and `__init` was already called. unsafe {{ // Invokes `drop()` on `__MOD`, which should be used for cleanup. - __MOD = None; + __MOD.assume_init_drop(); }} }} |