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