Skip to content

Commit bdea1a1

Browse files
committed
rust: macros: expose module parameters through MODPARAM struct
Instead of creating a struct + constant pair for each parameter, expose the parameters as methods over a single struct MODPARAM. In this example the parameter `foobar` is available at the Rust end as `MODPARAM.foobar()`. The rationale is that currently the `module!` macro generates a constant with the name of the parameter which can lead to surprising behavior when attempting to create a let binding of the same name: module! { type: ParamName, // ... params: { foobar : bool { default: true, permissions: 0o644, description: "test", }, }, } fn clash() { let foobar = 42; } This causes rustc to error out because `foobar` is treated as a pattern on the left hand side of the let expression: 10 | / module! { 11 | | type: ParamName, 12 | | name: "param_name", 13 | | author: "A. U. Thor", ... | 21 | | }, 22 | | } | |_- constant defined here ... 25 | let foobar = 42; | ^^^^^^ -- this expression has type `{integer}` | | | expected integer, found struct `__param_name_foobar` | `foobar` is interpreted as a constant, not a new binding | help: introduce a new binding instead: `other_foobar` Essentially, having a parameter `foobar` prevents the creation of a binding of the same name anywhere else in the module. Signed-off-by: Philipp Gesang <phg@phi-gamma.net> Suggested-by: Gary Guo <gary@garyguo.net>
1 parent 5423795 commit bdea1a1

File tree

2 files changed

+33
-14
lines changed

2 files changed

+33
-14
lines changed

rust/macros/module.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
329329
assert_eq!(params.delimiter(), Delimiter::Brace);
330330

331331
let mut it = params.stream().into_iter();
332+
let mut read_funcs = Vec::new();
332333

333334
loop {
334335
let param_name = match it.next() {
@@ -388,7 +389,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
388389
let read_func = if permissions_are_readonly(&param_permissions) {
389390
format!(
390391
"
391-
fn read(&self)
392+
fn {param_name}(&self)
392393
-> &<{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
393394
// SAFETY: Parameters do not need to be locked because they are
394395
// read only or sysfs is not enabled.
@@ -406,7 +407,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
406407
} else {
407408
format!(
408409
"
409-
fn read<'lck>(&self, lock: &'lck kernel::KParamGuard)
410+
fn {param_name}<'lck>(&self, lock: &'lck kernel::KParamGuard)
410411
-> &'lck <{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
411412
// SAFETY: Parameters are locked by `KParamGuard`.
412413
unsafe {{
@@ -421,6 +422,8 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
421422
param_type_internal = param_type_internal,
422423
)
423424
};
425+
read_funcs.push(read_func);
426+
424427
let kparam = format!(
425428
"
426429
kernel::bindings::kernel_param__bindgen_ty_1 {{
@@ -436,12 +439,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
436439
"
437440
static mut __{name}_{param_name}_value: {param_type_internal} = {param_default};
438441
439-
struct __{name}_{param_name};
440-
441-
impl __{name}_{param_name} {{ {read_func} }}
442-
443-
const {param_name}: __{name}_{param_name} = __{name}_{param_name};
444-
445442
// Note: the C macro that generates the static structs for the `__param` section
446443
// asks for them to be `aligned(sizeof(void *))`. However, that was put in place
447444
// in 2003 in commit 38d5b085d2a0 (\"[PATCH] Fix over-alignment problem on x86-64\")
@@ -483,7 +480,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
483480
",
484481
name = info.name,
485482
param_type_internal = param_type_internal,
486-
read_func = read_func,
487483
param_default = param_default,
488484
param_name = param_name,
489485
ops = ops,
@@ -492,6 +488,29 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
492488
)
493489
.unwrap();
494490
}
491+
492+
write!(
493+
modinfo.buffer,
494+
"
495+
struct __MODPARAM;
496+
497+
impl __MODPARAM {{
498+
"
499+
)
500+
.unwrap();
501+
502+
read_funcs.iter().for_each(|read_func| {
503+
writeln!(modinfo.buffer, "{}", read_func).unwrap();
504+
});
505+
506+
write!(
507+
modinfo.buffer,
508+
"}}
509+
510+
const MODPARAM: __MODPARAM = __MODPARAM;
511+
"
512+
)
513+
.unwrap();
495514
}
496515

497516
let mut generated_array_types = String::new();

samples/rust/rust_module_parameters.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ impl kernel::Module for RustModuleParameters {
4848
{
4949
let lock = module.kernel_param_lock();
5050
pr_info!("Parameters:\n");
51-
pr_info!(" my_bool: {}\n", my_bool.read());
52-
pr_info!(" my_i32: {}\n", my_i32.read(&lock));
51+
pr_info!(" my_bool: {}\n", MODPARAM.my_bool());
52+
pr_info!(" my_i32: {}\n", MODPARAM.my_i32(&lock));
5353
pr_info!(
5454
" my_str: {}\n",
55-
core::str::from_utf8(my_str.read(&lock))?
55+
core::str::from_utf8(MODPARAM.my_str(&lock))?
5656
);
57-
pr_info!(" my_usize: {}\n", my_usize.read(&lock));
58-
pr_info!(" my_array: {:?}\n", my_array.read());
57+
pr_info!(" my_usize: {}\n", MODPARAM.my_usize(&lock));
58+
pr_info!(" my_array: {:?}\n", MODPARAM.my_array());
5959
}
6060

6161
Ok(RustModuleParameters)

0 commit comments

Comments
 (0)