kernel/
configfs.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! configfs interface: Userspace-driven Kernel Object Configuration
4//!
5//! configfs is an in-memory pseudo file system for configuration of kernel
6//! modules. Please see the [C documentation] for details and intended use of
7//! configfs.
8//!
9//! This module does not support the following configfs features:
10//!
11//! - Items. All group children are groups.
12//! - Symlink support.
13//! - `disconnect_notify` hook.
14//! - Default groups.
15//!
16//! See the [`rust_configfs.rs`] sample for a full example use of this module.
17//!
18//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)
19//!
20//! # Examples
21//!
22//! ```ignore
23//! use kernel::alloc::flags;
24//! use kernel::c_str;
25//! use kernel::configfs_attrs;
26//! use kernel::configfs;
27//! use kernel::new_mutex;
28//! use kernel::page::PAGE_SIZE;
29//! use kernel::sync::Mutex;
30//! use kernel::ThisModule;
31//!
32//! #[pin_data]
33//! struct RustConfigfs {
34//!     #[pin]
35//!     config: configfs::Subsystem<Configuration>,
36//! }
37//!
38//! impl kernel::InPlaceModule for RustConfigfs {
39//!     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
40//!         pr_info!("Rust configfs sample (init)\n");
41//!
42//!         let item_type = configfs_attrs! {
43//!             container: configfs::Subsystem<Configuration>,
44//!             data: Configuration,
45//!             attributes: [
46//!                 message: 0,
47//!                 bar: 1,
48//!             ],
49//!         };
50//!
51//!         try_pin_init!(Self {
52//!             config <- configfs::Subsystem::new(
53//!                 c_str!("rust_configfs"), item_type, Configuration::new()
54//!             ),
55//!         })
56//!     }
57//! }
58//!
59//! #[pin_data]
60//! struct Configuration {
61//!     message: &'static CStr,
62//!     #[pin]
63//!     bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
64//! }
65//!
66//! impl Configuration {
67//!     fn new() -> impl PinInit<Self, Error> {
68//!         try_pin_init!(Self {
69//!             message: c_str!("Hello World\n"),
70//!             bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
71//!         })
72//!     }
73//! }
74//!
75//! #[vtable]
76//! impl configfs::AttributeOperations<0> for Configuration {
77//!     type Data = Configuration;
78//!
79//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
80//!         pr_info!("Show message\n");
81//!         let data = container.message;
82//!         page[0..data.len()].copy_from_slice(data);
83//!         Ok(data.len())
84//!     }
85//! }
86//!
87//! #[vtable]
88//! impl configfs::AttributeOperations<1> for Configuration {
89//!     type Data = Configuration;
90//!
91//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
92//!         pr_info!("Show bar\n");
93//!         let guard = container.bar.lock();
94//!         let data = guard.0.as_slice();
95//!         let len = guard.1;
96//!         page[0..len].copy_from_slice(&data[0..len]);
97//!         Ok(len)
98//!     }
99//!
100//!     fn store(container: &Configuration, page: &[u8]) -> Result {
101//!         pr_info!("Store bar\n");
102//!         let mut guard = container.bar.lock();
103//!         guard.0[0..page.len()].copy_from_slice(page);
104//!         guard.1 = page.len();
105//!         Ok(())
106//!     }
107//! }
108//! ```
109//!
110//! [C documentation]: srctree/Documentation/filesystems/configfs.rst
111//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs
112
113use crate::alloc::flags;
114use crate::container_of;
115use crate::page::PAGE_SIZE;
116use crate::prelude::*;
117use crate::str::CString;
118use crate::sync::Arc;
119use crate::sync::ArcBorrow;
120use crate::types::Opaque;
121use core::cell::UnsafeCell;
122use core::marker::PhantomData;
123
124/// A configfs subsystem.
125///
126/// This is the top level entrypoint for a configfs hierarchy. To register
127/// with configfs, embed a field of this type into your kernel module struct.
128#[pin_data(PinnedDrop)]
129pub struct Subsystem<Data> {
130    #[pin]
131    subsystem: Opaque<bindings::configfs_subsystem>,
132    #[pin]
133    data: Data,
134}
135
136// SAFETY: We do not provide any operations on `Subsystem`.
137unsafe impl<Data> Sync for Subsystem<Data> {}
138
139// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
140unsafe impl<Data> Send for Subsystem<Data> {}
141
142impl<Data> Subsystem<Data> {
143    /// Create an initializer for a [`Subsystem`].
144    ///
145    /// The subsystem will appear in configfs as a directory name given by
146    /// `name`. The attributes available in directory are specified by
147    /// `item_type`.
148    pub fn new(
149        name: &'static CStr,
150        item_type: &'static ItemType<Subsystem<Data>, Data>,
151        data: impl PinInit<Data, Error>,
152    ) -> impl PinInit<Self, Error> {
153        try_pin_init!(Self {
154            subsystem <- pin_init::init_zeroed().chain(
155                |place: &mut Opaque<bindings::configfs_subsystem>| {
156                    // SAFETY: We initialized the required fields of `place.group` above.
157                    unsafe {
158                        bindings::config_group_init_type_name(
159                            &mut (*place.get()).su_group,
160                            name.as_ptr(),
161                            item_type.as_ptr(),
162                        )
163                    };
164
165                    // SAFETY: `place.su_mutex` is valid for use as a mutex.
166                    unsafe {
167                        bindings::__mutex_init(
168                            &mut (*place.get()).su_mutex,
169                            kernel::optional_name!().as_char_ptr(),
170                            kernel::static_lock_class!().as_ptr(),
171                        )
172                    }
173                    Ok(())
174                }
175            ),
176            data <- data,
177        })
178        .pin_chain(|this| {
179            crate::error::to_result(
180                // SAFETY: We initialized `this.subsystem` according to C API contract above.
181                unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) },
182            )
183        })
184    }
185}
186
187#[pinned_drop]
188impl<Data> PinnedDrop for Subsystem<Data> {
189    fn drop(self: Pin<&mut Self>) {
190        // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`.
191        unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) };
192        // SAFETY: We initialized the mutex in `Subsystem::new`.
193        unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) };
194    }
195}
196
197/// Trait that allows offset calculations for structs that embed a
198/// `bindings::config_group`.
199///
200/// Users of the configfs API should not need to implement this trait.
201///
202/// # Safety
203///
204/// - Implementers of this trait must embed a `bindings::config_group`.
205/// - Methods must be implemented according to method documentation.
206pub unsafe trait HasGroup<Data> {
207    /// Return the address of the `bindings::config_group` embedded in [`Self`].
208    ///
209    /// # Safety
210    ///
211    /// - `this` must be a valid allocation of at least the size of [`Self`].
212    unsafe fn group(this: *const Self) -> *const bindings::config_group;
213
214    /// Return the address of the [`Self`] that `group` is embedded in.
215    ///
216    /// # Safety
217    ///
218    /// - `group` must point to the `bindings::config_group` that is embedded in
219    ///   [`Self`].
220    unsafe fn container_of(group: *const bindings::config_group) -> *const Self;
221}
222
223// SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`
224// within the `subsystem` field.
225unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {
226    unsafe fn group(this: *const Self) -> *const bindings::config_group {
227        // SAFETY: By impl and function safety requirement this projection is in bounds.
228        unsafe { &raw const (*(*this).subsystem.get()).su_group }
229    }
230
231    unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
232        // SAFETY: By impl and function safety requirement this projection is in bounds.
233        let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) };
234        let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>();
235        // SAFETY: By impl and function safety requirement, `opaque_ptr` and the
236        // pointer it returns, are within the same allocation.
237        unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) }
238    }
239}
240
241/// A configfs group.
242///
243/// To add a subgroup to configfs, pass this type as `ctype` to
244/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].
245#[pin_data]
246pub struct Group<Data> {
247    #[pin]
248    group: Opaque<bindings::config_group>,
249    #[pin]
250    data: Data,
251}
252
253impl<Data> Group<Data> {
254    /// Create an initializer for a new group.
255    ///
256    /// When instantiated, the group will appear as a directory with the name
257    /// given by `name` and it will contain attributes specified by `item_type`.
258    pub fn new(
259        name: CString,
260        item_type: &'static ItemType<Group<Data>, Data>,
261        data: impl PinInit<Data, Error>,
262    ) -> impl PinInit<Self, Error> {
263        try_pin_init!(Self {
264            group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
265                let place = v.get();
266                let name = name.as_bytes_with_nul().as_ptr();
267                // SAFETY: It is safe to initialize a group once it has been zeroed.
268                unsafe {
269                    bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
270                };
271                Ok(())
272            }),
273            data <- data,
274        })
275    }
276}
277
278// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
279// within the `group` field.
280unsafe impl<Data> HasGroup<Data> for Group<Data> {
281    unsafe fn group(this: *const Self) -> *const bindings::config_group {
282        Opaque::raw_get(
283            // SAFETY: By impl and function safety requirements this field
284            // projection is within bounds of the allocation.
285            unsafe { &raw const (*this).group },
286        )
287    }
288
289    unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
290        let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();
291        // SAFETY: By impl and function safety requirement, `opaque_ptr` and
292        // pointer it returns will be in the same allocation.
293        unsafe { container_of!(opaque_ptr, Self, group) }
294    }
295}
296
297/// # Safety
298///
299/// `this` must be a valid pointer.
300///
301/// If `this` does not represent the root group of a configfs subsystem,
302/// `this` must be a pointer to a `bindings::config_group` embedded in a
303/// `Group<Parent>`.
304///
305/// Otherwise, `this` must be a pointer to a `bindings::config_group` that
306/// is embedded in a `bindings::configfs_subsystem` that is embedded in a
307/// `Subsystem<Parent>`.
308unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
309    // SAFETY: `this` is a valid pointer.
310    let is_root = unsafe { (*this).cg_subsys.is_null() };
311
312    if !is_root {
313        // SAFETY: By C API contact,`this` was returned from a call to
314        // `make_group`. The pointer is known to be embedded within a
315        // `Group<Parent>`.
316        unsafe { &(*Group::<Parent>::container_of(this)).data }
317    } else {
318        // SAFETY: By C API contract, `this` is a pointer to the
319        // `bindings::config_group` field within a `Subsystem<Parent>`.
320        unsafe { &(*Subsystem::container_of(this)).data }
321    }
322}
323
324struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
325
326impl<Parent, Child> GroupOperationsVTable<Parent, Child>
327where
328    Parent: GroupOperations<Child = Child>,
329    Child: 'static,
330{
331    /// # Safety
332    ///
333    /// `this` must be a valid pointer.
334    ///
335    /// If `this` does not represent the root group of a configfs subsystem,
336    /// `this` must be a pointer to a `bindings::config_group` embedded in a
337    /// `Group<Parent>`.
338    ///
339    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
340    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
341    /// `Subsystem<Parent>`.
342    ///
343    /// `name` must point to a null terminated string.
344    unsafe extern "C" fn make_group(
345        this: *mut bindings::config_group,
346        name: *const kernel::ffi::c_char,
347    ) -> *mut bindings::config_group {
348        // SAFETY: By function safety requirements of this function, this call
349        // is safe.
350        let parent_data = unsafe { get_group_data(this) };
351
352        let group_init = match Parent::make_group(
353            parent_data,
354            // SAFETY: By function safety requirements, name points to a null
355            // terminated string.
356            unsafe { CStr::from_char_ptr(name) },
357        ) {
358            Ok(init) => init,
359            Err(e) => return e.to_ptr(),
360        };
361
362        let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(
363            group_init,
364            flags::GFP_KERNEL,
365        );
366
367        match child_group {
368            Ok(child_group) => {
369                let child_group_ptr = child_group.into_raw();
370                // SAFETY: We allocated the pointee of `child_ptr` above as a
371                // `Group<Child>`.
372                unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()
373            }
374            Err(e) => e.to_ptr(),
375        }
376    }
377
378    /// # Safety
379    ///
380    /// If `this` does not represent the root group of a configfs subsystem,
381    /// `this` must be a pointer to a `bindings::config_group` embedded in a
382    /// `Group<Parent>`.
383    ///
384    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
385    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
386    /// `Subsystem<Parent>`.
387    ///
388    /// `item` must point to a `bindings::config_item` within a
389    /// `bindings::config_group` within a `Group<Child>`.
390    unsafe extern "C" fn drop_item(
391        this: *mut bindings::config_group,
392        item: *mut bindings::config_item,
393    ) {
394        // SAFETY: By function safety requirements of this function, this call
395        // is safe.
396        let parent_data = unsafe { get_group_data(this) };
397
398        // SAFETY: By function safety requirements, `item` is embedded in a
399        // `config_group`.
400        let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };
401        // SAFETY: By function safety requirements, `c_child_group_ptr` is
402        // embedded within a `Group<Child>`.
403        let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };
404
405        if Parent::HAS_DROP_ITEM {
406            // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in
407            // `make_group`.
408            let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };
409
410            Parent::drop_item(parent_data, arc.as_arc_borrow());
411            arc.into_raw();
412        }
413
414        // SAFETY: By C API contract, we are required to drop a refcount on
415        // `item`.
416        unsafe { bindings::config_item_put(item) };
417    }
418
419    const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {
420        make_item: None,
421        make_group: Some(Self::make_group),
422        disconnect_notify: None,
423        drop_item: Some(Self::drop_item),
424        is_visible: None,
425        is_bin_visible: None,
426    };
427
428    const fn vtable_ptr() -> *const bindings::configfs_group_operations {
429        &Self::VTABLE
430    }
431}
432
433struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
434
435impl<Data> ItemOperationsVTable<Group<Data>, Data>
436where
437    Data: 'static,
438{
439    /// # Safety
440    ///
441    /// `this` must be a pointer to a `bindings::config_group` embedded in a
442    /// `Group<Parent>`.
443    ///
444    /// This function will destroy the pointee of `this`. The pointee of `this`
445    /// must not be accessed after the function returns.
446    unsafe extern "C" fn release(this: *mut bindings::config_item) {
447        // SAFETY: By function safety requirements, `this` is embedded in a
448        // `config_group`.
449        let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };
450        // SAFETY: By function safety requirements, `c_group_ptr` is
451        // embedded within a `Group<Data>`.
452        let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };
453
454        // SAFETY: We called `into_raw` on `r_group_ptr` in
455        // `make_group`.
456        let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };
457        drop(pin_self);
458    }
459
460    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
461        release: Some(Self::release),
462        allow_link: None,
463        drop_link: None,
464    };
465
466    const fn vtable_ptr() -> *const bindings::configfs_item_operations {
467        &Self::VTABLE
468    }
469}
470
471impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
472    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
473        release: None,
474        allow_link: None,
475        drop_link: None,
476    };
477
478    const fn vtable_ptr() -> *const bindings::configfs_item_operations {
479        &Self::VTABLE
480    }
481}
482
483/// Operations implemented by configfs groups that can create subgroups.
484///
485/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].
486#[vtable]
487pub trait GroupOperations {
488    /// The child data object type.
489    ///
490    /// This group will create subgroups (subdirectories) backed by this kind of
491    /// object.
492    type Child: 'static;
493
494    /// Creates a new subgroup.
495    ///
496    /// The kernel will call this method in response to `mkdir(2)` in the
497    /// directory representing `this`.
498    ///
499    /// To accept the request to create a group, implementations should
500    /// return an initializer of a `Group<Self::Child>`. To prevent creation,
501    /// return a suitable error.
502    fn make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, Error>>;
503
504    /// Prepares the group for removal from configfs.
505    ///
506    /// The kernel will call this method before the directory representing `_child` is removed from
507    /// configfs.
508    ///
509    /// Implementations can use this method to do house keeping before configfs drops its
510    /// reference to `Child`.
511    ///
512    /// NOTE: "drop" in the name of this function is not related to the Rust drop term. Rather, the
513    /// name is inherited from the callback name in the underlying C code.
514    fn drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>) {
515        kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
516    }
517}
518
519/// A configfs attribute.
520///
521/// An attribute appears as a file in configfs, inside a folder that represent
522/// the group that the attribute belongs to.
523#[repr(transparent)]
524pub struct Attribute<const ID: u64, O, Data> {
525    attribute: Opaque<bindings::configfs_attribute>,
526    _p: PhantomData<(O, Data)>,
527}
528
529// SAFETY: We do not provide any operations on `Attribute`.
530unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}
531
532// SAFETY: Ownership of `Attribute` can safely be transferred to other threads.
533unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
534
535impl<const ID: u64, O, Data> Attribute<ID, O, Data>
536where
537    O: AttributeOperations<ID, Data = Data>,
538{
539    /// # Safety
540    ///
541    /// `item` must be embedded in a `bindings::config_group`.
542    ///
543    /// If `item` does not represent the root group of a configfs subsystem,
544    /// the group must be embedded in a `Group<Data>`.
545    ///
546    /// Otherwise, the group must be a embedded in a
547    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
548    ///
549    /// `page` must point to a writable buffer of size at least [`PAGE_SIZE`].
550    unsafe extern "C" fn show(
551        item: *mut bindings::config_item,
552        page: *mut kernel::ffi::c_char,
553    ) -> isize {
554        let c_group: *mut bindings::config_group =
555            // SAFETY: By function safety requirements, `item` is embedded in a
556            // `config_group`.
557            unsafe { container_of!(item, bindings::config_group, cg_item) };
558
559        // SAFETY: The function safety requirements for this function satisfy
560        // the conditions for this call.
561        let data: &Data = unsafe { get_group_data(c_group) };
562
563        // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
564        let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });
565
566        match ret {
567            Ok(size) => size as isize,
568            Err(err) => err.to_errno() as isize,
569        }
570    }
571
572    /// # Safety
573    ///
574    /// `item` must be embedded in a `bindings::config_group`.
575    ///
576    /// If `item` does not represent the root group of a configfs subsystem,
577    /// the group must be embedded in a `Group<Data>`.
578    ///
579    /// Otherwise, the group must be a embedded in a
580    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
581    ///
582    /// `page` must point to a readable buffer of size at least `size`.
583    unsafe extern "C" fn store(
584        item: *mut bindings::config_item,
585        page: *const kernel::ffi::c_char,
586        size: usize,
587    ) -> isize {
588        let c_group: *mut bindings::config_group =
589        // SAFETY: By function safety requirements, `item` is embedded in a
590        // `config_group`.
591            unsafe { container_of!(item, bindings::config_group, cg_item) };
592
593        // SAFETY: The function safety requirements for this function satisfy
594        // the conditions for this call.
595        let data: &Data = unsafe { get_group_data(c_group) };
596
597        let ret = O::store(
598            data,
599            // SAFETY: By function safety requirements, `page` is readable
600            // for at least `size`.
601            unsafe { core::slice::from_raw_parts(page.cast(), size) },
602        );
603
604        match ret {
605            Ok(()) => size as isize,
606            Err(err) => err.to_errno() as isize,
607        }
608    }
609
610    /// Create a new attribute.
611    ///
612    /// The attribute will appear as a file with name given by `name`.
613    pub const fn new(name: &'static CStr) -> Self {
614        Self {
615            attribute: Opaque::new(bindings::configfs_attribute {
616                ca_name: name.as_char_ptr(),
617                ca_owner: core::ptr::null_mut(),
618                ca_mode: 0o660,
619                show: Some(Self::show),
620                store: if O::HAS_STORE {
621                    Some(Self::store)
622                } else {
623                    None
624                },
625            }),
626            _p: PhantomData,
627        }
628    }
629}
630
631/// Operations supported by an attribute.
632///
633/// Implement this trait on type and pass that type as generic parameter when
634/// creating an [`Attribute`]. The type carrying the implementation serve no
635/// purpose other than specifying the attribute operations.
636///
637/// This trait must be implemented on the `Data` type of for types that
638/// implement `HasGroup<Data>`. The trait must be implemented once for each
639/// attribute of the group. The constant type parameter `ID` maps the
640/// implementation to a specific `Attribute`. `ID` must be passed when declaring
641/// attributes via the [`kernel::configfs_attrs`] macro, to tie
642/// `AttributeOperations` implementations to concrete named attributes.
643#[vtable]
644pub trait AttributeOperations<const ID: u64 = 0> {
645    /// The type of the object that contains the field that is backing the
646    /// attribute for this operation.
647    type Data;
648
649    /// Renders the value of an attribute.
650    ///
651    /// This function is called by the kernel to read the value of an attribute.
652    ///
653    /// Implementations should write the rendering of the attribute to `page`
654    /// and return the number of bytes written.
655    fn show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>;
656
657    /// Stores the value of an attribute.
658    ///
659    /// This function is called by the kernel to update the value of an attribute.
660    ///
661    /// Implementations should parse the value from `page` and update internal
662    /// state to reflect the parsed value.
663    fn store(_data: &Self::Data, _page: &[u8]) -> Result {
664        kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
665    }
666}
667
668/// A list of attributes.
669///
670/// This type is used to construct a new [`ItemType`]. It represents a list of
671/// [`Attribute`] that will appear in the directory representing a [`Group`].
672/// Users should not directly instantiate this type, rather they should use the
673/// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a
674/// group.
675///
676/// # Note
677///
678/// Instances of this type are constructed statically at compile by the
679/// [`kernel::configfs_attrs`] macro.
680#[repr(transparent)]
681pub struct AttributeList<const N: usize, Data>(
682    /// Null terminated Array of pointers to [`Attribute`]. The type is [`c_void`]
683    /// to conform to the C API.
684    UnsafeCell<[*mut kernel::ffi::c_void; N]>,
685    PhantomData<Data>,
686);
687
688// SAFETY: Ownership of `AttributeList` can safely be transferred to other threads.
689unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
690
691// SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
692unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
693
694impl<const N: usize, Data> AttributeList<N, Data> {
695    /// # Safety
696    ///
697    /// This function must only be called by the [`kernel::configfs_attrs`]
698    /// macro.
699    #[doc(hidden)]
700    pub const unsafe fn new() -> Self {
701        Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData)
702    }
703
704    /// # Safety
705    ///
706    /// The caller must ensure that there are no other concurrent accesses to
707    /// `self`. That is, the caller has exclusive access to `self.`
708    #[doc(hidden)]
709    pub const unsafe fn add<const I: usize, const ID: u64, O>(
710        &'static self,
711        attribute: &'static Attribute<ID, O, Data>,
712    ) where
713        O: AttributeOperations<ID, Data = Data>,
714    {
715        // We need a space at the end of our list for a null terminator.
716        const { assert!(I < N - 1, "Invalid attribute index") };
717
718        // SAFETY: By function safety requirements, we have exclusive access to
719        // `self` and the reference created below will be exclusive.
720        unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
721    }
722}
723
724/// A representation of the attributes that will appear in a [`Group`] or
725/// [`Subsystem`].
726///
727/// Users should not directly instantiate objects of this type. Rather, they
728/// should use the [`kernel::configfs_attrs`] macro to statically declare the
729/// shape of a [`Group`] or [`Subsystem`].
730#[pin_data]
731pub struct ItemType<Container, Data> {
732    #[pin]
733    item_type: Opaque<bindings::config_item_type>,
734    _p: PhantomData<(Container, Data)>,
735}
736
737// SAFETY: We do not provide any operations on `ItemType` that need synchronization.
738unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
739
740// SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
741unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
742
743macro_rules! impl_item_type {
744    ($tpe:ty) => {
745        impl<Data> ItemType<$tpe, Data> {
746            #[doc(hidden)]
747            pub const fn new_with_child_ctor<const N: usize, Child>(
748                owner: &'static ThisModule,
749                attributes: &'static AttributeList<N, Data>,
750            ) -> Self
751            where
752                Data: GroupOperations<Child = Child>,
753                Child: 'static,
754            {
755                Self {
756                    item_type: Opaque::new(bindings::config_item_type {
757                        ct_owner: owner.as_ptr(),
758                        ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
759                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
760                        ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
761                        ct_bin_attrs: core::ptr::null_mut(),
762                    }),
763                    _p: PhantomData,
764                }
765            }
766
767            #[doc(hidden)]
768            pub const fn new<const N: usize>(
769                owner: &'static ThisModule,
770                attributes: &'static AttributeList<N, Data>,
771            ) -> Self {
772                Self {
773                    item_type: Opaque::new(bindings::config_item_type {
774                        ct_owner: owner.as_ptr(),
775                        ct_group_ops: core::ptr::null_mut(),
776                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
777                        ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
778                        ct_bin_attrs: core::ptr::null_mut(),
779                    }),
780                    _p: PhantomData,
781                }
782            }
783        }
784    };
785}
786
787impl_item_type!(Subsystem<Data>);
788impl_item_type!(Group<Data>);
789
790impl<Container, Data> ItemType<Container, Data> {
791    fn as_ptr(&self) -> *const bindings::config_item_type {
792        self.item_type.get()
793    }
794}
795
796/// Define a list of configfs attributes statically.
797///
798/// Invoking the macro in the following manner:
799///
800/// ```ignore
801/// let item_type = configfs_attrs! {
802///     container: configfs::Subsystem<Configuration>,
803///     data: Configuration,
804///     child: Child,
805///     attributes: [
806///         message: 0,
807///         bar: 1,
808///     ],
809/// };
810/// ```
811///
812/// Expands the following output:
813///
814/// ```ignore
815/// let item_type = {
816///     static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
817///         0,
818///         Configuration,
819///         Configuration,
820///     > = unsafe {
821///         kernel::configfs::Attribute::new({
822///             const S: &str = "message\u{0}";
823///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
824///                 S.as_bytes()
825///             ) {
826///                 Ok(v) => v,
827///                 Err(_) => {
828///                     core::panicking::panic_fmt(core::const_format_args!(
829///                         "string contains interior NUL"
830///                     ));
831///                 }
832///             };
833///             C
834///         })
835///     };
836///
837///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
838///             1,
839///             Configuration,
840///             Configuration
841///     > = unsafe {
842///         kernel::configfs::Attribute::new({
843///             const S: &str = "bar\u{0}";
844///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
845///                 S.as_bytes()
846///             ) {
847///                 Ok(v) => v,
848///                 Err(_) => {
849///                     core::panicking::panic_fmt(core::const_format_args!(
850///                         "string contains interior NUL"
851///                     ));
852///                 }
853///             };
854///             C
855///         })
856///     };
857///
858///     const N: usize = (1usize + (1usize + 0usize)) + 1usize;
859///
860///     static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
861///         unsafe { kernel::configfs::AttributeList::new() };
862///
863///     {
864///         const N: usize = 0usize;
865///         unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
866///     }
867///
868///     {
869///         const N: usize = (1usize + 0usize);
870///         unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
871///     }
872///
873///     static CONFIGURATION_TPE:
874///       kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
875///         = kernel::configfs::ItemType::<
876///                 configfs::Subsystem<Configuration>,
877///                 Configuration
878///                 >::new_with_child_ctor::<N,Child>(
879///             &THIS_MODULE,
880///             &CONFIGURATION_ATTRS
881///         );
882///
883///     &CONFIGURATION_TPE
884/// }
885/// ```
886#[macro_export]
887macro_rules! configfs_attrs {
888    (
889        container: $container:ty,
890        data: $data:ty,
891        attributes: [
892            $($name:ident: $attr:literal),* $(,)?
893        ] $(,)?
894    ) => {
895        $crate::configfs_attrs!(
896            count:
897            @container($container),
898            @data($data),
899            @child(),
900            @no_child(x),
901            @attrs($($name $attr)*),
902            @eat($($name $attr,)*),
903            @assign(),
904            @cnt(0usize),
905        )
906    };
907    (
908        container: $container:ty,
909        data: $data:ty,
910        child: $child:ty,
911        attributes: [
912            $($name:ident: $attr:literal),* $(,)?
913        ] $(,)?
914    ) => {
915        $crate::configfs_attrs!(
916            count:
917            @container($container),
918            @data($data),
919            @child($child),
920            @no_child(),
921            @attrs($($name $attr)*),
922            @eat($($name $attr,)*),
923            @assign(),
924            @cnt(0usize),
925        )
926    };
927    (count:
928     @container($container:ty),
929     @data($data:ty),
930     @child($($child:ty)?),
931     @no_child($($no_child:ident)?),
932     @attrs($($aname:ident $aattr:literal)*),
933     @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
934     @assign($($assign:block)*),
935     @cnt($cnt:expr),
936    ) => {
937        $crate::configfs_attrs!(
938            count:
939            @container($container),
940            @data($data),
941            @child($($child)?),
942            @no_child($($no_child)?),
943            @attrs($($aname $aattr)*),
944            @eat($($rname $rattr,)*),
945            @assign($($assign)* {
946                const N: usize = $cnt;
947                // The following macro text expands to a call to `Attribute::add`.
948
949                // SAFETY: By design of this macro, the name of the variable we
950                // invoke the `add` method on below, is not visible outside of
951                // the macro expansion. The macro does not operate concurrently
952                // on this variable, and thus we have exclusive access to the
953                // variable.
954                unsafe {
955                    $crate::macros::paste!(
956                        [< $data:upper _ATTRS >]
957                            .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
958                    )
959                };
960            }),
961            @cnt(1usize + $cnt),
962        )
963    };
964    (count:
965     @container($container:ty),
966     @data($data:ty),
967     @child($($child:ty)?),
968     @no_child($($no_child:ident)?),
969     @attrs($($aname:ident $aattr:literal)*),
970     @eat(),
971     @assign($($assign:block)*),
972     @cnt($cnt:expr),
973    ) =>
974    {
975        $crate::configfs_attrs!(
976            final:
977            @container($container),
978            @data($data),
979            @child($($child)?),
980            @no_child($($no_child)?),
981            @attrs($($aname $aattr)*),
982            @assign($($assign)*),
983            @cnt($cnt),
984        )
985    };
986    (final:
987     @container($container:ty),
988     @data($data:ty),
989     @child($($child:ty)?),
990     @no_child($($no_child:ident)?),
991     @attrs($($name:ident $attr:literal)*),
992     @assign($($assign:block)*),
993     @cnt($cnt:expr),
994    ) =>
995    {
996        $crate::macros::paste!{
997            {
998                $(
999                    // SAFETY: We are expanding `configfs_attrs`.
1000                    static [< $data:upper _ $name:upper _ATTR >]:
1001                        $crate::configfs::Attribute<$attr, $data, $data> =
1002                            unsafe {
1003                                $crate::configfs::Attribute::new(c_str!(::core::stringify!($name)))
1004                            };
1005                )*
1006
1007
1008                // We need space for a null terminator.
1009                const N: usize = $cnt + 1usize;
1010
1011                // SAFETY: We are expanding `configfs_attrs`.
1012                static [< $data:upper _ATTRS >]:
1013                $crate::configfs::AttributeList<N, $data> =
1014                    unsafe { $crate::configfs::AttributeList::new() };
1015
1016                $($assign)*
1017
1018                $(
1019                    const [<$no_child:upper>]: bool = true;
1020
1021                    static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  =
1022                        $crate::configfs::ItemType::<$container, $data>::new::<N>(
1023                            &THIS_MODULE, &[<$ data:upper _ATTRS >]
1024                        );
1025                )?
1026
1027                $(
1028                    static [< $data:upper _TPE >]:
1029                        $crate::configfs::ItemType<$container, $data>  =
1030                            $crate::configfs::ItemType::<$container, $data>::
1031                            new_with_child_ctor::<N, $child>(
1032                                &THIS_MODULE, &[<$ data:upper _ATTRS >]
1033                            );
1034                )?
1035
1036                & [< $data:upper _TPE >]
1037            }
1038        }
1039    };
1040
1041}