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