[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260110-this_module_fix-v3-2-97a3d9c14e8b@gmail.com>
Date: Sat, 10 Jan 2026 17:08:00 +0200
From: Kari Argillander <kari.argillander@...il.com>
To: Miguel Ojeda <ojeda@...nel.org>, Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <lossin@...nel.org>, Andreas Hindborg <a.hindborg@...nel.org>,
Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>,
Danilo Krummrich <dakr@...nel.org>, Alexandre Courbot <acourbot@...dia.com>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
rust-for-linux@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-modules@...r.kernel.org, Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>, Daniel Gomez <da.gomez@...nel.org>,
Sami Tolvanen <samitolvanen@...gle.com>, Aaron Tomlin <atomlin@...mlin.com>,
Kari Argillander <kari.argillander@...il.com>
Subject: [PATCH RFC v3 02/15] rust: add new ThisModule trait and
THIS_MODULE impl
To make clear separation between module crates and kernel crate we
introduce ThisModule trait which is meant to be used by kernel space.
THIS_MODULE is meant to be used by modules. So kernel create will be
unable to even accidentally use THIS_MODULE.
As ThisModule is trait we can pass that around in const context. This is
needed so that we can read ownership information in const context when
we create example file_operations structs for modules.
New ThisModule will also eventually replace kernel::ModuleMetadata trait
and for this reason it also have NAME field.
To make transition smooth use mod this_module so we can have two
ThisModule same time. Also some functionality is added to THIS_MODULE
temporarily so that we do not have to change everything at once.
Also docs examples will need THIS_MODULE so also define that in docs.
Signed-off-by: Kari Argillander <kari.argillander@...il.com>
---
rust/kernel/configfs.rs | 6 +-
rust/kernel/lib.rs | 159 ++++++++++++++++++++++++++++++++++++++++++++
rust/macros/module.rs | 16 +----
scripts/rustdoc_test_gen.rs | 2 +
4 files changed, 166 insertions(+), 17 deletions(-)
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 466fb7f40762..fe80439ab21f 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -876,7 +876,7 @@ fn as_ptr(&self) -> *const bindings::config_item_type {
/// configfs::Subsystem<Configuration>,
/// Configuration
/// >::new_with_child_ctor::<N,Child>(
-/// &THIS_MODULE,
+/// THIS_MODULE.as_ref(),
/// &CONFIGURATION_ATTRS
/// );
///
@@ -1020,7 +1020,7 @@ macro_rules! configfs_attrs {
static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =
$crate::configfs::ItemType::<$container, $data>::new::<N>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ THIS_MODULE.as_ref(), &[<$ data:upper _ATTRS >]
);
)?
@@ -1029,7 +1029,7 @@ macro_rules! configfs_attrs {
$crate::configfs::ItemType<$container, $data> =
$crate::configfs::ItemType::<$container, $data>::
new_with_child_ctor::<N, $child>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ THIS_MODULE.as_ref(), &[<$ data:upper _ATTRS >]
);
)?
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 510d4bfc7c2b..4b899f75e56d 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -233,6 +233,165 @@ pub const fn as_ptr(&self) -> *mut bindings::module {
}
}
+pub mod this_module {
+ //! Access to the module identity and ownership information.
+ //!
+ //! This module provides the Rust equivalent of the kernel’s `THIS_MODULE`
+ //! symbol from the [C API](srctree/include/linux/init.h).
+ //!
+ //! # For driver creators
+ //!
+ //! If you see ThisModule you need to pass THIS_NODULE for it so it can
+ //! track module ownership.
+ //!
+ //! Each Rust module defines its own `THIS_MODULE` using the
+ //! [`create_this_module`] macro. The generated `THIS_MODULE` identifies the
+ //! owning kernel module and expose some metadata about it.
+ //!
+ //! # For abstraction creators
+ //!
+ //! Many times C-apis expect a `struct module *` pointer so they can
+ //! increase the module reference count. This is because module could be
+ //! unloaded while example file operations are in progress. Many times
+ //! structs which needs owner fields should also be const. For this reason
+ //! ThisModule is usually passes as a type parameter `TM` to abstractions
+ //! which need to know the module owner. In vtables ThisModule is usually
+ //! used as name.
+ //!
+ //! ## Example
+ //!
+ //! ```
+ //! # use kernel::{bindings, this_module::ThisModule};
+ //! # use core::marker::PhantomData;
+ //!
+ //! // Example function signature which needs ThisModule.
+ //! pub fn create_device<TM: ThisModule>() {}
+ //!
+ //! // Example of a vtable which uses ThisModule.
+ //! #[vtable]
+ //! pub trait MyStruct {
+ //! type ThisModule: ThisModule;
+ //! }
+ //!
+ //! pub(crate) struct MyStructVTable<T: MyStruct>(PhantomData<T>);
+ //!
+ //! impl<T: MyStruct> MyStructVTable<T> {
+ //! const FOPS: bindings::file_operations = bindings::file_operations {
+ //! owner: T::ThisModule::OWNER.as_ptr(),
+ //! ..pin_init::zeroed()
+ //! };
+ //! }
+ //! ```
+
+ /// See [`this_module`]
+ pub trait ThisModule {
+ /// Wrapper around the owning `struct module` pointer.
+ ///
+ /// This is null for built-in code and non-null for loadable modules.
+ const OWNER: ModuleWrapper;
+ /// Name of the module.
+ const NAME: &'static kernel::str::CStr;
+ }
+
+ /// Wrapper around a pointer to `struct module`.
+ ///
+ /// This type exists as a workaround for the lack of `const fn` methods in
+ /// traits. It allows the module pointer to be stored as an associated
+ /// constant while still providing a `const` accessor.
+ pub struct ModuleWrapper {
+ ptr: *mut bindings::module,
+ }
+
+ impl ModuleWrapper {
+ /// Get the raw pointer to the underlying `struct module`.
+ ///
+ /// TODO: Should be only available for kernel create.
+ pub const fn as_ptr(&self) -> *mut bindings::module {
+ self.ptr
+ }
+
+ /// Only meant to be used from [`create_this_module`].
+ ///
+ /// # Safety
+ ///
+ /// - Only modules are allowed to create non null `ModuleWrapper`s.
+ /// - The non null pointer must point to a valid `struct module`
+ /// provided by the kernel.
+ #[doc(hidden)]
+ pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> Self {
+ ModuleWrapper { ptr }
+ }
+ }
+
+ /// Creates the `THIS_MODULE` definition for a Rust module.
+ ///
+ /// This macro is an internal building block and is not intended to be used
+ /// directly by module authors. It is invoked by [`macros::module::module`]
+ /// and by kernel doctests.
+ ///
+ /// A macro is required so that `cfg(MODULE)` is evaluated in the context of
+ /// the consuming crate, and to prevent accidental use of THIS_MODULE from
+ /// within the kernel crate itself.
+ #[macro_export]
+ #[doc(hidden)]
+ macro_rules! create_this_module {
+ ($name:literal) => {
+ /// THIS_MODULE for module `{name}`. See [`kernel::this_module`].
+ #[allow(non_camel_case_types)]
+ pub struct THIS_MODULE;
+
+ impl ::kernel::this_module::ThisModule for THIS_MODULE {
+ #[cfg(not(MODULE))]
+ /// SAFETY: TODO
+ const OWNER: ::kernel::this_module::ModuleWrapper = unsafe {
+ ::kernel::this_module::ModuleWrapper::from_ptr(::core::ptr::null_mut())
+ };
+
+ #[cfg(MODULE)]
+ // SAFETY:
+ // - `__this_module` is constructed by the kernel at module load time.
+ const OWNER: ::kernel::this_module::ModuleWrapper = unsafe {
+ extern "C" {
+ static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
+ }
+
+ ::kernel::this_module::ModuleWrapper::from_ptr(__this_module.get())
+ };
+
+ const NAME: &'static ::kernel::str::CStr = $crate::c_str!($name);
+ }
+
+ impl THIS_MODULE {
+ /// Returns the name of this module.
+ pub const fn name() -> &'static ::kernel::str::CStr {
+ $crate::c_str!($name)
+ }
+
+ // TODO: Temporary to provide functionality old `THIS_MODULE` provided.
+ // SAFETY: `__this_module` is constructed by the kernel at load time and
+ // will not be freed until the module is unloaded.
+ const ThisModule: ::kernel::ThisModule = unsafe {{
+ ::kernel::ThisModule::from_ptr(
+ <Self as ::kernel::this_module::ThisModule>::OWNER.as_ptr()
+ )
+ }};
+
+ /// Gets a pointer to the underlying `struct module`.
+ // TODO: Temporary to provide functionality old `THIS_MODULE` provided.
+ pub const fn as_ptr(&self) -> *mut ::kernel::bindings::module {{
+ Self::ThisModule.as_ptr()
+ }}
+
+ /// Gets a reference to the underlying `ThisModule`.
+ /// TODO: Temporary to provide functionality old `THIS_MODULE` provided.
+ pub const fn as_ref(&self) -> &'static ::kernel::ThisModule {{
+ &Self::ThisModule
+ }}
+ }
+ };
+ }
+}
+
#[cfg(not(testlib))]
#[panic_handler]
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 80cb9b16f5aa..1bcd703735fe 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -371,20 +371,8 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
/// Used by the printing macros, e.g. [`info!`].
const __LOG_PREFIX: &[u8] = b\"{name}\\0\";
- // SAFETY: `__this_module` is constructed by the kernel at load time and will not be
- // freed until the module is unloaded.
- #[cfg(MODULE)]
- static THIS_MODULE: ::kernel::ThisModule = unsafe {{
- extern \"C\" {{
- static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
- }}
+ ::kernel::create_this_module!(\"{name}\");
- ::kernel::ThisModule::from_ptr(__this_module.get())
- }};
- #[cfg(not(MODULE))]
- static THIS_MODULE: ::kernel::ThisModule = unsafe {{
- ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
- }};
/// The `LocalModule` type is the type of the module created by `module!`,
/// `module_pci_driver!`, `module_platform_driver!`, etc.
@@ -502,7 +490,7 @@ mod __module_init {{
/// This function must only be called once.
unsafe fn __init() -> ::kernel::ffi::c_int {{
let initer =
- <{type_} as ::kernel::InPlaceModule>::init(&super::super::THIS_MODULE);
+ <{type_} as ::kernel::InPlaceModule>::init(&super::super::THIS_MODULE.as_ref());
// 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`.
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index 6fd9f5c84e2e..089e38b49cdd 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -232,6 +232,8 @@ macro_rules! assert_eq {{
const __LOG_PREFIX: &[u8] = b"rust_doctests_kernel\0";
+::kernel::create_this_module!("rust_doctests_kernel");
+
{rust_tests}
"#
)
--
2.43.0
Powered by blists - more mailing lists