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 <[email protected]> --- 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

