xref: /linux/rust/kernel/configfs.rs (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
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::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"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"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.rst
110 //! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs
111 
112 use crate::alloc::flags;
113 use crate::container_of;
114 use crate::page::PAGE_SIZE;
115 use crate::prelude::*;
116 use crate::str::CString;
117 use crate::sync::Arc;
118 use crate::sync::ArcBorrow;
119 use crate::types::Opaque;
120 use core::cell::UnsafeCell;
121 use core::marker::PhantomData;
122 
123 /// A configfs subsystem.
124 ///
125 /// This is the top level entrypoint for a configfs hierarchy. To register
126 /// with configfs, embed a field of this type into your kernel module struct.
127 #[pin_data(PinnedDrop)]
128 pub struct Subsystem<Data> {
129     #[pin]
130     subsystem: Opaque<bindings::configfs_subsystem>,
131     #[pin]
132     data: Data,
133 }
134 
135 // SAFETY: We do not provide any operations on `Subsystem`.
136 unsafe impl<Data> Sync for Subsystem<Data> {}
137 
138 // SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
139 unsafe impl<Data> Send for Subsystem<Data> {}
140 
141 impl<Data> Subsystem<Data> {
142     /// Create an initializer for a [`Subsystem`].
143     ///
144     /// The subsystem will appear in configfs as a directory name given by
145     /// `name`. The attributes available in directory are specified by
146     /// `item_type`.
147     pub fn new(
148         name: &'static CStr,
149         item_type: &'static ItemType<Subsystem<Data>, Data>,
150         data: impl PinInit<Data, Error>,
151     ) -> impl PinInit<Self, Error> {
152         try_pin_init!(Self {
153             subsystem <- pin_init::init_zeroed().chain(
154                 |place: &mut Opaque<bindings::configfs_subsystem>| {
155                     // SAFETY: We initialized the required fields of `place.group` above.
156                     unsafe {
157                         bindings::config_group_init_type_name(
158                             &mut (*place.get()).su_group,
159                             name.as_char_ptr(),
160                             item_type.as_ptr(),
161                         )
162                     };
163 
164                     // SAFETY: `place.su_mutex` is valid for use as a mutex.
165                     unsafe {
166                         bindings::__mutex_init(
167                             &mut (*place.get()).su_mutex,
168                             kernel::optional_name!().as_char_ptr(),
169                             kernel::static_lock_class!().as_ptr(),
170                         )
171                     }
172                     Ok(())
173                 }
174             ),
175             data <- data,
176         })
177         .pin_chain(|this| {
178             crate::error::to_result(
179                 // SAFETY: We initialized `this.subsystem` according to C API contract above.
180                 unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) },
181             )
182         })
183     }
184 }
185 
186 #[pinned_drop]
187 impl<Data> PinnedDrop for Subsystem<Data> {
188     fn drop(self: Pin<&mut Self>) {
189         // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`.
190         unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) };
191         // SAFETY: We initialized the mutex in `Subsystem::new`.
192         unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) };
193     }
194 }
195 
196 /// Trait that allows offset calculations for structs that embed a
197 /// `bindings::config_group`.
198 ///
199 /// Users of the configfs API should not need to implement this trait.
200 ///
201 /// # Safety
202 ///
203 /// - Implementers of this trait must embed a `bindings::config_group`.
204 /// - Methods must be implemented according to method documentation.
205 pub unsafe trait HasGroup<Data> {
206     /// Return the address of the `bindings::config_group` embedded in [`Self`].
207     ///
208     /// # Safety
209     ///
210     /// - `this` must be a valid allocation of at least the size of [`Self`].
211     unsafe fn group(this: *const Self) -> *const bindings::config_group;
212 
213     /// Return the address of the [`Self`] that `group` is embedded in.
214     ///
215     /// # Safety
216     ///
217     /// - `group` must point to the `bindings::config_group` that is embedded in
218     ///   [`Self`].
219     unsafe fn container_of(group: *const bindings::config_group) -> *const Self;
220 }
221 
222 // SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`
223 // within the `subsystem` field.
224 unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {
225     unsafe fn group(this: *const Self) -> *const bindings::config_group {
226         // SAFETY: By impl and function safety requirement this projection is in bounds.
227         unsafe { &raw const (*(*this).subsystem.get()).su_group }
228     }
229 
230     unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
231         // SAFETY: By impl and function safety requirement this projection is in bounds.
232         let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) };
233         let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>();
234         // SAFETY: By impl and function safety requirement, `opaque_ptr` and the
235         // pointer it returns, are within the same allocation.
236         unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) }
237     }
238 }
239 
240 /// A configfs group.
241 ///
242 /// To add a subgroup to configfs, pass this type as `ctype` to
243 /// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].
244 #[pin_data]
245 pub struct Group<Data> {
246     #[pin]
247     group: Opaque<bindings::config_group>,
248     #[pin]
249     data: Data,
250 }
251 
252 impl<Data> Group<Data> {
253     /// Create an initializer for a new group.
254     ///
255     /// When instantiated, the group will appear as a directory with the name
256     /// given by `name` and it will contain attributes specified by `item_type`.
257     pub fn new(
258         name: CString,
259         item_type: &'static ItemType<Group<Data>, Data>,
260         data: impl PinInit<Data, Error>,
261     ) -> impl PinInit<Self, Error> {
262         try_pin_init!(Self {
263             group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
264                 let place = v.get();
265                 let name = name.to_bytes_with_nul().as_ptr();
266                 // SAFETY: It is safe to initialize a group once it has been zeroed.
267                 unsafe {
268                     bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
269                 };
270                 Ok(())
271             }),
272             data <- data,
273         })
274     }
275 }
276 
277 // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
278 // within the `group` field.
279 unsafe impl<Data> HasGroup<Data> for Group<Data> {
280     unsafe fn group(this: *const Self) -> *const bindings::config_group {
281         Opaque::cast_into(
282             // SAFETY: By impl and function safety requirements this field
283             // projection is within bounds of the allocation.
284             unsafe { &raw const (*this).group },
285         )
286     }
287 
288     unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
289         let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();
290         // SAFETY: By impl and function safety requirement, `opaque_ptr` and
291         // pointer it returns will be in the same allocation.
292         unsafe { container_of!(opaque_ptr, Self, group) }
293     }
294 }
295 
296 /// # Safety
297 ///
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 a
302 /// `Group<Parent>`.
303 ///
304 /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
305 /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
306 /// `Subsystem<Parent>`.
307 unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
308     // SAFETY: `this` is a valid pointer.
309     let is_root = unsafe { (*this).cg_subsys.is_null() };
310 
311     if !is_root {
312         // SAFETY: By C API contact,`this` was returned from a call to
313         // `make_group`. The pointer is known to be embedded within a
314         // `Group<Parent>`.
315         unsafe { &(*Group::<Parent>::container_of(this)).data }
316     } else {
317         // SAFETY: By C API contract, `this` is a pointer to the
318         // `bindings::config_group` field within a `Subsystem<Parent>`.
319         unsafe { &(*Subsystem::container_of(this)).data }
320     }
321 }
322 
323 struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
324 
325 impl<Parent, Child> GroupOperationsVTable<Parent, Child>
326 where
327     Parent: GroupOperations<Child = Child>,
328     Child: 'static,
329 {
330     /// # Safety
331     ///
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 a
336     /// `Group<Parent>`.
337     ///
338     /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
339     /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
340     /// `Subsystem<Parent>`.
341     ///
342     /// `name` must point to a null terminated string.
343     unsafe extern "C" fn make_group(
344         this: *mut bindings::config_group,
345         name: *const kernel::ffi::c_char,
346     ) -> *mut bindings::config_group {
347         // SAFETY: By function safety requirements of this function, this call
348         // is safe.
349         let parent_data = unsafe { get_group_data(this) };
350 
351         let group_init = match Parent::make_group(
352             parent_data,
353             // SAFETY: By function safety requirements, name points to a null
354             // terminated string.
355             unsafe { CStr::from_char_ptr(name) },
356         ) {
357             Ok(init) => init,
358             Err(e) => return e.to_ptr(),
359         };
360 
361         let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(
362             group_init,
363             flags::GFP_KERNEL,
364         );
365 
366         match child_group {
367             Ok(child_group) => {
368                 let child_group_ptr = child_group.into_raw();
369                 // SAFETY: We allocated the pointee of `child_ptr` above as a
370                 // `Group<Child>`.
371                 unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()
372             }
373             Err(e) => e.to_ptr(),
374         }
375     }
376 
377     /// # Safety
378     ///
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 a
381     /// `Group<Parent>`.
382     ///
383     /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
384     /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
385     /// `Subsystem<Parent>`.
386     ///
387     /// `item` must point to a `bindings::config_item` within a
388     /// `bindings::config_group` within a `Group<Child>`.
389     unsafe extern "C" fn drop_item(
390         this: *mut bindings::config_group,
391         item: *mut bindings::config_item,
392     ) {
393         // SAFETY: By function safety requirements of this function, this call
394         // is safe.
395         let parent_data = unsafe { get_group_data(this) };
396 
397         // SAFETY: By function safety requirements, `item` is embedded in a
398         // `config_group`.
399         let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };
400         // SAFETY: By function safety requirements, `c_child_group_ptr` is
401         // embedded within a `Group<Child>`.
402         let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };
403 
404         if Parent::HAS_DROP_ITEM {
405             // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in
406             // `make_group`.
407             let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };
408 
409             Parent::drop_item(parent_data, arc.as_arc_borrow());
410             arc.into_raw();
411         }
412 
413         // SAFETY: By C API contract, we are required to drop a refcount on
414         // `item`.
415         unsafe { bindings::config_item_put(item) };
416     }
417 
418     const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {
419         make_item: None,
420         make_group: Some(Self::make_group),
421         disconnect_notify: None,
422         drop_item: Some(Self::drop_item),
423         is_visible: None,
424         is_bin_visible: None,
425     };
426 
427     const fn vtable_ptr() -> *const bindings::configfs_group_operations {
428         &Self::VTABLE
429     }
430 }
431 
432 struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
433 
434 impl<Data> ItemOperationsVTable<Group<Data>, Data>
435 where
436     Data: 'static,
437 {
438     /// # Safety
439     ///
440     /// `this` must be a pointer to a `bindings::config_group` embedded in a
441     /// `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.
445     unsafe extern "C" fn release(this: *mut bindings::config_item) {
446         // SAFETY: By function safety requirements, `this` is embedded in a
447         // `config_group`.
448         let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };
449         // SAFETY: By function safety requirements, `c_group_ptr` is
450         // embedded within a `Group<Data>`.
451         let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };
452 
453         // SAFETY: We called `into_raw` on `r_group_ptr` in
454         // `make_group`.
455         let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };
456         drop(pin_self);
457     }
458 
459     const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
460         release: Some(Self::release),
461         allow_link: None,
462         drop_link: None,
463     };
464 
465     const fn vtable_ptr() -> *const bindings::configfs_item_operations {
466         &Self::VTABLE
467     }
468 }
469 
470 impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
471     const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
472         release: None,
473         allow_link: None,
474         drop_link: None,
475     };
476 
477     const fn vtable_ptr() -> *const bindings::configfs_item_operations {
478         &Self::VTABLE
479     }
480 }
481 
482 /// 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]
486 pub trait GroupOperations {
487     /// The child data object type.
488     ///
489     /// This group will create subgroups (subdirectories) backed by this kind of
490     /// object.
491     type Child: 'static;
492 
493     /// Creates a new subgroup.
494     ///
495     /// The kernel will call this method in response to `mkdir(2)` in the
496     /// directory representing `this`.
497     ///
498     /// To accept the request to create a group, implementations should
499     /// return an initializer of a `Group<Self::Child>`. To prevent creation,
500     /// return a suitable error.
501     fn make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, Error>>;
502 
503     /// Prepares the group for removal from configfs.
504     ///
505     /// The kernel will call this method before the directory representing `_child` is removed from
506     /// configfs.
507     ///
508     /// Implementations can use this method to do house keeping before configfs drops its
509     /// reference to `Child`.
510     ///
511     /// NOTE: "drop" in the name of this function is not related to the Rust drop term. Rather, the
512     /// name is inherited from the callback name in the underlying C code.
513     fn drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>) {
514         kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
515     }
516 }
517 
518 /// A configfs attribute.
519 ///
520 /// An attribute appears as a file in configfs, inside a folder that represent
521 /// the group that the attribute belongs to.
522 #[repr(transparent)]
523 pub struct Attribute<const ID: u64, O, Data> {
524     attribute: Opaque<bindings::configfs_attribute>,
525     _p: PhantomData<(O, Data)>,
526 }
527 
528 // SAFETY: We do not provide any operations on `Attribute`.
529 unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}
530 
531 // SAFETY: Ownership of `Attribute` can safely be transferred to other threads.
532 unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
533 
534 impl<const ID: u64, O, Data> Attribute<ID, O, Data>
535 where
536     O: AttributeOperations<ID, Data = Data>,
537 {
538     /// # Safety
539     ///
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 a
546     /// `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`].
549     unsafe extern "C" fn show(
550         item: *mut bindings::config_item,
551         page: *mut kernel::ffi::c_char,
552     ) -> isize {
553         let c_group: *mut bindings::config_group =
554             // SAFETY: By function safety requirements, `item` is embedded in a
555             // `config_group`.
556             unsafe { container_of!(item, bindings::config_group, cg_item) };
557 
558         // SAFETY: The function safety requirements for this function satisfy
559         // the conditions for this call.
560         let data: &Data = unsafe { get_group_data(c_group) };
561 
562         // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
563         let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });
564 
565         match ret {
566             Ok(size) => size as isize,
567             Err(err) => err.to_errno() as isize,
568         }
569     }
570 
571     /// # Safety
572     ///
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 a
579     /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
580     ///
581     /// `page` must point to a readable buffer of size at least `size`.
582     unsafe extern "C" fn store(
583         item: *mut bindings::config_item,
584         page: *const kernel::ffi::c_char,
585         size: usize,
586     ) -> isize {
587         let c_group: *mut bindings::config_group =
588         // SAFETY: By function safety requirements, `item` is embedded in a
589         // `config_group`.
590             unsafe { container_of!(item, bindings::config_group, cg_item) };
591 
592         // SAFETY: The function safety requirements for this function satisfy
593         // the conditions for this call.
594         let data: &Data = unsafe { get_group_data(c_group) };
595 
596         let ret = O::store(
597             data,
598             // SAFETY: By function safety requirements, `page` is readable
599             // for at least `size`.
600             unsafe { core::slice::from_raw_parts(page.cast(), size) },
601         );
602 
603         match ret {
604             Ok(()) => size as isize,
605             Err(err) => err.to_errno() as isize,
606         }
607     }
608 
609     /// Create a new attribute.
610     ///
611     /// The attribute will appear as a file with name given by `name`.
612     pub const fn new(name: &'static CStr) -> Self {
613         Self {
614             attribute: Opaque::new(bindings::configfs_attribute {
615                 ca_name: crate::str::as_char_ptr_in_const_context(name),
616                 ca_owner: core::ptr::null_mut(),
617                 ca_mode: 0o660,
618                 show: Some(Self::show),
619                 store: if O::HAS_STORE {
620                     Some(Self::store)
621                 } else {
622                     None
623                 },
624             }),
625             _p: PhantomData,
626         }
627     }
628 }
629 
630 /// Operations supported by an attribute.
631 ///
632 /// Implement this trait on type and pass that type as generic parameter when
633 /// creating an [`Attribute`]. The type carrying the implementation serve no
634 /// purpose other than specifying the attribute operations.
635 ///
636 /// This trait must be implemented on the `Data` type of for types that
637 /// implement `HasGroup<Data>`. The trait must be implemented once for each
638 /// attribute of the group. The constant type parameter `ID` maps the
639 /// implementation to a specific `Attribute`. `ID` must be passed when declaring
640 /// attributes via the [`kernel::configfs_attrs`] macro, to tie
641 /// `AttributeOperations` implementations to concrete named attributes.
642 #[vtable]
643 pub trait AttributeOperations<const ID: u64 = 0> {
644     /// The type of the object that contains the field that is backing the
645     /// attribute for this operation.
646     type Data;
647 
648     /// 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.
654     fn show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>;
655 
656     /// 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 internal
661     /// state to reflect the parsed value.
662     fn store(_data: &Self::Data, _page: &[u8]) -> Result {
663         kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
664     }
665 }
666 
667 /// A list of attributes.
668 ///
669 /// This type is used to construct a new [`ItemType`]. It represents a list of
670 /// [`Attribute`] that will appear in the directory representing a [`Group`].
671 /// Users should not directly instantiate this type, rather they should use the
672 /// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a
673 /// group.
674 ///
675 /// # Note
676 ///
677 /// Instances of this type are constructed statically at compile by the
678 /// [`kernel::configfs_attrs`] macro.
679 #[repr(transparent)]
680 pub 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.
683     UnsafeCell<[*mut kernel::ffi::c_void; N]>,
684     PhantomData<Data>,
685 );
686 
687 // SAFETY: Ownership of `AttributeList` can safely be transferred to other threads.
688 unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
689 
690 // SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
691 unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
692 
693 impl<const N: usize, Data> AttributeList<N, Data> {
694     /// # Safety
695     ///
696     /// This function must only be called by the [`kernel::configfs_attrs`]
697     /// macro.
698     #[doc(hidden)]
699     pub const unsafe fn new() -> Self {
700         Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData)
701     }
702 
703     /// # Safety
704     ///
705     /// The caller must ensure that there are no other concurrent accesses to
706     /// `self`. That is, the caller has exclusive access to `self.`
707     #[doc(hidden)]
708     pub const unsafe fn add<const I: usize, const ID: u64, O>(
709         &'static self,
710         attribute: &'static Attribute<ID, O, Data>,
711     ) where
712         O: AttributeOperations<ID, Data = Data>,
713     {
714         // We need a space at the end of our list for a null terminator.
715         const { assert!(I < N - 1, "Invalid attribute index") };
716 
717         // SAFETY: By function safety requirements, we have exclusive access to
718         // `self` and the reference created below will be exclusive.
719         unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
720     }
721 }
722 
723 /// A representation of the attributes that will appear in a [`Group`] or
724 /// [`Subsystem`].
725 ///
726 /// Users should not directly instantiate objects of this type. Rather, they
727 /// should use the [`kernel::configfs_attrs`] macro to statically declare the
728 /// shape of a [`Group`] or [`Subsystem`].
729 #[pin_data]
730 pub struct ItemType<Container, Data> {
731     #[pin]
732     item_type: Opaque<bindings::config_item_type>,
733     _p: PhantomData<(Container, Data)>,
734 }
735 
736 // SAFETY: We do not provide any operations on `ItemType` that need synchronization.
737 unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
738 
739 // SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
740 unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
741 
742 macro_rules! impl_item_type {
743     ($tpe:ty) => {
744         impl<Data> ItemType<$tpe, Data> {
745             #[doc(hidden)]
746             pub const fn new_with_child_ctor<const N: usize, Child>(
747                 owner: &'static ThisModule,
748                 attributes: &'static AttributeList<N, Data>,
749             ) -> Self
750             where
751                 Data: GroupOperations<Child = Child>,
752                 Child: 'static,
753             {
754                 Self {
755                     item_type: Opaque::new(bindings::config_item_type {
756                         ct_owner: owner.as_ptr(),
757                         ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
758                         ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
759                         ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
760                         ct_bin_attrs: core::ptr::null_mut(),
761                     }),
762                     _p: PhantomData,
763                 }
764             }
765 
766             #[doc(hidden)]
767             pub const fn new<const N: usize>(
768                 owner: &'static ThisModule,
769                 attributes: &'static AttributeList<N, Data>,
770             ) -> Self {
771                 Self {
772                     item_type: Opaque::new(bindings::config_item_type {
773                         ct_owner: owner.as_ptr(),
774                         ct_group_ops: core::ptr::null_mut(),
775                         ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
776                         ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
777                         ct_bin_attrs: core::ptr::null_mut(),
778                     }),
779                     _p: PhantomData,
780                 }
781             }
782         }
783     };
784 }
785 
786 impl_item_type!(Subsystem<Data>);
787 impl_item_type!(Group<Data>);
788 
789 impl<Container, Data> ItemType<Container, Data> {
790     fn as_ptr(&self) -> *const bindings::config_item_type {
791         self.item_type.get()
792     }
793 }
794 
795 /// Define a list of configfs attributes statically.
796 ///
797 /// Invoking the macro in the following manner:
798 ///
799 /// ```ignore
800 /// 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 /// ```ignore
814 /// 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 ///             C
833 ///         })
834 ///     };
835 ///
836 ///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
837 ///             1,
838 ///             Configuration,
839 ///             Configuration
840 ///     > = 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 ///             C
854 ///         })
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 ///                 Configuration
877 ///                 >::new_with_child_ctor::<N,Child>(
878 ///             &THIS_MODULE,
879 ///             &CONFIGURATION_ATTRS
880 ///         );
881 ///
882 ///     &CONFIGURATION_TPE
883 /// }
884 /// ```
885 #[macro_export]
886 macro_rules! configfs_attrs {
887     (
888         container: $container:ty,
889         data: $data:ty,
890         attributes: [
891             $($name:ident: $attr:literal),* $(,)?
892         ] $(,)?
893     ) => {
894         $crate::configfs_attrs!(
895             count:
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     (
907         container: $container:ty,
908         data: $data:ty,
909         child: $child:ty,
910         attributes: [
911             $($name:ident: $attr:literal),* $(,)?
912         ] $(,)?
913     ) => {
914         $crate::configfs_attrs!(
915             count:
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!(
937             count:
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)* {
945                 const N: usize = $cnt;
946                 // The following macro text expands to a call to `Attribute::add`.
947 
948                 // SAFETY: By design of this macro, the name of the variable we
949                 // invoke the `add` method on below, is not visible outside of
950                 // the macro expansion. The macro does not operate concurrently
951                 // on this variable, and thus we have exclusive access to the
952                 // variable.
953                 unsafe {
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!(
975             final:
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`.
999                     static [< $data:upper _ $name:upper _ATTR >]:
1000                         $crate::configfs::Attribute<$attr, $data, $data> =
1001                             unsafe {
1002                                 $crate::configfs::Attribute::new(
1003                                     $crate::c_str!(::core::stringify!($name)),
1004                                 )
1005                             };
1006                 )*
1007 
1008 
1009                 // We need space for a null terminator.
1010                 const N: usize = $cnt + 1usize;
1011 
1012                 // SAFETY: We are expanding `configfs_attrs`.
1013                 static [< $data:upper _ATTRS >]:
1014                 $crate::configfs::AttributeList<N, $data> =
1015                     unsafe { $crate::configfs::AttributeList::new() };
1016 
1017                 $($assign)*
1018 
1019                 $(
1020                     const [<$no_child:upper>]: bool = true;
1021 
1022                     static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  =
1023                         $crate::configfs::ItemType::<$container, $data>::new::<N>(
1024                             &THIS_MODULE, &[<$ data:upper _ATTRS >]
1025                         );
1026                 )?
1027 
1028                 $(
1029                     static [< $data:upper _TPE >]:
1030                         $crate::configfs::ItemType<$container, $data>  =
1031                             $crate::configfs::ItemType::<$container, $data>::
1032                             new_with_child_ctor::<N, $child>(
1033                                 &THIS_MODULE, &[<$ data:upper _ATTRS >]
1034                             );
1035                 )?
1036 
1037                 & [< $data:upper _TPE >]
1038             }
1039         }
1040     };
1041 
1042 }
1043 
1044 pub use crate::configfs_attrs;
1045