// SPDX-License-Identifier: GPL-2.012//! configfs interface: Userspace-driven Kernel Object Configuration3//!4//! configfs is an in-memory pseudo file system for configuration of kernel5//! modules. Please see the [C documentation] for details and intended use of6//! configfs.7//!8//! This module does not support the following configfs features:9//!10//! - Items. All group children are groups.11//! - Symlink support.12//! - `disconnect_notify` hook.13//! - Default groups.14//!15//! See the [`rust_configfs.rs`] sample for a full example use of this module.16//!17//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)18//!19//! # Examples20//!21//! ```ignore22//! use kernel::alloc::flags;23//! use kernel::c_str;24//! use kernel::configfs_attrs;25//! use kernel::configfs;26//! use kernel::new_mutex;27//! use kernel::page::PAGE_SIZE;28//! use kernel::sync::Mutex;29//! use kernel::ThisModule;30//!31//! #[pin_data]32//! struct RustConfigfs {33//! #[pin]34//! config: configfs::Subsystem<Configuration>,35//! }36//!37//! impl kernel::InPlaceModule for RustConfigfs {38//! fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {39//! pr_info!("Rust configfs sample (init)\n");40//!41//! let item_type = configfs_attrs! {42//! container: configfs::Subsystem<Configuration>,43//! data: Configuration,44//! attributes: [45//! message: 0,46//! bar: 1,47//! ],48//! };49//!50//! try_pin_init!(Self {51//! config <- configfs::Subsystem::new(52//! c_str!("rust_configfs"), item_type, Configuration::new()53//! ),54//! })55//! }56//! }57//!58//! #[pin_data]59//! struct Configuration {60//! message: &'static CStr,61//! #[pin]62//! bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,63//! }64//!65//! impl Configuration {66//! fn new() -> impl PinInit<Self, Error> {67//! try_pin_init!(Self {68//! message: c_str!("Hello World\n"),69//! bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),70//! })71//! }72//! }73//!74//! #[vtable]75//! impl configfs::AttributeOperations<0> for Configuration {76//! type Data = Configuration;77//!78//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {79//! pr_info!("Show message\n");80//! let data = container.message;81//! page[0..data.len()].copy_from_slice(data);82//! Ok(data.len())83//! }84//! }85//!86//! #[vtable]87//! impl configfs::AttributeOperations<1> for Configuration {88//! type Data = Configuration;89//!90//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {91//! pr_info!("Show bar\n");92//! let guard = container.bar.lock();93//! let data = guard.0.as_slice();94//! let len = guard.1;95//! page[0..len].copy_from_slice(&data[0..len]);96//! Ok(len)97//! }98//!99//! fn store(container: &Configuration, page: &[u8]) -> Result {100//! pr_info!("Store bar\n");101//! let mut guard = container.bar.lock();102//! guard.0[0..page.len()].copy_from_slice(page);103//! guard.1 = page.len();104//! Ok(())105//! }106//! }107//! ```108//!109//! [C documentation]: srctree/Documentation/filesystems/configfs.rst110//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs111112use crate::alloc::flags;113use crate::container_of;114use crate::page::PAGE_SIZE;115use crate::prelude::*;116use crate::str::CString;117use crate::sync::Arc;118use crate::sync::ArcBorrow;119use crate::types::Opaque;120use core::cell::UnsafeCell;121use core::marker::PhantomData;122123/// A configfs subsystem.124///125/// This is the top level entrypoint for a configfs hierarchy. To register126/// with configfs, embed a field of this type into your kernel module struct.127#[pin_data(PinnedDrop)]128pub struct Subsystem<Data> {129#[pin]130subsystem: Opaque<bindings::configfs_subsystem>,131#[pin]132data: Data,133}134135// SAFETY: We do not provide any operations on `Subsystem`.136unsafe impl<Data> Sync for Subsystem<Data> {}137138// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.139unsafe impl<Data> Send for Subsystem<Data> {}140141impl<Data> Subsystem<Data> {142/// Create an initializer for a [`Subsystem`].143///144/// The subsystem will appear in configfs as a directory name given by145/// `name`. The attributes available in directory are specified by146/// `item_type`.147pub fn new(148name: &'static CStr,149item_type: &'static ItemType<Subsystem<Data>, Data>,150data: impl PinInit<Data, Error>,151) -> impl PinInit<Self, Error> {152try_pin_init!(Self {153subsystem <- pin_init::init_zeroed().chain(154|place: &mut Opaque<bindings::configfs_subsystem>| {155// SAFETY: We initialized the required fields of `place.group` above.156unsafe {157bindings::config_group_init_type_name(158&mut (*place.get()).su_group,159name.as_ptr(),160item_type.as_ptr(),161)162};163164// SAFETY: `place.su_mutex` is valid for use as a mutex.165unsafe {166bindings::__mutex_init(167&mut (*place.get()).su_mutex,168kernel::optional_name!().as_char_ptr(),169kernel::static_lock_class!().as_ptr(),170)171}172Ok(())173}174),175data <- data,176})177.pin_chain(|this| {178crate::error::to_result(179// SAFETY: We initialized `this.subsystem` according to C API contract above.180unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) },181)182})183}184}185186#[pinned_drop]187impl<Data> PinnedDrop for Subsystem<Data> {188fn drop(self: Pin<&mut Self>) {189// SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`.190unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) };191// SAFETY: We initialized the mutex in `Subsystem::new`.192unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) };193}194}195196/// Trait that allows offset calculations for structs that embed a197/// `bindings::config_group`.198///199/// Users of the configfs API should not need to implement this trait.200///201/// # Safety202///203/// - Implementers of this trait must embed a `bindings::config_group`.204/// - Methods must be implemented according to method documentation.205pub unsafe trait HasGroup<Data> {206/// Return the address of the `bindings::config_group` embedded in [`Self`].207///208/// # Safety209///210/// - `this` must be a valid allocation of at least the size of [`Self`].211unsafe fn group(this: *const Self) -> *const bindings::config_group;212213/// Return the address of the [`Self`] that `group` is embedded in.214///215/// # Safety216///217/// - `group` must point to the `bindings::config_group` that is embedded in218/// [`Self`].219unsafe fn container_of(group: *const bindings::config_group) -> *const Self;220}221222// SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`223// within the `subsystem` field.224unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {225unsafe fn group(this: *const Self) -> *const bindings::config_group {226// SAFETY: By impl and function safety requirement this projection is in bounds.227unsafe { &raw const (*(*this).subsystem.get()).su_group }228}229230unsafe fn container_of(group: *const bindings::config_group) -> *const Self {231// SAFETY: By impl and function safety requirement this projection is in bounds.232let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) };233let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>();234// SAFETY: By impl and function safety requirement, `opaque_ptr` and the235// pointer it returns, are within the same allocation.236unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) }237}238}239240/// A configfs group.241///242/// To add a subgroup to configfs, pass this type as `ctype` to243/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].244#[pin_data]245pub struct Group<Data> {246#[pin]247group: Opaque<bindings::config_group>,248#[pin]249data: Data,250}251252impl<Data> Group<Data> {253/// Create an initializer for a new group.254///255/// When instantiated, the group will appear as a directory with the name256/// given by `name` and it will contain attributes specified by `item_type`.257pub fn new(258name: CString,259item_type: &'static ItemType<Group<Data>, Data>,260data: impl PinInit<Data, Error>,261) -> impl PinInit<Self, Error> {262try_pin_init!(Self {263group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {264let place = v.get();265let name = name.to_bytes_with_nul().as_ptr();266// SAFETY: It is safe to initialize a group once it has been zeroed.267unsafe {268bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())269};270Ok(())271}),272data <- data,273})274}275}276277// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`278// within the `group` field.279unsafe impl<Data> HasGroup<Data> for Group<Data> {280unsafe fn group(this: *const Self) -> *const bindings::config_group {281Opaque::cast_into(282// SAFETY: By impl and function safety requirements this field283// projection is within bounds of the allocation.284unsafe { &raw const (*this).group },285)286}287288unsafe fn container_of(group: *const bindings::config_group) -> *const Self {289let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();290// SAFETY: By impl and function safety requirement, `opaque_ptr` and291// pointer it returns will be in the same allocation.292unsafe { container_of!(opaque_ptr, Self, group) }293}294}295296/// # Safety297///298/// `this` must be a valid pointer.299///300/// If `this` does not represent the root group of a configfs subsystem,301/// `this` must be a pointer to a `bindings::config_group` embedded in a302/// `Group<Parent>`.303///304/// Otherwise, `this` must be a pointer to a `bindings::config_group` that305/// is embedded in a `bindings::configfs_subsystem` that is embedded in a306/// `Subsystem<Parent>`.307unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {308// SAFETY: `this` is a valid pointer.309let is_root = unsafe { (*this).cg_subsys.is_null() };310311if !is_root {312// SAFETY: By C API contact,`this` was returned from a call to313// `make_group`. The pointer is known to be embedded within a314// `Group<Parent>`.315unsafe { &(*Group::<Parent>::container_of(this)).data }316} else {317// SAFETY: By C API contract, `this` is a pointer to the318// `bindings::config_group` field within a `Subsystem<Parent>`.319unsafe { &(*Subsystem::container_of(this)).data }320}321}322323struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);324325impl<Parent, Child> GroupOperationsVTable<Parent, Child>326where327Parent: GroupOperations<Child = Child>,328Child: 'static,329{330/// # Safety331///332/// `this` must be a valid pointer.333///334/// If `this` does not represent the root group of a configfs subsystem,335/// `this` must be a pointer to a `bindings::config_group` embedded in a336/// `Group<Parent>`.337///338/// Otherwise, `this` must be a pointer to a `bindings::config_group` that339/// is embedded in a `bindings::configfs_subsystem` that is embedded in a340/// `Subsystem<Parent>`.341///342/// `name` must point to a null terminated string.343unsafe extern "C" fn make_group(344this: *mut bindings::config_group,345name: *const kernel::ffi::c_char,346) -> *mut bindings::config_group {347// SAFETY: By function safety requirements of this function, this call348// is safe.349let parent_data = unsafe { get_group_data(this) };350351let group_init = match Parent::make_group(352parent_data,353// SAFETY: By function safety requirements, name points to a null354// terminated string.355unsafe { CStr::from_char_ptr(name) },356) {357Ok(init) => init,358Err(e) => return e.to_ptr(),359};360361let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(362group_init,363flags::GFP_KERNEL,364);365366match child_group {367Ok(child_group) => {368let child_group_ptr = child_group.into_raw();369// SAFETY: We allocated the pointee of `child_ptr` above as a370// `Group<Child>`.371unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()372}373Err(e) => e.to_ptr(),374}375}376377/// # Safety378///379/// If `this` does not represent the root group of a configfs subsystem,380/// `this` must be a pointer to a `bindings::config_group` embedded in a381/// `Group<Parent>`.382///383/// Otherwise, `this` must be a pointer to a `bindings::config_group` that384/// is embedded in a `bindings::configfs_subsystem` that is embedded in a385/// `Subsystem<Parent>`.386///387/// `item` must point to a `bindings::config_item` within a388/// `bindings::config_group` within a `Group<Child>`.389unsafe extern "C" fn drop_item(390this: *mut bindings::config_group,391item: *mut bindings::config_item,392) {393// SAFETY: By function safety requirements of this function, this call394// is safe.395let parent_data = unsafe { get_group_data(this) };396397// SAFETY: By function safety requirements, `item` is embedded in a398// `config_group`.399let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };400// SAFETY: By function safety requirements, `c_child_group_ptr` is401// embedded within a `Group<Child>`.402let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };403404if Parent::HAS_DROP_ITEM {405// SAFETY: We called `into_raw` to produce `r_child_group_ptr` in406// `make_group`.407let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };408409Parent::drop_item(parent_data, arc.as_arc_borrow());410arc.into_raw();411}412413// SAFETY: By C API contract, we are required to drop a refcount on414// `item`.415unsafe { bindings::config_item_put(item) };416}417418const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {419make_item: None,420make_group: Some(Self::make_group),421disconnect_notify: None,422drop_item: Some(Self::drop_item),423is_visible: None,424is_bin_visible: None,425};426427const fn vtable_ptr() -> *const bindings::configfs_group_operations {428&Self::VTABLE429}430}431432struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);433434impl<Data> ItemOperationsVTable<Group<Data>, Data>435where436Data: 'static,437{438/// # Safety439///440/// `this` must be a pointer to a `bindings::config_group` embedded in a441/// `Group<Parent>`.442///443/// This function will destroy the pointee of `this`. The pointee of `this`444/// must not be accessed after the function returns.445unsafe extern "C" fn release(this: *mut bindings::config_item) {446// SAFETY: By function safety requirements, `this` is embedded in a447// `config_group`.448let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };449// SAFETY: By function safety requirements, `c_group_ptr` is450// embedded within a `Group<Data>`.451let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };452453// SAFETY: We called `into_raw` on `r_group_ptr` in454// `make_group`.455let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };456drop(pin_self);457}458459const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {460release: Some(Self::release),461allow_link: None,462drop_link: None,463};464465const fn vtable_ptr() -> *const bindings::configfs_item_operations {466&Self::VTABLE467}468}469470impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {471const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {472release: None,473allow_link: None,474drop_link: None,475};476477const fn vtable_ptr() -> *const bindings::configfs_item_operations {478&Self::VTABLE479}480}481482/// Operations implemented by configfs groups that can create subgroups.483///484/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].485#[vtable]486pub trait GroupOperations {487/// The child data object type.488///489/// This group will create subgroups (subdirectories) backed by this kind of490/// object.491type Child: 'static;492493/// Creates a new subgroup.494///495/// The kernel will call this method in response to `mkdir(2)` in the496/// directory representing `this`.497///498/// To accept the request to create a group, implementations should499/// return an initializer of a `Group<Self::Child>`. To prevent creation,500/// return a suitable error.501fn make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, Error>>;502503/// Prepares the group for removal from configfs.504///505/// The kernel will call this method before the directory representing `_child` is removed from506/// configfs.507///508/// Implementations can use this method to do house keeping before configfs drops its509/// reference to `Child`.510///511/// NOTE: "drop" in the name of this function is not related to the Rust drop term. Rather, the512/// name is inherited from the callback name in the underlying C code.513fn drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>) {514kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)515}516}517518/// A configfs attribute.519///520/// An attribute appears as a file in configfs, inside a folder that represent521/// the group that the attribute belongs to.522#[repr(transparent)]523pub struct Attribute<const ID: u64, O, Data> {524attribute: Opaque<bindings::configfs_attribute>,525_p: PhantomData<(O, Data)>,526}527528// SAFETY: We do not provide any operations on `Attribute`.529unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}530531// SAFETY: Ownership of `Attribute` can safely be transferred to other threads.532unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}533534impl<const ID: u64, O, Data> Attribute<ID, O, Data>535where536O: AttributeOperations<ID, Data = Data>,537{538/// # Safety539///540/// `item` must be embedded in a `bindings::config_group`.541///542/// If `item` does not represent the root group of a configfs subsystem,543/// the group must be embedded in a `Group<Data>`.544///545/// Otherwise, the group must be a embedded in a546/// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.547///548/// `page` must point to a writable buffer of size at least [`PAGE_SIZE`].549unsafe extern "C" fn show(550item: *mut bindings::config_item,551page: *mut kernel::ffi::c_char,552) -> isize {553let c_group: *mut bindings::config_group =554// SAFETY: By function safety requirements, `item` is embedded in a555// `config_group`.556unsafe { container_of!(item, bindings::config_group, cg_item) };557558// SAFETY: The function safety requirements for this function satisfy559// the conditions for this call.560let data: &Data = unsafe { get_group_data(c_group) };561562// SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.563let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });564565match ret {566Ok(size) => size as isize,567Err(err) => err.to_errno() as isize,568}569}570571/// # Safety572///573/// `item` must be embedded in a `bindings::config_group`.574///575/// If `item` does not represent the root group of a configfs subsystem,576/// the group must be embedded in a `Group<Data>`.577///578/// Otherwise, the group must be a embedded in a579/// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.580///581/// `page` must point to a readable buffer of size at least `size`.582unsafe extern "C" fn store(583item: *mut bindings::config_item,584page: *const kernel::ffi::c_char,585size: usize,586) -> isize {587let c_group: *mut bindings::config_group =588// SAFETY: By function safety requirements, `item` is embedded in a589// `config_group`.590unsafe { container_of!(item, bindings::config_group, cg_item) };591592// SAFETY: The function safety requirements for this function satisfy593// the conditions for this call.594let data: &Data = unsafe { get_group_data(c_group) };595596let ret = O::store(597data,598// SAFETY: By function safety requirements, `page` is readable599// for at least `size`.600unsafe { core::slice::from_raw_parts(page.cast(), size) },601);602603match ret {604Ok(()) => size as isize,605Err(err) => err.to_errno() as isize,606}607}608609/// Create a new attribute.610///611/// The attribute will appear as a file with name given by `name`.612pub const fn new(name: &'static CStr) -> Self {613Self {614attribute: Opaque::new(bindings::configfs_attribute {615ca_name: crate::str::as_char_ptr_in_const_context(name),616ca_owner: core::ptr::null_mut(),617ca_mode: 0o660,618show: Some(Self::show),619store: if O::HAS_STORE {620Some(Self::store)621} else {622None623},624}),625_p: PhantomData,626}627}628}629630/// Operations supported by an attribute.631///632/// Implement this trait on type and pass that type as generic parameter when633/// creating an [`Attribute`]. The type carrying the implementation serve no634/// purpose other than specifying the attribute operations.635///636/// This trait must be implemented on the `Data` type of for types that637/// implement `HasGroup<Data>`. The trait must be implemented once for each638/// attribute of the group. The constant type parameter `ID` maps the639/// implementation to a specific `Attribute`. `ID` must be passed when declaring640/// attributes via the [`kernel::configfs_attrs`] macro, to tie641/// `AttributeOperations` implementations to concrete named attributes.642#[vtable]643pub trait AttributeOperations<const ID: u64 = 0> {644/// The type of the object that contains the field that is backing the645/// attribute for this operation.646type Data;647648/// Renders the value of an attribute.649///650/// This function is called by the kernel to read the value of an attribute.651///652/// Implementations should write the rendering of the attribute to `page`653/// and return the number of bytes written.654fn show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>;655656/// Stores the value of an attribute.657///658/// This function is called by the kernel to update the value of an attribute.659///660/// Implementations should parse the value from `page` and update internal661/// state to reflect the parsed value.662fn store(_data: &Self::Data, _page: &[u8]) -> Result {663kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)664}665}666667/// A list of attributes.668///669/// This type is used to construct a new [`ItemType`]. It represents a list of670/// [`Attribute`] that will appear in the directory representing a [`Group`].671/// Users should not directly instantiate this type, rather they should use the672/// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a673/// group.674///675/// # Note676///677/// Instances of this type are constructed statically at compile by the678/// [`kernel::configfs_attrs`] macro.679#[repr(transparent)]680pub struct AttributeList<const N: usize, Data>(681/// Null terminated Array of pointers to [`Attribute`]. The type is [`c_void`]682/// to conform to the C API.683UnsafeCell<[*mut kernel::ffi::c_void; N]>,684PhantomData<Data>,685);686687// SAFETY: Ownership of `AttributeList` can safely be transferred to other threads.688unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}689690// SAFETY: We do not provide any operations on `AttributeList` that need synchronization.691unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}692693impl<const N: usize, Data> AttributeList<N, Data> {694/// # Safety695///696/// This function must only be called by the [`kernel::configfs_attrs`]697/// macro.698#[doc(hidden)]699pub const unsafe fn new() -> Self {700Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData)701}702703/// # Safety704///705/// The caller must ensure that there are no other concurrent accesses to706/// `self`. That is, the caller has exclusive access to `self.`707#[doc(hidden)]708pub const unsafe fn add<const I: usize, const ID: u64, O>(709&'static self,710attribute: &'static Attribute<ID, O, Data>,711) where712O: AttributeOperations<ID, Data = Data>,713{714// We need a space at the end of our list for a null terminator.715const { assert!(I < N - 1, "Invalid attribute index") };716717// SAFETY: By function safety requirements, we have exclusive access to718// `self` and the reference created below will be exclusive.719unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };720}721}722723/// A representation of the attributes that will appear in a [`Group`] or724/// [`Subsystem`].725///726/// Users should not directly instantiate objects of this type. Rather, they727/// should use the [`kernel::configfs_attrs`] macro to statically declare the728/// shape of a [`Group`] or [`Subsystem`].729#[pin_data]730pub struct ItemType<Container, Data> {731#[pin]732item_type: Opaque<bindings::config_item_type>,733_p: PhantomData<(Container, Data)>,734}735736// SAFETY: We do not provide any operations on `ItemType` that need synchronization.737unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}738739// SAFETY: Ownership of `ItemType` can safely be transferred to other threads.740unsafe impl<Container, Data> Send for ItemType<Container, Data> {}741742macro_rules! impl_item_type {743($tpe:ty) => {744impl<Data> ItemType<$tpe, Data> {745#[doc(hidden)]746pub const fn new_with_child_ctor<const N: usize, Child>(747owner: &'static ThisModule,748attributes: &'static AttributeList<N, Data>,749) -> Self750where751Data: GroupOperations<Child = Child>,752Child: 'static,753{754Self {755item_type: Opaque::new(bindings::config_item_type {756ct_owner: owner.as_ptr(),757ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),758ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),759ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),760ct_bin_attrs: core::ptr::null_mut(),761}),762_p: PhantomData,763}764}765766#[doc(hidden)]767pub const fn new<const N: usize>(768owner: &'static ThisModule,769attributes: &'static AttributeList<N, Data>,770) -> Self {771Self {772item_type: Opaque::new(bindings::config_item_type {773ct_owner: owner.as_ptr(),774ct_group_ops: core::ptr::null_mut(),775ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),776ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),777ct_bin_attrs: core::ptr::null_mut(),778}),779_p: PhantomData,780}781}782}783};784}785786impl_item_type!(Subsystem<Data>);787impl_item_type!(Group<Data>);788789impl<Container, Data> ItemType<Container, Data> {790fn as_ptr(&self) -> *const bindings::config_item_type {791self.item_type.get()792}793}794795/// Define a list of configfs attributes statically.796///797/// Invoking the macro in the following manner:798///799/// ```ignore800/// let item_type = configfs_attrs! {801/// container: configfs::Subsystem<Configuration>,802/// data: Configuration,803/// child: Child,804/// attributes: [805/// message: 0,806/// bar: 1,807/// ],808/// };809/// ```810///811/// Expands the following output:812///813/// ```ignore814/// let item_type = {815/// static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<816/// 0,817/// Configuration,818/// Configuration,819/// > = unsafe {820/// kernel::configfs::Attribute::new({821/// const S: &str = "message\u{0}";822/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(823/// S.as_bytes()824/// ) {825/// Ok(v) => v,826/// Err(_) => {827/// core::panicking::panic_fmt(core::const_format_args!(828/// "string contains interior NUL"829/// ));830/// }831/// };832/// C833/// })834/// };835///836/// static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<837/// 1,838/// Configuration,839/// Configuration840/// > = unsafe {841/// kernel::configfs::Attribute::new({842/// const S: &str = "bar\u{0}";843/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(844/// S.as_bytes()845/// ) {846/// Ok(v) => v,847/// Err(_) => {848/// core::panicking::panic_fmt(core::const_format_args!(849/// "string contains interior NUL"850/// ));851/// }852/// };853/// C854/// })855/// };856///857/// const N: usize = (1usize + (1usize + 0usize)) + 1usize;858///859/// static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =860/// unsafe { kernel::configfs::AttributeList::new() };861///862/// {863/// const N: usize = 0usize;864/// unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };865/// }866///867/// {868/// const N: usize = (1usize + 0usize);869/// unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };870/// }871///872/// static CONFIGURATION_TPE:873/// kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>874/// = kernel::configfs::ItemType::<875/// configfs::Subsystem<Configuration>,876/// Configuration877/// >::new_with_child_ctor::<N,Child>(878/// &THIS_MODULE,879/// &CONFIGURATION_ATTRS880/// );881///882/// &CONFIGURATION_TPE883/// }884/// ```885#[macro_export]886macro_rules! configfs_attrs {887(888container: $container:ty,889data: $data:ty,890attributes: [891$($name:ident: $attr:literal),* $(,)?892] $(,)?893) => {894$crate::configfs_attrs!(895count:896@container($container),897@data($data),898@child(),899@no_child(x),900@attrs($($name $attr)*),901@eat($($name $attr,)*),902@assign(),903@cnt(0usize),904)905};906(907container: $container:ty,908data: $data:ty,909child: $child:ty,910attributes: [911$($name:ident: $attr:literal),* $(,)?912] $(,)?913) => {914$crate::configfs_attrs!(915count:916@container($container),917@data($data),918@child($child),919@no_child(),920@attrs($($name $attr)*),921@eat($($name $attr,)*),922@assign(),923@cnt(0usize),924)925};926(count:927@container($container:ty),928@data($data:ty),929@child($($child:ty)?),930@no_child($($no_child:ident)?),931@attrs($($aname:ident $aattr:literal)*),932@eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),933@assign($($assign:block)*),934@cnt($cnt:expr),935) => {936$crate::configfs_attrs!(937count:938@container($container),939@data($data),940@child($($child)?),941@no_child($($no_child)?),942@attrs($($aname $aattr)*),943@eat($($rname $rattr,)*),944@assign($($assign)* {945const N: usize = $cnt;946// The following macro text expands to a call to `Attribute::add`.947948// SAFETY: By design of this macro, the name of the variable we949// invoke the `add` method on below, is not visible outside of950// the macro expansion. The macro does not operate concurrently951// on this variable, and thus we have exclusive access to the952// variable.953unsafe {954$crate::macros::paste!(955[< $data:upper _ATTRS >]956.add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])957)958};959}),960@cnt(1usize + $cnt),961)962};963(count:964@container($container:ty),965@data($data:ty),966@child($($child:ty)?),967@no_child($($no_child:ident)?),968@attrs($($aname:ident $aattr:literal)*),969@eat(),970@assign($($assign:block)*),971@cnt($cnt:expr),972) =>973{974$crate::configfs_attrs!(975final:976@container($container),977@data($data),978@child($($child)?),979@no_child($($no_child)?),980@attrs($($aname $aattr)*),981@assign($($assign)*),982@cnt($cnt),983)984};985(final:986@container($container:ty),987@data($data:ty),988@child($($child:ty)?),989@no_child($($no_child:ident)?),990@attrs($($name:ident $attr:literal)*),991@assign($($assign:block)*),992@cnt($cnt:expr),993) =>994{995$crate::macros::paste!{996{997$(998// SAFETY: We are expanding `configfs_attrs`.999static [< $data:upper _ $name:upper _ATTR >]:1000$crate::configfs::Attribute<$attr, $data, $data> =1001unsafe {1002$crate::configfs::Attribute::new(c_str!(::core::stringify!($name)))1003};1004)*100510061007// We need space for a null terminator.1008const N: usize = $cnt + 1usize;10091010// SAFETY: We are expanding `configfs_attrs`.1011static [< $data:upper _ATTRS >]:1012$crate::configfs::AttributeList<N, $data> =1013unsafe { $crate::configfs::AttributeList::new() };10141015$($assign)*10161017$(1018const [<$no_child:upper>]: bool = true;10191020static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =1021$crate::configfs::ItemType::<$container, $data>::new::<N>(1022&THIS_MODULE, &[<$ data:upper _ATTRS >]1023);1024)?10251026$(1027static [< $data:upper _TPE >]:1028$crate::configfs::ItemType<$container, $data> =1029$crate::configfs::ItemType::<$container, $data>::1030new_with_child_ctor::<N, $child>(1031&THIS_MODULE, &[<$ data:upper _ATTRS >]1032);1033)?10341035& [< $data:upper _TPE >]1036}1037}1038};10391040}10411042pub use crate::configfs_attrs;104310441045