From nobody Mon Feb 9 02:13:05 2026 Received: from mail-lj1-f169.google.com (mail-lj1-f169.google.com [209.85.208.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0800E242D6A for ; Tue, 6 Jan 2026 16:13:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767715994; cv=none; b=i8Kje2N+YbtTpo0iy6jbvFWagvGDAMUL8iJNWgnZX3l9A6rp/lH06a2JRs4JonPr2WL0pSderfDW9Lsaz5ArOSA6jN83ix/iruZOxVTqrEhUa/91c38QpRe9qJ7uRwRiRI2wfi5E8BrWo0T1SmkSU2UBNdtK6QC/y4b5+1kcJbw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767715994; c=relaxed/simple; bh=/Ms0ilmTmhT/+pTanvifPfpMypKbgHczZgI+jrgEiCU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R2wXIi/pY72WK6PnsONXTDZ7nE6IDU8nZSNN7PrOfoHiMzxtKRKcPYDpqXG45ZmzjzAacWqbCHSY0sBNjoMDn7jfEpgKd3C0ApDM+a2GJTXbaKCXef5DB4A4uJqwuJLEgyEBE6eLTPWUV+blEPM90FVdbpFJ8x3+kBu+5S7njUM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lwiw2qGL; arc=none smtp.client-ip=209.85.208.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lwiw2qGL" Received: by mail-lj1-f169.google.com with SMTP id 38308e7fff4ca-37bac34346dso8975971fa.2 for ; Tue, 06 Jan 2026 08:13:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767715990; x=1768320790; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=gDBwaX2tbeEhZrSwSpdBrEdEsO8lUCzTxea91t7m1AM=; b=lwiw2qGLxAngZQU7k6WuVQ6LPcoxhICXf6Nser9Y5SGkVXmk0jeEifxgMn6Mn+F9Q/ 4WwtIsDGlwEKTm1TpsYTQC20xTxHveT++jKLJP1OcRXfkwr71ed0dn6UU7cgVrf6GdyM uczK9C9iDU6BWRj/8hpcqBi5OrP/pPmJCN22nDwRlRHQhOCSrpQMh9sb4vMCaidJKXq3 1mJqyEP/rOJ+KL+R3pG4bFdQW8Bx56vwhAxDZLgMqLqpKf9E5YpRKJ4mE9EZc0aTRhcm Az8sF0DEZwTkM61/k7Dzs/Nga2Mni44OCVPVN3WkK1w087BSa8tn4n1oId6EVdwLqKC9 a0HA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767715990; x=1768320790; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=gDBwaX2tbeEhZrSwSpdBrEdEsO8lUCzTxea91t7m1AM=; b=eTvXXq/0T0H9j3JyJ2z2wYJqx+NyETY3SfZestf7MLOcIWAR0dLhF9dqhgWMu1ku5W uD1MV3AxmmvIARz+wE4HmNig+YyEAcrvMN0ejm7/hWjgANuPsbcgExvmBHWC0GZY3u+r a0n/ABQxwU/K3VghIlIHnf9uy4TzhsBkIKla6eWMDFWdjWCMMiYEREp5f6bmPm4IRfn4 oZ10YlPp7VFr/qnNUoL8wQka5VY40Mwg2EHmbnTrcgK3rKWOPVfwB2RSSAFudfV0rMyv uwBY9dNOs8jkEixZ9kpNPE/0JzjboMO/PLh2BSnexHEeytjwT77FGEB4qlN43LnizFI6 oPQA== X-Forwarded-Encrypted: i=1; AJvYcCUhSwSfgtrKawytznmsZq3ac8nxXOWbq3Dx6UUOTw7gQUj5hIoH7AfNMyM+ZZnucKglxayGGhRKoWdkN80=@vger.kernel.org X-Gm-Message-State: AOJu0Yyu7BtCj+xNibZLXnc+omJbeX5bhvUXFFaK8nxh35JnwRMiRjUV hmVxlY0bG8ToeqDHaJ97H4CwVHyokhgOC/UVrwqoCWYd+L6jDjOipC/S X-Gm-Gg: AY/fxX4JpH0rfCCntsf9clJm30tJlDqNtUDAV99tAaUvleAoy5tcbyyYvHKYYHMaqN5 FMkCb6NQdxQDATsTJaDxjUaV/Cb18K6CMU/B7cj8Sh9Ud9xVhmRq7G7NVuQx2hv/T7nUQf1PhI5 /svxgYLgT0FBQe3nmQzLzpWb3cfT0XLlp9Sqlb5eImw3/cFivckvpdoEdXhcQjtAJE1ZPfhBASr lXeoIGG/KwOFagDIEZDZYVVKOU9ySoQZEMn/e4SdSw6ZQHgUym0UOXYnrbkQKx5MLdwMoEDRbIM 3hAtsVj+scjun2vYCAxLcTqp/BUW5ZcYVkqhDahQdsMXujqYG1sV9dJSQ5rsdaSkZMmAqG1+7Kp mf8QJ7NQMKxclISwvwTWFP5i87P8n8TsHmpr5ZwzJSIoV5Itawr9Qh1gGuhjMEx84KOjUtgci9+ oyxImIq5+w+AMaTFIxqY00LXFWeoaAqAeJIEqan4u1avv6sJhDqgUmxoSRjvlPkW+HiPyoNkhYy 1PsNw== X-Google-Smtp-Source: AGHT+IGRuC9x0JKm120kgdj5Px6SiSPfgvsaiYELSkLjYGdy8H5Bizj14zDJzMyXimu7DD0V6rf86A== X-Received: by 2002:a05:651c:50c:b0:37b:9615:e43a with SMTP id 38308e7fff4ca-382ea9f2dc6mr8741011fa.1.1767715989652; Tue, 06 Jan 2026 08:13:09 -0800 (PST) Received: from LT-5CG5341NQ4.nordic.imtech.com (37-33-180-149.bb.dnainternet.fi. [37.33.180.149]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-382eb91dfbdsm5256091fa.44.2026.01.06.08.13.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Jan 2026 08:13:09 -0800 (PST) From: Kari Argillander Date: Tue, 06 Jan 2026 18:11:40 +0200 Subject: [PATCH RFC v2 02/11] rust: add new ThisModule trait and THIS_MODULE impl Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260106-this_module_fix-v2-2-842ac026f00b@gmail.com> References: <20260106-this_module_fix-v2-0-842ac026f00b@gmail.com> In-Reply-To: <20260106-this_module_fix-v2-0-842ac026f00b@gmail.com> To: Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Alexandre Courbot Cc: Greg Kroah-Hartman , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , Aaron Tomlin , Kari Argillander X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1767715983; l=15432; i=kari.argillander@gmail.com; s=20251219; h=from:subject:message-id; bh=/Ms0ilmTmhT/+pTanvifPfpMypKbgHczZgI+jrgEiCU=; b=VCF39GJJp1wwxCEZh6OVLtm+AKyLVcUz5twsoTod+rQGN3fE6N85Tcj4afu8q8Y/2rGR/8HwV 0VezZT6Bh+wDLrPTUcVyEVHc5BuWrNRBOZXrfGgU63KHQwTWcnHrQgz X-Developer-Key: i=kari.argillander@gmail.com; a=ed25519; pk=RwSxyhTpE3z4sywdDbIkC3q33ZQLNyhYWxT44iTY6r4= 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 --- 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 =20 -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 =20 -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, // +}; =20 /// A configfs subsystem. /// @@ -744,8 +749,7 @@ macro_rules! impl_item_type { ($tpe:ty) =3D> { impl ItemType<$tpe, Data> { #[doc(hidden)] - pub const fn new_with_child_ctor( - owner: &'static ThisModule, + pub const fn new_with_child_ctor( attributes: &'static AttributeList, ) -> Self where @@ -754,7 +758,7 @@ pub const fn new_with_child_ctor( { Self { item_type: Opaque::new(bindings::config_item_type { - ct_owner: owner.as_ptr(), + ct_owner: TM::OWNER.as_ptr(), ct_group_ops: GroupOperationsVTable::= ::vtable_ptr().cast_mut(), ct_item_ops: ItemOperationsVTable::<$tpe, Data>::v= table_ptr().cast_mut(), ct_attrs: core::ptr::from_ref(attributes).cast_mut= ().cast(), @@ -765,13 +769,12 @@ pub const fn new_with_child_ctor( } =20 #[doc(hidden)] - pub const fn new( - owner: &'static ThisModule, + pub const fn new( attributes: &'static AttributeList, ) -> 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>::v= table_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 { /// =3D kernel::configfs::ItemType::< /// configfs::Subsystem, /// Configuration -/// >::new_with_child_ctor::( -/// &THIS_MODULE, +/// >::new_with_child_ctor::( /// &CONFIGURATION_ATTRS /// ); /// @@ -1019,8 +1021,8 @@ macro_rules! configfs_attrs { const [<$no_child:upper>]: bool =3D true; =20 static [< $data:upper _TPE >] : $crate::configfs::Item= Type<$container, $data> =3D - $crate::configfs::ItemType::<$container, $data>::n= ew::( - &THIS_MODULE, &[<$ data:upper _ATTRS >] + $crate::configfs::ItemType::<$container, $data>::n= ew::( + &[<$ data:upper _ATTRS >] ); )? =20 @@ -1028,8 +1030,8 @@ macro_rules! configfs_attrs { static [< $data:upper _TPE >]: $crate::configfs::ItemType<$container, $data> =3D $crate::configfs::ItemType::<$container, $data= >:: - new_with_child_ctor::( - &THIS_MODULE, &[<$ data:upper _ATTRS >] + new_with_child_ctor::( + &[<$ data:upper _ATTRS >] ); )? =20 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 { } } =20 +pub mod this_module { + //! Access to the module identity and ownership information. + //! + //! This module provides the Rust equivalent of the kernel=E2=80=99s `= 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` identifi= es 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 re= ason + //! ThisModule is usually passes as a type parameter `TM` to abstracti= ons + //! which need to know the module owner. In vtables ThisModule is usua= lly + //! used as name. + //! + //! ## Example + //! + //! ``` + //! # use kernel::{bindings, this_module::ThisModule}; + //! # use core::marker::PhantomData; + //! + //! // Example function signature which needs ThisModule. + //! pub fn create_device() {} + //! + //! // Example of a vtable which uses ThisModule. + //! #[vtable] + //! pub trait MyStruct { + //! type ThisModule: ThisModule; + //! } + //! + //! pub(crate) struct MyStructVTable(PhantomData); + //! + //! impl MyStructVTable { + //! const FOPS: bindings::file_operations =3D bindings::file_opera= tions { + //! 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 modul= es. + 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` method= s 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::mod= ule`] + /// and by kernel doctests. + /// + /// A macro is required so that `cfg(MODULE)` is evaluated in the cont= ext 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) =3D> { + /// 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 =3D unsa= fe { + ::kernel::this_module::ModuleWrapper::from_ptr(::core:= :ptr::null_mut()) + }; + + #[cfg(MODULE)] + // SAFETY: + // - `__this_module` is constructed by the kernel at modul= e load time. + const OWNER: ::kernel::this_module::ModuleWrapper =3D unsa= fe { + extern "C" { + static __this_module: ::kernel::types::Opaque<::ke= rnel::bindings::module>; + } + + ::kernel::this_module::ModuleWrapper::from_ptr(__this_= module.get()) + }; + + const NAME: &'static ::kernel::str::CStr =3D $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_MODU= LE` 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 =3D unsafe {{ + ::kernel::ThisModule::from_ptr( + ::OWNER= .as_ptr() + ) + }}; + =20 + /// Gets a pointer to the underlying `struct module`. + // TODO: Temporary to provide functionality old `THIS_MODU= LE` provided. + pub const fn as_ptr(&self) -> *mut ::kernel::bindings::mod= ule {{ + Self::ThisModule.as_ptr() + }} + + /// Gets a reference to the underlying `ThisModule`. + /// TODO: Temporary to provide functionality old `THIS_MOD= ULE` provided. + pub const fn as_ref(&self) -> &'static ::kernel::ThisModul= e {{ + &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] =3D b\"{name}\\0\"; =20 - // SAFETY: `__this_module` is constructed by the kernel at loa= d time and will not be - // freed until the module is unloaded. - #[cfg(MODULE)] - static THIS_MODULE: ::kernel::ThisModule =3D unsafe {{ - extern \"C\" {{ - static __this_module: ::kernel::types::Opaque<::kernel= ::bindings::module>; - }} + ::kernel::create_this_module!(\"{name}\"); =20 - ::kernel::ThisModule::from_ptr(__this_module.get()) - }}; - #[cfg(not(MODULE))] - static THIS_MODULE: ::kernel::ThisModule =3D unsafe {{ - ::kernel::ThisModule::from_ptr(::core::ptr::null_mut()) - }}; =20 /// The `LocalModule` type is the type of the module created b= y `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 =3D - <{type_} as ::kernel::InPlaceModule>::init(&su= per::super::THIS_MODULE); + <{type_} as ::kernel::InPlaceModule>::init(&su= per::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 befor= e 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 {{ =20 const __LOG_PREFIX: &[u8] =3D b"rust_doctests_kernel\0"; =20 +::kernel::create_this_module!("rust_doctests_kernel"); + {rust_tests} "# ) --=20 2.43.0