From: Kari Argillander <kari.argillander@gmail.com>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-modules@vger.kernel.org,
Luis Chamberlain <mcgrof@kernel.org>,
Petr Pavlu <petr.pavlu@suse.com>,
Daniel Gomez <da.gomez@kernel.org>,
Sami Tolvanen <samitolvanen@google.com>,
Aaron Tomlin <atomlin@atomlin.com>,
Kari Argillander <kari.argillander@gmail.com>
Subject: [PATCH RFC v3 02/15] rust: add new ThisModule trait and THIS_MODULE impl
Date: Sat, 10 Jan 2026 17:08:00 +0200 [thread overview]
Message-ID: <20260110-this_module_fix-v3-2-97a3d9c14e8b@gmail.com> (raw)
In-Reply-To: <20260110-this_module_fix-v3-0-97a3d9c14e8b@gmail.com>
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@gmail.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
next prev parent reply other threads:[~2026-01-10 15:09 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-10 15:07 [PATCH RFC v3 00/15] rust: Reimplement ThisModule to fix ownership problems Kari Argillander
2026-01-10 15:07 ` [PATCH RFC v3 01/15] rust: enable const_refs_to_static feature Kari Argillander
2026-01-10 15:08 ` Kari Argillander [this message]
2026-01-14 14:26 ` [PATCH RFC v3 02/15] rust: add new ThisModule trait and THIS_MODULE impl Petr Pavlu
2026-01-10 15:08 ` [PATCH RFC v3 03/15] rust: miscdevice: fix use after free because missing .owner Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 04/15] rust: block: fix missing owner field in block_device_operations Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 05/15] rust: drm: fix missing owner in file_operations Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 06/15] rust: configfs: use new THIS_MODULE Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 07/15] rust: binder: " Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 08/15] rust: firmware: use THIS_MODULE over LocalModule for name Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 09/15] gpu: nova-core: " Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 10/15] samples: rust: auxiliary: " Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 11/15] rust: driver: make RegistrationOps::register() to use new ThisModule Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 12/15] rust: phy: make Registration::register() " Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 13/15] rust: remove module argument from InPlaceModule::init() Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 14/15] rust: remove kernel::ModuleMetadata Kari Argillander
2026-01-10 15:08 ` [PATCH RFC v3 15/15] rust: remove old version of ThisModule Kari Argillander
2026-01-12 17:56 ` [PATCH RFC v3 00/15] rust: Reimplement ThisModule to fix ownership problems Christophe Leroy (CS GROUP)
2026-01-13 10:33 ` Miguel Ojeda
2026-01-14 14:37 ` Miguel Ojeda
2026-01-27 14:53 ` Gary Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260110-this_module_fix-v3-2-97a3d9c14e8b@gmail.com \
--to=kari.argillander@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=atomlin@atomlin.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=da.gomez@kernel.org \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=mcgrof@kernel.org \
--cc=ojeda@kernel.org \
--cc=petr.pavlu@suse.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=samitolvanen@google.com \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.