File Index
Files and directories
Sign in
FILE

configfs.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/configfs.rs RUST
   1// SPDX-License-Identifier: GPL-2.0
   2
   3//! configfs interface: Userspace-driven Kernel Object Configuration
   4//!
   5//! configfs is an in-memory pseudo file system for configuration of kernel
   6//! modules. Please see the [C documentation] for details and intended use of
   7//! configfs.
   8//!
   9//! This module does not support the following configfs features:
  10//!
  11//! - Items. All group children are groups.
  12//! - Symlink support.
  13//! - `disconnect_notify` hook.
  14//! - Default groups.
  15//!
  16//! See the [`rust_configfs.rs`] sample for a full example use of this module.
  17//!
  18//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)
  19//!
  20//! # Examples
  21//!
  22//! ```ignore
  23//! use kernel::alloc::flags;
  24//! use kernel::c_str;
  25//! use kernel::configfs_attrs;
  26//! use kernel::configfs;
  27//! use kernel::new_mutex;
  28//! use kernel::page::PAGE_SIZE;
  29//! use kernel::sync::Mutex;
  30//! use kernel::ThisModule;
  31//!
  32//! #[pin_data]
  33//! struct RustConfigfs {
  34//!     #[pin]
  35//!     config: configfs::Subsystem<Configuration>,
  36//! }
  37//!
  38//! impl kernel::InPlaceModule for RustConfigfs {
  39//!     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
  40//!         pr_info!("Rust configfs sample (init)\n");
  41//!
  42//!         let item_type = configfs_attrs! {
  43//!             container: configfs::Subsystem<Configuration>,
  44//!             data: Configuration,
  45//!             attributes: [
  46//!                 message: 0,
  47//!                 bar: 1,
  48//!             ],
  49//!         };
  50//!
  51//!         try_pin_init!(Self {
  52//!             config <- configfs::Subsystem::new(
  53//!                 c_str!("rust_configfs"), item_type, Configuration::new()
  54//!             ),
  55//!         })
  56//!     }
  57//! }
  58//!
  59//! #[pin_data]
  60//! struct Configuration {
  61//!     message: &'static CStr,
  62//!     #[pin]
  63//!     bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
  64//! }
  65//!
  66//! impl Configuration {
  67//!     fn new() -> impl PinInit<Self, Error> {
  68//!         try_pin_init!(Self {
  69//!             message: c_str!("Hello World\n"),
  70//!             bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
  71//!         })
  72//!     }
  73//! }
  74//!
  75//! #[vtable]
  76//! impl configfs::AttributeOperations<0> for Configuration {
  77//!     type Data = Configuration;
  78//!
  79//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
  80//!         pr_info!("Show message\n");
  81//!         let data = container.message;
  82//!         page[0..data.len()].copy_from_slice(data);
  83//!         Ok(data.len())
  84//!     }
  85//! }
  86//!
  87//! #[vtable]
  88//! impl configfs::AttributeOperations<1> for Configuration {
  89//!     type Data = Configuration;
  90//!
  91//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
  92//!         pr_info!("Show bar\n");
  93//!         let guard = container.bar.lock();
  94//!         let data = guard.0.as_slice();
  95//!         let len = guard.1;
  96//!         page[0..len].copy_from_slice(&data[0..len]);
  97//!         Ok(len)
  98//!     }
  99//!
 100//!     fn store(container: &Configuration, page: &[u8]) -> Result {
 101//!         pr_info!("Store bar\n");
 102//!         let mut guard = container.bar.lock();
 103//!         guard.0[0..page.len()].copy_from_slice(page);
 104//!         guard.1 = page.len();
 105//!         Ok(())
 106//!     }
 107//! }
 108//! ```
 109//!
 110//! [C documentation]: srctree/Documentation/filesystems/configfs.rst
 111//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs
 112
 113use crate::alloc::flags;
 114use crate::container_of;
 115use crate::page::PAGE_SIZE;
 116use crate::prelude::*;
 117use crate::str::CString;
 118use crate::sync::Arc;
 119use crate::sync::ArcBorrow;
 120use crate::types::Opaque;
 121use core::cell::UnsafeCell;
 122use 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)]
 129pub 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`.
 137unsafe impl<Data> Sync for Subsystem<Data> {}
 138
 139// SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.
 140unsafe impl<Data> Send for Subsystem<Data> {}
 141
 142impl<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]
 188impl<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.
 206pub 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.
 225unsafe 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]
 246pub struct Group<Data> {
 247    #[pin]
 248    group: Opaque<bindings::config_group>,
 249    #[pin]
 250    data: Data,
 251}
 252
 253impl<Data> Group<Data> {
 254    /// Create an initializer for a new group.
 255    ///
 256    /// When instantiated, the group will appear as a directory with the name
 257    /// given by `name` and it will contain attributes specified by `item_type`.
 258    pub fn new(
 259        name: CString,
 260        item_type: &'static ItemType<Group<Data>, Data>,
 261        data: impl PinInit<Data, Error>,
 262    ) -> impl PinInit<Self, Error> {
 263        try_pin_init!(Self {
 264            group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
 265                let place = v.get();
 266                let name = name.to_bytes_with_nul().as_ptr();
 267                // SAFETY: It is safe to initialize a group once it has been zeroed.
 268                unsafe {
 269                    bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())
 270                };
 271                Ok(())
 272            }),
 273            data <- data,
 274        })
 275    }
 276}
 277
 278// SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`
 279// within the `group` field.
 280unsafe impl<Data> HasGroup<Data> for Group<Data> {
 281    unsafe fn group(this: *const Self) -> *const bindings::config_group {
 282        Opaque::cast_into(
 283            // SAFETY: By impl and function safety requirements this field
 284            // projection is within bounds of the allocation.
 285            unsafe { &raw const (*this).group },
 286        )
 287    }
 288
 289    unsafe fn container_of(group: *const bindings::config_group) -> *const Self {
 290        let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();
 291        // SAFETY: By impl and function safety requirement, `opaque_ptr` and
 292        // pointer it returns will be in the same allocation.
 293        unsafe { container_of!(opaque_ptr, Self, group) }
 294    }
 295}
 296
 297/// # Safety
 298///
 299/// `this` must be a valid pointer.
 300///
 301/// If `this` does not represent the root group of a configfs subsystem,
 302/// `this` must be a pointer to a `bindings::config_group` embedded in a
 303/// `Group<Parent>`.
 304///
 305/// Otherwise, `this` must be a pointer to a `bindings::config_group` that
 306/// is embedded in a `bindings::configfs_subsystem` that is embedded in a
 307/// `Subsystem<Parent>`.
 308unsafe 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
 324struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>);
 325
 326impl<Parent, Child> GroupOperationsVTable<Parent, Child>
 327where
 328    Parent: GroupOperations<Child = Child>,
 329    Child: 'static,
 330{
 331    /// # Safety
 332    ///
 333    /// `this` must be a valid pointer.
 334    ///
 335    /// If `this` does not represent the root group of a configfs subsystem,
 336    /// `this` must be a pointer to a `bindings::config_group` embedded in a
 337    /// `Group<Parent>`.
 338    ///
 339    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
 340    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
 341    /// `Subsystem<Parent>`.
 342    ///
 343    /// `name` must point to a null terminated string.
 344    unsafe extern "C" fn make_group(
 345        this: *mut bindings::config_group,
 346        name: *const kernel::ffi::c_char,
 347    ) -> *mut bindings::config_group {
 348        // SAFETY: By function safety requirements of this function, this call
 349        // is safe.
 350        let parent_data = unsafe { get_group_data(this) };
 351
 352        let group_init = match Parent::make_group(
 353            parent_data,
 354            // SAFETY: By function safety requirements, name points to a null
 355            // terminated string.
 356            unsafe { CStr::from_char_ptr(name) },
 357        ) {
 358            Ok(init) => init,
 359            Err(e) => return e.to_ptr(),
 360        };
 361
 362        let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(
 363            group_init,
 364            flags::GFP_KERNEL,
 365        );
 366
 367        match child_group {
 368            Ok(child_group) => {
 369                let child_group_ptr = child_group.into_raw();
 370                // SAFETY: We allocated the pointee of `child_ptr` above as a
 371                // `Group<Child>`.
 372                unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()
 373            }
 374            Err(e) => e.to_ptr(),
 375        }
 376    }
 377
 378    /// # Safety
 379    ///
 380    /// If `this` does not represent the root group of a configfs subsystem,
 381    /// `this` must be a pointer to a `bindings::config_group` embedded in a
 382    /// `Group<Parent>`.
 383    ///
 384    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that
 385    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a
 386    /// `Subsystem<Parent>`.
 387    ///
 388    /// `item` must point to a `bindings::config_item` within a
 389    /// `bindings::config_group` within a `Group<Child>`.
 390    unsafe extern "C" fn drop_item(
 391        this: *mut bindings::config_group,
 392        item: *mut bindings::config_item,
 393    ) {
 394        // SAFETY: By function safety requirements of this function, this call
 395        // is safe.
 396        let parent_data = unsafe { get_group_data(this) };
 397
 398        // SAFETY: By function safety requirements, `item` is embedded in a
 399        // `config_group`.
 400        let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };
 401        // SAFETY: By function safety requirements, `c_child_group_ptr` is
 402        // embedded within a `Group<Child>`.
 403        let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };
 404
 405        if Parent::HAS_DROP_ITEM {
 406            // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in
 407            // `make_group`.
 408            let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };
 409
 410            Parent::drop_item(parent_data, arc.as_arc_borrow());
 411            arc.into_raw();
 412        }
 413
 414        // SAFETY: By C API contract, we are required to drop a refcount on
 415        // `item`.
 416        unsafe { bindings::config_item_put(item) };
 417    }
 418
 419    const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {
 420        make_item: None,
 421        make_group: Some(Self::make_group),
 422        disconnect_notify: None,
 423        drop_item: Some(Self::drop_item),
 424        is_visible: None,
 425        is_bin_visible: None,
 426    };
 427
 428    const fn vtable_ptr() -> *const bindings::configfs_group_operations {
 429        &Self::VTABLE
 430    }
 431}
 432
 433struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>);
 434
 435impl<Data> ItemOperationsVTable<Group<Data>, Data>
 436where
 437    Data: 'static,
 438{
 439    /// # Safety
 440    ///
 441    /// `this` must be a pointer to a `bindings::config_group` embedded in a
 442    /// `Group<Parent>`.
 443    ///
 444    /// This function will destroy the pointee of `this`. The pointee of `this`
 445    /// must not be accessed after the function returns.
 446    unsafe extern "C" fn release(this: *mut bindings::config_item) {
 447        // SAFETY: By function safety requirements, `this` is embedded in a
 448        // `config_group`.
 449        let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };
 450        // SAFETY: By function safety requirements, `c_group_ptr` is
 451        // embedded within a `Group<Data>`.
 452        let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };
 453
 454        // SAFETY: We called `into_raw` on `r_group_ptr` in
 455        // `make_group`.
 456        let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };
 457        drop(pin_self);
 458    }
 459
 460    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
 461        release: Some(Self::release),
 462        allow_link: None,
 463        drop_link: None,
 464    };
 465
 466    const fn vtable_ptr() -> *const bindings::configfs_item_operations {
 467        &Self::VTABLE
 468    }
 469}
 470
 471impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
 472    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {
 473        release: None,
 474        allow_link: None,
 475        drop_link: None,
 476    };
 477
 478    const fn vtable_ptr() -> *const bindings::configfs_item_operations {
 479        &Self::VTABLE
 480    }
 481}
 482
 483/// Operations implemented by configfs groups that can create subgroups.
 484///
 485/// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].
 486#[vtable]
 487pub 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)]
 524pub 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`.
 530unsafe 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.
 533unsafe impl<const ID: u64, O, Data> Send for Attribute<ID, O, Data> {}
 534
 535impl<const ID: u64, O, Data> Attribute<ID, O, Data>
 536where
 537    O: AttributeOperations<ID, Data = Data>,
 538{
 539    /// # Safety
 540    ///
 541    /// `item` must be embedded in a `bindings::config_group`.
 542    ///
 543    /// If `item` does not represent the root group of a configfs subsystem,
 544    /// the group must be embedded in a `Group<Data>`.
 545    ///
 546    /// Otherwise, the group must be a embedded in a
 547    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
 548    ///
 549    /// `page` must point to a writable buffer of size at least [`PAGE_SIZE`].
 550    unsafe extern "C" fn show(
 551        item: *mut bindings::config_item,
 552        page: *mut kernel::ffi::c_char,
 553    ) -> isize {
 554        let c_group: *mut bindings::config_group =
 555            // SAFETY: By function safety requirements, `item` is embedded in a
 556            // `config_group`.
 557            unsafe { container_of!(item, bindings::config_group, cg_item) };
 558
 559        // SAFETY: The function safety requirements for this function satisfy
 560        // the conditions for this call.
 561        let data: &Data = unsafe { get_group_data(c_group) };
 562
 563        // SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
 564        let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });
 565
 566        match ret {
 567            Ok(size) => size as isize,
 568            Err(err) => err.to_errno() as isize,
 569        }
 570    }
 571
 572    /// # Safety
 573    ///
 574    /// `item` must be embedded in a `bindings::config_group`.
 575    ///
 576    /// If `item` does not represent the root group of a configfs subsystem,
 577    /// the group must be embedded in a `Group<Data>`.
 578    ///
 579    /// Otherwise, the group must be a embedded in a
 580    /// `bindings::configfs_subsystem` that is embedded in a `Subsystem<Data>`.
 581    ///
 582    /// `page` must point to a readable buffer of size at least `size`.
 583    unsafe extern "C" fn store(
 584        item: *mut bindings::config_item,
 585        page: *const kernel::ffi::c_char,
 586        size: usize,
 587    ) -> isize {
 588        let c_group: *mut bindings::config_group =
 589        // SAFETY: By function safety requirements, `item` is embedded in a
 590        // `config_group`.
 591            unsafe { container_of!(item, bindings::config_group, cg_item) };
 592
 593        // SAFETY: The function safety requirements for this function satisfy
 594        // the conditions for this call.
 595        let data: &Data = unsafe { get_group_data(c_group) };
 596
 597        let ret = O::store(
 598            data,
 599            // SAFETY: By function safety requirements, `page` is readable
 600            // for at least `size`.
 601            unsafe { core::slice::from_raw_parts(page.cast(), size) },
 602        );
 603
 604        match ret {
 605            Ok(()) => size as isize,
 606            Err(err) => err.to_errno() as isize,
 607        }
 608    }
 609
 610    /// Create a new attribute.
 611    ///
 612    /// The attribute will appear as a file with name given by `name`.
 613    pub const fn new(name: &'static CStr) -> Self {
 614        Self {
 615            attribute: Opaque::new(bindings::configfs_attribute {
 616                ca_name: crate::str::as_char_ptr_in_const_context(name),
 617                ca_owner: core::ptr::null_mut(),
 618                ca_mode: 0o660,
 619                show: Some(Self::show),
 620                store: if O::HAS_STORE {
 621                    Some(Self::store)
 622                } else {
 623                    None
 624                },
 625            }),
 626            _p: PhantomData,
 627        }
 628    }
 629}
 630
 631/// Operations supported by an attribute.
 632///
 633/// Implement this trait on type and pass that type as generic parameter when
 634/// creating an [`Attribute`]. The type carrying the implementation serve no
 635/// purpose other than specifying the attribute operations.
 636///
 637/// This trait must be implemented on the `Data` type of for types that
 638/// implement `HasGroup<Data>`. The trait must be implemented once for each
 639/// attribute of the group. The constant type parameter `ID` maps the
 640/// implementation to a specific `Attribute`. `ID` must be passed when declaring
 641/// attributes via the [`kernel::configfs_attrs`] macro, to tie
 642/// `AttributeOperations` implementations to concrete named attributes.
 643#[vtable]
 644pub 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)]
 681pub 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.
 689unsafe impl<const N: usize, Data> Send for AttributeList<N, Data> {}
 690
 691// SAFETY: We do not provide any operations on `AttributeList` that need synchronization.
 692unsafe impl<const N: usize, Data> Sync for AttributeList<N, Data> {}
 693
 694impl<const N: usize, Data> AttributeList<N, Data> {
 695    /// # Safety
 696    ///
 697    /// This function must only be called by the [`kernel::configfs_attrs`]
 698    /// macro.
 699    #[doc(hidden)]
 700    pub const unsafe fn new() -> Self {
 701        Self(UnsafeCell::new([core::ptr::null_mut(); N]), PhantomData)
 702    }
 703
 704    /// # Safety
 705    ///
 706    /// The caller must ensure that there are no other concurrent accesses to
 707    /// `self`. That is, the caller has exclusive access to `self.`
 708    #[doc(hidden)]
 709    pub const unsafe fn add<const I: usize, const ID: u64, O>(
 710        &'static self,
 711        attribute: &'static Attribute<ID, O, Data>,
 712    ) where
 713        O: AttributeOperations<ID, Data = Data>,
 714    {
 715        // We need a space at the end of our list for a null terminator.
 716        const { assert!(I < N - 1, "Invalid attribute index") };
 717
 718        // SAFETY: By function safety requirements, we have exclusive access to
 719        // `self` and the reference created below will be exclusive.
 720        unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
 721    }
 722}
 723
 724/// A representation of the attributes that will appear in a [`Group`] or
 725/// [`Subsystem`].
 726///
 727/// Users should not directly instantiate objects of this type. Rather, they
 728/// should use the [`kernel::configfs_attrs`] macro to statically declare the
 729/// shape of a [`Group`] or [`Subsystem`].
 730#[pin_data]
 731pub struct ItemType<Container, Data> {
 732    #[pin]
 733    item_type: Opaque<bindings::config_item_type>,
 734    _p: PhantomData<(Container, Data)>,
 735}
 736
 737// SAFETY: We do not provide any operations on `ItemType` that need synchronization.
 738unsafe impl<Container, Data> Sync for ItemType<Container, Data> {}
 739
 740// SAFETY: Ownership of `ItemType` can safely be transferred to other threads.
 741unsafe impl<Container, Data> Send for ItemType<Container, Data> {}
 742
 743macro_rules! impl_item_type {
 744    ($tpe:ty) => {
 745        impl<Data> ItemType<$tpe, Data> {
 746            #[doc(hidden)]
 747            pub const fn new_with_child_ctor<const N: usize, Child>(
 748                owner: &'static ThisModule,
 749                attributes: &'static AttributeList<N, Data>,
 750            ) -> Self
 751            where
 752                Data: GroupOperations<Child = Child>,
 753                Child: 'static,
 754            {
 755                Self {
 756                    item_type: Opaque::new(bindings::config_item_type {
 757                        ct_owner: owner.as_ptr(),
 758                        ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
 759                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
 760                        ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
 761                        ct_bin_attrs: core::ptr::null_mut(),
 762                    }),
 763                    _p: PhantomData,
 764                }
 765            }
 766
 767            #[doc(hidden)]
 768            pub const fn new<const N: usize>(
 769                owner: &'static ThisModule,
 770                attributes: &'static AttributeList<N, Data>,
 771            ) -> Self {
 772                Self {
 773                    item_type: Opaque::new(bindings::config_item_type {
 774                        ct_owner: owner.as_ptr(),
 775                        ct_group_ops: core::ptr::null_mut(),
 776                        ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
 777                        ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
 778                        ct_bin_attrs: core::ptr::null_mut(),
 779                    }),
 780                    _p: PhantomData,
 781                }
 782            }
 783        }
 784    };
 785}
 786
 787impl_item_type!(Subsystem<Data>);
 788impl_item_type!(Group<Data>);
 789
 790impl<Container, Data> ItemType<Container, Data> {
 791    fn as_ptr(&self) -> *const bindings::config_item_type {
 792        self.item_type.get()
 793    }
 794}
 795
 796/// Define a list of configfs attributes statically.
 797///
 798/// Invoking the macro in the following manner:
 799///
 800/// ```ignore
 801/// let item_type = configfs_attrs! {
 802///     container: configfs::Subsystem<Configuration>,
 803///     data: Configuration,
 804///     child: Child,
 805///     attributes: [
 806///         message: 0,
 807///         bar: 1,
 808///     ],
 809/// };
 810/// ```
 811///
 812/// Expands the following output:
 813///
 814/// ```ignore
 815/// let item_type = {
 816///     static CONFIGURATION_MESSAGE_ATTR: kernel::configfs::Attribute<
 817///         0,
 818///         Configuration,
 819///         Configuration,
 820///     > = unsafe {
 821///         kernel::configfs::Attribute::new({
 822///             const S: &str = "message\u{0}";
 823///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
 824///                 S.as_bytes()
 825///             ) {
 826///                 Ok(v) => v,
 827///                 Err(_) => {
 828///                     core::panicking::panic_fmt(core::const_format_args!(
 829///                         "string contains interior NUL"
 830///                     ));
 831///                 }
 832///             };
 833///             C
 834///         })
 835///     };
 836///
 837///     static CONFIGURATION_BAR_ATTR: kernel::configfs::Attribute<
 838///             1,
 839///             Configuration,
 840///             Configuration
 841///     > = unsafe {
 842///         kernel::configfs::Attribute::new({
 843///             const S: &str = "bar\u{0}";
 844///             const C: &kernel::str::CStr = match kernel::str::CStr::from_bytes_with_nul(
 845///                 S.as_bytes()
 846///             ) {
 847///                 Ok(v) => v,
 848///                 Err(_) => {
 849///                     core::panicking::panic_fmt(core::const_format_args!(
 850///                         "string contains interior NUL"
 851///                     ));
 852///                 }
 853///             };
 854///             C
 855///         })
 856///     };
 857///
 858///     const N: usize = (1usize + (1usize + 0usize)) + 1usize;
 859///
 860///     static CONFIGURATION_ATTRS: kernel::configfs::AttributeList<N, Configuration> =
 861///         unsafe { kernel::configfs::AttributeList::new() };
 862///
 863///     {
 864///         const N: usize = 0usize;
 865///         unsafe { CONFIGURATION_ATTRS.add::<N, 0, _>(&CONFIGURATION_MESSAGE_ATTR) };
 866///     }
 867///
 868///     {
 869///         const N: usize = (1usize + 0usize);
 870///         unsafe { CONFIGURATION_ATTRS.add::<N, 1, _>(&CONFIGURATION_BAR_ATTR) };
 871///     }
 872///
 873///     static CONFIGURATION_TPE:
 874///       kernel::configfs::ItemType<configfs::Subsystem<Configuration> ,Configuration>
 875///         = kernel::configfs::ItemType::<
 876///                 configfs::Subsystem<Configuration>,
 877///                 Configuration
 878///                 >::new_with_child_ctor::<N,Child>(
 879///             &THIS_MODULE,
 880///             &CONFIGURATION_ATTRS
 881///         );
 882///
 883///     &CONFIGURATION_TPE
 884/// }
 885/// ```
 886#[macro_export]
 887macro_rules! configfs_attrs {
 888    (
 889        container: $container:ty,
 890        data: $data:ty,
 891        attributes: [
 892            $($name:ident: $attr:literal),* $(,)?
 893        ] $(,)?
 894    ) => {
 895        $crate::configfs_attrs!(
 896            count:
 897            @container($container),
 898            @data($data),
 899            @child(),
 900            @no_child(x),
 901            @attrs($($name $attr)*),
 902            @eat($($name $attr,)*),
 903            @assign(),
 904            @cnt(0usize),
 905        )
 906    };
 907    (
 908        container: $container:ty,
 909        data: $data:ty,
 910        child: $child:ty,
 911        attributes: [
 912            $($name:ident: $attr:literal),* $(,)?
 913        ] $(,)?
 914    ) => {
 915        $crate::configfs_attrs!(
 916            count:
 917            @container($container),
 918            @data($data),
 919            @child($child),
 920            @no_child(),
 921            @attrs($($name $attr)*),
 922            @eat($($name $attr,)*),
 923            @assign(),
 924            @cnt(0usize),
 925        )
 926    };
 927    (count:
 928     @container($container:ty),
 929     @data($data:ty),
 930     @child($($child:ty)?),
 931     @no_child($($no_child:ident)?),
 932     @attrs($($aname:ident $aattr:literal)*),
 933     @eat($name:ident $attr:literal, $($rname:ident $rattr:literal,)*),
 934     @assign($($assign:block)*),
 935     @cnt($cnt:expr),
 936    ) => {
 937        $crate::configfs_attrs!(
 938            count:
 939            @container($container),
 940            @data($data),
 941            @child($($child)?),
 942            @no_child($($no_child)?),
 943            @attrs($($aname $aattr)*),
 944            @eat($($rname $rattr,)*),
 945            @assign($($assign)* {
 946                const N: usize = $cnt;
 947                // The following macro text expands to a call to `Attribute::add`.
 948
 949                // SAFETY: By design of this macro, the name of the variable we
 950                // invoke the `add` method on below, is not visible outside of
 951                // the macro expansion. The macro does not operate concurrently
 952                // on this variable, and thus we have exclusive access to the
 953                // variable.
 954                unsafe {
 955                    $crate::macros::paste!(
 956                        [< $data:upper _ATTRS >]
 957                            .add::<N, $attr, _>(&[< $data:upper _ $name:upper _ATTR >])
 958                    )
 959                };
 960            }),
 961            @cnt(1usize + $cnt),
 962        )
 963    };
 964    (count:
 965     @container($container:ty),
 966     @data($data:ty),
 967     @child($($child:ty)?),
 968     @no_child($($no_child:ident)?),
 969     @attrs($($aname:ident $aattr:literal)*),
 970     @eat(),
 971     @assign($($assign:block)*),
 972     @cnt($cnt:expr),
 973    ) =>
 974    {
 975        $crate::configfs_attrs!(
 976            final:
 977            @container($container),
 978            @data($data),
 979            @child($($child)?),
 980            @no_child($($no_child)?),
 981            @attrs($($aname $aattr)*),
 982            @assign($($assign)*),
 983            @cnt($cnt),
 984        )
 985    };
 986    (final:
 987     @container($container:ty),
 988     @data($data:ty),
 989     @child($($child:ty)?),
 990     @no_child($($no_child:ident)?),
 991     @attrs($($name:ident $attr:literal)*),
 992     @assign($($assign:block)*),
 993     @cnt($cnt:expr),
 994    ) =>
 995    {
 996        $crate::macros::paste!{
 997            {
 998                $(
 999                    // SAFETY: We are expanding `configfs_attrs`.
1000                    static [< $data:upper _ $name:upper _ATTR >]:
1001                        $crate::configfs::Attribute<$attr, $data, $data> =
1002                            unsafe {
1003                                $crate::configfs::Attribute::new(c_str!(::core::stringify!($name)))
1004                            };
1005                )*
1006
1007
1008                // We need space for a null terminator.
1009                const N: usize = $cnt + 1usize;
1010
1011                // SAFETY: We are expanding `configfs_attrs`.
1012                static [< $data:upper _ATTRS >]:
1013                $crate::configfs::AttributeList<N, $data> =
1014                    unsafe { $crate::configfs::AttributeList::new() };
1015
1016                $($assign)*
1017
1018                $(
1019                    const [<$no_child:upper>]: bool = true;
1020
1021                    static [< $data:upper _TPE >] : $crate::configfs::ItemType<$container, $data>  =
1022                        $crate::configfs::ItemType::<$container, $data>::new::<N>(
1023                            &THIS_MODULE, &[<$ data:upper _ATTRS >]
1024                        );
1025                )?
1026
1027                $(
1028                    static [< $data:upper _TPE >]:
1029                        $crate::configfs::ItemType<$container, $data>  =
1030                            $crate::configfs::ItemType::<$container, $data>::
1031                            new_with_child_ctor::<N, $child>(
1032                                &THIS_MODULE, &[<$ data:upper _ATTRS >]
1033                            );
1034                )?
1035
1036                & [< $data:upper _TPE >]
1037            }
1038        }
1039    };
1040
1041}
1042
1043pub use crate::configfs_attrs;
~/ Read-only file preview.