Skip to content

Commit c68f2dc

Browse files
wedsonafDanilo Krummrich
authored andcommitted
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 <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 59fb386 commit c68f2dc

File tree

2 files changed

+35
-16
lines changed

2 files changed

+35
-16
lines changed

rust/kernel/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,29 @@ pub trait Module: Sized + Sync + Send {
8383
fn init(module: &'static ThisModule) -> error::Result<Self>;
8484
}
8585

86+
/// A module that is pinned and initialised in-place.
87+
pub trait InPlaceModule: Sync + Send {
88+
/// Creates an initialiser for the module.
89+
///
90+
/// It is called when the module is loaded.
91+
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error>;
92+
}
93+
94+
impl<T: Module> InPlaceModule for T {
95+
fn init(module: &'static ThisModule) -> impl init::PinInit<Self, error::Error> {
96+
let initer = move |slot: *mut Self| {
97+
let m = <Self as Module>::init(module)?;
98+
99+
// SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`.
100+
unsafe { slot.write(m) };
101+
Ok(())
102+
};
103+
104+
// SAFETY: On success, `initer` always fully initialises an instance of `Self`.
105+
unsafe { init::pin_init_from_closure(initer) }
106+
}
107+
}
108+
86109
/// Equivalent to `THIS_MODULE` in the C API.
87110
///
88111
/// C header: [`include/linux/init.h`](srctree/include/linux/init.h)

rust/macros/module.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
232232
mod __module_init {{
233233
mod __module_init {{
234234
use super::super::{type_};
235+
use kernel::init::PinInit;
235236
236237
/// The \"Rust loadable module\" mark.
237238
//
@@ -242,7 +243,8 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
242243
#[used]
243244
static __IS_RUST_MODULE: () = ();
244245
245-
static mut __MOD: Option<{type_}> = None;
246+
static mut __MOD: core::mem::MaybeUninit<{type_}> =
247+
core::mem::MaybeUninit::uninit();
246248
247249
// Loadable modules need to export the `{{init,cleanup}}_module` identifiers.
248250
/// # Safety
@@ -331,20 +333,14 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
331333
///
332334
/// This function must only be called once.
333335
unsafe fn __init() -> core::ffi::c_int {{
334-
match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{
335-
Ok(m) => {{
336-
// SAFETY: No data race, since `__MOD` can only be accessed by this
337-
// module and there only `__init` and `__exit` access it. These
338-
// functions are only called once and `__exit` cannot be called
339-
// before or during `__init`.
340-
unsafe {{
341-
__MOD = Some(m);
342-
}}
343-
return 0;
344-
}}
345-
Err(e) => {{
346-
return e.to_errno();
347-
}}
336+
let initer =
337+
<{type_} as kernel::InPlaceModule>::init(&super::super::THIS_MODULE);
338+
// SAFETY: No data race, since `__MOD` can only be accessed by this module
339+
// and there only `__init` and `__exit` access it. These functions are only
340+
// called once and `__exit` cannot be called before or during `__init`.
341+
match unsafe {{ initer.__pinned_init(__MOD.as_mut_ptr()) }} {{
342+
Ok(m) => 0,
343+
Err(e) => e.to_errno(),
348344
}}
349345
}}
350346
@@ -359,7 +355,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
359355
// called once and `__init` was already called.
360356
unsafe {{
361357
// Invokes `drop()` on `__MOD`, which should be used for cleanup.
362-
__MOD = None;
358+
__MOD.assume_init_drop();
363359
}}
364360
}}
365361

0 commit comments

Comments
 (0)