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 //! # Example 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::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::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::raw_get( 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 as *const bindings::configfs_group_operations 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 as *const bindings::configfs_item_operations 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 as *const bindings::configfs_item_operations 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 as *mut [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 { 721 (&mut *self.0.get())[I] = (attribute as *const Attribute<ID, O, Data>) 722 .cast_mut() 723 .cast() 724 }; 725 } 726 } 727 728 /// A representation of the attributes that will appear in a [`Group`] or 729 /// [`Subsystem`]. 730 /// 731 /// Users should not directly instantiate objects of this type. Rather, they 732 /// should use the [`kernel::configfs_attrs`] macro to statically declare the 733 /// shape of a [`Group`] or [`Subsystem`]. 734 #[pin_data] 735 pub struct ItemType<Container, Data> { 736 #[pin] 737 item_type: Opaque<bindings::config_item_type>, 738 _p: PhantomData<(Container, Data)>, 739 } 740 741 // SAFETY: We do not provide any operations on `ItemType` that need synchronization. 742 unsafe impl<Container, Data> Sync for ItemType<Container, Data> {} 743 744 // SAFETY: Ownership of `ItemType` can safely be transferred to other threads. 745 unsafe impl<Container, Data> Send for ItemType<Container, Data> {} 746 747 macro_rules! impl_item_type { 748 ($tpe:ty) => { 749 impl<Data> ItemType<$tpe, Data> { 750 #[doc(hidden)] 751 pub const fn new_with_child_ctor<const N: usize, Child>( 752 owner: &'static ThisModule, 753 attributes: &'static AttributeList<N, Data>, 754 ) -> Self 755 where 756 Data: GroupOperations<Child = Child>, 757 Child: 'static, 758 { 759 Self { 760 item_type: Opaque::new(bindings::config_item_type { 761 ct_owner: owner.as_ptr(), 762 ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(), 763 ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), 764 ct_attrs: (attributes as *const AttributeList<N, Data>) 765 .cast_mut() 766 .cast(), 767 ct_bin_attrs: core::ptr::null_mut(), 768 }), 769 _p: PhantomData, 770 } 771 } 772 773 #[doc(hidden)] 774 pub const fn new<const N: usize>( 775 owner: &'static ThisModule, 776 attributes: &'static AttributeList<N, Data>, 777 ) -> Self { 778 Self { 779 item_type: Opaque::new(bindings::config_item_type { 780 ct_owner: owner.as_ptr(), 781 ct_group_ops: core::ptr::null_mut(), 782 ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(), 783 ct_attrs: (attributes as *const AttributeList<N, Data>) 784 .cast_mut() 785 .cast(), 786 ct_bin_attrs: core::ptr::null_mut(), 787 }), 788 _p: PhantomData, 789 } 790 } 791 } 792 }; 793 } 794 795 impl_item_type!(Subsystem<Data>); 796 impl_item_type!(Group<Data>); 797 798 impl<Container, Data> ItemType<Container, Data> { 799 fn as_ptr(&self) -> *const bindings::config_item_type { 800 self.item_type.get() 801 } 802 } 803 804 /// Define a list of configfs attributes statically. 805 /// 806 /// Invoking the macro in the following manner: 807 /// 808 /// ```ignore 809 /// let item_type = configfs_attrs! { 810 /// container: configfs::Subsystem<Configuration>, 811 /// data: Configuration, 812 /// child: Child, 813 /// attributes: [ 814 /// message: 0, 815 /// bar: 1, 816 /// ], 817 /// }; 818 /// ``` 819 /// 820 /// Expands the following output: 821 /// 822 /// ```ignore 823 /// let item_type = { 824 /// static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute< 825 /// 0, 826 /// Configuration, 827 /// Configuration, 828 /// > = unsafe { 829 /// kernel::configfs::Attribute::new({ 830 /// const S: &str = "message\u{0}"; 831 /// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul( 832 /// S.as_bytes() 833 /// ) { 834 /// Ok(v) => v, 835 /// Err(_) => { 836 /// core::panicking::panic_fmt(core::const_format_args!( 837 /// "string contains interior NUL" 838 /// )); 839 /// } 840 /// }; 841 /// C 842 /// }) 843 /// }; 844 /// 845 /// static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute< 846 /// 1, 847 /// Configuration, 848 /// Configuration 849 /// > = unsafe { 850 /// kernel::configfs::Attribute::new({ 851 /// const S: &str = "bar\u{0}"; 852 /// const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul( 853 /// S.as_bytes() 854 /// ) { 855 /// Ok(v) => v, 856 /// Err(_) => { 857 /// core::panicking::panic_fmt(core::const_format_args!( 858 /// "string contains interior NUL" 859 /// )); 860 /// } 861 /// }; 862 /// C 863 /// }) 864 /// }; 865 /// 866 /// const N: usize = (1usize + (1usize + 0usize)) + 1usize; 867 /// 868 /// static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> = 869 /// unsafe { kernel::configfs::AttributeList::new() }; 870 /// 871 /// { 872 /// const N: usize = 0usize; 873 /// unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) }; 874 /// } 875 /// 876 /// { 877 /// const N: usize = (1usize + 0usize); 878 /// unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) }; 879 /// } 880 /// 881 /// static CONFIGURATION_TPE: 882 /// kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration> 883 /// = kernel::configfs::ItemType::< 884 /// configfs::Subsystem<Configuration>, 885 /// Configuration 886 /// >::new_with_child_ctor::<N,Child>( 887 /// &THIS_MODULE, 888 /// &CONFIGURATION_ATTRS 889 /// ); 890 /// 891 /// &CONFIGURATION_TPE 892 /// } 893 /// ``` 894 #[macro_export] 895 macro_rules! configfs_attrs { 896 ( 897 container: $container:ty, 898 data: $data:ty, 899 attributes: [ 900 $($name:ident: $attr:literal),* $(,)? 901 ] $(,)? 902 ) => { 903 $crate::configfs_attrs!( 904 count: 905 @container($container), 906 @data($data), 907 @child(), 908 @no_child(x), 909 @attrs($($name $attr)*), 910 @eat($($name $attr,)*), 911 @assign(), 912 @cnt(0usize), 913 ) 914 }; 915 ( 916 container: $container:ty, 917 data: $data:ty, 918 child: $child:ty, 919 attributes: [ 920 $($name:ident: $attr:literal),* $(,)? 921 ] $(,)? 922 ) => { 923 $crate::configfs_attrs!( 924 count: 925 @container($container), 926 @data($data), 927 @child($child), 928 @no_child(), 929 @attrs($($name $attr)*), 930 @eat($($name $attr,)*), 931 @assign(), 932 @cnt(0usize), 933 ) 934 }; 935 (count: 936 @container($container:ty), 937 @data($data:ty), 938 @child($($child:ty)?), 939 @no_child($($no_child:ident)?), 940 @attrs($($aname:ident $aattr:literal)*), 941 @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*), 942 @assign($($assign:block)*), 943 @cnt($cnt:expr), 944 ) => { 945 $crate::configfs_attrs!( 946 count: 947 @container($container), 948 @data($data), 949 @child($($child)?), 950 @no_child($($no_child)?), 951 @attrs($($aname $aattr)*), 952 @eat($($rname $rattr,)*), 953 @assign($($assign)* { 954 const N: usize = $cnt; 955 // The following macro text expands to a call to `Attribute::add`. 956 957 // SAFETY: By design of this macro, the name of the variable we 958 // invoke the `add` method on below, is not visible outside of 959 // the macro expansion. The macro does not operate concurrently 960 // on this variable, and thus we have exclusive access to the 961 // variable. 962 unsafe { 963 $crate::macros::paste!( 964 [< $data:upper _ATTRS >] 965 .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >]) 966 ) 967 }; 968 }), 969 @cnt(1usize + $cnt), 970 ) 971 }; 972 (count: 973 @container($container:ty), 974 @data($data:ty), 975 @child($($child:ty)?), 976 @no_child($($no_child:ident)?), 977 @attrs($($aname:ident $aattr:literal)*), 978 @eat(), 979 @assign($($assign:block)*), 980 @cnt($cnt:expr), 981 ) => 982 { 983 $crate::configfs_attrs!( 984 final: 985 @container($container), 986 @data($data), 987 @child($($child)?), 988 @no_child($($no_child)?), 989 @attrs($($aname $aattr)*), 990 @assign($($assign)*), 991 @cnt($cnt), 992 ) 993 }; 994 (final: 995 @container($container:ty), 996 @data($data:ty), 997 @child($($child:ty)?), 998 @no_child($($no_child:ident)?), 999 @attrs($($name:ident $attr:literal)*), 1000 @assign($($assign:block)*), 1001 @cnt($cnt:expr), 1002 ) => 1003 { 1004 $crate::macros::paste!{ 1005 { 1006 $( 1007 // SAFETY: We are expanding `configfs_attrs`. 1008 static [< $data:upper _ $name:upper _ATTR >]: 1009 $crate::configfs::Attribute<$attr, $data, $data> = 1010 unsafe { 1011 $crate::configfs::Attribute::new(c_str!(::core::stringify!($name))) 1012 }; 1013 )* 1014 1015 1016 // We need space for a null terminator. 1017 const N: usize = $cnt + 1usize; 1018 1019 // SAFETY: We are expanding `configfs_attrs`. 1020 static [< $data:upper _ATTRS >]: 1021 $crate::configfs::AttributeList<N, $data> = 1022 unsafe { $crate::configfs::AttributeList::new() }; 1023 1024 $($assign)* 1025 1026 $( 1027 const [<$no_child:upper>]: bool = true; 1028 1029 static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data> = 1030 $crate::configfs::ItemType::<$container, $data>::new::<N>( 1031 &THIS_MODULE, &[<$ data:upper _ATTRS >] 1032 ); 1033 )? 1034 1035 $( 1036 static [< $data:upper _TPE >]: 1037 $crate::configfs::ItemType<$container, $data> = 1038 $crate::configfs::ItemType::<$container, $data>:: 1039 new_with_child_ctor::<N, $child>( 1040 &THIS_MODULE, &[<$ data:upper _ATTRS >] 1041 ); 1042 )? 1043 1044 & [< $data:upper _TPE >] 1045 } 1046 } 1047 }; 1048 1049 } 1050