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