rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Benno Lossin" <lossin@kernel.org>
To: "Andreas Hindborg" <a.hindborg@kernel.org>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Masahiro Yamada" <masahiroy@kernel.org>,
	"Nathan Chancellor" <nathan@kernel.org>,
	"Luis Chamberlain" <mcgrof@kernel.org>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Nicolas Schier" <nicolas.schier@linux.dev>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Adam Bratschi-Kaye" <ark.email@gmail.com>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-kbuild@vger.kernel.org, "Petr Pavlu" <petr.pavlu@suse.com>,
	"Sami Tolvanen" <samitolvanen@google.com>,
	"Daniel Gomez" <da.gomez@samsung.com>,
	"Simona Vetter" <simona.vetter@ffwll.ch>,
	"Greg KH" <gregkh@linuxfoundation.org>,
	"Fiona Behrens" <me@kloenk.dev>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	linux-modules@vger.kernel.org
Subject: Re: [PATCH v13 2/6] rust: introduce module_param module
Date: Mon, 23 Jun 2025 17:20:30 +0200	[thread overview]
Message-ID: <DAU0J3T0IEVM.2K7ZRQOVOHF8H@kernel.org> (raw)
In-Reply-To: <87v7om4jhq.fsf@kernel.org>

On Mon Jun 23, 2025 at 4:31 PM CEST, Andreas Hindborg wrote:
> "Benno Lossin" <lossin@kernel.org> writes:
>
>> On Mon Jun 23, 2025 at 11:44 AM CEST, Andreas Hindborg wrote:
>>> "Benno Lossin" <lossin@kernel.org> writes:
>>>
>>>> On Fri Jun 20, 2025 at 1:29 PM CEST, Andreas Hindborg wrote:
>>>>> "Benno Lossin" <lossin@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).
>>>
>>> I see, I did not consider this situation. Thanks for pointing this out.
>>>
>>> Could we get around this without a lock maybe? If we change
>>> `ModuleParamAccess::get` to take a closure instead:
>>>
>>>     /// Call `func` with a reference to the parameter value stored in `Self`.
>>>     pub fn read(&self, func: impl FnOnce(&T)) {
>>>         // SAFETY: As we only support read only parameters with no sysfs
>>>         // exposure, the kernel will not touch the parameter data after module
>>>         // initialization.
>>>         let data = unsafe { &*self.data.get() };
>>>
>>>         func(data)
>>>     }
>>>
>>> I think this would bound the lifetime of the reference passed to the
>>> closure to the duration of the call, right?
>>
>> Yes that is correct. Now you can't assign the reference to a static.
>> However, this API is probably very clunky to use, since you always have
>> to create a closure etc.
>>
>> Since you mentioned in the other reply that one could spin up a thread
>> and do something simultaneously, I don't think this is enough. You could
>> have a loop spin over the new `read` function and read the value and
>> then the write happens.
>
> Yes you are right, we have to treat it as if it could be written at any
> point in time.
>
>> One way to fix this issue would be to use atomics to read the value and
>> to not create a reference to it. So essentially have
>>
>>     pub fn read(&self) -> T {
>>         unsafe { atomic_read_unsafe_cell(&self.data) }
>>     }
>
> That could work.
>
>> Another way would be to use a `Once`-like type (does that exist on the C
>> side?) so a type that can be initialized once and then never changes.
>> While it doesn't have a value set, we return some default value for the
>> param and print a warning, when it's set, we just return the value. But
>> this probably also requires atomics...
>
> I think atomic bool is not that far away. Either that, or we can lock.
>
>> Is parameter accessing used that often in hot paths? Can't you just copy
>> the value into your `Module` struct?
>
> I don't imagine this being read in a hot path. If so, the user could
> make a copy.

That's good to know, then let's try to go for something simple.

I don't think that we can just use a `Mutex<T>`, because we don't have a
way to create it at const time... I guess we could have

    impl<T> Mutex<T>
        /// # Safety
        ///
        /// The returned value needs to be pinned and then `init` needs
        /// to be called before any other methods are called on this.
        pub unsafe const fn const_new() -> Self;

        pub unsafe fn init(&self);
    }

But that seems like a bad idea, because where would we call the `init`
function? That also needs to be synchronized...

