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