On Fri Jun 20, 2025 at 1:29 PM CEST, Andreas Hindborg wrote:
> "Benno Lossin" <los...@kernel.org> 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.

Gotcha and there never ever will be custom code that is executed
before/during parameter setting (so code aside from code in `kernel`)?

>> 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).

If you have `&'static i64`, then the value at that reference is never
allowed to change.

>> 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?

Yes it builds a dependency graph, but that is irrelevant? The problem is
that I can create a `'static` reference to the inner value *before* the
parameter is written-to (as the static is initialized before the
parameters).

---
Cheers,
Benno

Reply via email to