[PATCH v2] configfs: rust: add an API for adding default groups from C
From: Andreas Hindborg
Date: Fri Jun 05 2026 - 09:23:37 EST
Some C subsystems provide a feature to add configfs default groups to the
configfs hierarchy of other drivers or subsystems. Rust abstractions for
these subsystems will want a way to add these default groups via the
configfs Rust API. So add infrastructure to make this possible.
Signed-off-by: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
---
Changes in v2:
- Drop the spurious `__` prefix on the symbol name of the
`configfs_remove_default_groups` Rust helper (Alice).
- Wrap the body of `Group::new` in `pin_init::pin_init_scope` so that
allocation failure from `KVec::push` is propagated with `?` instead
of panicking via `unwrap` (Danilo).
- Only build configfs rust helpers when configfs is enabled.
- Link to v1: https://msgid.link/20260215-configfs-c-default-groups-v1-1-e967daef6c36@xxxxxxxxxx
To: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
To: Boqun Feng <boqun@xxxxxxxxxx>
To: Jens Axboe <axboe@xxxxxxxxx>
To: Miguel Ojeda <ojeda@xxxxxxxxxx>
To: Gary Guo <gary@xxxxxxxxxxx>
To: Björn Roy Baron <bjorn3_gh@xxxxxxxxxxxxxx>
To: Benno Lossin <lossin@xxxxxxxxxx>
To: Alice Ryhl <aliceryhl@xxxxxxxxxx>
To: Trevor Gross <tmgross@xxxxxxxxx>
To: Danilo Krummrich <dakr@xxxxxxxxxx>
To: Breno Leitao <leitao@xxxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
Cc: linux-block@xxxxxxxxxxxxxxx
Cc: rust-for-linux@xxxxxxxxxxxxxxx
---
drivers/block/rnull/configfs.rs | 1 +
rust/helpers/configfs.c | 20 +++++++++++++
rust/helpers/helpers.c | 1 +
rust/kernel/configfs.rs | 63 +++++++++++++++++++++++++++++++++--------
samples/rust/rust_configfs.rs | 8 +++++-
5 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 7c2eb5c0b722..b165347e9413 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -76,6 +76,7 @@ fn make_group(
name: name.try_into()?,
}),
}),
+ core::iter::empty(),
))
}
}
diff --git a/rust/helpers/configfs.c b/rust/helpers/configfs.c
new file mode 100644
index 000000000000..4c71c33211bf
--- /dev/null
+++ b/rust/helpers/configfs.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/configfs.h>
+
+#ifdef CONFIG_CONFIGFS_FS
+
+__rust_helper void
+rust_helper_configfs_add_default_group(struct config_group *new_group,
+ struct config_group *group)
+{
+ configfs_add_default_group(new_group, group);
+}
+
+__rust_helper void
+rust_helper_configfs_remove_default_groups(struct config_group *group)
+{
+ configfs_remove_default_groups(group);
+}
+
+#endif
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 625921e27dfb..851dc77d76b1 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -51,6 +51,7 @@
#include "build_bug.c"
#include "clk.c"
#include "completion.c"
+#include "configfs.c"
#include "cpu.c"
#include "cpufreq.c"
#include "cpumask.c"
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 2339c6467325..8891fa491496 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -241,12 +241,22 @@ unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
///
/// To add a subgroup to configfs, pass this type as `ctype` to
/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].
-#[pin_data]
+#[pin_data(PinnedDrop)]
pub struct Group<Data> {
#[pin]
group: Opaque<bindings::config_group>,
#[pin]
data: Data,
+ default_groups: KVec<Arc<dyn CDefaultGroup>>,
+}
+
+#[pinned_drop]
+impl<Data> PinnedDrop for Group<Data> {
+ fn drop(self: Pin<&mut Self>) {
+ // SAFETY: We have exclusive access to `self` and we know the default groups are alive
+ // because we reference them through `self.default_groups`.
+ unsafe { bindings::configfs_remove_default_groups(self.group.get()) };
+ }
}
impl<Data> Group<Data> {
@@ -258,22 +268,51 @@ pub fn new(
name: CString,
item_type: &'static ItemType<Group<Data>, Data>,
data: impl PinInit<Data, Error>,
+ default_groups: impl IntoIterator<Item = Arc<dyn CDefaultGroup>>,
) -> impl PinInit<Self, Error> {
- try_pin_init!(Self {
- group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
- let place = v.get();
- let name = name.to_bytes_with_nul().as_ptr();
- // SAFETY: It is safe to initialize a group once it has been zeroed.
- unsafe {
- bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
- };
- Ok(())
- }),
- data <- data,
+ pin_init::pin_init_scope(move || {
+ let mut dg = KVec::new();
+ for group in default_groups {
+ dg.push(group, GFP_KERNEL)?;
+ }
+
+ Ok(try_pin_init!(Self {
+ group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
+ let place = v.get();
+ let name = name.to_bytes_with_nul().as_ptr();
+ // SAFETY: It is safe to initialize a group once it has been zeroed.
+ unsafe {
+ bindings::config_group_init_type_name(
+ place,
+ name.cast(),
+ item_type.as_ptr(),
+ )
+ };
+
+ for default_group in &dg {
+ // SAFETY: We keep the default groups alive until `Self` is dropped.
+ unsafe {
+ bindings::configfs_add_default_group(default_group.group_ptr(), place)
+ }
+ }
+ Ok(())
+ }),
+ data <- data,
+ default_groups: dg,
+ }))
})
}
}
+/// A trait for default configfs groups added by C code.
+///
+/// Rust abstractions that work with C code that creates configfs groups can implement this trait to
+/// add the groups as default groups via the Rust configfs API.
+pub trait CDefaultGroup {
+ /// Return a raw pointer to the group definition.
+ fn group_ptr(&self) -> *mut bindings::config_group;
+}
+
// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
// within the `group` field.
unsafe impl<Data> HasGroup<Data> for Group<Data> {
diff --git a/samples/rust/rust_configfs.rs b/samples/rust/rust_configfs.rs
index a1bd9db6010d..ada378bc331b 100644
--- a/samples/rust/rust_configfs.rs
+++ b/samples/rust/rust_configfs.rs
@@ -83,7 +83,12 @@ fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<Child>,
],
};
- Ok(configfs::Group::new(name.try_into()?, tpe, Child::new()))
+ Ok(configfs::Group::new(
+ name.try_into()?,
+ tpe,
+ Child::new(),
+ core::iter::empty(),
+ ))
}
}
@@ -152,6 +157,7 @@ fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandCh
name.try_into()?,
tpe,
GrandChild::new(),
+ core::iter::empty(),
))
}
}
---
base-commit: 7fd2df204f342fc17d1a0bfcd474b24232fb0f32
change-id: 20260215-configfs-c-default-groups-bdb0a44633a6
Best regards,
--
Andreas Hindborg <a.hindborg@xxxxxxxxxx>