xref: /linux/rust/kernel/configfs.rs (revision ec7714e4947909190ffb3041a03311a975350fe0)
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 
113 use crate::alloc::flags;
114 use crate::container_of;
115 use crate::page::PAGE_SIZE;
116 use crate::prelude::*;
117 use crate::str::CString;
118 use crate::sync::Arc;
119 use crate::sync::ArcBorrow;
120 use crate::types::Opaque;
121 use core::cell::UnsafeCell;
122 use 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)]
129 pub 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`.
137 unsafe impl<Data> Sync for Subsystem<Data> {}
138 
139 // SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
140 unsafe impl<Data> 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`.
new( name: &'static CStr, item_type: &'static ItemType<Subsystem<Data>, Data>, data: impl PinInit<Data, Error>, ) -> impl PinInit<Self, Error>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]
188 impl<Data> PinnedDrop for Subsystem<Data> {
drop(self: Pin<&mut Self>)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`].
group(this: *const Self) -> *const bindings::config_group212     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`].
container_of(group: *const bindings::config_group) -> *const Self220     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> {
group(this: *const Self) -> *const bindings::config_group226     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 
container_of(group: *const bindings::config_group) -> *const Self231     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 impl<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`.
new( name: CString, item_type: &'static ItemType<Group<Data>, Data>, data: impl PinInit<Data, Error>, ) -> impl PinInit<Self, Error>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.
280 unsafe impl<Data> HasGroup<Data> for Group<Data> {
group(this: *const Self) -> *const bindings::config_group281     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 
container_of(group: *const bindings::config_group) -> *const Self289     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>`.
get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent308 unsafe 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 
324 struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
325 
326 impl<Parent, Child> GroupOperationsVTable<Parent, Child>
327 where
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.
make_group( this: *mut bindings::config_group, name: *const kernel::ffi::c_char, ) -> *mut bindings::config_group344     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>`.
drop_item( this: *mut bindings::config_group, item: *mut bindings::config_item, )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 
vtable_ptr() -> *const bindings::configfs_group_operations428     const fn vtable_ptr() -> *const bindings::configfs_group_operations {
429         &Self::VTABLE as *const bindings::configfs_group_operations
430     }
431 }
432 
433 struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
434 
435 impl<Data> ItemOperationsVTable<Group<Data>, Data>
436 where
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.
release(this: *mut bindings::config_item)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 
vtable_ptr() -> *const bindings::configfs_item_operations466     const fn vtable_ptr() -> *const bindings::configfs_item_operations {
467         &Self::VTABLE as *const bindings::configfs_item_operations
468     }
469 }
470 
471 impl<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 
vtable_ptr() -> *const bindings::configfs_item_operations478     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]
487 pub 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.
make_group(&self, name: &CStr) -> Result<impl PinInit<Group<Self::Child>, 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.
drop_item(&self, _child: ArcBorrow<'_, Group<Self::Child>>)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)]
524 pub 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`.
530 unsafe 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.
533 unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
534 
535 impl<const ID: u64, O, Data> Attribute<ID, O, Data>
536 where
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`].
show( item: *mut bindings::config_item, page: *mut kernel::ffi::c_char, ) -> isize550     unsafe extern "C" fn show(
551         item: *mut bindings::config_item,
552         page: *mut kernel::ffi::c_char,
553     ) -> isize {
554         let c_group: *mut bindings::config_group =
555             // SAFETY: By function safety requirements, `item` is embedded in a
556             // `config_group`.
557             unsafe { container_of!(item, bindings::config_group, cg_item) };
558 
559         // SAFETY: The function safety requirements for this function satisfy
560         // the conditions for this call.
561         let data: &Data = unsafe { get_group_data(c_group) };
562 
563         // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
564         let ret = O::show(data, unsafe { &mut *(page 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`.
store( item: *mut bindings::config_item, page: *const kernel::ffi::c_char, size: usize, ) -> isize583     unsafe extern "C" fn store(
584         item: *mut bindings::config_item,
585         page: *const kernel::ffi::c_char,
586         size: usize,
587     ) -> isize {
588         let c_group: *mut bindings::config_group =
589         // SAFETY: By function safety requirements, `item` is embedded in a
590         // `config_group`.
591             unsafe { container_of!(item, bindings::config_group, cg_item) };
592 
593         // SAFETY: The function safety requirements for this function satisfy
594         // the conditions for this call.
595         let data: &Data = unsafe { get_group_data(c_group) };
596 
597         let ret = O::store(
598             data,
599             // SAFETY: By function safety requirements, `page` is readable
600             // for at least `size`.
601             unsafe { core::slice::from_raw_parts(page.cast(), size) },
602         );
603 
604         match ret {
605             Ok(()) => size as isize,
606             Err(err) => err.to_errno() as isize,
607         }
608     }
609 
610     /// Create a new attribute.
611     ///
612     /// The attribute will appear as a file with name given by `name`.
new(name: &'static CStr) -> Self613     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]
644 pub 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.
show(data: &Self::Data, page: &mut [u8; PAGE_SIZE]) -> Result<usize>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.
store(_data: &Self::Data, _page: &[u8]) -> Result663     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)]
681 pub 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.
689 unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
690 
691 // SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
692 unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
693 
694 impl<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)]
new() -> Self700     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)]
add<const I: usize, const ID: u64, O>( &'static self, attribute: &'static Attribute<ID, O, Data>, ) where O: AttributeOperations<ID, Data = Data>,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]
735 pub 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.
742 unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
743 
744 // SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
745 unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
746 
747 macro_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 
795 impl_item_type!(Subsystem<Data>);
796 impl_item_type!(Group<Data>);
797 
798 impl<Container, Data> ItemType<Container, Data> {
as_ptr(&self) -> *const bindings::config_item_type799     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]
895 macro_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 }
1050