"Benno Lossin" <lossin@xxxxxxxxxx> writes: > On Thu Jun 12, 2025 at 3:40 PM CEST, Andreas Hindborg wrote: >> +/// A wrapper for kernel parameters. >> +/// >> +/// This type is instantiated by the [`module!`] macro when module parameters are >> +/// defined. You should never need to instantiate this type directly. >> +/// >> +/// Note: This type is `pub` because it is used by module crates to access >> +/// parameter values. >> +#[repr(transparent)] >> +pub struct ModuleParamAccess<T> { >> + data: core::cell::UnsafeCell<T>, >> +} >> + >> +// SAFETY: We only create shared references to the contents of this container, >> +// so if `T` is `Sync`, so is `ModuleParamAccess`. >> +unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {} >> + >> +impl<T> ModuleParamAccess<T> { >> + #[doc(hidden)] >> + pub const fn new(value: T) -> Self { >> + Self { >> + data: core::cell::UnsafeCell::new(value), >> + } >> + } >> + >> + /// Get a shared reference to the parameter value. >> + // Note: When sysfs access to parameters are enabled, we have to pass in a >> + // held lock guard here. >> + pub fn get(&self) -> &T { >> + // SAFETY: As we only support read only parameters with no sysfs >> + // exposure, the kernel will not touch the parameter data after module >> + // initialization. > > This should be a type invariant. But I'm having difficulty defining one > that's actually correct: after parsing the parameter, this is written > to, but when is that actually? For built-in modules it is during kernel initialization. For loadable modules, it during module load. No code from the module will execute before parameters are set. > Would we eventually execute other Rust > code during that time? (for example when we allow custom parameter > parsing) I don't think we will need to synchronize because of custom parameter parsing. Parameters are initialized sequentially. It is not a problem if the custom parameter parsing code name other parameters, because they are all initialized to valid values (as they are statics). > > This function also must never be `const` because of the following: > > module! { > // ... > params: { > my_param: i64 { > default: 0, > description: "", > }, > }, > } > > static BAD: &'static i64 = module_parameters::my_param.get(); > > AFAIK, this static will be executed before loading module parameters and > thus it makes writing to the parameter UB. As I understand, the static will be initialized by a constant expression evaluated at compile time. I am not sure what happens when this is evaluated in const context: pub fn get(&self) -> &T { // SAFETY: As we only support read only parameters with no sysfs // exposure, the kernel will not touch the parameter data after module // initialization. unsafe { &*self.data.get() } } Why would that not be OK? I would assume the compiler builds a dependency graph when initializing statics? Best regards, Andreas Hindborg