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//! # Example
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::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::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 as *const bindings::configfs_group_operations
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 as *const bindings::configfs_item_operations
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 as *const bindings::configfs_item_operations
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) }.cast_mut();
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 as *mut [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) }.cast_mut();
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 {
721            (&mut *self.0.get())[I] = (attribute as *const Attribute<ID, O, Data>)
722                .cast_mut()
723                .cast()
724        };
725    }
726}
727
728/// A representation of the attributes that will appear in a [`Group`] or
729/// [`Subsystem`].
730///
731/// Users should not directly instantiate objects of this type. Rather, they
732/// should use the [`kernel::configfs_attrs`] macro to statically declare the
733/// shape of a [`Group`] or [`Subsystem`].
734#[pin_data]
735pub struct ItemType<Container, Data> {
736    #[pin]
737    item_type: Opaque<bindings::config_item_type>,
738    _p: PhantomData<(Container, Data)>,
739}
740
741// SAFETY: We do not provide any operations on `ItemType` that need synchronization.
742unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
743
744// SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
745unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
746
747macro_rules! impl_item_type {
748    ($tpe:ty) => {
749        impl<Data> ItemType<$tpe, Data> {
750            #[doc(hidden)]
751            pub const fn new_with_child_ctor<const N: usize, Child>(
752                owner: &'static ThisModule,
753                attributes: &'static AttributeList<N, Data>,
754            ) -> Self
755            where
756                Data: GroupOperations<Child = Child>,
757                Child: 'static,
758            {
759                Self {
760                    item_type: Opaque::new(bindings::config_item_type {
761                        ct_owner: owner.as_ptr(),
762                        ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
763                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
764                        ct_attrs: (attributes as *const AttributeList<N, Data>)
765                            .cast_mut()
766                            .cast(),
767                        ct_bin_attrs: core::ptr::null_mut(),
768                    }),
769                    _p: PhantomData,
770                }
771            }
772
773            #[doc(hidden)]
774            pub const fn new<const N: usize>(
775                owner: &'static ThisModule,
776                attributes: &'static AttributeList<N, Data>,
777            ) -> Self {
778                Self {
779                    item_type: Opaque::new(bindings::config_item_type {
780                        ct_owner: owner.as_ptr(),
781                        ct_group_ops: core::ptr::null_mut(),
782                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
783                        ct_attrs: (attributes as *const AttributeList<N, Data>)
784                            .cast_mut()
785                            .cast(),
786                        ct_bin_attrs: core::ptr::null_mut(),
787                    }),
788                    _p: PhantomData,
789                }
790            }
791        }
792    };
793}
794
795impl_item_type!(Subsystem<Data>);
796impl_item_type!(Group<Data>);
797
798impl<Container, Data> ItemType<Container, Data> {
799    fn as_ptr(&self) -> *const bindings::config_item_type {
800        self.item_type.get()
801    }
802}
803
804/// Define a list of configfs attributes statically.
805///
806/// Invoking the macro in the following manner:
807///
808/// ```ignore
809/// let item_type = configfs_attrs! {
810///     container: configfs::Subsystem<Configuration>,
811///     data: Configuration,
812///     child: Child,
813///     attributes: [
814///         message: 0,
815///         bar: 1,
816///     ],
817/// };
818/// ```
819///
820/// Expands the following output:
821///
822/// ```ignore
823/// let item_type = {
824///     static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
825///         0,
826///         Configuration,
827///         Configuration,
828///     > = unsafe {
829///         kernel::configfs::Attribute::new({
830///             const S: &str = "message\u{0}";
831///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
832///                 S.as_bytes()
833///             ) {
834///                 Ok(v) => v,
835///                 Err(_) => {
836///                     core::panicking::panic_fmt(core::const_format_args!(
837///                         "string contains interior NUL"
838///                     ));
839///                 }
840///             };
841///             C
842///         })
843///     };
844///
845///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
846///             1,
847///             Configuration,
848///             Configuration
849///     > = unsafe {
850///         kernel::configfs::Attribute::new({
851///             const S: &str = "bar\u{0}";
852///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
853///                 S.as_bytes()
854///             ) {
855///                 Ok(v) => v,
856///                 Err(_) => {
857///                     core::panicking::panic_fmt(core::const_format_args!(
858///                         "string contains interior NUL"
859///                     ));
860///                 }
861///             };
862///             C
863///         })
864///     };
865///
866///     const N: usize = (1usize + (1usize + 0usize)) + 1usize;
867///
868///     static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
869///         unsafe { kernel::configfs::AttributeList::new() };
870///
871///     {
872///         const N: usize = 0usize;
873///         unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
874///     }
875///
876///     {
877///         const N: usize = (1usize + 0usize);
878///         unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
879///     }
880///
881///     static CONFIGURATION_TPE:
882///       kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
883///         = kernel::configfs::ItemType::<
884///                 configfs::Subsystem<Configuration>,
885///                 Configuration
886///                 >::new_with_child_ctor::<N,Child>(
887///             &THIS_MODULE,
888///             &CONFIGURATION_ATTRS
889///         );
890///
891///     &CONFIGURATION_TPE
892/// }
893/// ```
894#[macro_export]
895macro_rules! configfs_attrs {
896    (
897        container: $container:ty,
898        data: $data:ty,
899        attributes: [
900            $($name:ident: $attr:literal),* $(,)?
901        ] $(,)?
902    ) => {
903        $crate::configfs_attrs!(
904            count:
905            @container($container),
906            @data($data),
907            @child(),
908            @no_child(x),
909            @attrs($($name $attr)*),
910            @eat($($name $attr,)*),
911            @assign(),
912            @cnt(0usize),
913        )
914    };
915    (
916        container: $container:ty,
917        data: $data:ty,
918        child: $child:ty,
919        attributes: [
920            $($name:ident: $attr:literal),* $(,)?
921        ] $(,)?
922    ) => {
923        $crate::configfs_attrs!(
924            count:
925            @container($container),
926            @data($data),
927            @child($child),
928            @no_child(),
929            @attrs($($name $attr)*),
930            @eat($($name $attr,)*),
931            @assign(),
932            @cnt(0usize),
933        )
934    };
935    (count:
936     @container($container:ty),
937     @data($data:ty),
938     @child($($child:ty)?),
939     @no_child($($no_child:ident)?),
940     @attrs($($aname:ident $aattr:literal)*),
941     @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
942     @assign($($assign:block)*),
943     @cnt($cnt:expr),
944    ) => {
945        $crate::configfs_attrs!(
946            count:
947            @container($container),
948            @data($data),
949            @child($($child)?),
950            @no_child($($no_child)?),
951            @attrs($($aname $aattr)*),
952            @eat($($rname $rattr,)*),
953            @assign($($assign)* {
954                const N: usize = $cnt;
955                // The following macro text expands to a call to `Attribute::add`.
956
957                // SAFETY: By design of this macro, the name of the variable we
958                // invoke the `add` method on below, is not visible outside of
959                // the macro expansion. The macro does not operate concurrently
960                // on this variable, and thus we have exclusive access to the
961                // variable.
962                unsafe {
963                    $crate::macros::paste!(
964                        [< $data:upper _ATTRS >]
965                            .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
966                    )
967                };
968            }),
969            @cnt(1usize + $cnt),
970        )
971    };
972    (count:
973     @container($container:ty),
974     @data($data:ty),
975     @child($($child:ty)?),
976     @no_child($($no_child:ident)?),
977     @attrs($($aname:ident $aattr:literal)*),
978     @eat(),
979     @assign($($assign:block)*),
980     @cnt($cnt:expr),
981    ) =>
982    {
983        $crate::configfs_attrs!(
984            final:
985            @container($container),
986            @data($data),
987            @child($($child)?),
988            @no_child($($no_child)?),
989            @attrs($($aname $aattr)*),
990            @assign($($assign)*),
991            @cnt($cnt),
992        )
993    };
994    (final:
995     @container($container:ty),
996     @data($data:ty),
997     @child($($child:ty)?),
998     @no_child($($no_child:ident)?),
999     @attrs($($name:ident $attr:literal)*),
1000     @assign($($assign:block)*),
1001     @cnt($cnt:expr),
1002    ) =>
1003    {
1004        $crate::macros::paste!{
1005            {
1006                $(
1007                    // SAFETY: We are expanding `configfs_attrs`.
1008                    static [< $data:upper _ $name:upper _ATTR >]:
1009                        $crate::configfs::Attribute<$attr, $data, $data> =
1010                            unsafe {
1011                                $crate::configfs::Attribute::new(c_str!(::core::stringify!($name)))
1012                            };
1013                )*
1014
1015
1016                // We need space for a null terminator.
1017                const N: usize = $cnt + 1usize;
1018
1019                // SAFETY: We are expanding `configfs_attrs`.
1020                static [< $data:upper _ATTRS >]:
1021                $crate::configfs::AttributeList<N, $data> =
1022                    unsafe { $crate::configfs::AttributeList::new() };
1023
1024                $($assign)*
1025
1026                $(
1027                    const [<$no_child:upper>]: bool = true;
1028
1029                    static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  =
1030                        $crate::configfs::ItemType::<$container, $data>::new::<N>(
1031                            &THIS_MODULE, &[<$ data:upper _ATTRS >]
1032                        );
1033                )?
1034
1035                $(
1036                    static [< $data:upper _TPE >]:
1037                        $crate::configfs::ItemType<$container, $data>  =
1038                            $crate::configfs::ItemType::<$container, $data>::
1039                            new_with_child_ctor::<N, $child>(
1040                                &THIS_MODULE, &[<$ data:upper _ATTRS >]
1041                            );
1042                )?
1043
1044                & [< $data:upper _TPE >]
1045            }
1046        }
1047    };
1048
1049}