On Wed, Jan 7, 2026 at 11:59 AM Gary Guo <[email protected]> wrote:
>
> From: Gary Guo <[email protected]>
>
> This has no behavioural change, but is good for maintainability. With
> `quote!`, we're no longer using string templates, so we don't need to
> quote " and {} inside the template anymore. Further more, editors can
> now highlight the code template.
>
> This also improves the robustness as it eliminates the need for string
> quoting and escaping.
>
> Co-developed-by: Benno Lossin <[email protected]>
> Signed-off-by: Benno Lossin <[email protected]>
> Signed-off-by: Gary Guo <[email protected]>

Are there significant changes here? You didn't pick up my tag.

> ---
>  rust/macros/module.rs | 558 ++++++++++++++++++++++--------------------
>  1 file changed, 295 insertions(+), 263 deletions(-)
>
> diff --git a/rust/macros/module.rs b/rust/macros/module.rs
> index 6ad7b411ccde4..ba345d672839e 100644
> --- a/rust/macros/module.rs
> +++ b/rust/macros/module.rs
> @@ -1,12 +1,15 @@
>  // SPDX-License-Identifier: GPL-2.0
>
> -use std::fmt::Write;
> +use std::ffi::CString;
>
>  use proc_macro2::{
>      Literal,
>      TokenStream, //
>  };
> -use quote::ToTokens;
> +use quote::{
> +    format_ident,
> +    quote, //
> +};
>  use syn::{
>      braced,
>      bracketed,
> @@ -15,11 +18,13 @@
>          Parse,
>          ParseStream, //
>      },
> +    parse_quote,
>      punctuated::Punctuated,
>      Error,
>      Expr,
>      Ident,
>      LitStr,
> +    Path,
>      Result,
>      Token, //
>  };
> @@ -29,8 +34,8 @@
>  struct ModInfoBuilder<'a> {
>      module: &'a str,
>      counter: usize,
> -    buffer: String,
> -    param_buffer: String,
> +    ts: TokenStream,
> +    param_ts: TokenStream,
>  }
>
>  impl<'a> ModInfoBuilder<'a> {
> @@ -38,8 +43,8 @@ fn new(module: &'a str) -> Self {
>          ModInfoBuilder {
>              module,
>              counter: 0,
> -            buffer: String::new(),
> -            param_buffer: String::new(),
> +            ts: TokenStream::new(),
> +            param_ts: TokenStream::new(),
>          }
>      }
>
> @@ -56,33 +61,32 @@ fn emit_base(&mut self, field: &str, content: &str, 
> builtin: bool, param: bool)
>              // Loadable modules' modinfo strings go as-is.
>              format!("{field}={content}\0")
>          };
> -
> -        let buffer = if param {
> -            &mut self.param_buffer
> +        let length = string.len();
> +        let string = Literal::byte_string(string.as_bytes());
> +        let cfg = if builtin {
> +            quote!(#[cfg(not(MODULE))])
>          } else {
> -            &mut self.buffer
> +            quote!(#[cfg(MODULE)])
>          };
>
> -        write!(
> -            buffer,
> -            "
> -                {cfg}
> -                #[doc(hidden)]
> -                #[cfg_attr(not(target_os = \"macos\"), link_section = 
> \".modinfo\")]
> -                #[used(compiler)]
> -                pub static __{module}_{counter}: [u8; {length}] = *{string};
> -            ",
> -            cfg = if builtin {
> -                "#[cfg(not(MODULE))]"
> -            } else {
> -                "#[cfg(MODULE)]"
> -            },
> +        let counter = format_ident!(
> +            "__{module}_{counter}",
>              module = self.module.to_uppercase(),
> -            counter = self.counter,
> -            length = string.len(),
> -            string = Literal::byte_string(string.as_bytes()),
> -        )
> -        .unwrap();
> +            counter = self.counter
> +        );
> +        let item = quote! {
> +            #cfg
> +            #[doc(hidden)]
> +            #[cfg_attr(not(target_os = "macos"), link_section = ".modinfo")]
> +            #[used(compiler)]
> +            pub static #counter: [u8; #length] = *#string;
> +        };
> +
> +        if param {
> +            self.param_ts.extend(item);
> +        } else {
> +            self.ts.extend(item);
> +        }
>
>          self.counter += 1;
>      }
> @@ -115,77 +119,86 @@ fn emit_params(&mut self, info: &ModuleInfo) {
>          };
>
>          for param in params {
> -            let param_name = param.name.to_string();
> -            let param_type = param.ptype.to_string();
> -            let param_default = param.default.to_token_stream().to_string();
> +            let param_name_str = param.name.to_string();
> +            let param_type_str = param.ptype.to_string();

This renaming is unfortunately; these variables were just introduced
in the previous patch.

>
> -            let ops = param_ops_path(&param_type);
> +            let ops = param_ops_path(&param_type_str);
>
>              // Note: The spelling of these fields is dictated by the user 
> space
>              // tool `modinfo`.
> -            self.emit_param("parmtype", &param_name, &param_type);
> -            self.emit_param("parm", &param_name, &param.description.value());
> -
> -            write!(
> -                self.param_buffer,
> -                "
> -                pub(crate) static {param_name}:
> -                    ::kernel::module_param::ModuleParamAccess<{param_type}> =
> -                        
> ::kernel::module_param::ModuleParamAccess::new({param_default});
> -
> -                const _: () = {{
> -                    #[link_section = \"__param\"]
> -                    #[used]
> -                    static __{module_name}_{param_name}_struct:
> +            self.emit_param("parmtype", &param_name_str, &param_type_str);
> +            self.emit_param("parm", &param_name_str, 
> &param.description.value());
> +
> +            let static_name = format_ident!("__{}_{}_struct", self.module, 
> param.name);
> +            let param_name_cstr = Literal::c_string(
> +                &CString::new(param_name_str).expect("name contains 
> NUL-terminator"),
> +            );
> +            let param_name_cstr_with_module = Literal::c_string(
> +                &CString::new(format!("{}.{}", self.module, param.name))
> +                    .expect("name contains NUL-terminator"),
> +            );
> +
> +            let param_name = &param.name;
> +            let param_type = &param.ptype;
> +            let param_default = &param.default;
> +
> +            self.param_ts.extend(quote!{
> +                #[allow(non_upper_case_globals)]
> +                pub(crate) static #param_name:
> +                    ::kernel::module_param::ModuleParamAccess<#param_type> =
> +                        
> ::kernel::module_param::ModuleParamAccess::new(#param_default);
> +
> +                const _: () = {
> +                    #[allow(non_upper_case_globals)]
> +                    #[link_section = "__param"]
> +                    #[used(compiler)]
> +                    static #static_name:
>                          ::kernel::module_param::KernelParam =
>                          ::kernel::module_param::KernelParam::new(
> -                            ::kernel::bindings::kernel_param {{
> -                                name: if ::core::cfg!(MODULE) {{
> -                                    
> ::kernel::c_str!(\"{param_name}\").to_bytes_with_nul()
> -                                }} else {{
> -                                    
> ::kernel::c_str!(\"{module_name}.{param_name}\")
> -                                        .to_bytes_with_nul()
> -                                }}.as_ptr(),
> +                            ::kernel::bindings::kernel_param {
> +                                name: 
> kernel::str::as_char_ptr_in_const_context(
> +                                    if ::core::cfg!(MODULE) {
> +                                        #param_name_cstr
> +                                    } else {
> +                                        #param_name_cstr_with_module
> +                                    }
> +                                ),
>                                  // SAFETY: `__this_module` is constructed by 
> the kernel at load
>                                  // time and will not be freed until the 
> module is unloaded.
>                                  #[cfg(MODULE)]
> -                                mod_: unsafe {{
> +                                mod_: unsafe {
>                                      
> core::ptr::from_ref(&::kernel::bindings::__this_module)
>                                          .cast_mut()
> -                                }},
> +                                },
>                                  #[cfg(not(MODULE))]
>                                  mod_: ::core::ptr::null_mut(),
> -                                ops: core::ptr::from_ref(&{ops}),
> +                                ops: core::ptr::from_ref(&#ops),
>                                  perm: 0, // Will not appear in sysfs
>                                  level: -1,
>                                  flags: 0,
> -                                __bindgen_anon_1: 
> ::kernel::bindings::kernel_param__bindgen_ty_1 {{
> -                                    arg: {param_name}.as_void_ptr()
> -                                }},
> -                            }}
> +                                __bindgen_anon_1: 
> ::kernel::bindings::kernel_param__bindgen_ty_1 {
> +                                    arg: #param_name.as_void_ptr()
> +                                },
> +                            }
>                          );
> -                }};
> -                ",
> -                module_name = info.name.value(),
> -                ops = ops,
> -            )
> -            .unwrap();
> +                };
> +            });
>          }
>      }
>  }
>
> -fn param_ops_path(param_type: &str) -> &'static str {
> +fn param_ops_path(param_type: &str) -> Path {
>      match param_type {
> -        "i8" => "::kernel::module_param::PARAM_OPS_I8",
> -        "u8" => "::kernel::module_param::PARAM_OPS_U8",
> -        "i16" => "::kernel::module_param::PARAM_OPS_I16",
> -        "u16" => "::kernel::module_param::PARAM_OPS_U16",
> -        "i32" => "::kernel::module_param::PARAM_OPS_I32",
> -        "u32" => "::kernel::module_param::PARAM_OPS_U32",
> -        "i64" => "::kernel::module_param::PARAM_OPS_I64",
> -        "u64" => "::kernel::module_param::PARAM_OPS_U64",
> -        "isize" => "::kernel::module_param::PARAM_OPS_ISIZE",
> -        "usize" => "::kernel::module_param::PARAM_OPS_USIZE",
> +        "i8" => parse_quote!(::kernel::module_param::PARAM_OPS_I8),
> +        "u8" => parse_quote!(::kernel::module_param::PARAM_OPS_U8),
> +        "i16" => parse_quote!(::kernel::module_param::PARAM_OPS_I16),
> +        "u16" => parse_quote!(::kernel::module_param::PARAM_OPS_U16),
> +        "i32" => parse_quote!(::kernel::module_param::PARAM_OPS_I32),
> +        "u32" => parse_quote!(::kernel::module_param::PARAM_OPS_U32),
> +        "i64" => parse_quote!(::kernel::module_param::PARAM_OPS_I64),
> +        "u64" => parse_quote!(::kernel::module_param::PARAM_OPS_U64),
> +        "isize" => parse_quote!(::kernel::module_param::PARAM_OPS_ISIZE),
> +        "usize" => parse_quote!(::kernel::module_param::PARAM_OPS_USIZE),
>          t => panic!("Unsupported parameter type {}", t),
>      }
>  }
> @@ -424,29 +437,41 @@ fn parse(input: ParseStream<'_>) -> Result<Self> {
>  }
>
>  pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
> +    let ModuleInfo {
> +        type_,
> +        license,
> +        name,
> +        authors,
> +        description,
> +        alias,
> +        firmware,
> +        imports_ns,
> +        params: _,
> +    } = &info;
> +
>      // Rust does not allow hyphens in identifiers, use underscore instead.
> -    let ident = info.name.value().replace('-', "_");
> +    let ident = name.value().replace('-', "_");
>      let mut modinfo = ModInfoBuilder::new(ident.as_ref());
> -    if let Some(authors) = &info.authors {
> +    if let Some(authors) = authors {
>          for author in authors {
>              modinfo.emit("author", &author.value());
>          }
>      }
> -    if let Some(description) = &info.description {
> +    if let Some(description) = description {
>          modinfo.emit("description", &description.value());
>      }
> -    modinfo.emit("license", &info.license.value());
> -    if let Some(aliases) = &info.alias {
> +    modinfo.emit("license", &license.value());
> +    if let Some(aliases) = alias {
>          for alias in aliases {
>              modinfo.emit("alias", &alias.value());
>          }
>      }
> -    if let Some(firmware) = &info.firmware {
> +    if let Some(firmware) = firmware {
>          for fw in firmware {
>              modinfo.emit("firmware", &fw.value());
>          }
>      }
> -    if let Some(imports) = &info.imports_ns {
> +    if let Some(imports) = imports_ns {
>          for ns in imports {
>              modinfo.emit("import_ns", &ns.value());
>          }
> @@ -459,182 +484,189 @@ pub(crate) fn module(info: ModuleInfo) -> 
> Result<TokenStream> {
>
>      modinfo.emit_params(&info);
>
> -    Ok(format!(
> -        "
> -            /// The module name.
> -            ///
> -            /// 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::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.
> -            type LocalModule = {type_};
> -
> -            impl ::kernel::ModuleMetadata for {type_} {{
> -                const NAME: &'static ::kernel::str::CStr = c\"{name}\";
> -            }}
> -
> -            // Double nested modules, since then nobody can access the 
> public items inside.
> -            mod __module_init {{
> -                mod __module_init {{
> -                    use super::super::{type_};
> -                    use pin_init::PinInit;
> -
> -                    /// The \"Rust loadable module\" mark.
> -                    //
> -                    // This may be best done another way later on, e.g. as a 
> new modinfo
> -                    // key or a new section. For the moment, keep it simple.
> -                    #[cfg(MODULE)]
> -                    #[doc(hidden)]
> -                    #[used(compiler)]
> -                    static __IS_RUST_MODULE: () = ();
> -
> -                    static mut __MOD: ::core::mem::MaybeUninit<{type_}> =
> -                        ::core::mem::MaybeUninit::uninit();
> -
> -                    // Loadable modules need to export the 
> `{{init,cleanup}}_module` identifiers.
> -                    /// # Safety
> -                    ///
> -                    /// This function must not be called after module 
> initialization, because it may be
> -                    /// freed after that completes.
> -                    #[cfg(MODULE)]
> -                    #[doc(hidden)]
> -                    #[no_mangle]
> -                    #[link_section = \".init.text\"]
> -                    pub unsafe extern \"C\" fn init_module() -> 
> ::kernel::ffi::c_int {{
> -                        // SAFETY: This function is inaccessible to the 
> outside due to the double
> -                        // module wrapping it. It is called exactly once by 
> the C side via its
> -                        // unique name.
> -                        unsafe {{ __init() }}
> -                    }}
> -
> -                    #[cfg(MODULE)]
> -                    #[doc(hidden)]
> -                    #[used(compiler)]
> -                    #[link_section = \".init.data\"]
> -                    static __UNIQUE_ID___addressable_init_module: unsafe 
> extern \"C\" fn() -> i32 = init_module;
> -
> -                    #[cfg(MODULE)]
> -                    #[doc(hidden)]
> -                    #[no_mangle]
> -                    #[link_section = \".exit.text\"]
> -                    pub extern \"C\" fn cleanup_module() {{
> -                        // SAFETY:
> -                        // - This function is inaccessible to the outside 
> due to the double
> -                        //   module wrapping it. It is called exactly once 
> by the C side via its
> -                        //   unique name,
> -                        // - furthermore it is only called after 
> `init_module` has returned `0`
> -                        //   (which delegates to `__init`).
> -                        unsafe {{ __exit() }}
> -                    }}
> -
> -                    #[cfg(MODULE)]
> -                    #[doc(hidden)]
> -                    #[used(compiler)]
> -                    #[link_section = \".exit.data\"]
> -                    static __UNIQUE_ID___addressable_cleanup_module: extern 
> \"C\" fn() = cleanup_module;
> -
> -                    // Built-in modules are initialized through an initcall 
> pointer
> -                    // and the identifiers need to be unique.
> -                    #[cfg(not(MODULE))]
> -                    #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
> -                    #[doc(hidden)]
> -                    #[link_section = \"{initcall_section}\"]
> -                    #[used(compiler)]
> -                    pub static __{ident}_initcall: extern \"C\" fn() ->
> -                        ::kernel::ffi::c_int = __{ident}_init;
> -
> -                    #[cfg(not(MODULE))]
> -                    #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
> -                    ::core::arch::global_asm!(
> -                        r#\".section \"{initcall_section}\", \"a\"
> -                        __{ident}_initcall:
> -                            .long   __{ident}_init - .
> -                            .previous
> -                        \"#
> -                    );
> -
> -                    #[cfg(not(MODULE))]
> -                    #[doc(hidden)]
> -                    #[no_mangle]
> -                    pub extern \"C\" fn __{ident}_init() -> 
> ::kernel::ffi::c_int {{
> -                        // SAFETY: This function is inaccessible to the 
> outside due to the double
> -                        // module wrapping it. It is called exactly once by 
> the C side via its
> -                        // placement above in the initcall section.
> -                        unsafe {{ __init() }}
> -                    }}
> -
> -                    #[cfg(not(MODULE))]
> -                    #[doc(hidden)]
> -                    #[no_mangle]
> -                    pub extern \"C\" fn __{ident}_exit() {{
> -                        // SAFETY:
> -                        // - This function is inaccessible to the outside 
> due to the double
> -                        //   module wrapping it. It is called exactly once 
> by the C side via its
> -                        //   unique name,
> -                        // - furthermore it is only called after 
> `__{ident}_init` has
> -                        //   returned `0` (which delegates to `__init`).
> -                        unsafe {{ __exit() }}
> -                    }}
> -
> -                    /// # Safety
> -                    ///
> -                    /// 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);
> -                        // 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`.
> -                        match unsafe {{ 
> initer.__pinned_init(__MOD.as_mut_ptr()) }} {{
> -                            Ok(m) => 0,
> -                            Err(e) => e.to_errno(),
> -                        }}
> -                    }}
> -
> -                    /// # Safety
> -                    ///
> -                    /// This function must
> -                    /// - only be called once,
> -                    /// - be called after `__init` has been called and 
> returned `0`.
> -                    unsafe fn __exit() {{
> -                        // 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 `__init` was already called.
> -                        unsafe {{
> -                            // Invokes `drop()` on `__MOD`, which should be 
> used for cleanup.
> -                            __MOD.assume_init_drop();
> -                        }}
> -                    }}
> -                    {modinfo}
> -                }}
> -            }}
> -            mod module_parameters {{
> -                {params}
> -            }}
> -        ",
> -        type_ = info.type_,
> -        name = info.name.value(),
> -        ident = ident,
> -        modinfo = modinfo.buffer,
> -        params = modinfo.param_buffer,
> -        initcall_section = ".initcall6.init"
> -    )
> -    .parse()
> -    .expect("Error parsing formatted string into token stream."))
> +    let modinfo_ts = modinfo.ts;
> +    let params_ts = modinfo.param_ts;
> +
> +    let ident_init = format_ident!("__{ident}_init");
> +    let ident_exit = format_ident!("__{ident}_exit");
> +    let ident_initcall = format_ident!("__{ident}_initcall");
> +    let initcall_section = ".initcall6.init";
> +
> +    let global_asm = format!(
> +        r#".section "{initcall_section}", "a"
> +        __{ident}_initcall:
> +            .long   __{ident}_init - .
> +            .previous
> +        "#
> +    );
> +
> +    let name_cstr =
> +        Literal::c_string(&CString::new(name.value()).expect("name contains 
> NUL-terminator"));
> +
> +    Ok(quote! {
> +        /// The module name.
> +        ///
> +        /// Used by the printing macros, e.g. [`info!`].
> +        const __LOG_PREFIX: &[u8] = #name_cstr.to_bytes_with_nul();
> +
> +        // 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::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.
> +        type LocalModule = #type_;
> +
> +        impl ::kernel::ModuleMetadata for #type_ {
> +            const NAME: &'static ::kernel::str::CStr = #name_cstr;
> +        }
> +
> +        // Double nested modules, since then nobody can access the public 
> items inside.
> +        mod __module_init {
> +            mod __module_init {
> +                use super::super::#type_;
> +                use pin_init::PinInit;
> +
> +                /// The "Rust loadable module" mark.
> +                //
> +                // This may be best done another way later on, e.g. as a new 
> modinfo
> +                // key or a new section. For the moment, keep it simple.
> +                #[cfg(MODULE)]
> +                #[doc(hidden)]
> +                #[used(compiler)]
> +                static __IS_RUST_MODULE: () = ();
> +
> +                static mut __MOD: ::core::mem::MaybeUninit<#type_> =
> +                    ::core::mem::MaybeUninit::uninit();
> +
> +                // Loadable modules need to export the 
> `{init,cleanup}_module` identifiers.
> +                /// # Safety
> +                ///
> +                /// This function must not be called after module 
> initialization, because it may be
> +                /// freed after that completes.
> +                #[cfg(MODULE)]
> +                #[doc(hidden)]
> +                #[no_mangle]
> +                #[link_section = ".init.text"]
> +                pub unsafe extern "C" fn init_module() -> 
> ::kernel::ffi::c_int {
> +                    // SAFETY: This function is inaccessible to the outside 
> due to the double
> +                    // module wrapping it. It is called exactly once by the 
> C side via its
> +                    // unique name.
> +                    unsafe { __init() }
> +                }
> +
> +                #[cfg(MODULE)]
> +                #[doc(hidden)]
> +                #[used(compiler)]
> +                #[link_section = ".init.data"]
> +                static __UNIQUE_ID___addressable_init_module: unsafe extern 
> "C" fn() -> i32 =
> +                    init_module;
> +
> +                #[cfg(MODULE)]
> +                #[doc(hidden)]
> +                #[no_mangle]
> +                #[link_section = ".exit.text"]
> +                pub extern "C" fn cleanup_module() {
> +                    // SAFETY:
> +                    // - This function is inaccessible to the outside due to 
> the double
> +                    //   module wrapping it. It is called exactly once by 
> the C side via its
> +                    //   unique name,
> +                    // - furthermore it is only called after `init_module` 
> has returned `0`
> +                    //   (which delegates to `__init`).
> +                    unsafe { __exit() }
> +                }
> +
> +                #[cfg(MODULE)]
> +                #[doc(hidden)]
> +                #[used(compiler)]
> +                #[link_section = ".exit.data"]
> +                static __UNIQUE_ID___addressable_cleanup_module: extern "C" 
> fn() = cleanup_module;
> +
> +                // Built-in modules are initialized through an initcall 
> pointer
> +                // and the identifiers need to be unique.
> +                #[cfg(not(MODULE))]
> +                #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
> +                #[doc(hidden)]
> +                #[link_section = #initcall_section]
> +                #[used(compiler)]
> +                pub static #ident_initcall: extern "C" fn() ->
> +                    ::kernel::ffi::c_int = #ident_initcall;
> +
> +                #[cfg(not(MODULE))]
> +                #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
> +                ::core::arch::global_asm!(#global_asm);
> +
> +                #[cfg(not(MODULE))]
> +                #[doc(hidden)]
> +                #[no_mangle]
> +                pub extern "C" fn #ident_init() -> ::kernel::ffi::c_int {
> +                    // SAFETY: This function is inaccessible to the outside 
> due to the double
> +                    // module wrapping it. It is called exactly once by the 
> C side via its
> +                    // placement above in the initcall section.
> +                    unsafe { __init() }
> +                }
> +
> +                #[cfg(not(MODULE))]
> +                #[doc(hidden)]
> +                #[no_mangle]
> +                pub extern "C" fn #ident_exit() {
> +                    // SAFETY:
> +                    // - This function is inaccessible to the outside due to 
> the double
> +                    //   module wrapping it. It is called exactly once by 
> the C side via its
> +                    //   unique name,
> +                    // - furthermore it is only called after `#ident_init` 
> has
> +                    //   returned `0` (which delegates to `__init`).
> +                    unsafe { __exit() }
> +                }
> +
> +                /// # Safety
> +                ///
> +                /// 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);
> +                    // 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`.
> +                    match unsafe { initer.__pinned_init(__MOD.as_mut_ptr()) 
> } {
> +                        Ok(m) => 0,
> +                        Err(e) => e.to_errno(),
> +                    }
> +                }
> +
> +                /// # Safety
> +                ///
> +                /// This function must
> +                /// - only be called once,
> +                /// - be called after `__init` has been called and returned 
> `0`.
> +                unsafe fn __exit() {
> +                    // 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 `__init` was already called.
> +                    unsafe {
> +                        // Invokes `drop()` on `__MOD`, which should be used 
> for cleanup.
> +                        __MOD.assume_init_drop();
> +                    }
> +                }
> +
> +                #modinfo_ts
> +            }
> +        }
> +
> +        mod module_parameters {
> +            #params_ts
> +        }
> +    })
>  }
> --
> 2.51.2
>
>

Reply via email to