xref: /linux/rust/kernel/configfs.rs (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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 // if its data can be transferred as well.
140 unsafe impl<Data: Send> Send for Subsystem<Data> {}
141 
142 impl<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_char_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]
188 impl<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.
206 pub 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.
225 unsafe 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]
246 pub struct Group<Data> {
247     #[pin]
248     group: Opaque<bindings::config_group>,
249     #[pin]
250     data: Data,
251 }
252 
253 // SAFETY: We do not provide any operations on `Group`.
254 unsafe impl<Data> Sync for Group<Data> {}
255 
256 // SAFETY: Ownership of `Group` can safely be transferred to other threads if
257 // its data can be transferred as well.
258 unsafe impl<Data: Send> Send for Group<Data> {}
259 
260 impl<Data> Group<Data> {
261     /// Create an initializer for a new group.
262     ///
263     /// When instantiated, the group will appear as a directory with the name
264     /// given by `name` and it will contain attributes specified by `item_type`.
265     pub fn new(
266         name: CString,
267         item_type: &'static ItemType<Group<Data>, Data>,
268         data: impl PinInit<Data, Error>,
269     ) -> impl PinInit<Self, Error> {
270         try_pin_init!(Self {
271             group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
272                 let place = v.get();
273                 let name = name.to_bytes_with_nul().as_ptr();
274                 // SAFETY: It is safe to initialize a group once it has been zeroed.
275                 unsafe {
276                     bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
277                 };
278                 Ok(())
279             }),
280             data <- data,
281         })
282     }
283 }
284 
285 // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
286 // within the `group` field.
287 unsafe impl<Data> HasGroup<Data> for Group<Data> {
288     unsafe fn group(this: *const Self) -> *const bindings::config_group {
289         Opaque::cast_into(
290             // SAFETY: By impl and function safety requirements this field
291             // projection is within bounds of the allocation.
292             unsafe { &raw const (*this).group },
293         )
294     }
295 
296     unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
297         let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();
298         // SAFETY: By impl and function safety requirement, `opaque_ptr` and
299         // pointer it returns will be in the same allocation.
300         unsafe { container_of!(opaque_ptr, Self, group) }
301     }
302 }
303 
304 /// # Safety
305 ///
306 /// `this` must be a valid pointer.
307 ///
308 /// If `this` is the `su_group` field of a `bindings::configfs_subsystem`, that
309 /// `configfs_subsystem` must be embedded in a `Subsystem<Parent>`.
310 ///
311 /// Otherwise, `this` must be a pointer to a `bindings::config_group` embedded
312 /// in a `Group<Parent>`.
313 unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
314     // SAFETY: `this` is a valid pointer.
315     let subsys = unsafe { (*this).cg_subsys };
316 
317     // `link_group()` in `fs/configfs/dir.c` assigns `cg_subsys` for every
318     // `config_group` attached anywhere in a registered subsystem, including
319     // the subsystem's own `su_group` (which gets a pointer to itself). The
320     // only `config_group` with a NULL `cg_subsys` is the configfs root, and
321     // userspace cannot trigger callbacks on it. The group is therefore the
322     // subsystem's `su_group` iff it equals `&cg_subsys->su_group`.
323     let is_root = !subsys.is_null()
324         && core::ptr::eq(
325             this.cast_const(),
326             // SAFETY: For every `config_group` the configfs core dispatches a
327             // callback on, `cg_subsys` was set by `link_group()` at registration time
328             // and points to a valid `configfs_subsystem` that outlives the callback.
329             unsafe { &raw const (*subsys).su_group },
330         );
331 
332     if is_root {
333         // SAFETY: By the above, `this` is the `su_group` field of a
334         // `configfs_subsystem` that, by function safety requirements, is
335         // embedded in a `Subsystem<Parent>`.
336         unsafe { &(*Subsystem::container_of(this)).data }
337     } else {
338         // SAFETY: By function safety requirements, `this` is a
339         // `config_group` embedded in a `Group<Parent>`.
340         unsafe { &(*Group::<Parent>::container_of(this)).data }
341     }
342 }
343 
344 struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
345 
346 impl<Parent, Child> GroupOperationsVTable<Parent, Child>
347 where
348     Parent: GroupOperations<Child = Child>,
349     // We transfer `Arc<Group<Data>>` across a thread boundary in `make_group`
350     // and `drop_item`.
351     Arc<Group<Child>>: Send,
352 {
353     /// # Safety
354     ///
355     /// `this` must be a valid pointer.
356     ///
357     /// If `this` does not represent the root group of a configfs subsystem,
358     /// `this` must be a pointer to a `bindings::config_group` embedded in a
359     /// `Group<Parent>`.
360     ///
361     /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
362     /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
363     /// `Subsystem<Parent>`.
364     ///
365     /// `name` must point to a null terminated string.
366     unsafe extern "C" fn make_group(
367         this: *mut bindings::config_group,
368         name: *const kernel::ffi::c_char,
369     ) -> *mut bindings::config_group {
370         // SAFETY: By function safety requirements, `this` points to a configfs
371         // group containing `Parent`. The `GroupOperations` bound guarantees
372         // that `Parent: Sync`, so it is safe to share it with this thread.
373         let parent_data = unsafe { get_group_data(this) };
374 
375         let group_init = match Parent::make_group(
376             parent_data,
377             // SAFETY: By function safety requirements, name points to a null
378             // terminated string.
379             unsafe { CStr::from_char_ptr(name) },
380         ) {
381             Ok(init) => init,
382             Err(e) => return e.to_ptr(),
383         };
384 
385         let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(
386             group_init,
387             flags::GFP_KERNEL,
388         );
389 
390         match child_group {
391             Ok(child_group) => {
392                 let child_group_ptr = child_group.into_raw();
393                 // SAFETY: We allocated the pointee of `child_ptr` above as a
394                 // `Group<Child>`.
395                 unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()
396             }
397             Err(e) => e.to_ptr(),
398         }
399     }
400 
401     /// # Safety
402     ///
403     /// If `this` does not represent the root group of a configfs subsystem,
404     /// `this` must be a pointer to a `bindings::config_group` embedded in a
405     /// `Group<Parent>`.
406     ///
407     /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
408     /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
409     /// `Subsystem<Parent>`.
410     ///
411     /// `item` must point to a `bindings::config_item` within a
412     /// `bindings::config_group` within a `Group<Child>`.
413     unsafe extern "C" fn drop_item(
414         this: *mut bindings::config_group,
415         item: *mut bindings::config_item,
416     ) {
417         // SAFETY: By function safety requirements, `this` points to a configfs
418         // group containing `Parent`. The `GroupOperations` bound guarantees
419         // that `Parent: Sync`, so it is safe to share it with this thread.
420         let parent_data = unsafe { get_group_data(this) };
421 
422         // SAFETY: By function safety requirements, `item` is embedded in a
423         // `config_group`.
424         let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };
425         // SAFETY: By function safety requirements, `c_child_group_ptr` is
426         // embedded within a `Group<Child>`.
427         let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };
428 
429         if Parent::HAS_DROP_ITEM {
430             // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in
431             // `make_group`. This function may be executing on a different
432             // thread than `into_raw`. As `Arc<Group<Child>>: Send` this
433             // ownership transfer is safe.
434             let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };
435 
436             Parent::drop_item(parent_data, arc.as_arc_borrow());
437             arc.into_raw();
438         }
439 
440         // SAFETY: By C API contract, we are required to drop a refcount on
441         // `item`.
442         unsafe { bindings::config_item_put(item) };
443     }
444 
445     const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {
446         make_item: None,
447         make_group: Some(Self::make_group),
448         disconnect_notify: None,
449         drop_item: Some(Self::drop_item),
450         is_visible: None,
451         is_bin_visible: None,
452     };
453 
454     const fn vtable_ptr() -> *const bindings::configfs_group_operations {
455         &Self::VTABLE
456     }
457 }
458 
459 struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
460 
461 impl<Data> ItemOperationsVTable<Group<Data>, Data>
462 where
463     Data: 'static,
464     // We transfer `Arc<Group<Data>>` across a thread boundary in `release`.
465     Arc<Group<Data>>: Send,
466 {
467     /// # Safety
468     ///
469     /// `this` must be a pointer to the `cg_item` field of a `bindings::config_group` embedded in a
470     /// valid `Group<Data>`.
471     ///
472     /// This function will destroy the pointee of `this`. The pointee of `this`
473     /// must not be accessed after the function returns.
474     unsafe extern "C" fn release(this: *mut bindings::config_item) {
475         // SAFETY: By function safety requirements, `this` is embedded in a
476         // `config_group`.
477         let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };
478         // SAFETY: By function safety requirements, `c_group_ptr` is
479         // embedded within a `Group<Data>`.
480         let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };
481 
482         // SAFETY: We called `into_raw` on `r_group_ptr` in `make_group`. This
483         // function may be running on a different thread than the thread that
484         // called `into_raw`. As `Arc<Group<Data>>: Send`, this is safe.
485         let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };
486         drop(pin_self);
487     }
488 
489     const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
490         release: Some(Self::release),
491         allow_link: None,
492         drop_link: None,
493     };
494 
495     const fn vtable_ptr() -> *const bindings::configfs_item_operations {
496         &Self::VTABLE
497     }
498 }
499 
500 impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
501     const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
502         release: None,
503         allow_link: None,
504         drop_link: None,
505     };
506 
507     const fn vtable_ptr() -> *const bindings::configfs_item_operations {
508         &Self::VTABLE
509     }
510 }
511 
512 /// Operations implemented by configfs groups that can create subgroups.
513 ///
514 /// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].
515 #[vtable]
516 pub trait GroupOperations: Sync {
517     /// The child data object type.
518     ///
519     /// This group will create subgroups (subdirectories) backed by this kind of
520     /// object.
521     type Child: 'static + Send;
522 
523     /// Creates a new subgroup.
524     ///
525     /// The kernel will call this method in response to `mkdir(2)` in the
526     /// directory representing `this`.
527     ///
528     /// To accept the request to create a group, implementations should
529     /// return an initializer of a `Group<Self::Child>`. To prevent creation,
530     /// return a suitable error.
531     fn make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, Error>>;
532 
533     /// Prepares the group for removal from configfs.
534     ///
535     /// The kernel will call this method before the directory representing `_child` is removed from
536     /// configfs.
537     ///
538     /// Implementations can use this method to do house keeping before configfs drops its
539     /// reference to `Child`.
540     ///
541     /// NOTE: "drop" in the name of this function is not related to the Rust drop term. Rather, the
542     /// name is inherited from the callback name in the underlying C code.
543     fn drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>) {
544         kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
545     }
546 }
547 
548 /// A configfs attribute.
549 ///
550 /// An attribute appears as a file in configfs, inside a folder that represent
551 /// the group that the attribute belongs to.
552 #[repr(transparent)]
553 pub struct Attribute<const ID: u64, O, Data> {
554     attribute: Opaque<bindings::configfs_attribute>,
555     _p: PhantomData<(O, Data)>,
556 }
557 
558 // SAFETY: We do not provide any operations on `Attribute`.
559 unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}
560 
561 // SAFETY: Ownership of `Attribute` can safely be transferred to other threads.
562 unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
563 
564 impl<const ID: u64, O, Data> Attribute<ID, O, Data>
565 where
566     O: AttributeOperations<ID, Data = Data>,
567 {
568     /// # Safety
569     ///
570     /// `item` must be embedded in a `bindings::config_group`.
571     ///
572     /// If `item` does not represent the root group of a configfs subsystem,
573     /// the group must be embedded in a `Group<Data>`.
574     ///
575     /// Otherwise, the group must be a embedded in a
576     /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
577     ///
578     /// `page` must point to a writable buffer of size at least [`PAGE_SIZE`].
579     unsafe extern "C" fn show(
580         item: *mut bindings::config_item,
581         page: *mut kernel::ffi::c_char,
582     ) -> isize {
583         let c_group: *mut bindings::config_group =
584             // SAFETY: By function safety requirements, `item` is embedded in a
585             // `config_group`.
586             unsafe { container_of!(item, bindings::config_group, cg_item) };
587 
588         // SAFETY: By function safety requirements, `c_group` points to a
589         // configfs group containing `Data`. The `AttributeOperations` bound
590         // guarantees that `Data: Sync`, so it is safe to share it with this
591         // thread.
592         let data: &Data = unsafe { get_group_data(c_group) };
593 
594         // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
595         let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });
596 
597         match ret {
598             Ok(size) => size as isize,
599             Err(err) => err.to_errno() as isize,
600         }
601     }
602 
603     /// # Safety
604     ///
605     /// `item` must be embedded in a `bindings::config_group`.
606     ///
607     /// If `item` does not represent the root group of a configfs subsystem,
608     /// the group must be embedded in a `Group<Data>`.
609     ///
610     /// Otherwise, the group must be a embedded in a
611     /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
612     ///
613     /// `page` must point to a readable buffer of size at least `size`.
614     unsafe extern "C" fn store(
615         item: *mut bindings::config_item,
616         page: *const kernel::ffi::c_char,
617         size: usize,
618     ) -> isize {
619         let c_group: *mut bindings::config_group =
620         // SAFETY: By function safety requirements, `item` is embedded in a
621         // `config_group`.
622             unsafe { container_of!(item, bindings::config_group, cg_item) };
623 
624         // SAFETY: By function safety requirements, `c_group` points to a
625         // configfs group containing `Data`. The `AttributeOperations` bound
626         // guarantees that `Data: Sync`, so it is safe to share it with this
627         // thread.
628         let data: &Data = unsafe { get_group_data(c_group) };
629 
630         let ret = O::store(
631             data,
632             // SAFETY: By function safety requirements, `page` is readable
633             // for at least `size`.
634             unsafe { core::slice::from_raw_parts(page.cast(), size) },
635         );
636 
637         match ret {
638             Ok(()) => size as isize,
639             Err(err) => err.to_errno() as isize,
640         }
641     }
642 
643     /// Create a new attribute.
644     ///
645     /// The attribute will appear as a file with name given by `name`.
646     pub const fn new(name: &'static CStr) -> Self {
647         Self {
648             attribute: Opaque::new(bindings::configfs_attribute {
649                 ca_name: crate::str::as_char_ptr_in_const_context(name),
650                 ca_owner: core::ptr::null_mut(),
651                 ca_mode: 0o660,
652                 show: Some(Self::show),
653                 store: if O::HAS_STORE {
654                     Some(Self::store)
655                 } else {
656                     None
657                 },
658             }),
659             _p: PhantomData,
660         }
661     }
662 }
663 
664 /// Operations supported by an attribute.
665 ///
666 /// Implement this trait on type and pass that type as generic parameter when
667 /// creating an [`Attribute`]. The type carrying the implementation serve no
668 /// purpose other than specifying the attribute operations.
669 ///
670 /// This trait must be implemented on the `Data` type of for types that
671 /// implement `HasGroup<Data>`. The trait must be implemented once for each
672 /// attribute of the group. The constant type parameter `ID` maps the
673 /// implementation to a specific `Attribute`. `ID` must be passed when declaring
674 /// attributes via the [`kernel::configfs_attrs`] macro, to tie
675 /// `AttributeOperations` implementations to concrete named attributes.
676 #[vtable]
677 pub trait AttributeOperations<const ID: u64 = 0> {
678     /// The type of the object that contains the field that is backing the
679     /// attribute for this operation.
680     type Data: Sync;
681 
682     /// Renders the value of an attribute.
683     ///
684     /// This function is called by the kernel to read the value of an attribute.
685     ///
686     /// Implementations should write the rendering of the attribute to `page`
687     /// and return the number of bytes written.
688     fn show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>;
689 
690     /// Stores the value of an attribute.
691     ///
692     /// This function is called by the kernel to update the value of an attribute.
693     ///
694     /// Implementations should parse the value from `page` and update internal
695     /// state to reflect the parsed value.
696     fn store(_data: &Self::Data, _page: &[u8]) -> Result {
697         kernel::build_error!(kernel::error::VTABLE_DEFAULT_ERROR)
698     }
699 }
700 
701 /// A list of attributes.
702 ///
703 /// This type is used to construct a new [`ItemType`]. It represents a list of
704 /// [`Attribute`] that will appear in the directory representing a [`Group`].
705 /// Users should not directly instantiate this type, rather they should use the
706 /// [`kernel::configfs_attrs`] macro to declare a static set of attributes for a
707 /// group.
708 ///
709 /// # Note
710 ///
711 /// Instances of this type are constructed statically at compile by the
712 /// [`kernel::configfs_attrs`] macro.
713 #[repr(transparent)]
714 pub struct AttributeList<const N: usize, Data>(
715     /// Null terminated Array of pointers to [`Attribute`]. The type is [`c_void`]
716     /// to conform to the C API.
717     UnsafeCell<[*mut kernel::ffi::c_void; N]>,
718     PhantomData<Data>,
719 );
720 
721 // SAFETY: Ownership of `AttributeList` can safely be transferred to other threads.
722 unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
723 
724 // SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
725 unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
726 
727 impl<const N: usize, Data> AttributeList<N, Data> {
728     /// # Safety
729     ///
730     /// This function must only be called by the [`kernel::configfs_attrs`]
731     /// macro.
732     #[doc(hidden)]
733     pub const unsafe fn new() -> Self {
734         Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData)
735     }
736 
737     /// # Safety
738     ///
739     /// The caller must ensure that there are no other concurrent accesses to
740     /// `self`. That is, the caller has exclusive access to `self.`
741     #[doc(hidden)]
742     pub const unsafe fn add<const I: usize, const ID: u64, O>(
743         &'static self,
744         attribute: &'static Attribute<ID, O, Data>,
745     ) where
746         O: AttributeOperations<ID, Data = Data>,
747     {
748         // We need a space at the end of our list for a null terminator.
749         const { assert!(I < N - 1, "Invalid attribute index") };
750 
751         // SAFETY: By function safety requirements, we have exclusive access to
752         // `self` and the reference created below will be exclusive.
753         unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
754     }
755 }
756 
757 /// A representation of the attributes that will appear in a [`Group`] or
758 /// [`Subsystem`].
759 ///
760 /// Users should not directly instantiate objects of this type. Rather, they
761 /// should use the [`kernel::configfs_attrs`] macro to statically declare the
762 /// shape of a [`Group`] or [`Subsystem`].
763 #[pin_data]
764 pub struct ItemType<Container, Data> {
765     #[pin]
766     item_type: Opaque<bindings::config_item_type>,
767     _p: PhantomData<(Container, Data)>,
768 }
769 
770 // SAFETY: We do not provide any operations on `ItemType` that need synchronization.
771 unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
772 
773 // SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
774 unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
775 
776 macro_rules! impl_item_type {
777     ($tpe:ty) => {
778         impl<Data> ItemType<$tpe, Data> {
779             #[doc(hidden)]
780             pub const fn new_with_child_ctor<const N: usize, Child>(
781                 owner: &'static ThisModule,
782                 attributes: &'static AttributeList<N, Data>,
783             ) -> Self
784             where
785                 Data: GroupOperations<Child = Child>,
786                 Arc<Group<Child>>: Send,
787                 Arc<Group<Data>>: Send,
788             {
789                 Self {
790                     item_type: Opaque::new(bindings::config_item_type {
791                         ct_owner: owner.as_ptr(),
792                         ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr(),
793                         ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr(),
794                         __bindgen_anon_1: bindings::config_item_type__bindgen_ty_1 {
795                             ct_attrs_const: core::ptr::from_ref(attributes).cast(),
796                         },
797                         ct_bin_attrs: core::ptr::null(),
798                     }),
799                     _p: PhantomData,
800                 }
801             }
802 
803             #[doc(hidden)]
804             pub const fn new<const N: usize>(
805                 owner: &'static ThisModule,
806                 attributes: &'static AttributeList<N, Data>,
807             ) -> Self
808             where
809                 Arc<Group<Data>>: Send,
810             {
811                 Self {
812                     item_type: Opaque::new(bindings::config_item_type {
813                         ct_owner: owner.as_ptr(),
814                         ct_group_ops: core::ptr::null(),
815                         ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr(),
816                         __bindgen_anon_1: bindings::config_item_type__bindgen_ty_1 {
817                             ct_attrs_const: core::ptr::from_ref(attributes).cast(),
818                         },
819                         ct_bin_attrs: core::ptr::null(),
820                     }),
821                     _p: PhantomData,
822                 }
823             }
824         }
825     };
826 }
827 
828 impl_item_type!(Subsystem<Data>);
829 impl_item_type!(Group<Data>);
830 
831 impl<Container, Data> ItemType<Container, Data> {
832     fn as_ptr(&self) -> *const bindings::config_item_type {
833         self.item_type.get()
834     }
835 }
836 
837 /// Define a list of configfs attributes statically.
838 ///
839 /// Invoking the macro in the following manner:
840 ///
841 /// ```ignore
842 /// let item_type = configfs_attrs! {
843 ///     container: configfs::Subsystem<Configuration>,
844 ///     data: Configuration,
845 ///     child: Child,
846 ///     attributes: [
847 ///         message: 0,
848 ///         bar: 1,
849 ///     ],
850 /// };
851 /// ```
852 ///
853 /// Expands the following output:
854 ///
855 /// ```ignore
856 /// let item_type = {
857 ///     static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
858 ///         0,
859 ///         Configuration,
860 ///         Configuration,
861 ///     > = unsafe {
862 ///         kernel::configfs::Attribute::new({
863 ///             const S: &str = "message\u{0}";
864 ///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
865 ///                 S.as_bytes()
866 ///             ) {
867 ///                 Ok(v) => v,
868 ///                 Err(_) => {
869 ///                     core::panicking::panic_fmt(core::const_format_args!(
870 ///                         "string contains interior NUL"
871 ///                     ));
872 ///                 }
873 ///             };
874 ///             C
875 ///         })
876 ///     };
877 ///
878 ///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
879 ///             1,
880 ///             Configuration,
881 ///             Configuration
882 ///     > = unsafe {
883 ///         kernel::configfs::Attribute::new({
884 ///             const S: &str = "bar\u{0}";
885 ///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
886 ///                 S.as_bytes()
887 ///             ) {
888 ///                 Ok(v) => v,
889 ///                 Err(_) => {
890 ///                     core::panicking::panic_fmt(core::const_format_args!(
891 ///                         "string contains interior NUL"
892 ///                     ));
893 ///                 }
894 ///             };
895 ///             C
896 ///         })
897 ///     };
898 ///
899 ///     const N: usize = (1usize + (1usize + 0usize)) + 1usize;
900 ///
901 ///     static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
902 ///         unsafe { kernel::configfs::AttributeList::new() };
903 ///
904 ///     {
905 ///         const N: usize = 0usize;
906 ///         unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
907 ///     }
908 ///
909 ///     {
910 ///         const N: usize = (1usize + 0usize);
911 ///         unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
912 ///     }
913 ///
914 ///     static CONFIGURATION_TPE:
915 ///       kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
916 ///         = kernel::configfs::ItemType::<
917 ///                 configfs::Subsystem<Configuration>,
918 ///                 Configuration
919 ///                 >::new_with_child_ctor::<N,Child>(
920 ///             ::kernel::module::this_module::<crate::LocalModule>(),
921 ///             &CONFIGURATION_ATTRS
922 ///         );
923 ///
924 ///     &CONFIGURATION_TPE
925 /// }
926 /// ```
927 #[allow(clippy::crate_in_macro_def)]
928 #[macro_export]
929 macro_rules! configfs_attrs {
930     (
931         container: $container:ty,
932         data: $data:ty,
933         attributes: [
934             $($name:ident: $attr:literal),* $(,)?
935         ] $(,)?
936     ) => {
937         $crate::configfs_attrs!(
938             count:
939             @container($container),
940             @data($data),
941             @child(),
942             @no_child(x),
943             @attrs($($name $attr)*),
944             @eat($($name $attr,)*),
945             @assign(),
946             @cnt(0usize),
947         )
948     };
949     (
950         container: $container:ty,
951         data: $data:ty,
952         child: $child:ty,
953         attributes: [
954             $($name:ident: $attr:literal),* $(,)?
955         ] $(,)?
956     ) => {
957         $crate::configfs_attrs!(
958             count:
959             @container($container),
960             @data($data),
961             @child($child),
962             @no_child(),
963             @attrs($($name $attr)*),
964             @eat($($name $attr,)*),
965             @assign(),
966             @cnt(0usize),
967         )
968     };
969     (count:
970      @container($container:ty),
971      @data($data:ty),
972      @child($($child:ty)?),
973      @no_child($($no_child:ident)?),
974      @attrs($($aname:ident $aattr:literal)*),
975      @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
976      @assign($($assign:block)*),
977      @cnt($cnt:expr),
978     ) => {
979         $crate::configfs_attrs!(
980             count:
981             @container($container),
982             @data($data),
983             @child($($child)?),
984             @no_child($($no_child)?),
985             @attrs($($aname $aattr)*),
986             @eat($($rname $rattr,)*),
987             @assign($($assign)* {
988                 const N: usize = $cnt;
989                 // The following macro text expands to a call to `Attribute::add`.
990 
991                 // SAFETY: By design of this macro, the name of the variable we
992                 // invoke the `add` method on below, is not visible outside of
993                 // the macro expansion. The macro does not operate concurrently
994                 // on this variable, and thus we have exclusive access to the
995                 // variable.
996                 unsafe {
997                     $crate::macros::paste!(
998                         [< $data:upper _ATTRS >]
999                             .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
1000                     )
1001                 };
1002             }),
1003             @cnt(1usize + $cnt),
1004         )
1005     };
1006     (count:
1007      @container($container:ty),
1008      @data($data:ty),
1009      @child($($child:ty)?),
1010      @no_child($($no_child:ident)?),
1011      @attrs($($aname:ident $aattr:literal)*),
1012      @eat(),
1013      @assign($($assign:block)*),
1014      @cnt($cnt:expr),
1015     ) =>
1016     {
1017         $crate::configfs_attrs!(
1018             final:
1019             @container($container),
1020             @data($data),
1021             @child($($child)?),
1022             @no_child($($no_child)?),
1023             @attrs($($aname $aattr)*),
1024             @assign($($assign)*),
1025             @cnt($cnt),
1026         )
1027     };
1028     (final:
1029      @container($container:ty),
1030      @data($data:ty),
1031      @child($($child:ty)?),
1032      @no_child($($no_child:ident)?),
1033      @attrs($($name:ident $attr:literal)*),
1034      @assign($($assign:block)*),
1035      @cnt($cnt:expr),
1036     ) =>
1037     {
1038         $crate::macros::paste!{
1039             {
1040                 $(
1041                     // SAFETY: We are expanding `configfs_attrs`.
1042                     static [< $data:upper _ $name:upper _ATTR >]:
1043                         $crate::configfs::Attribute<$attr, $data, $data> =
1044                             unsafe {
1045                                 $crate::configfs::Attribute::new(
1046                                     $crate::c_str!(::core::stringify!($name)),
1047                                 )
1048                             };
1049                 )*
1050 
1051 
1052                 // We need space for a null terminator.
1053                 const N: usize = $cnt + 1usize;
1054 
1055                 // SAFETY: We are expanding `configfs_attrs`.
1056                 static [< $data:upper _ATTRS >]:
1057                 $crate::configfs::AttributeList<N, $data> =
1058                     unsafe { $crate::configfs::AttributeList::new() };
1059 
1060                 $($assign)*
1061 
1062                 $(
1063                     const [<$no_child:upper>]: bool = true;
1064 
1065                     static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  =
1066                         $crate::configfs::ItemType::<$container, $data>::new::<N>(
1067                             $crate::module::this_module::<crate::LocalModule>(),
1068                             &[<$ data:upper _ATTRS >]
1069                         );
1070                 )?
1071 
1072                 $(
1073                     static [< $data:upper _TPE >]:
1074                         $crate::configfs::ItemType<$container, $data>  =
1075                             $crate::configfs::ItemType::<$container, $data>::
1076                             new_with_child_ctor::<N, $child>(
1077                                 $crate::module::this_module::<crate::LocalModule>(),
1078                                 &[<$ data:upper _ATTRS >]
1079                             );
1080                 )?
1081 
1082                 & [< $data:upper _TPE >]
1083             }
1084         }
1085     };
1086 
1087 }
1088 
1089 pub use crate::configfs_attrs;
1090