From 35426a8ca7a6079711cfbd87614fc20c08a545c1 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Fri, 5 Jun 2026 15:15:40 +0200 Subject: [PATCH] configfs: rust: add an API for adding default groups from C 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 --- 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(-) create mode 100644 rust/helpers/configfs.c diff --git a/drivers/block/rnull/configfs.rs b/drivers/block/rnull/configfs.rs index 7c2eb5c0b7228..b165347e94130 100644 --- a/drivers/block/rnull/configfs.rs +++ b/drivers/block/rnull/configfs.rs @@ -76,6 +76,7 @@ impl configfs::GroupOperations for Config { 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..4c71c33211bf7 --- /dev/null +++ b/rust/helpers/configfs.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#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 998e31052e660..30911e4ec088b 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -52,6 +52,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 2339c6467325d..8891fa4914962 100644 --- a/rust/kernel/configfs.rs +++ b/rust/kernel/configfs.rs @@ -241,12 +241,22 @@ unsafe impl HasGroup for Subsystem { /// /// 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 { #[pin] group: Opaque, #[pin] data: Data, + default_groups: KVec>, +} + +#[pinned_drop] +impl PinnedDrop for Group { + 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 Group { @@ -258,22 +268,51 @@ impl Group { name: CString, item_type: &'static ItemType, Data>, data: impl PinInit, + default_groups: impl IntoIterator>, ) -> impl PinInit { - try_pin_init!(Self { - group <- pin_init::init_zeroed().chain(|v: &mut Opaque| { - 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| { + 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` embeds a field of type `bindings::config_group` // within the `group` field. unsafe impl HasGroup for Group { diff --git a/samples/rust/rust_configfs.rs b/samples/rust/rust_configfs.rs index a1bd9db6010da..ada378bc331b1 100644 --- a/samples/rust/rust_configfs.rs +++ b/samples/rust/rust_configfs.rs @@ -83,7 +83,12 @@ impl configfs::GroupOperations for Configuration { ], }; - 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 @@ impl configfs::GroupOperations for Child { name.try_into()?, tpe, GrandChild::new(), + core::iter::empty(), )) } }