[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260106-this_module_fix-v2-2-842ac026f00b@gmail.com>
Date: Tue, 06 Jan 2026 18:11:40 +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 v2 02/11] 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 examples will need THIS_MODULE so also define that in docs.
Signed-off-by: Kari Argillander <kari.argillander@...il.com>
---
drivers/block/rnull/configfs.rs | 2 +-
rust/kernel/configfs.rs | 46 ++++++------
rust/kernel/lib.rs | 159 ++++++++++++++++++++++++++++++++++++++++
rust/macros/module.rs | 16 +---
scripts/rustdoc_test_gen.rs | 2 +
5 files changed, 188 insertions(+), 37 deletions(-)
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 2f5a7da03af5..7223ee7c3032 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
-use super::{NullBlkDevice, THIS_MODULE};
+use super::NullBlkDevice;
use kernel::{
block::mq::gen_disk::{GenDisk, GenDiskBuilder},
c_str,
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 466fb7f40762..908cb98d404f 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -110,16 +110,21 @@
//! [C documentation]: srctree/Documentation/filesystems/configfs.rst
//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs
-use crate::alloc::flags;
-use crate::container_of;
-use crate::page::PAGE_SIZE;
-use crate::prelude::*;
-use crate::str::CString;
-use crate::sync::Arc;
-use crate::sync::ArcBorrow;
-use crate::types::Opaque;
-use core::cell::UnsafeCell;
-use core::marker::PhantomData;
+use crate::{
+ alloc::flags,
+ container_of,
+ page::PAGE_SIZE,
+ prelude::*,
+ str::CString,
+ sync::Arc,
+ sync::ArcBorrow,
+ this_module::ThisModule,
+ types::Opaque, //
+};
+use core::{
+ cell::UnsafeCell,
+ marker::PhantomData, //
+};
/// A configfs subsystem.
///
@@ -744,8 +749,7 @@ macro_rules! impl_item_type {
($tpe:ty) => {
impl<Data> ItemType<$tpe, Data> {
#[doc(hidden)]
- pub const fn new_with_child_ctor<const N: usize, Child>(
- owner: &'static ThisModule,
+ pub const fn new_with_child_ctor<const N: usize, Child, TM: ThisModule>(
attributes: &'static AttributeList<N, Data>,
) -> Self
where
@@ -754,7 +758,7 @@ pub const fn new_with_child_ctor<const N: usize, Child>(
{
Self {
item_type: Opaque::new(bindings::config_item_type {
- ct_owner: owner.as_ptr(),
+ ct_owner: TM::OWNER.as_ptr(),
ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
@@ -765,13 +769,12 @@ pub const fn new_with_child_ctor<const N: usize, Child>(
}
#[doc(hidden)]
- pub const fn new<const N: usize>(
- owner: &'static ThisModule,
+ pub const fn new<const N: usize, TM: ThisModule>(
attributes: &'static AttributeList<N, Data>,
) -> Self {
Self {
item_type: Opaque::new(bindings::config_item_type {
- ct_owner: owner.as_ptr(),
+ ct_owner: TM::OWNER.as_ptr(),
ct_group_ops: core::ptr::null_mut(),
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
@@ -875,8 +878,7 @@ fn as_ptr(&self) -> *const bindings::config_item_type {
/// = kernel::configfs::ItemType::<
/// configfs::Subsystem<Configuration>,
/// Configuration
-/// >::new_with_child_ctor::<N,Child>(
-/// &THIS_MODULE,
+/// >::new_with_child_ctor::<N, Child, crate::THIS_MODULE>(
/// &CONFIGURATION_ATTRS
/// );
///
@@ -1019,8 +1021,8 @@ macro_rules! configfs_attrs {
const [<$no_child:upper>]: bool = true;
static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =
- $crate::configfs::ItemType::<$container, $data>::new::<N>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ $crate::configfs::ItemType::<$container, $data>::new::<N, crate::THIS_MODULE>(
+ &[<$ data:upper _ATTRS >]
);
)?
@@ -1028,8 +1030,8 @@ macro_rules! configfs_attrs {
static [< $data:upper _TPE >]:
$crate::configfs::ItemType<$container, $data> =
$crate::configfs::ItemType::<$container, $data>::
- new_with_child_ctor::<N, $child>(
- &THIS_MODULE, &[<$ data:upper _ATTRS >]
+ new_with_child_ctor::<N, $child, crate::THIS_MODULE>(
+ &[<$ data:upper _ATTRS >]
);
)?
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 510d4bfc7c2b..2ccd75f68f03 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