Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/block/rnull/configfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl configfs::GroupOperations for Config {
name: name.try_into()?,
}),
}),
core::iter::empty(),
))
}
}
Expand Down
16 changes: 16 additions & 0 deletions rust/helpers/configfs.c
Original file line number Diff line number Diff line change
@@ -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);
}
1 change: 1 addition & 0 deletions rust/helpers/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "build_bug.c"
#include "clk.c"
#include "completion.c"
#include "configfs.c"
#include "cpu.c"
#include "cpufreq.c"
#include "cpumask.c"
Expand Down
33 changes: 32 additions & 1 deletion rust/kernel/configfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,22 @@ unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {
///
/// 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> {
Expand All @@ -258,7 +268,13 @@ impl<Data> Group<Data> {
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();
Expand All @@ -267,13 +283,28 @@ impl<Data> Group<Data> {
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> {
Expand Down
8 changes: 7 additions & 1 deletion samples/rust/rust_configfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
))
}
}

Expand Down Expand Up @@ -152,6 +157,7 @@ impl configfs::GroupOperations for Child {
name.try_into()?,
tpe,
GrandChild::new(),
core::iter::empty(),
))
}
}
Expand Down
Loading