[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <DG7Y3UT2VT41.1WC83IEOWJ2UG@garyguo.net>
Date: Fri, 06 Feb 2026 14:23:44 +0000
From: "Gary Guo" <gary@...yguo.net>
To: "Greg KH" <gregkh@...uxfoundation.org>, "Alice Ryhl"
<aliceryhl@...gle.com>
Cc: "Danilo Krummrich" <dakr@...nel.org>, <rafael@...nel.org>,
<ojeda@...nel.org>, <boqun.feng@...il.com>, <gary@...yguo.net>,
<bjorn3_gh@...tonmail.com>, <lossin@...nel.org>, <a.hindborg@...nel.org>,
<tmgross@...ch.edu>, <driver-core@...ts.linux.dev>,
<rust-for-linux@...r.kernel.org>, <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH 2/5] devres: export devres_node_init() and
devres_node_add()
On Fri Feb 6, 2026 at 1:55 PM GMT, Greg KH wrote:
> On Fri, Feb 06, 2026 at 01:33:53PM +0000, Alice Ryhl wrote:
>> On Fri, Feb 06, 2026 at 02:22:42PM +0100, Greg KH wrote:
>> > On Fri, Feb 06, 2026 at 02:16:05PM +0100, Danilo Krummrich wrote:
>> > > On Fri Feb 6, 2026 at 1:34 PM CET, Greg KH wrote:
>> > > > That's fine, because the rust driver core code should also be built into
>> > > > the kernel, not as a module, right?
>> > >
>> > > Yes, but the Rust compiler may still choose to put some of the core code into
>> > > the module.
>> >
>> > What exactly do you mean by "the module"?
>> >
>> > > Especially with generic types and functions the Rust compiler may move some the
>> > > generated code for a certain type instance into the module that instanciates the
>> > > type.
>> >
>> > Ah, that's a mess. why? The code lives in the .rs file in the kernel
>> > core, right?
>>
>> It might still be inlined into downstream compilation units. Rust has no
>> equivalent to 'static inline' function in a header file, after all.
>>
>> > > For instance, even though rust/kernel/devres.rs is *always* built-in, we get the
>> > > following error when devres_node_init() is not exported when the users of this
>> > > built-in code are built as module.
>> > >
>> > > ERROR: modpost: "devres_node_init" [drivers/pwm/pwm_th1520.ko] undefined!
>> > > ERROR: modpost: "devres_node_init" [drivers/gpu/drm/tyr/tyr.ko] undefined!
>> > > ERROR: modpost: "devres_node_init" [drivers/gpu/nova-core/nova_core.ko] undefined!
>> > > ERROR: modpost: "devres_node_init" [samples/rust/rust_dma.ko] undefined!
>> > > ERROR: modpost: "devres_node_init" [samples/rust/rust_driver_pci.ko] undefined!
>> > > ERROR: modpost: "devres_node_init" [samples/rust/rust_driver_auxiliary.ko] undefined!
>> > > make[2]: *** [scripts/Makefile.modpost:147: Module.symvers] Error 1
>> >
>> > This feels like a compiler bug, how is the compiler reaching into
>> > devres.rs and sucking out code to put into the module? Doesn't the
>> > build/link boundry stay at the .rs boundry?
>>
>> It's quite intentional.
>>
>> It used to be the case that only functions marked #[inline] could be
>> inlined like this, but it was changed so that small functions without
>> any marker are also eligible for inlining. Now you need #[inline(never)]
>> to ensure it does not happen.
>>
>> Note that this analysis only applies to non-generic code. If you call
>> devres_node_init() from within this function:
>>
>> impl Devres<T> {
>> fn new() -> Self {
>> ... devres_node_init() ...
>> }
>> }
>>
>> then since `new()` is generic over T, it is duplicated for each type T
>> it is used with (via monomorphisation, like C++ templates). So the
>> actual `new` function might be instantiated in the crate that uses
>> Devres<MyDriverType>, and in this case it ends up in the module even
>> with #[inline(never)].
>>
>> So you'd need a non-generic Rust function with #[inline(never)] in this
>> case, and have Devres::<T>::new() call that function.
>>
>> > > However, sprinkling "raw" EXPORT_SYMBOL_GPL() due to that is not great at all.
>> > > Hence, we could do something like in [1] instead. I don't know if there are
>> > > other options that may be better though.
>> > >
>> > > [1] https://lore.kernel.org/all/DG7UR3WWZB4V.2MYMJJH1VDHH@kernel.org/
>> >
>> > That's a start, but still messy. There's no compiler options to prevent
>> > this "lifting" of the code out of devres.rs? If not, this is not going
>> > to be the only problem that drivers run into like this in the future.
>>
>> Because of how monomorphisation, as-is the code actually lives in the
>> module to begin with.
>
> Ok, but again, that is going to cause all sorts of "the symbol is
> undefined" type of problems going forward as a developers just "assumes"
> that the place where the symbol is exported will actually have the
> symbol exported from it, not that this place will be copied inline into
> somewhere else.
Note that this won't be an issue for a Rust module to reference a symbol defiend
in Rust, because everything is EXPORT_SYMBOL_RUST_GPL'd (we use language-builtin
visibilities to control whether people should access an API or not).
For APIs intended for general usage inlined through helpers, it is also a
non-issue because everything is exported already.
The issue is only when a subsystem wants to export a non-public API for Rust
abstraction to use. So far we haven't had a need yet, Devres is the first one
that runs into this.
Best,
Gary
>
> Think about the interaction between module symbol namespaces here. This
> isn't going to scale, and will trip people up and cause us to be forced
> to export way more than we really want to (like this patch series shows,
> I don't want to export any of these...)
>
> thanks,
>
> greg k-h
Powered by blists - more mailing lists