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.as_bytes_with_nul().as_ptr(); 267 // SAFETY: It is safe to initialize a group once it has been zeroed. 268 unsafe { 269 bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr()) 270 }; 271 Ok(()) 272 }), 273 data <- data, 274 }) 275 } 276 } 277 278 // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group` 279 // within the `group` field. 280 unsafe impl<Data> HasGroup<Data> for Group<Data> { 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: name.as_char_ptr(), 617 ca_owner: core::ptr::null_mut(), 618 ca_mode: 0o660, 619 show: Some(Self::show), 620 store: if O::HAS_STORE { 621 Some(Self::store) 622 } else { 623 None 624 }, 625 }), 626 _p: PhantomData, 627 } 628 } 629 } 630 631 /// Operations supported by an attribute. 632 /// 633 /// Implement this trait on type and pass that type as generic parameter when 634 /// creating an [`Attribute`]. The type carrying the implementation serve no 635 /// purpose other than specifying the attribute operations. 636 /// 637 /// This trait must be implemented on the `Data` type of for types that 638 /// implement `HasGroup<Data>`. The trait must be implemented once for each 639 /// attribute of the group. The constant type parameter `ID` maps the 640 /// implementation to a specific `Attribute`. `ID` must be passed when declaring 641 /// attributes via the [`kernel::configfs_attrs`] macro, to tie 642 /// `AttributeOperations` implementations to concrete named attributes. 643 #[vtable] 644 pub trait AttributeOperations<const ID: u64 = 0> { 645 /// The type of the object that contains the field that is backing the 646 /// attribute for this operation. 647 type Data; 648 649 /// Renders the value of an attribute. 650 /// 651 /// This function is called by the kernel to read the value of an attribute. 652 /// 653 /// Implementations should write the rendering of the attribute to `page` 654 /// and return the number of bytes written. 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