[PATCH] configfs: rust: add an API for adding default groups from C

From: Andreas Hindborg

Date: Sun Feb 15 2026 - 15:34:26 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>
---
drivers/block/rnull/configfs.rs | 1 +
rust/helpers/configfs.c | 16 ++++++++++++++++
rust/helpers/helpers.c | 1 +
rust/kernel/configfs.rs | 33 ++++++++++++++++++++++++++++++++-
samples/rust/rust_configfs.rs | 8 +++++++-
5 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs
index 6713a6d92391d..ea38b27a9011c 100644
--- a/drivers/block/rnull/configfs.rs
+++ b/drivers/block/rnull/configfs.rs
@@ -78,6 +78,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 0000000000000..7cec8ffcb093d
--- /dev/null
+++ b/rust/helpers/configfs.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/configfs.h>
+
+__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);
+}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 79c72762ad9c4..613b41e8b781c 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -19,6 +19,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 466fb7f407628..705f1647269d9 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -242,12 +242,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> {
@@ -259,7 +269,13 @@ 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> {
+ let mut dg = KVec::new();
+ for group in default_groups {
+ dg.push(group, GFP_KERNEL).unwrap();
+ }
+
try_pin_init!(Self {
group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
let place = v.get();
@@ -268,13 +284,28 @@ pub fn new(
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 0ccc7553ef395..c65dda8bfacd2 100644
--- a/samples/rust/rust_configfs.rs
+++ b/samples/rust/rust_configfs.rs
@@ -84,7 +84,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(),
+ ))
}
}

@@ -153,6 +158,7 @@ fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandCh
name.try_into()?,
tpe,
GrandChild::new(),
+ core::iter::empty(),
))
}
}

---
base-commit: 05f7e89ab9731565d8a62e3b5d1ec206485eeb0b
change-id: 20260215-configfs-c-default-groups-bdb0a44633a6

Best regards,
--
Andreas Hindborg <a.hindborg@xxxxxxxxxx>