Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/configfs.rs
29266 views
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::c_str;
25
//! use kernel::configfs_attrs;
26
//! use kernel::configfs;
27
//! use kernel::new_mutex;
28
//! use kernel::page::PAGE_SIZE;
29
//! use kernel::sync::Mutex;
30
//! use kernel::ThisModule;
31
//!
32
//! #[pin_data]
33
//! struct RustConfigfs {
34
//! #[pin]
35
//! config: configfs::Subsystem<Configuration>,
36
//! }
37
//!
38
//! impl kernel::InPlaceModule for RustConfigfs {
39
//! fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
40
//! pr_info!("Rust configfs sample (init)\n");
41
//!
42
//! let item_type = configfs_attrs! {
43
//! container: configfs::Subsystem<Configuration>,
44
//! data: Configuration,
45
//! attributes: [
46
//! message: 0,
47
//! bar: 1,
48
//! ],
49
//! };
50
//!
51
//! try_pin_init!(Self {
52
//! config <- configfs::Subsystem::new(
53
//! c_str!("rust_configfs"), item_type, Configuration::new()
54
//! ),
55
//! })
56
//! }
57
//! }
58
//!
59
//! #[pin_data]
60
//! struct Configuration {
61
//! message: &'static CStr,
62
//! #[pin]
63
//! bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
64
//! }
65
//!
66
//! impl Configuration {
67
//! fn new() -> impl PinInit<Self, Error> {
68
//! try_pin_init!(Self {
69
//! message: c_str!("Hello World\n"),
70
//! bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
71
//! })
72
//! }
73
//! }
74
//!
75
//! #[vtable]
76
//! impl configfs::AttributeOperations<0> for Configuration {
77
//! type Data = Configuration;
78
//!
79
//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
80
//! pr_info!("Show message\n");
81
//! let data = container.message;
82
//! page[0..data.len()].copy_from_slice(data);
83
//! Ok(data.len())
84
//! }
85
//! }
86
//!
87
//! #[vtable]
88
//! impl configfs::AttributeOperations<1> for Configuration {
89
//! type Data = Configuration;
90
//!
91
//! fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
92
//! pr_info!("Show bar\n");
93
//! let guard = container.bar.lock();
94
//! let data = guard.0.as_slice();
95
//! let len = guard.1;
96
//! page[0..len].copy_from_slice(&data[0..len]);
97
//! Ok(len)
98
//! }
99
//!
100
//! fn store(container: &Configuration, page: &[u8]) -> Result {
101
//! pr_info!("Store bar\n");
102
//! let mut guard = container.bar.lock();
103
//! guard.0[0..page.len()].copy_from_slice(page);
104
//! guard.1 = page.len();
105
//! Ok(())
106
//! }
107
//! }
108
//! ```
109
//!
110
//! [C documentation]: srctree/Documentation/filesystems/configfs.rst
111
//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs
112
113
use crate::alloc::flags;
114
use crate::container_of;
115
use crate::page::PAGE_SIZE;
116
use crate::prelude::*;
117
use crate::str::CString;
118
use crate::sync::Arc;
119
use crate::sync::ArcBorrow;
120
use crate::types::Opaque;
121
use core::cell::UnsafeCell;
122
use core::marker::PhantomData;
123
124
/// A configfs subsystem.
125
///
126
/// This is the top level entrypoint for a configfs hierarchy. To register
127
/// with configfs, embed a field of this type into your kernel module struct.
128
#[pin_data(PinnedDrop)]
129
pub struct Subsystem<Data> {
130
#[pin]
131
subsystem: Opaque<bindings::configfs_subsystem>,
132
#[pin]
133
data: Data,
134
}
135
136
// SAFETY: We do not provide any operations on `Subsystem`.
137
unsafe impl<Data> Sync for Subsystem<Data> {}
138
139
// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
140
unsafe impl<Data> Send for Subsystem<Data> {}
141
142
impl<Data> Subsystem<Data> {
143
/// Create an initializer for a [`Subsystem`].
144
///
145
/// The subsystem will appear in configfs as a directory name given by
146
/// `name`. The attributes available in directory are specified by
147
/// `item_type`.
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_ptr(),
161
item_type.as_ptr(),
162
)
163
};
164
165
// SAFETY: `place.su_mutex` is valid for use as a mutex.
166
unsafe {
167
bindings::__mutex_init(
168
&mut (*place.get()).su_mutex,
169
kernel::optional_name!().as_char_ptr(),
170
kernel::static_lock_class!().as_ptr(),
171
)
172
}
173
Ok(())
174
}
175
),
176
data <- data,
177
})
178
.pin_chain(|this| {
179
crate::error::to_result(
180
// SAFETY: We initialized `this.subsystem` according to C API contract above.
181
unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) },
182
)
183
})
184
}
185
}
186
187
#[pinned_drop]
188
impl<Data> PinnedDrop for Subsystem<Data> {
189
fn drop(self: Pin<&mut Self>) {
190
// SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`.
191
unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) };
192
// SAFETY: We initialized the mutex in `Subsystem::new`.
193
unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) };
194
}
195
}
196
197
/// Trait that allows offset calculations for structs that embed a
198
/// `bindings::config_group`.
199
///
200
/// Users of the configfs API should not need to implement this trait.
201
///
202
/// # Safety
203
///
204
/// - Implementers of this trait must embed a `bindings::config_group`.
205
/// - Methods must be implemented according to method documentation.
206
pub unsafe trait HasGroup<Data> {
207
/// Return the address of the `bindings::config_group` embedded in [`Self`].
208
///
209
/// # Safety
210
///
211
/// - `this` must be a valid allocation of at least the size of [`Self`].
212
unsafe fn group(this: *const Self) -> *const bindings::config_group;
213
214
/// Return the address of the [`Self`] that `group` is embedded in.
215
///
216
/// # Safety
217
///
218
/// - `group` must point to the `bindings::config_group` that is embedded in
219
/// [`Self`].
220
unsafe fn container_of(group: *const bindings::config_group) -> *const Self;
221
}
222
223
// SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`
224
// within the `subsystem` field.
225
unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {
226
unsafe fn group(this: *const Self) -> *const bindings::config_group {
227
// SAFETY: By impl and function safety requirement this projection is in bounds.
228
unsafe { &raw const (*(*this).subsystem.get()).su_group }
229
}
230
231
unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
232
// SAFETY: By impl and function safety requirement this projection is in bounds.
233
let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) };
234
let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>();
235
// SAFETY: By impl and function safety requirement, `opaque_ptr` and the
236
// pointer it returns, are within the same allocation.
237
unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) }
238
}
239
}
240
241
/// A configfs group.
242
///
243
/// To add a subgroup to configfs, pass this type as `ctype` to
244
/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].
245
#[pin_data]
246
pub struct Group<Data> {
247
#[pin]
248
group: Opaque<bindings::config_group>,
249
#[pin]
250
data: Data,
251
}
252
253
impl<Data> Group<Data> {
254
/// Create an initializer for a new group.
255
///
256
/// When instantiated, the group will appear as a directory with the name
257
/// given by `name` and it will contain attributes specified by `item_type`.
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::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
265
let place = v.get();
266
let name = name.to_bytes_with_nul().as_ptr();
267
// SAFETY: It is safe to initialize a group once it has been zeroed.
268
unsafe {
269
bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
270
};
271
Ok(())
272
}),
273
data <- data,
274
})
275
}
276
}
277
278
// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
279
// within the `group` field.
280
unsafe impl<Data> HasGroup<Data> for Group<Data> {
281
unsafe fn group(this: *const Self) -> *const bindings::config_group {
282
Opaque::cast_into(
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>`.
308
unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {
309
// SAFETY: `this` is a valid pointer.
310
let is_root = unsafe { (*this).cg_subsys.is_null() };
311
312
if !is_root {
313
// SAFETY: By C API contact,`this` was returned from a call to
314
// `make_group`. The pointer is known to be embedded within a
315
// `Group<Parent>`.
316
unsafe { &(*Group::<Parent>::container_of(this)).data }
317
} else {
318
// SAFETY: By C API contract, `this` is a pointer to the
319
// `bindings::config_group` field within a `Subsystem<Parent>`.
320
unsafe { &(*Subsystem::container_of(this)).data }
321
}
322
}
323
324
struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
325
326
impl<Parent, Child> GroupOperationsVTable<Parent, Child>
327
where
328
Parent: GroupOperations<Child = Child>,
329
Child: 'static,
330
{
331
/// # Safety
332
///
333
/// `this` must be a valid pointer.
334
///
335
/// If `this` does not represent the root group of a configfs subsystem,
336
/// `this` must be a pointer to a `bindings::config_group` embedded in a
337
/// `Group<Parent>`.
338
///
339
/// Otherwise, `this` must be a pointer to a `bindings::config_group` that
340
/// is embedded in a `bindings::configfs_subsystem` that is embedded in a
341
/// `Subsystem<Parent>`.
342
///
343
/// `name` must point to a null terminated string.
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
430
}
431
}
432
433
struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
434
435
impl<Data> ItemOperationsVTable<Group<Data>, Data>
436
where
437
Data: 'static,
438
{
439
/// # Safety
440
///
441
/// `this` must be a pointer to a `bindings::config_group` embedded in a
442
/// `Group<Parent>`.
443
///
444
/// This function will destroy the pointee of `this`. The pointee of `this`
445
/// must not be accessed after the function returns.
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
468
}
469
}
470
471
impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
472
const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
473
release: None,
474
allow_link: None,
475
drop_link: None,
476
};
477
478
const fn vtable_ptr() -> *const bindings::configfs_item_operations {
479
&Self::VTABLE
480
}
481
}
482
483
/// Operations implemented by configfs groups that can create subgroups.
484
///
485
/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].
486
#[vtable]
487
pub trait GroupOperations {
488
/// The child data object type.
489
///
490
/// This group will create subgroups (subdirectories) backed by this kind of
491
/// object.
492
type Child: 'static;
493
494
/// Creates a new subgroup.
495
///
496
/// The kernel will call this method in response to `mkdir(2)` in the
497
/// directory representing `this`.
498
///
499
/// To accept the request to create a group, implementations should
500
/// return an initializer of a `Group<Self::Child>`. To prevent creation,
501
/// return a suitable error.
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)]
524
pub struct Attribute<const ID: u64, O, Data> {
525
attribute: Opaque<bindings::configfs_attribute>,
526
_p: PhantomData<(O, Data)>,
527
}
528
529
// SAFETY: We do not provide any operations on `Attribute`.
530
unsafe impl<const ID: u64, O, Data> Sync for Attribute<ID, O, Data> {}
531
532
// SAFETY: Ownership of `Attribute` can safely be transferred to other threads.
533
unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
534
535
impl<const ID: u64, O, Data> Attribute<ID, O, Data>
536
where
537
O: AttributeOperations<ID, Data = Data>,
538
{
539
/// # Safety
540
///
541
/// `item` must be embedded in a `bindings::config_group`.
542
///
543
/// If `item` does not represent the root group of a configfs subsystem,
544
/// the group must be embedded in a `Group<Data>`.
545
///
546
/// Otherwise, the group must be a embedded in a
547
/// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
548
///
549
/// `page` must point to a writable buffer of size at least [`PAGE_SIZE`].
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) };
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.cast::<[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) };
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: crate::str::as_char_ptr_in_const_context(name),
617
ca_owner: core::ptr::null_mut(),
618
ca_mode: 0o660,
619
show: Some(Self::show),
620
store: if O::HAS_STORE {
621
Some(Self::store)
622
} else {
623
None
624
},
625
}),
626
_p: PhantomData,
627
}
628
}
629
}
630
631
/// Operations supported by an attribute.
632
///
633
/// Implement this trait on type and pass that type as generic parameter when
634
/// creating an [`Attribute`]. The type carrying the implementation serve no
635
/// purpose other than specifying the attribute operations.
636
///
637
/// This trait must be implemented on the `Data` type of for types that
638
/// implement `HasGroup<Data>`. The trait must be implemented once for each
639
/// attribute of the group. The constant type parameter `ID` maps the
640
/// implementation to a specific `Attribute`. `ID` must be passed when declaring
641
/// attributes via the [`kernel::configfs_attrs`] macro, to tie
642
/// `AttributeOperations` implementations to concrete named attributes.
643
#[vtable]
644
pub trait AttributeOperations<const ID: u64 = 0> {
645
/// The type of the object that contains the field that is backing the
646
/// attribute for this operation.
647
type Data;
648
649
/// Renders the value of an attribute.
650
///
651
/// This function is called by the kernel to read the value of an attribute.
652
///
653
/// Implementations should write the rendering of the attribute to `page`
654
/// and return the number of bytes written.
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)]
681
pub struct AttributeList<const N: usize, Data>(
682
/// Null terminated Array of pointers to [`Attribute`]. The type is [`c_void`]
683
/// to conform to the C API.
684
UnsafeCell<[*mut kernel::ffi::c_void; N]>,
685
PhantomData<Data>,
686
);
687
688
// SAFETY: Ownership of `AttributeList` can safely be transferred to other threads.
689
unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
690
691
// SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
692
unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
693
694
impl<const N: usize, Data> AttributeList<N, Data> {
695
/// # Safety
696
///
697
/// This function must only be called by the [`kernel::configfs_attrs`]
698
/// macro.
699
#[doc(hidden)]
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 { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
721
}
722
}
723
724
/// A representation of the attributes that will appear in a [`Group`] or
725
/// [`Subsystem`].
726
///
727
/// Users should not directly instantiate objects of this type. Rather, they
728
/// should use the [`kernel::configfs_attrs`] macro to statically declare the
729
/// shape of a [`Group`] or [`Subsystem`].
730
#[pin_data]
731
pub struct ItemType<Container, Data> {
732
#[pin]
733
item_type: Opaque<bindings::config_item_type>,
734
_p: PhantomData<(Container, Data)>,
735
}
736
737
// SAFETY: We do not provide any operations on `ItemType` that need synchronization.
738
unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
739
740
// SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
741
unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
742
743
macro_rules! impl_item_type {
744
($tpe:ty) => {
745
impl<Data> ItemType<$tpe, Data> {
746
#[doc(hidden)]
747
pub const fn new_with_child_ctor<const N: usize, Child>(
748
owner: &'static ThisModule,
749
attributes: &'static AttributeList<N, Data>,
750
) -> Self
751
where
752
Data: GroupOperations<Child = Child>,
753
Child: 'static,
754
{
755
Self {
756
item_type: Opaque::new(bindings::config_item_type {
757
ct_owner: owner.as_ptr(),
758
ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
759
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
760
ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
761
ct_bin_attrs: core::ptr::null_mut(),
762
}),
763
_p: PhantomData,
764
}
765
}
766
767
#[doc(hidden)]
768
pub const fn new<const N: usize>(
769
owner: &'static ThisModule,
770
attributes: &'static AttributeList<N, Data>,
771
) -> Self {
772
Self {
773
item_type: Opaque::new(bindings::config_item_type {
774
ct_owner: owner.as_ptr(),
775
ct_group_ops: core::ptr::null_mut(),
776
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
777
ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
778
ct_bin_attrs: core::ptr::null_mut(),
779
}),
780
_p: PhantomData,
781
}
782
}
783
}
784
};
785
}
786
787
impl_item_type!(Subsystem<Data>);
788
impl_item_type!(Group<Data>);
789
790
impl<Container, Data> ItemType<Container, Data> {
791
fn as_ptr(&self) -> *const bindings::config_item_type {
792
self.item_type.get()
793
}
794
}
795
796
/// Define a list of configfs attributes statically.
797
///
798
/// Invoking the macro in the following manner:
799
///
800
/// ```ignore
801
/// let item_type = configfs_attrs! {
802
/// container: configfs::Subsystem<Configuration>,
803
/// data: Configuration,
804
/// child: Child,
805
/// attributes: [
806
/// message: 0,
807
/// bar: 1,
808
/// ],
809
/// };
810
/// ```
811
///
812
/// Expands the following output:
813
///
814
/// ```ignore
815
/// let item_type = {
816
/// static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
817
/// 0,
818
/// Configuration,
819
/// Configuration,
820
/// > = unsafe {
821
/// kernel::configfs::Attribute::new({
822
/// const S: &str = "message\u{0}";
823
/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
824
/// S.as_bytes()
825
/// ) {
826
/// Ok(v) => v,
827
/// Err(_) => {
828
/// core::panicking::panic_fmt(core::const_format_args!(
829
/// "string contains interior NUL"
830
/// ));
831
/// }
832
/// };
833
/// C
834
/// })
835
/// };
836
///
837
/// static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
838
/// 1,
839
/// Configuration,
840
/// Configuration
841
/// > = unsafe {
842
/// kernel::configfs::Attribute::new({
843
/// const S: &str = "bar\u{0}";
844
/// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
845
/// S.as_bytes()
846
/// ) {
847
/// Ok(v) => v,
848
/// Err(_) => {
849
/// core::panicking::panic_fmt(core::const_format_args!(
850
/// "string contains interior NUL"
851
/// ));
852
/// }
853
/// };
854
/// C
855
/// })
856
/// };
857
///
858
/// const N: usize = (1usize + (1usize + 0usize)) + 1usize;
859
///
860
/// static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
861
/// unsafe { kernel::configfs::AttributeList::new() };
862
///
863
/// {
864
/// const N: usize = 0usize;
865
/// unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
866
/// }
867
///
868
/// {
869
/// const N: usize = (1usize + 0usize);
870
/// unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
871
/// }
872
///
873
/// static CONFIGURATION_TPE:
874
/// kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
875
/// = kernel::configfs::ItemType::<
876
/// configfs::Subsystem<Configuration>,
877
/// Configuration
878
/// >::new_with_child_ctor::<N,Child>(
879
/// &THIS_MODULE,
880
/// &CONFIGURATION_ATTRS
881
/// );
882
///
883
/// &CONFIGURATION_TPE
884
/// }
885
/// ```
886
#[macro_export]
887
macro_rules! configfs_attrs {
888
(
889
container: $container:ty,
890
data: $data:ty,
891
attributes: [
892
$($name:ident: $attr:literal),* $(,)?
893
] $(,)?
894
) => {
895
$crate::configfs_attrs!(
896
count:
897
@container($container),
898
@data($data),
899
@child(),
900
@no_child(x),
901
@attrs($($name $attr)*),
902
@eat($($name $attr,)*),
903
@assign(),
904
@cnt(0usize),
905
)
906
};
907
(
908
container: $container:ty,
909
data: $data:ty,
910
child: $child:ty,
911
attributes: [
912
$($name:ident: $attr:literal),* $(,)?
913
] $(,)?
914
) => {
915
$crate::configfs_attrs!(
916
count:
917
@container($container),
918
@data($data),
919
@child($child),
920
@no_child(),
921
@attrs($($name $attr)*),
922
@eat($($name $attr,)*),
923
@assign(),
924
@cnt(0usize),
925
)
926
};
927
(count:
928
@container($container:ty),
929
@data($data:ty),
930
@child($($child:ty)?),
931
@no_child($($no_child:ident)?),
932
@attrs($($aname:ident $aattr:literal)*),
933
@eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
934
@assign($($assign:block)*),
935
@cnt($cnt:expr),
936
) => {
937
$crate::configfs_attrs!(
938
count:
939
@container($container),
940
@data($data),
941
@child($($child)?),
942
@no_child($($no_child)?),
943
@attrs($($aname $aattr)*),
944
@eat($($rname $rattr,)*),
945
@assign($($assign)* {
946
const N: usize = $cnt;
947
// The following macro text expands to a call to `Attribute::add`.
948
949
// SAFETY: By design of this macro, the name of the variable we
950
// invoke the `add` method on below, is not visible outside of
951
// the macro expansion. The macro does not operate concurrently
952
// on this variable, and thus we have exclusive access to the
953
// variable.
954
unsafe {
955
$crate::macros::paste!(
956
[< $data:upper _ATTRS >]
957
.add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
958
)
959
};
960
}),
961
@cnt(1usize + $cnt),
962
)
963
};
964
(count:
965
@container($container:ty),
966
@data($data:ty),
967
@child($($child:ty)?),
968
@no_child($($no_child:ident)?),
969
@attrs($($aname:ident $aattr:literal)*),
970
@eat(),
971
@assign($($assign:block)*),
972
@cnt($cnt:expr),
973
) =>
974
{
975
$crate::configfs_attrs!(
976
final:
977
@container($container),
978
@data($data),
979
@child($($child)?),
980
@no_child($($no_child)?),
981
@attrs($($aname $aattr)*),
982
@assign($($assign)*),
983
@cnt($cnt),
984
)
985
};
986
(final:
987
@container($container:ty),
988
@data($data:ty),
989
@child($($child:ty)?),
990
@no_child($($no_child:ident)?),
991
@attrs($($name:ident $attr:literal)*),
992
@assign($($assign:block)*),
993
@cnt($cnt:expr),
994
) =>
995
{
996
$crate::macros::paste!{
997
{
998
$(
999
// SAFETY: We are expanding `configfs_attrs`.
1000
static [< $data:upper _ $name:upper _ATTR >]:
1001
$crate::configfs::Attribute<$attr, $data, $data> =
1002
unsafe {
1003
$crate::configfs::Attribute::new(c_str!(::core::stringify!($name)))
1004
};
1005
)*
1006
1007
1008
// We need space for a null terminator.
1009
const N: usize = $cnt + 1usize;
1010
1011
// SAFETY: We are expanding `configfs_attrs`.
1012
static [< $data:upper _ATTRS >]:
1013
$crate::configfs::AttributeList<N, $data> =
1014
unsafe { $crate::configfs::AttributeList::new() };
1015
1016
$($assign)*
1017
1018
$(
1019
const [<$no_child:upper>]: bool = true;
1020
1021
static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> =
1022
$crate::configfs::ItemType::<$container, $data>::new::<N>(
1023
&THIS_MODULE, &[<$ data:upper _ATTRS >]
1024
);
1025
)?
1026
1027
$(
1028
static [< $data:upper _TPE >]:
1029
$crate::configfs::ItemType<$container, $data> =
1030
$crate::configfs::ItemType::<$container, $data>::
1031
new_with_child_ctor::<N, $child>(
1032
&THIS_MODULE, &[<$ data:upper _ATTRS >]
1033
);
1034
)?
1035
1036
& [< $data:upper _TPE >]
1037
}
1038
}
1039
};
1040
1041
}
1042
1043
pub use crate::configfs_attrs;
1044
1045