* [PATCH 0/5] Use struct devres_node in Devres<T>
@ 2026-02-05 22:31 Danilo Krummrich
2026-02-05 22:31 ` [PATCH 1/5] devres: move struct devres_node into base.h Danilo Krummrich
` (4 more replies)
0 siblings, 5 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
Currently, the Devres<T> container uses devm_add_action() to register a
devres callback.
devm_add_action() allocates a struct action_devres, which on top of
struct devres_node, just keeps a data pointer and release function
pointer.
This is an unnecessary indirection, given that analogous to struct
devres, the Devres<T> container can just embed a struct devres_node
directly without an additional allocation.
In contrast to struct devres, we don't need to force an alignment of
ARCH_DMA_MINALIGN (as struct devres does to account for the worst case)
since we have generics in Rust. I.e. the compiler already ensures
correct alignment of the embedded T in Devres<T>.
Thus, get rid of devm_add_action() and instead embed a struct
devres_node directly.
This patch series is based on [1] and [2].
[1] https://lore.kernel.org/lkml/20260205222529.91465-1-dakr@kernel.org/
[2] https://lore.kernel.org/lkml/20260202235210.55176-1-dakr@kernel.org/
Danilo Krummrich (5):
devres: move struct devres_node into base.h
devres: export devres_node_init() and devres_node_add()
devres: add devres_node_remove()
devres: rename and export set_node_dbginfo()
rust: devres: embed struct devres_node directly
drivers/base/base.h | 18 +++++++
drivers/base/devres.c | 54 +++++++++++--------
rust/kernel/devres.rs | 123 ++++++++++++++++++++++++++----------------
3 files changed, 127 insertions(+), 68 deletions(-)
base-commit: c98d3727720db5f74bf40a8cd1c2da05081845ee
--
2.52.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 1/5] devres: move struct devres_node into base.h
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
@ 2026-02-05 22:31 ` Danilo Krummrich
2026-02-05 22:31 ` [PATCH 2/5] devres: export devres_node_init() and devres_node_add() Danilo Krummrich
` (3 subsequent siblings)
4 siblings, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
Move struct devres_node into base.h, such that we can access it from the
Rust devres code.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/base/base.h | 12 ++++++++++++
drivers/base/devres.c | 12 ------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 8c2175820da9..5e0e7eefa405 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -222,6 +222,18 @@ static inline void device_set_driver(struct device *dev, const struct device_dri
WRITE_ONCE(dev->driver, (struct device_driver *)drv);
}
+struct devres_node;
+typedef void (*dr_node_release_t)(struct device *dev, struct devres_node *node);
+typedef void (*dr_node_free_t)(struct devres_node *node);
+
+struct devres_node {
+ struct list_head entry;
+ dr_node_release_t release;
+ dr_node_free_t free_node;
+ const char *name;
+ size_t size;
+};
+
void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 0fca73b56168..7c9ef6fc6827 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -16,18 +16,6 @@
#include "base.h"
#include "trace.h"
-struct devres_node;
-typedef void (*dr_node_release_t)(struct device *dev, struct devres_node *node);
-typedef void (*dr_node_free_t)(struct devres_node *node);
-
-struct devres_node {
- struct list_head entry;
- dr_node_release_t release;
- dr_node_free_t free_node;
- const char *name;
- size_t size;
-};
-
struct devres {
struct devres_node node;
dr_release_t release;
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
2026-02-05 22:31 ` [PATCH 1/5] devres: move struct devres_node into base.h Danilo Krummrich
@ 2026-02-05 22:31 ` Danilo Krummrich
2026-02-06 10:43 ` Danilo Krummrich
2026-02-05 22:31 ` [PATCH 3/5] devres: add devres_node_remove() Danilo Krummrich
` (2 subsequent siblings)
4 siblings, 1 reply; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
Export devres_node_init() and devres_node_add() through base.h, such
that we can access is from the Rust devres code.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/base/base.h | 3 +++
drivers/base/devres.c | 10 ++++++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 5e0e7eefa405..0ad52a847bd0 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -234,6 +234,9 @@ struct devres_node {
size_t size;
};
+void devres_node_init(struct devres_node *node, dr_node_release_t release,
+ dr_node_free_t free_node);
+void devres_node_add(struct device *dev, struct devres_node *node);
void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 7c9ef6fc6827..51d079acc9b3 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -36,14 +36,15 @@ struct devres_group {
/* -- 8 pointers */
};
-static void devres_node_init(struct devres_node *node,
- dr_node_release_t release,
- dr_node_free_t free_node)
+void devres_node_init(struct devres_node *node,
+ dr_node_release_t release,
+ dr_node_free_t free_node)
{
INIT_LIST_HEAD(&node->entry);
node->release = release;
node->free_node = free_node;
}
+EXPORT_SYMBOL_GPL(devres_node_init);
static inline void free_node(struct devres_node *node)
{
@@ -256,12 +257,13 @@ void devres_free(void *res)
}
EXPORT_SYMBOL_GPL(devres_free);
-static void devres_node_add(struct device *dev, struct devres_node *node)
+void devres_node_add(struct device *dev, struct devres_node *node)
{
guard(spinlock_irqsave)(&dev->devres_lock);
add_dr(dev, node);
}
+EXPORT_SYMBOL_GPL(devres_node_add);
/**
* devres_add - Register device resource
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 3/5] devres: add devres_node_remove()
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
2026-02-05 22:31 ` [PATCH 1/5] devres: move struct devres_node into base.h Danilo Krummrich
2026-02-05 22:31 ` [PATCH 2/5] devres: export devres_node_init() and devres_node_add() Danilo Krummrich
@ 2026-02-05 22:31 ` Danilo Krummrich
2026-02-05 22:31 ` [PATCH 4/5] devres: rename and export set_node_dbginfo() Danilo Krummrich
2026-02-05 22:31 ` [PATCH 5/5] rust: devres: embed struct devres_node directly Danilo Krummrich
4 siblings, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
When the Rust Devres<T> container type is dropped we need a way to
remove the embedded struct devres_node from the device's node list.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/base/base.h | 1 +
drivers/base/devres.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 0ad52a847bd0..93b2020baa99 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -237,6 +237,7 @@ struct devres_node {
void devres_node_init(struct devres_node *node, dr_node_release_t release,
dr_node_free_t free_node);
void devres_node_add(struct device *dev, struct devres_node *node);
+bool devres_node_remove(struct device *dev, struct devres_node *node);
void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 51d079acc9b3..54a41ae599d0 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -363,6 +363,23 @@ void *devres_get(struct device *dev, void *new_res,
}
EXPORT_SYMBOL_GPL(devres_get);
+bool devres_node_remove(struct device *dev, struct devres_node *node)
+{
+ struct devres_node *__node;
+
+ guard(spinlock_irqsave)(&dev->devres_lock);
+ list_for_each_entry_reverse(__node, &dev->devres_head, entry) {
+ if (__node == node) {
+ list_del_init(&node->entry);
+ devres_log(dev, node, "REM");
+ return true;
+ }
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(devres_node_remove);
+
/**
* devres_remove - Find a device resource and remove it
* @dev: Device to find resource from
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 4/5] devres: rename and export set_node_dbginfo()
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
` (2 preceding siblings ...)
2026-02-05 22:31 ` [PATCH 3/5] devres: add devres_node_remove() Danilo Krummrich
@ 2026-02-05 22:31 ` Danilo Krummrich
2026-02-05 22:31 ` [PATCH 5/5] rust: devres: embed struct devres_node directly Danilo Krummrich
4 siblings, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
Rename set_node_dbginfo() to devres_set_node_dbginfo() and export it
through base.h, such that we can access is from the Rust devres code.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
drivers/base/base.h | 2 ++
drivers/base/devres.c | 15 ++++++++-------
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 93b2020baa99..9aed7e2c78ef 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -238,6 +238,8 @@ void devres_node_init(struct devres_node *node, dr_node_release_t release,
dr_node_free_t free_node);
void devres_node_add(struct device *dev, struct devres_node *node);
bool devres_node_remove(struct device *dev, struct devres_node *node);
+void devres_set_node_dbginfo(struct devres_node *node, const char *name,
+ size_t size);
void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 54a41ae599d0..89c7a2e3cd53 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -51,12 +51,13 @@ static inline void free_node(struct devres_node *node)
node->free_node(node);
}
-static void set_node_dbginfo(struct devres_node *node, const char *name,
+void devres_set_node_dbginfo(struct devres_node *node, const char *name,
size_t size)
{
node->name = name;
node->size = size;
}
+EXPORT_SYMBOL_GPL(devres_set_node_dbginfo);
#ifdef CONFIG_DEBUG_DEVRES
static int log_devres = 0;
@@ -190,7 +191,7 @@ void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
if (unlikely(!dr))
return NULL;
- set_node_dbginfo(&dr->node, name, size);
+ devres_set_node_dbginfo(&dr->node, name, size);
return dr->data;
}
EXPORT_SYMBOL_GPL(__devres_alloc_node);
@@ -606,8 +607,8 @@ void *devres_open_group(struct device *dev, void *id, gfp_t gfp)
devres_node_init(&grp->node[0], &group_open_release, devres_group_free);
devres_node_init(&grp->node[1], &group_close_release, NULL);
- set_node_dbginfo(&grp->node[0], "grp<", 0);
- set_node_dbginfo(&grp->node[1], "grp>", 0);
+ devres_set_node_dbginfo(&grp->node[0], "grp<", 0);
+ devres_set_node_dbginfo(&grp->node[1], "grp>", 0);
grp->id = grp;
if (id)
grp->id = id;
@@ -795,7 +796,7 @@ int __devm_add_action(struct device *dev, void (*action)(void *), void *data, co
return -ENOMEM;
devres_node_init(&devres->node, devm_action_release, devm_action_free);
- set_node_dbginfo(&devres->node, name, sizeof(*devres));
+ devres_set_node_dbginfo(&devres->node, name, sizeof(*devres));
devres->action.data = data;
devres->action.action = action;
@@ -956,7 +957,7 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
* This is named devm_kzalloc_release for historical reasons
* The initial implementation did not support kmalloc, only kzalloc
*/
- set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
+ devres_set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
devres_add(dev, dr->data);
return dr->data;
}
@@ -1027,7 +1028,7 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
if (!new_dr)
return NULL;
- set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size);
+ devres_set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size);
/*
* The spinlock protects the linked list against concurrent
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH 5/5] rust: devres: embed struct devres_node directly
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
` (3 preceding siblings ...)
2026-02-05 22:31 ` [PATCH 4/5] devres: rename and export set_node_dbginfo() Danilo Krummrich
@ 2026-02-05 22:31 ` Danilo Krummrich
4 siblings, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-05 22:31 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel, Danilo Krummrich
Currently, the Devres<T> container uses devm_add_action() to register a
devres callback.
devm_add_action() allocates a struct action_devres, which on top of
struct devres_node, just keeps a data pointer and release function
pointer.
This is an unnecessary indirection, given that analogous to struct
devres, the Devres<T> container can just embed a struct devres_node
directly without an additional allocation.
In contrast to struct devres, we don't need to force an alignment of
ARCH_DMA_MINALIGN (as struct devres does to account for the worst case)
since we have generics in Rust. I.e. the compiler already ensures
correct alignment of the embedded T in Devres<T>.
Thus, get rid of devm_add_action() and instead embed a struct
devres_node directly.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/devres.rs | 123 ++++++++++++++++++++++++++----------------
1 file changed, 78 insertions(+), 45 deletions(-)
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index ff66f561740a..649e34962c38 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -23,9 +23,22 @@
rcu,
Arc, //
},
- types::ForeignOwnable,
+ types::{
+ ForeignOwnable,
+ Opaque, //
+ },
};
+/// Inner type that embeds a `struct devres_node` and the `Revocable<T>`.
+#[repr(C)]
+#[pin_data]
+struct Inner<T> {
+ #[pin]
+ node: Opaque<bindings::devres_node>,
+ #[pin]
+ data: Revocable<T>,
+}
+
/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to
/// manage their lifetime.
///
@@ -111,12 +124,7 @@
/// ```
pub struct Devres<T: Send> {
dev: ARef<Device>,
- /// Pointer to [`Self::devres_callback`].
- ///
- /// Has to be stored, since Rust does not guarantee to always return the same address for a
- /// function. However, the C API uses the address as a key.
- callback: unsafe extern "C" fn(*mut c_void),
- data: Arc<Revocable<T>>,
+ inner: Arc<Inner<T>>,
}
impl<T: Send> Devres<T> {
@@ -128,57 +136,82 @@ pub fn new<E>(dev: &Device<Bound>, data: impl PinInit<T, E>) -> Result<Self>
where
Error: From<E>,
{
- let callback = Self::devres_callback;
- let data = Arc::pin_init(Revocable::new(data), GFP_KERNEL)?;
+ let inner = Arc::pin_init::<Error>(
+ try_pin_init!(Inner {
+ node <- Opaque::ffi_init(|node: *mut bindings::devres_node| {
+ // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
+ unsafe {
+ bindings::devres_node_init(
+ node,
+ Some(Self::devres_node_release),
+ Some(Self::devres_node_free_node),
+ )
+ };
+
+ // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
+ unsafe {
+ bindings::devres_set_node_dbginfo(
+ node,
+ // TODO: Use `core::any::type_name::<T>()` once we are able to convert
+ // the `&str` to a NULL terminated `&CStr` without additional
+ // allocation.
+ c"Devres<T>".as_char_ptr(),
+ core::mem::size_of::<Revocable<T>>(),
+ )
+ };
+ }),
+ data <- Revocable::new(data),
+ }),
+ GFP_KERNEL,
+ )?;
// SAFETY:
- // - `dev.as_raw()` is a pointer to a valid bound device.
- // - `data` is guaranteed to be a valid for the duration of the lifetime of `Self`.
- // - `devm_add_action()` is guaranteed not to call `callback` for the entire lifetime of
- // `dev`.
- to_result(unsafe {
- bindings::devm_add_action(
- dev.as_raw(),
- Some(callback),
- Arc::as_ptr(&data).cast_mut().cast(),
- )
- })?;
+ // - `dev` is a valid pointer to a bound `struct device`.
+ // - `node` is a valid pointer to a `struct devres_node`.
+ // - `devres_node_add()` is guaranteed not to call `devres_node_release()` for the entire
+ // lifetime of `dev`.
+ unsafe { bindings::devres_node_add(dev.as_raw(), inner.node.get()) };
- // Take additional reference count for `devm_add_action()`.
- core::mem::forget(data.clone());
+ // Take additional reference count for `devres_node_add()`.
+ core::mem::forget(inner.clone());
Ok(Self {
dev: dev.into(),
- callback,
- data,
+ inner,
})
}
fn data(&self) -> &Revocable<T> {
- &self.data
+ &self.inner.data
}
#[allow(clippy::missing_safety_doc)]
- unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) {
- // SAFETY: In `Self::new` we've passed a valid pointer of `Revocable<T>` to
- // `devm_add_action()`, hence `ptr` must be a valid pointer to `Revocable<T>`.
- let data = unsafe { Arc::from_raw(ptr.cast::<Revocable<T>>()) };
+ unsafe extern "C" fn devres_node_release(
+ _dev: *mut bindings::device,
+ node: *mut bindings::devres_node,
+ ) {
+ let node = Opaque::cast_from(node);
- data.revoke();
+ // SAFETY: `node` is in the same allocation as its container.
+ let inner = unsafe { kernel::container_of!(node, Inner<T>, node) };
+
+ // SAFETY: `inner` is a valid `Inner<T>` pointer.
+ let inner = unsafe { &*inner };
+
+ inner.data.revoke();
+ }
+
+ #[allow(clippy::missing_safety_doc)]
+ unsafe extern "C" fn devres_node_free_node(node: *mut bindings::devres_node) {
+ // SAFETY: `node` points to the entire `Inner<T>` allocation.
+ drop(unsafe { Arc::from_raw(node.cast::<Inner<T>>()) });
}
- fn remove_action(&self) -> bool {
+ fn remove_node(&self) -> bool {
// SAFETY:
- // - `self.dev` is a valid `Device`,
- // - the `action` and `data` pointers are the exact same ones as given to
- // `devm_add_action()` previously,
- (unsafe {
- bindings::devm_remove_action_nowarn(
- self.dev.as_raw(),
- Some(self.callback),
- core::ptr::from_ref(self.data()).cast_mut().cast(),
- )
- } == 0)
+ // - `self.device().as_raw()` is a valid pointer to a bound `struct device`.
+ // - `self.inner.node.get()` is a valid pointer to a `struct devres_node`.
+ unsafe { bindings::devres_node_remove(self.device().as_raw(), self.inner.node.get()) }
}
/// Return a reference of the [`Device`] this [`Devres`] instance has been created with.
@@ -260,12 +293,12 @@ fn drop(&mut self) {
// SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
// anymore, hence it is safe not to wait for the grace period to finish.
if unsafe { self.data().revoke_nosync() } {
- // We revoked `self.data` before the devres action did, hence try to remove it.
- if self.remove_action() {
+ // We revoked `self.data` before devres did, hence try to remove it.
+ if self.remove_node() {
// SAFETY: In `Self::new` we have taken an additional reference count of `self.data`
- // for `devm_add_action()`. Since `remove_action()` was successful, we have to drop
+ // for `devres_node_add()`. Since `remove_node()` was successful, we have to drop
// this additional reference count.
- drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.data)) });
+ drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.inner)) });
}
}
}
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-05 22:31 ` [PATCH 2/5] devres: export devres_node_init() and devres_node_add() Danilo Krummrich
@ 2026-02-06 10:43 ` Danilo Krummrich
2026-02-06 11:04 ` Greg KH
0 siblings, 1 reply; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 10:43 UTC (permalink / raw)
To: gregkh, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, aliceryhl, tmgross
Cc: driver-core, rust-for-linux, linux-kernel
On Thu Feb 5, 2026 at 11:31 PM CET, Danilo Krummrich wrote:
> +EXPORT_SYMBOL_GPL(devres_node_init);
I actually intended to use a Rust helper instead of exporting those symbols
directly, but forgot to do it eventually.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 10:43 ` Danilo Krummrich
@ 2026-02-06 11:04 ` Greg KH
2026-02-06 11:32 ` Danilo Krummrich
0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2026-02-06 11:04 UTC (permalink / raw)
To: Danilo Krummrich
Cc: rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg,
aliceryhl, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri, Feb 06, 2026 at 11:43:48AM +0100, Danilo Krummrich wrote:
> On Thu Feb 5, 2026 at 11:31 PM CET, Danilo Krummrich wrote:
> > +EXPORT_SYMBOL_GPL(devres_node_init);
>
> I actually intended to use a Rust helper instead of exporting those symbols
> directly, but forgot to do it eventually.
>
I don't understand, does that mean we do not need to export these?
Shouldn't the rust bindings just export these symbols are rust exports,
and the C exports are not needed?
We "only" want these symbols to go to the rust binding, not to any
module at all, which is what this patch series does, and is probably not
a good idea.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 11:04 ` Greg KH
@ 2026-02-06 11:32 ` Danilo Krummrich
2026-02-06 11:34 ` Alice Ryhl
0 siblings, 1 reply; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 11:32 UTC (permalink / raw)
To: Greg KH
Cc: rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg,
aliceryhl, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri Feb 6, 2026 at 12:04 PM CET, Greg KH wrote:
> On Fri, Feb 06, 2026 at 11:43:48AM +0100, Danilo Krummrich wrote:
>> On Thu Feb 5, 2026 at 11:31 PM CET, Danilo Krummrich wrote:
>> > +EXPORT_SYMBOL_GPL(devres_node_init);
>>
>> I actually intended to use a Rust helper instead of exporting those symbols
>> directly, but forgot to do it eventually.
>>
>
> I don't understand, does that mean we do not need to export these?
> Shouldn't the rust bindings just export these symbols are rust exports,
> and the C exports are not needed?
>
> We "only" want these symbols to go to the rust binding, not to any
> module at all, which is what this patch series does, and is probably not
> a good idea.
Correct, I just forgot to replace the exports with a Rust helper.
The Rust compiler might inline some of the core code into modules (e.g. due to
generics), thus requiring an export.
But, instead of adding
EXPORT_SYMBOL_GPL(devres_node_init)
in drivers/base/devres.c, I actually intended to create a Rust helper in
rust/helpers/devres.c:
__rust_helper void rust_helper_devres_node_init(struct devres_node *node,
dr_node_release_t release,
dr_node_free_t free_node)
{
devres_nod_init(node, release, free_node);
}
This will automatically create:
EXPORT_SYMBOL_RUST_GPL(rust_helper_devres_node_init)
behind the scenes.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 11:32 ` Danilo Krummrich
@ 2026-02-06 11:34 ` Alice Ryhl
2026-02-06 11:46 ` Danilo Krummrich
2026-02-06 12:34 ` Greg KH
0 siblings, 2 replies; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 11:34 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Greg KH, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri, Feb 6, 2026 at 12:32 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Fri Feb 6, 2026 at 12:04 PM CET, Greg KH wrote:
> > On Fri, Feb 06, 2026 at 11:43:48AM +0100, Danilo Krummrich wrote:
> >> On Thu Feb 5, 2026 at 11:31 PM CET, Danilo Krummrich wrote:
> >> > +EXPORT_SYMBOL_GPL(devres_node_init);
> >>
> >> I actually intended to use a Rust helper instead of exporting those symbols
> >> directly, but forgot to do it eventually.
> >>
> >
> > I don't understand, does that mean we do not need to export these?
> > Shouldn't the rust bindings just export these symbols are rust exports,
> > and the C exports are not needed?
> >
> > We "only" want these symbols to go to the rust binding, not to any
> > module at all, which is what this patch series does, and is probably not
> > a good idea.
>
> Correct, I just forgot to replace the exports with a Rust helper.
>
> The Rust compiler might inline some of the core code into modules (e.g. due to
> generics), thus requiring an export.
>
> But, instead of adding
>
> EXPORT_SYMBOL_GPL(devres_node_init)
>
> in drivers/base/devres.c, I actually intended to create a Rust helper in
> rust/helpers/devres.c:
>
> __rust_helper void rust_helper_devres_node_init(struct devres_node *node,
> dr_node_release_t release,
> dr_node_free_t free_node)
> {
> devres_nod_init(node, release, free_node);
> }
>
> This will automatically create:
>
> EXPORT_SYMBOL_RUST_GPL(rust_helper_devres_node_init)
>
> behind the scenes.
That doesn't work if this option is enabled:
https://lore.kernel.org/all/20260203-inline-helpers-v2-0-beb8547a03c9@google.com/
then the helper is linked into the module, so it still has a direct
call to devres_nod_init.
Alice
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 11:34 ` Alice Ryhl
@ 2026-02-06 11:46 ` Danilo Krummrich
2026-02-06 12:34 ` Greg KH
1 sibling, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 11:46 UTC (permalink / raw)
To: Alice Ryhl, Greg KH
Cc: rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, driver-core, rust-for-linux, linux-kernel
On Fri Feb 6, 2026 at 12:34 PM CET, Alice Ryhl wrote:
> That doesn't work if this option is enabled:
> https://lore.kernel.org/all/20260203-inline-helpers-v2-0-beb8547a03c9@google.com/
>
> then the helper is linked into the module, so it still has a direct
> call to devres_nod_init.
That's unfortunate, maybe we can leverage MODULE_IMPORT_NS() and
EXPORT_SYMBOL_NS_GPL(), i.e.
#define EXPORT_SYMBOL_RUST_INTERNAL(sym) EXPORT_SYMBOL_NS_GPL(sym, "RUST_INTERNAL")
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 11:34 ` Alice Ryhl
2026-02-06 11:46 ` Danilo Krummrich
@ 2026-02-06 12:34 ` Greg KH
2026-02-06 13:16 ` Danilo Krummrich
1 sibling, 1 reply; 25+ messages in thread
From: Greg KH @ 2026-02-06 12:34 UTC (permalink / raw)
To: Alice Ryhl
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
On Fri, Feb 06, 2026 at 12:34:01PM +0100, Alice Ryhl wrote:
> On Fri, Feb 6, 2026 at 12:32 PM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Fri Feb 6, 2026 at 12:04 PM CET, Greg KH wrote:
> > > On Fri, Feb 06, 2026 at 11:43:48AM +0100, Danilo Krummrich wrote:
> > >> On Thu Feb 5, 2026 at 11:31 PM CET, Danilo Krummrich wrote:
> > >> > +EXPORT_SYMBOL_GPL(devres_node_init);
> > >>
> > >> I actually intended to use a Rust helper instead of exporting those symbols
> > >> directly, but forgot to do it eventually.
> > >>
> > >
> > > I don't understand, does that mean we do not need to export these?
> > > Shouldn't the rust bindings just export these symbols are rust exports,
> > > and the C exports are not needed?
> > >
> > > We "only" want these symbols to go to the rust binding, not to any
> > > module at all, which is what this patch series does, and is probably not
> > > a good idea.
> >
> > Correct, I just forgot to replace the exports with a Rust helper.
> >
> > The Rust compiler might inline some of the core code into modules (e.g. due to
> > generics), thus requiring an export.
> >
> > But, instead of adding
> >
> > EXPORT_SYMBOL_GPL(devres_node_init)
> >
> > in drivers/base/devres.c, I actually intended to create a Rust helper in
> > rust/helpers/devres.c:
> >
> > __rust_helper void rust_helper_devres_node_init(struct devres_node *node,
> > dr_node_release_t release,
> > dr_node_free_t free_node)
> > {
> > devres_nod_init(node, release, free_node);
> > }
> >
> > This will automatically create:
> >
> > EXPORT_SYMBOL_RUST_GPL(rust_helper_devres_node_init)
> >
> > behind the scenes.
>
> That doesn't work if this option is enabled:
> https://lore.kernel.org/all/20260203-inline-helpers-v2-0-beb8547a03c9@google.com/
>
> then the helper is linked into the module, so it still has a direct
> call to devres_nod_init.
That's fine, because the rust driver core code should also be built into
the kernel, not as a module, right?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 12:34 ` Greg KH
@ 2026-02-06 13:16 ` Danilo Krummrich
2026-02-06 13:20 ` Alice Ryhl
2026-02-06 13:22 ` Greg KH
0 siblings, 2 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 13:16 UTC (permalink / raw)
To: Greg KH
Cc: Alice Ryhl, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
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.
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.
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
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/
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:16 ` Danilo Krummrich
@ 2026-02-06 13:20 ` Alice Ryhl
2026-02-06 13:25 ` Greg KH
2026-02-06 13:22 ` Greg KH
1 sibling, 1 reply; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 13:20 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Greg KH, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri, Feb 6, 2026 at 2:16 PM Danilo Krummrich <dakr@kernel.org> 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.
>
> 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.
>
> 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
>
> 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/
You can use #[inline(never)] to prevent this.
Alice
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:16 ` Danilo Krummrich
2026-02-06 13:20 ` Alice Ryhl
@ 2026-02-06 13:22 ` Greg KH
2026-02-06 13:33 ` Alice Ryhl
1 sibling, 1 reply; 25+ messages in thread
From: Greg KH @ 2026-02-06 13:22 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Alice Ryhl, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
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?
> 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?
> 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.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:20 ` Alice Ryhl
@ 2026-02-06 13:25 ` Greg KH
2026-02-06 13:33 ` Danilo Krummrich
0 siblings, 1 reply; 25+ messages in thread
From: Greg KH @ 2026-02-06 13:25 UTC (permalink / raw)
To: Alice Ryhl
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
On Fri, Feb 06, 2026 at 02:20:06PM +0100, Alice Ryhl wrote:
> On Fri, Feb 6, 2026 at 2:16 PM Danilo Krummrich <dakr@kernel.org> 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.
> >
> > 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.
> >
> > 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
> >
> > 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/
>
> You can use #[inline(never)] to prevent this.
Ah, good!
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:25 ` Greg KH
@ 2026-02-06 13:33 ` Danilo Krummrich
2026-02-06 13:35 ` Alice Ryhl
0 siblings, 1 reply; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 13:33 UTC (permalink / raw)
To: Greg KH, Alice Ryhl
Cc: rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg,
tmgross, driver-core, rust-for-linux, linux-kernel
On Fri Feb 6, 2026 at 2:25 PM CET, Greg KH wrote:
> On Fri, Feb 06, 2026 at 02:20:06PM +0100, Alice Ryhl wrote:
>> On Fri, Feb 6, 2026 at 2:16 PM Danilo Krummrich <dakr@kernel.org> 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.
>> >
>> > 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.
>> >
>> > 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
>> >
>> > 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/
>>
>> You can use #[inline(never)] to prevent this.
>
> Ah, good!
I tried this before, but it doesn't work. It might prevent inlining, but it does
not prevent the compiler to move the function into the module binary.
For instance, even with #[inline(never)] on Devres::new() I see this:
$ objdump -t drivers/pwm/pwm_th1520.o | grep " F " | grep Devres | grep new
0000000000000000 g F .text 00000000000001d0 _RINvMNtCsgzhNYVB7wSz_6kernel6devresINtB3_6DevresINtNtNtB5_2io3mem5IoMemKjb0_EE3newNtNtB5_5error5ErrorINtNtCs4gKlGRWyJ5S_4core6result6ResultBK_B1i_EECsjBm7MKWXKwW_10pwm_th1520
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:22 ` Greg KH
@ 2026-02-06 13:33 ` Alice Ryhl
2026-02-06 13:55 ` Greg KH
2026-02-06 14:08 ` Danilo Krummrich
0 siblings, 2 replies; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 13:33 UTC (permalink / raw)
To: Greg KH
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
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.
And not lifting out code causes issues with super small wrapper
functions around C functions too.
Alice
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:33 ` Danilo Krummrich
@ 2026-02-06 13:35 ` Alice Ryhl
0 siblings, 0 replies; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 13:35 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Greg KH, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri, Feb 6, 2026 at 2:33 PM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Fri Feb 6, 2026 at 2:25 PM CET, Greg KH wrote:
> > On Fri, Feb 06, 2026 at 02:20:06PM +0100, Alice Ryhl wrote:
> >> On Fri, Feb 6, 2026 at 2:16 PM Danilo Krummrich <dakr@kernel.org> 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.
> >> >
> >> > 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.
> >> >
> >> > 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
> >> >
> >> > 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/
> >>
> >> You can use #[inline(never)] to prevent this.
> >
> > Ah, good!
>
> I tried this before, but it doesn't work. It might prevent inlining, but it does
> not prevent the compiler to move the function into the module binary.
>
> For instance, even with #[inline(never)] on Devres::new() I see this:
>
> $ objdump -t drivers/pwm/pwm_th1520.o | grep " F " | grep Devres | grep new
>
> 0000000000000000 g F .text 00000000000001d0 _RINvMNtCsgzhNYVB7wSz_6kernel6devresINtB3_6DevresINtNtNtB5_2io3mem5IoMemKjb0_EE3newNtNtB5_5error5ErrorINtNtCs4gKlGRWyJ5S_4core6result6ResultBK_B1i_EECsjBm7MKWXKwW_10pwm_th1520
Because it's generic, see my sibling reply.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:33 ` Alice Ryhl
@ 2026-02-06 13:55 ` Greg KH
2026-02-06 14:23 ` Gary Guo
2026-02-06 15:09 ` Alice Ryhl
2026-02-06 14:08 ` Danilo Krummrich
1 sibling, 2 replies; 25+ messages in thread
From: Greg KH @ 2026-02-06 13:55 UTC (permalink / raw)
To: Alice Ryhl
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
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.
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
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:33 ` Alice Ryhl
2026-02-06 13:55 ` Greg KH
@ 2026-02-06 14:08 ` Danilo Krummrich
1 sibling, 0 replies; 25+ messages in thread
From: Danilo Krummrich @ 2026-02-06 14:08 UTC (permalink / raw)
To: Alice Ryhl
Cc: Greg KH, rafael, ojeda, boqun.feng, gary, bjorn3_gh, lossin,
a.hindborg, tmgross, driver-core, rust-for-linux, linux-kernel
On Fri Feb 6, 2026 at 2:33 PM CET, Alice Ryhl wrote:
> So you'd need a non-generic Rust function with #[inline(never)] in this case,
> and have Devres::<T>::new() call that function.
Then we should probably figure out how we can teach bindgen to apply
#[inline(never)] for functions that are not exported. Because I don't think we
always want to write such wrappers by hand.
#[inline(never)]
#[allow(clippy::missing_safety_doc)]
unsafe fn devres_node_init(
node: *mut bindings::devres_node,
release: bindings::dr_node_release_t,
free: bindings::dr_node_free_t,
) {
// SAFETY: `devres_node_init()` inherits the safety requirements of
// `bindings::devres_node_init()`.
unsafe { bindings::devres_node_init(node, release, free) };
}
(I could probably abstract it on a higher level, but it would still create quite
some (unsafe) churn.)
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:55 ` Greg KH
@ 2026-02-06 14:23 ` Gary Guo
2026-02-06 14:31 ` Greg KH
2026-02-06 15:09 ` Alice Ryhl
1 sibling, 1 reply; 25+ messages in thread
From: Gary Guo @ 2026-02-06 14:23 UTC (permalink / raw)
To: Greg KH, Alice Ryhl
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
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
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 14:23 ` Gary Guo
@ 2026-02-06 14:31 ` Greg KH
0 siblings, 0 replies; 25+ messages in thread
From: Greg KH @ 2026-02-06 14:31 UTC (permalink / raw)
To: Gary Guo
Cc: Alice Ryhl, Danilo Krummrich, rafael, ojeda, boqun.feng,
bjorn3_gh, lossin, a.hindborg, tmgross, driver-core,
rust-for-linux, linux-kernel
On Fri, Feb 06, 2026 at 02:23:44PM +0000, Gary Guo wrote:
> 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).
What about module symbol namespaces?
> 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.
And this will happen more as we have more bindings from subsystem rust
code that should not be exported directly to modules/drivers to allow
them to access those symbols without going through the rust core.
Also, again, module symbol namespaces will play here, think about a
driver calling a symbol in another driver's namespace, that has within
it a call to a different namespace. That first driver would then have
to "import" that last namespace, which isn't ok.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 13:55 ` Greg KH
2026-02-06 14:23 ` Gary Guo
@ 2026-02-06 15:09 ` Alice Ryhl
2026-02-06 16:31 ` Alice Ryhl
1 sibling, 1 reply; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 15:09 UTC (permalink / raw)
To: Greg KH
Cc: Danilo Krummrich, rafael, ojeda, boqun.feng, gary, bjorn3_gh,
lossin, a.hindborg, tmgross, driver-core, rust-for-linux,
linux-kernel
On Fri, Feb 06, 2026 at 02:55:50PM +0100, 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:
> > > > 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.
>
> 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...)
Hmm. I don't know how to reconcile namespaces operating on symbols with
monomorphisation.
We should probably think about what to do about ... :)
Alice
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 2/5] devres: export devres_node_init() and devres_node_add()
2026-02-06 15:09 ` Alice Ryhl
@ 2026-02-06 16:31 ` Alice Ryhl
0 siblings, 0 replies; 25+ messages in thread
From: Alice Ryhl @ 2026-02-06 16:31 UTC (permalink / raw)
To: Greg KH
Cc: Danilo Krummrich, Matthew Maurer, rafael, ojeda, boqun.feng, gary,
bjorn3_gh, lossin, a.hindborg, tmgross, driver-core,
rust-for-linux, linux-kernel
On Fri, Feb 06, 2026 at 03:09:09PM +0000, Alice Ryhl wrote:
> On Fri, Feb 06, 2026 at 02:55:50PM +0100, 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:
> > > > > 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.
> >
> > 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...)
>
> Hmm. I don't know how to reconcile namespaces operating on symbols with
> monomorphisation.
>
> We should probably think about what to do about ... :)
Matthew Maurer pointed out to me that behavior-wise exporting and
namespaces behave almost exactly the same as how Rust handles unstable
language features.
In the Rust standard library, all functions are marked with one of:
#[unstable(feature = "feature_name_here")]
#[stable]
when you use a #[stable] method, all is good. But if you use an unstable
method, then that's a compiler error unless you have
#![feature(feature_name_here)]
at the crate root.
This seems equivalent to our situation here, if we consider:
* EXPORT_SYMBOL_GPL symbols are #[stable]
* un-exported symbols are #[unstable(feature = "core_kernel")]
* other namespaces are #[unstable(feature = "namespace_name_here")]
Of course the way this is enforced is through an entirely different
mechanism than symbol exports.
Alice
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2026-02-06 16:31 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-05 22:31 [PATCH 0/5] Use struct devres_node in Devres<T> Danilo Krummrich
2026-02-05 22:31 ` [PATCH 1/5] devres: move struct devres_node into base.h Danilo Krummrich
2026-02-05 22:31 ` [PATCH 2/5] devres: export devres_node_init() and devres_node_add() Danilo Krummrich
2026-02-06 10:43 ` Danilo Krummrich
2026-02-06 11:04 ` Greg KH
2026-02-06 11:32 ` Danilo Krummrich
2026-02-06 11:34 ` Alice Ryhl
2026-02-06 11:46 ` Danilo Krummrich
2026-02-06 12:34 ` Greg KH
2026-02-06 13:16 ` Danilo Krummrich
2026-02-06 13:20 ` Alice Ryhl
2026-02-06 13:25 ` Greg KH
2026-02-06 13:33 ` Danilo Krummrich
2026-02-06 13:35 ` Alice Ryhl
2026-02-06 13:22 ` Greg KH
2026-02-06 13:33 ` Alice Ryhl
2026-02-06 13:55 ` Greg KH
2026-02-06 14:23 ` Gary Guo
2026-02-06 14:31 ` Greg KH
2026-02-06 15:09 ` Alice Ryhl
2026-02-06 16:31 ` Alice Ryhl
2026-02-06 14:08 ` Danilo Krummrich
2026-02-05 22:31 ` [PATCH 3/5] devres: add devres_node_remove() Danilo Krummrich
2026-02-05 22:31 ` [PATCH 4/5] devres: rename and export set_node_dbginfo() Danilo Krummrich
2026-02-05 22:31 ` [PATCH 5/5] rust: devres: embed struct devres_node directly Danilo Krummrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox