// SPDX-License-Identifier: GPL-2.0 //! configfs interface: Userspace-driven Kernel Object Configuration//!//! configfs is an in-memory pseudo file system for configuration of kernel//! modules. Please see the [C documentation] for details and intended use of//! configfs.//!//! This module does not support the following configfs features://!//! - Items. All group children are groups.//! - Symlink support.//! - `disconnect_notify` hook.//! - Default groups.//!//! See the [`rust_configfs.rs`] sample for a full example use of this module.//!//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)//!//! # Examples//!//! ```ignore//! use kernel::alloc::flags;//! use kernel::configfs_attrs;//! use kernel::configfs;//! use kernel::new_mutex;//! use kernel::page::PAGE_SIZE;//! use kernel::sync::Mutex;//! use kernel::ThisModule;//!//! #[pin_data]//! struct RustConfigfs {//! #[pin]//! config: configfs::Subsystem<Configuration>,//! }//!//! impl kernel::InPlaceModule for RustConfigfs {//! fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {//! pr_info!("Rust configfs sample (init)\n");//!//! let item_type = configfs_attrs! {//! container: configfs::Subsystem<Configuration>,//! data: Configuration,//! attributes: [//! message: 0,//! bar: 1,//! ],//! };//!//! try_pin_init!(Self {//! config <- configfs::Subsystem::new(//! c"rust_configfs", item_type, Configuration::new()//! ),//! })//! }//! }//!//! #[pin_data]//! struct Configuration {//! message: &'static CStr,//! #[pin]//! bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,//! }//!//! impl Configuration {//! fn new() -> impl PinInit<Self, Error> {//! try_pin_init!(Self {//! message: c"Hello World\n",//! bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),//! })//! }//! }//!//! #[vtable]//! impl configfs::AttributeOperations<0> for Configuration {//! type Data = Configuration;//!//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {//! pr_info!("Show message\n");//! let data = container.message;//! page[0..data.len()].copy_from_slice(data);//! Ok(data.len())//! }//! }//!//! #[vtable]//! impl configfs::AttributeOperations<1> for Configuration {//! type Data = Configuration;//!//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {//! pr_info!("Show bar\n");//! let guard = container.bar.lock();//! let data = guard.0.as_slice();//! let len = guard.1;//! page[0..len].copy_from_slice(&data[0..len]);//! Ok(len)//! }//!//! fn store(container: &Configuration, page: &[u8]) -> Result {//! pr_info!("Store bar\n");//! let mut guard = container.bar.lock();//! guard.0[0..page.len()].copy_from_slice(page);//! guard.1 = page.len();//! Ok(())//! }//! }//! ```//!//! [C documentation]: srctree/Documentation/filesystems/configfs.rst//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs use crate::alloc::flags;use crate::container_of;use crate::page::PAGE_SIZE;use crate::prelude::*;use crate::str::CString;use crate::sync::Arc;use crate::sync::ArcBorrow;use crate::types::Opaque;use core::cell::UnsafeCell;use core::marker::PhantomData; /// A configfs subsystem.////// This is the top level entrypoint for a configfs hierarchy. To register/// with configfs, embed a field of this type into your kernel module struct.#[pin_data(PinnedDrop)]pub struct Subsystem<Data> { #[pin] subsystem: Opaque<bindings::configfs_subsystem>, #[pin] data: Data,} // SAFETY: We do not provide any operations on `Subsystem`.unsafe impl<Data> Sync for Subsystem<Data> {} // SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.unsafe impl<Data> Send for Subsystem<Data> {} impl<Data> Subsystem<Data> { /// Create an initializer for a [`Subsystem`]. /// /// The subsystem will appear in configfs as a directory name given by /// `name`. The attributes available in directory are specified by /// `item_type`. pub fn new( name: &'static CStr, item_type: &'static ItemType<Subsystem<Data>, Data>, data: impl PinInit<Data, Error>, ) -> impl PinInit<Self, Error> { try_pin_init!(Self { subsystem <- pin_init::init_zeroed().chain( |place: &mut Opaque<bindings::configfs_subsystem>| { // SAFETY: We initialized the required fields of `place.group` above. unsafe { bindings::config_group_init_type_name( &mut (*place.get()).su_group, name.as_char_ptr(), item_type.as_ptr(), ) }; // SAFETY: `place.su_mutex` is valid for use as a mutex. unsafe { bindings::__mutex_init( &mut (*place.get()).su_mutex, kernel::optional_name!().as_char_ptr(), kernel::static_lock_class!().as_ptr(), ) } Ok(()) } ), data <- data, }) .pin_chain(|this| { crate::error::to_result( // SAFETY: We initialized `this.subsystem` according to C API contract above. unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) }, ) }) }} #[pinned_drop]impl<Data> PinnedDrop for Subsystem<Data> { fn drop(self: Pin<&mut Self>) { // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`. unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) }; // SAFETY: We initialized the mutex in `Subsystem::new`. unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) }; }} /// Trait that allows offset calculations for structs that embed a/// `bindings::config_group`.////// Users of the configfs API should not need to implement this trait.////// # Safety////// - Implementers of this trait must embed a `bindings::config_group`./// - Methods must be implemented according to method documentation.pub unsafe trait HasGroup<Data> { /// Return the address of the `bindings::config_group` embedded in [`Self`]. /// /// # Safety /// /// - `this` must be a valid allocation of at least the size of [`Self`]. unsafe fn group(this: *const Self) -> *const bindings::config_group; /// Return the address of the [`Self`] that `group` is embedded in. /// /// # Safety /// /// - `group` must point to the `bindings::config_group` that is embedded in /// [`Self`]. unsafe fn container_of(group: *const bindings::config_group) -> *const Self;} // SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`// within the `subsystem` field.unsafe impl<Data> HasGroup<Data> for Subsystem<Data> { unsafe fn group(this: *const Self) -> *const bindings::config_group { // SAFETY: By impl and function safety requirement this projection is in bounds. unsafe { &raw const (*(*this).subsystem.get()).su_group } } unsafe fn container_of(group: *const bindings::config_group) -> *const Self { // SAFETY: By impl and function safety requirement this projection is in bounds. let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) }; let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>(); // SAFETY: By impl and function safety requirement, `opaque_ptr` and the // pointer it returns, are within the same allocation. unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) } }} /// A configfs group.////// 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]pub struct Group<Data> { #[pin] group: Opaque<bindings::config_group>, #[pin] data: Data,} impl<Data> Group<Data> { /// Create an initializer for a new group. /// /// When instantiated, the group will appear as a directory with the name /// given by `name` and it will contain attributes specified by `item_type`. pub fn new( name: CString, item_type: &'static ItemType<Group<Data>, Data>, data: impl PinInit<Data, Error>, ) -> 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, }) }} // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`// within the `group` field.unsafe impl<Data> HasGroup<Data> for Group<Data> { unsafe fn group(this: *const Self) -> *const bindings::config_group { Opaque::cast_into( // SAFETY: By impl and function safety requirements this field // projection is within bounds of the allocation. unsafe { &raw const (*this).group }, ) } unsafe fn container_of(group: *const bindings::config_group) -> *const Self { let opaque_ptr = group.cast::<Opaque<bindings::config_group>>(); // SAFETY: By impl and function safety requirement, `opaque_ptr` and // pointer it returns will be in the same allocation. unsafe { container_of!(opaque_ptr, Self, group) } }} /// # Safety////// `this` must be a valid pointer.////// If `this` does not represent the root group of a configfs subsystem,/// `this` must be a pointer to a `bindings::config_group` embedded in a/// `Group<Parent>`.////// Otherwise, `this` must be a pointer to a `bindings::config_group` that/// is embedded in a `bindings::configfs_subsystem` that is embedded in a/// `Subsystem<Parent>`.unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent { // SAFETY: `this` is a valid pointer. let is_root = unsafe { (*this).cg_subsys.is_null() }; if !is_root { // SAFETY: By C API contact,`this` was returned from a call to // `make_group`. The pointer is known to be embedded within a // `Group<Parent>`. unsafe { &(*Group::<Parent>::container_of(this)).data } } else { // SAFETY: By C API contract, `this` is a pointer to the // `bindings::config_group` field within a `Subsystem<Parent>`. unsafe { &(*Subsystem::container_of(this)).data } }} struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>); impl<Parent, Child> GroupOperationsVTable<Parent, Child>where Parent: GroupOperations<Child = Child>, Child: 'static,{ /// # Safety /// /// `this` must be a valid pointer. /// /// If `this` does not represent the root group of a configfs subsystem, /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// Otherwise, `this` must be a pointer to a `bindings::config_group` that /// is embedded in a `bindings::configfs_subsystem` that is embedded in a /// `Subsystem<Parent>`. /// /// `name` must point to a null terminated string. unsafe extern "C" fn make_group( this: *mut bindings::config_group, name: *const kernel::ffi::c_char, ) -> *mut bindings::config_group { // SAFETY: By function safety requirements of this function, this call // is safe. let parent_data = unsafe { get_group_data(this) }; let group_init = match Parent::make_group( parent_data, // SAFETY: By function safety requirements, name points to a null // terminated string. unsafe { CStr::from_char_ptr(name) }, ) { Ok(init) => init, Err(e) => return e.to_ptr(), }; let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init( group_init, flags::GFP_KERNEL, ); match child_group { Ok(child_group) => { let child_group_ptr = child_group.into_raw(); // SAFETY: We allocated the pointee of `child_ptr` above as a // `Group<Child>`. unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut() } Err(e) => e.to_ptr(), } } /// # Safety /// /// If `this` does not represent the root group of a configfs subsystem, /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// Otherwise, `this` must be a pointer to a `bindings::config_group` that /// is embedded in a `bindings::configfs_subsystem` that is embedded in a /// `Subsystem<Parent>`. /// /// `item` must point to a `bindings::config_item` within a /// `bindings::config_group` within a `Group<Child>`. unsafe extern "C" fn drop_item( this: *mut bindings::config_group, item: *mut bindings::config_item, ) { // SAFETY: By function safety requirements of this function, this call // is safe. let parent_data = unsafe { get_group_data(this) }; // SAFETY: By function safety requirements, `item` is embedded in a // `config_group`. let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) }; // SAFETY: By function safety requirements, `c_child_group_ptr` is // embedded within a `Group<Child>`. let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) }; if Parent::HAS_DROP_ITEM { // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in // `make_group`. let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) }; Parent::drop_item(parent_data, arc.as_arc_borrow()); arc.into_raw(); } // SAFETY: By C API contract, we are required to drop a refcount on // `item`. unsafe { bindings::config_item_put(item) }; } const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations { make_item: None, make_group: Some(Self::make_group), disconnect_notify: None, drop_item: Some(Self::drop_item), is_visible: None, is_bin_visible: None, }; const fn vtable_ptr() -> *const bindings::configfs_group_operations { &Self::VTABLE }} struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>); impl<Data> ItemOperationsVTable<Group<Data>, Data>where Data: 'static,{ /// # Safety /// /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// This function will destroy the pointee of `this`. The pointee of `this` /// must not be accessed after the function returns. unsafe extern "C" fn release(this: *mut bindings::config_item) { // SAFETY: By function safety requirements, `this` is embedded in a // `config_group`. let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) }; // SAFETY: By function safety requirements, `c_group_ptr` is // embedded within a `Group<Data>`. let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) }; // SAFETY: We called `into_raw` on `r_group_ptr` in // `make_group`. let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) }; drop(pin_self); } const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { release: Some(Self::release), allow_link: None, drop_link: None, }; const fn vtable_ptr() -> *const bindings::configfs_item_operations { &Self::VTABLE }} impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> { const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { release: None, allow_link: None, drop_link: None, }; const fn vtable_ptr() -> *const bindings::configfs_item_operations { &Self::VTABLE }} /// Operations implemented by configfs groups that can create subgroups.////// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].#[vtable]pub trait GroupOperations { /// The child data object type. /// /// This group will create subgroups (subdirectories) backed by this kind of /// object. type Child: 'static; /// Creates a new subgroup. /// /// The kernel will call this method in response to `mkdir(2)` in the /// directory representing `this`. /// /// To accept the request to create a group, implementations should /// return an initializer of a `Group<Self::Child>`. To prevent creation, /// return a suitable error.Lines 1–500 of 1044. Load more
// SPDX-License-Identifier: GPL-2.0 //! configfs interface: Userspace-driven Kernel Object Configuration //! //! configfs is an in-memory pseudo file system for configuration of kernel //! modules. Please see the [C documentation] for details and intended use of //! configfs. //! //! This module does not support the following configfs features: //! //! - Items. All group children are groups. //! - Symlink support. //! - `disconnect_notify` hook. //! - Default groups. //! //! See the [`rust_configfs.rs`] sample for a full example use of this module. //! //! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h) //! //! # Examples //! //! ```ignore //! use kernel::alloc::flags; //! use kernel::configfs_attrs; //! use kernel::configfs; //! use kernel::new_mutex; //! use kernel::page::PAGE_SIZE; //! use kernel::sync::Mutex; //! use kernel::ThisModule; //! //! #[pin_data] //! struct RustConfigfs { //! #[pin] //! config: configfs::Subsystem<Configuration>, //! } //! //! impl kernel::InPlaceModule for RustConfigfs { //! fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> { //! pr_info!("Rust configfs sample (init)\n"); //! //! let item_type = configfs_attrs! { //! container: configfs::Subsystem<Configuration>, //! data: Configuration, //! attributes: [ //! message: 0, //! bar: 1, //! ], //! }; //! //! try_pin_init!(Self { //! config <- configfs::Subsystem::new( //! c"rust_configfs", item_type, Configuration::new() //! ), //! }) //! } //! } //! //! #[pin_data] //! struct Configuration { //! message: &'static CStr, //! #[pin] //! bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>, //! } //! //! impl Configuration { //! fn new() -> impl PinInit<Self, Error> { //! try_pin_init!(Self { //! message: c"Hello World\n", //! bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)), //! }) //! } //! } //! //! #[vtable] //! impl configfs::AttributeOperations<0> for Configuration { //! type Data = Configuration; //! //! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { //! pr_info!("Show message\n"); //! let data = container.message; //! page[0..data.len()].copy_from_slice(data); //! Ok(data.len()) //! } //! } //! //! #[vtable] //! impl configfs::AttributeOperations<1> for Configuration { //! type Data = Configuration; //! //! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { //! pr_info!("Show bar\n"); //! let guard = container.bar.lock(); //! let data = guard.0.as_slice(); //! let len = guard.1; //! page[0..len].copy_from_slice(&data[0..len]); //! Ok(len) //! } //! //! fn store(container: &Configuration, page: &[u8]) -> Result { //! pr_info!("Store bar\n"); //! let mut guard = container.bar.lock(); //! guard.0[0..page.len()].copy_from_slice(page); //! guard.1 = page.len(); //! Ok(()) //! } //! } //! ``` //! //! [C documentation]: srctree/Documentation/filesystems/configfs.rst //! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs use crate::alloc::flags; use crate::container_of; use crate::page::PAGE_SIZE; use crate::prelude::*; use crate::str::CString; use crate::sync::Arc; use crate::sync::ArcBorrow; use crate::types::Opaque; use core::cell::UnsafeCell; use core::marker::PhantomData; /// A configfs subsystem. /// /// This is the top level entrypoint for a configfs hierarchy. To register /// with configfs, embed a field of this type into your kernel module struct. #[pin_data(PinnedDrop)] pub struct Subsystem<Data> { #[pin] subsystem: Opaque<bindings::configfs_subsystem>, #[pin] data: Data, } // SAFETY: We do not provide any operations on `Subsystem`. unsafe impl<Data> Sync for Subsystem<Data> {} // SAFETY: Ownership of `Subsystem` can safely be transferred to other threads. unsafe impl<Data> Send for Subsystem<Data> {} impl<Data> Subsystem<Data> { /// Create an initializer for a [`Subsystem`]. /// /// The subsystem will appear in configfs as a directory name given by /// `name`. The attributes available in directory are specified by /// `item_type`. pub fn new( name: &'static CStr, item_type: &'static ItemType<Subsystem<Data>, Data>, data: impl PinInit<Data, Error>, ) -> impl PinInit<Self, Error> { try_pin_init!(Self { subsystem <- pin_init::init_zeroed().chain( |place: &mut Opaque<bindings::configfs_subsystem>| { // SAFETY: We initialized the required fields of `place.group` above. unsafe { bindings::config_group_init_type_name( &mut (*place.get()).su_group, name.as_char_ptr(), item_type.as_ptr(), ) }; // SAFETY: `place.su_mutex` is valid for use as a mutex. unsafe { bindings::__mutex_init( &mut (*place.get()).su_mutex, kernel::optional_name!().as_char_ptr(), kernel::static_lock_class!().as_ptr(), ) } Ok(()) } ), data <- data, }) .pin_chain(|this| { crate::error::to_result( // SAFETY: We initialized `this.subsystem` according to C API contract above. unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) }, ) }) } } #[pinned_drop] impl<Data> PinnedDrop for Subsystem<Data> { fn drop(self: Pin<&mut Self>) { // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`. unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) }; // SAFETY: We initialized the mutex in `Subsystem::new`. unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) }; } } /// Trait that allows offset calculations for structs that embed a /// `bindings::config_group`. /// /// Users of the configfs API should not need to implement this trait. /// /// # Safety /// /// - Implementers of this trait must embed a `bindings::config_group`. /// - Methods must be implemented according to method documentation. pub unsafe trait HasGroup<Data> { /// Return the address of the `bindings::config_group` embedded in [`Self`]. /// /// # Safety /// /// - `this` must be a valid allocation of at least the size of [`Self`]. unsafe fn group(this: *const Self) -> *const bindings::config_group; /// Return the address of the [`Self`] that `group` is embedded in. /// /// # Safety /// /// - `group` must point to the `bindings::config_group` that is embedded in /// [`Self`]. unsafe fn container_of(group: *const bindings::config_group) -> *const Self; } // SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group` // within the `subsystem` field. unsafe impl<Data> HasGroup<Data> for Subsystem<Data> { unsafe fn group(this: *const Self) -> *const bindings::config_group { // SAFETY: By impl and function safety requirement this projection is in bounds. unsafe { &raw const (*(*this).subsystem.get()).su_group } } unsafe fn container_of(group: *const bindings::config_group) -> *const Self { // SAFETY: By impl and function safety requirement this projection is in bounds. let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) }; let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>(); // SAFETY: By impl and function safety requirement, `opaque_ptr` and the // pointer it returns, are within the same allocation. unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) } } } /// A configfs group. /// /// 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] pub struct Group<Data> { #[pin] group: Opaque<bindings::config_group>, #[pin] data: Data, } impl<Data> Group<Data> { /// Create an initializer for a new group. /// /// When instantiated, the group will appear as a directory with the name /// given by `name` and it will contain attributes specified by `item_type`. pub fn new( name: CString, item_type: &'static ItemType<Group<Data>, Data>, data: impl PinInit<Data, Error>, ) -> 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, }) } } // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group` // within the `group` field. unsafe impl<Data> HasGroup<Data> for Group<Data> { unsafe fn group(this: *const Self) -> *const bindings::config_group { Opaque::cast_into( // SAFETY: By impl and function safety requirements this field // projection is within bounds of the allocation. unsafe { &raw const (*this).group }, ) } unsafe fn container_of(group: *const bindings::config_group) -> *const Self { let opaque_ptr = group.cast::<Opaque<bindings::config_group>>(); // SAFETY: By impl and function safety requirement, `opaque_ptr` and // pointer it returns will be in the same allocation. unsafe { container_of!(opaque_ptr, Self, group) } } } /// # Safety /// /// `this` must be a valid pointer. /// /// If `this` does not represent the root group of a configfs subsystem, /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// Otherwise, `this` must be a pointer to a `bindings::config_group` that /// is embedded in a `bindings::configfs_subsystem` that is embedded in a /// `Subsystem<Parent>`. unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent { // SAFETY: `this` is a valid pointer. let is_root = unsafe { (*this).cg_subsys.is_null() }; if !is_root { // SAFETY: By C API contact,`this` was returned from a call to // `make_group`. The pointer is known to be embedded within a // `Group<Parent>`. unsafe { &(*Group::<Parent>::container_of(this)).data } } else { // SAFETY: By C API contract, `this` is a pointer to the // `bindings::config_group` field within a `Subsystem<Parent>`. unsafe { &(*Subsystem::container_of(this)).data } } } struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>); impl<Parent, Child> GroupOperationsVTable<Parent, Child> where Parent: GroupOperations<Child = Child>, Child: 'static, { /// # Safety /// /// `this` must be a valid pointer. /// /// If `this` does not represent the root group of a configfs subsystem, /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// Otherwise, `this` must be a pointer to a `bindings::config_group` that /// is embedded in a `bindings::configfs_subsystem` that is embedded in a /// `Subsystem<Parent>`. /// /// `name` must point to a null terminated string. unsafe extern "C" fn make_group( this: *mut bindings::config_group, name: *const kernel::ffi::c_char, ) -> *mut bindings::config_group { // SAFETY: By function safety requirements of this function, this call // is safe. let parent_data = unsafe { get_group_data(this) }; let group_init = match Parent::make_group( parent_data, // SAFETY: By function safety requirements, name points to a null // terminated string. unsafe { CStr::from_char_ptr(name) }, ) { Ok(init) => init, Err(e) => return e.to_ptr(), }; let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init( group_init, flags::GFP_KERNEL, ); match child_group { Ok(child_group) => { let child_group_ptr = child_group.into_raw(); // SAFETY: We allocated the pointee of `child_ptr` above as a // `Group<Child>`. unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut() } Err(e) => e.to_ptr(), } } /// # Safety /// /// If `this` does not represent the root group of a configfs subsystem, /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// Otherwise, `this` must be a pointer to a `bindings::config_group` that /// is embedded in a `bindings::configfs_subsystem` that is embedded in a /// `Subsystem<Parent>`. /// /// `item` must point to a `bindings::config_item` within a /// `bindings::config_group` within a `Group<Child>`. unsafe extern "C" fn drop_item( this: *mut bindings::config_group, item: *mut bindings::config_item, ) { // SAFETY: By function safety requirements of this function, this call // is safe. let parent_data = unsafe { get_group_data(this) }; // SAFETY: By function safety requirements, `item` is embedded in a // `config_group`. let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) }; // SAFETY: By function safety requirements, `c_child_group_ptr` is // embedded within a `Group<Child>`. let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) }; if Parent::HAS_DROP_ITEM { // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in // `make_group`. let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) }; Parent::drop_item(parent_data, arc.as_arc_borrow()); arc.into_raw(); } // SAFETY: By C API contract, we are required to drop a refcount on // `item`. unsafe { bindings::config_item_put(item) }; } const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations { make_item: None, make_group: Some(Self::make_group), disconnect_notify: None, drop_item: Some(Self::drop_item), is_visible: None, is_bin_visible: None, }; const fn vtable_ptr() -> *const bindings::configfs_group_operations { &Self::VTABLE } } struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>); impl<Data> ItemOperationsVTable<Group<Data>, Data> where Data: 'static, { /// # Safety /// /// `this` must be a pointer to a `bindings::config_group` embedded in a /// `Group<Parent>`. /// /// This function will destroy the pointee of `this`. The pointee of `this` /// must not be accessed after the function returns. unsafe extern "C" fn release(this: *mut bindings::config_item) { // SAFETY: By function safety requirements, `this` is embedded in a // `config_group`. let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) }; // SAFETY: By function safety requirements, `c_group_ptr` is // embedded within a `Group<Data>`. let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) }; // SAFETY: We called `into_raw` on `r_group_ptr` in // `make_group`. let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) }; drop(pin_self); } const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { release: Some(Self::release), allow_link: None, drop_link: None, }; const fn vtable_ptr() -> *const bindings::configfs_item_operations { &Self::VTABLE } } impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> { const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations { release: None, allow_link: None, drop_link: None, }; const fn vtable_ptr() -> *const bindings::configfs_item_operations { &Self::VTABLE } } /// Operations implemented by configfs groups that can create subgroups. /// /// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`]. #[vtable] pub trait GroupOperations { /// The child data object type. /// /// This group will create subgroups (subdirectories) backed by this kind of /// object. type Child: 'static; /// Creates a new subgroup. /// /// The kernel will call this method in response to `mkdir(2)` in the /// directory representing `this`. /// /// To accept the request to create a group, implementations should /// return an initializer of a `Group<Self::Child>`. To prevent creation, /// return a suitable error.