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