Maybe we can just like you said use an atomic bool?

---
Cheers,
Benno

  reply	other threads:[~2025-06-23 15:20 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-12 13:40 [PATCH v13 0/6] rust: extend `module!` macro with integer parameter support Andreas Hindborg
2025-06-12 13:40 ` [PATCH v13 1/6] rust: str: add radix prefixed integer parsing functions Andreas Hindborg
2025-06-18 20:38   ` Benno Lossin
2025-06-19 11:12     ` Andreas Hindborg
2025-06-19 12:17       ` Benno Lossin
2025-06-19 12:41         ` Andreas Hindborg
2025-06-12 13:40 ` [PATCH v13 2/6] rust: introduce module_param module Andreas Hindborg
2025-06-18 20:59   ` Benno Lossin
2025-06-19 12:20     ` Andreas Hindborg
2025-06-19 12:55       ` Benno Lossin
2025-06-20 10:31         ` Andreas Hindborg
2025-06-19 13:15   ` Benno Lossin
2025-06-20 11:29     ` Andreas Hindborg
2025-06-20 11:52       ` Andreas Hindborg
2025-06-20 12:28       ` Benno Lossin
2025-06-23  9:44         ` Andreas Hindborg
2025-06-23 11:48           ` Benno Lossin
2025-06-23 12:37             ` Miguel Ojeda
2025-06-23 13:55               ` Benno Lossin
2025-06-23 14:31             ` Andreas Hindborg
2025-06-23 15:20               ` Benno Lossin [this message]
2025-06-24 11:57                 ` Andreas Hindborg
2025-06-27  7:57                   ` Andreas Hindborg
2025-06-27  8:23                     ` Benno Lossin
2025-06-30 11:18                       ` Andreas Hindborg
2025-06-30 12:27                         ` Benno Lossin
2025-06-30 13:15                           ` Andreas Hindborg
2025-06-30 19:02                             ` Benno Lossin
2025-07-01  8:43                               ` Andreas Hindborg
2025-07-01  9:05                                 ` Benno Lossin
2025-07-01 14:14                                   ` Andreas Hindborg
2025-07-01 15:43                                     ` Benno Lossin
2025-07-01 16:27                                       ` Miguel Ojeda
2025-07-01 16:54                                         ` Benno Lossin
2025-07-02  8:30                                           ` Andreas Hindborg
2025-07-02  8:26                                         ` Andreas Hindborg
2025-07-02 10:01                                           ` Benno Lossin
2025-07-02  7:56                                       ` Andreas Hindborg
2025-06-23  9:47         ` Andreas Hindborg
2025-06-12 13:40 ` [PATCH v13 3/6] rust: module: use a reference in macros::module::module Andreas Hindborg
2025-06-18 20:07   ` Benno Lossin
2025-06-12 13:40 ` [PATCH v13 4/6] rust: module: update the module macro with module parameter support Andreas Hindborg
2025-06-18 21:07   ` Benno Lossin
2025-06-19 12:31     ` Andreas Hindborg
2025-06-12 13:40 ` [PATCH v13 5/6] rust: samples: add a module parameter to the rust_minimal sample Andreas Hindborg
2025-06-18 19:48   ` Benno Lossin
2025-06-30 11:30   ` Danilo Krummrich
2025-06-30 12:12     ` Andreas Hindborg
2025-06-30 12:18       ` Danilo Krummrich
2025-06-30 12:23         ` Danilo Krummrich
2025-06-30 12:31           ` Benno Lossin
2025-06-12 13:40 ` [PATCH v13 6/6] modules: add rust modules files to MAINTAINERS Andreas Hindborg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DAU0J3T0IEVM.2K7ZRQOVOHF8H@kernel.org \
    --to=lossin@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=ark.email@gmail.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=da.gomez@samsung.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-modules@vger.kernel.org \
    --cc=masahiroy@kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=me@kloenk.dev \
    --cc=nathan@kernel.org \
    --cc=nicolas.schier@linux.dev \
    --cc=ojeda@kernel.org \
    --cc=petr.pavlu@suse.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=samitolvanen@google.com \
    --cc=simona.vetter@ffwll.ch \
    --cc=tmgross@umich.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).