1047 lines · 36.4 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 //! configfs interface: Userspace-driven Kernel Object Configuration//!//! configfs is an in-memory pseudo file system for configuration of kernel//! modules. Please see the [C documentation] for details and intended use of//! configfs.//!//! This module does not support the following configfs features://!//! - Items. All group children are groups.//! - Symlink support.//! - `disconnect_notify` hook.//! - Default groups.//!//! See the [`rust_configfs.rs`] sample for a full example use of this module.//!//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)//!//! # Examples//!//! ```ignore//! use kernel::alloc::flags;//! use kernel::configfs_attrs;//! use kernel::configfs;//! use kernel::new_mutex;//! use kernel::page::PAGE_SIZE;//! use kernel::sync::Mutex;//! use kernel::ThisModule;//!//! #[pin_data]//! struct RustConfigfs {//!     #[pin]//!     config: configfs::Subsystem<Configuration>,//! }//!//! impl kernel::InPlaceModule for RustConfigfs {//!     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {//!         pr_info!("Rust configfs sample (init)\n");//!//!         let item_type = configfs_attrs! {//!             container: configfs::Subsystem<Configuration>,//!             data: Configuration,//!             attributes: [//!                 message: 0,//!                 bar: 1,//!             ],//!         };//!//!         try_pin_init!(Self {//!             config <- configfs::Subsystem::new(//!                 c"rust_configfs", item_type, Configuration::new()//!             ),//!         })//!     }//! }//!//! #[pin_data]//! struct Configuration {//!     message: &'static CStr,//!     #[pin]//!     bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,//! }//!//! impl Configuration {//!     fn new() -> impl PinInit<Self, Error> {//!         try_pin_init!(Self {//!             message: c"Hello World\n",//!             bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),//!         })//!     }//! }//!//! #[vtable]//! impl configfs::AttributeOperations<0> for Configuration {//!     type Data = Configuration;//!//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {//!         pr_info!("Show message\n");//!         let data = container.message;//!         page[0..data.len()].copy_from_slice(data);//!         Ok(data.len())//!     }//! }//!//! #[vtable]//! impl configfs::AttributeOperations<1> for Configuration {//!     type Data = Configuration;//!//!     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {//!         pr_info!("Show bar\n");//!         let guard = container.bar.lock();//!         let data = guard.0.as_slice();//!         let len = guard.1;//!         page[0..len].copy_from_slice(&data[0..len]);//!         Ok(len)//!     }//!//!     fn store(container: &Configuration, page: &[u8]) -> Result {//!         pr_info!("Store bar\n");//!         let mut guard = container.bar.lock();//!         guard.0[0..page.len()].copy_from_slice(page);//!         guard.1 = page.len();//!         Ok(())//!     }//! }//! ```//!//! [C documentation]: srctree/Documentation/filesystems/configfs.rst//! [`rust_configfs.rs`]: srctree/samples/rust/rust_configfs.rs use crate::alloc::flags;use crate::container_of;use crate::page::PAGE_SIZE;use crate::prelude::*;use crate::str::CString;use crate::sync::Arc;use crate::sync::ArcBorrow;use crate::types::Opaque;use core::cell::UnsafeCell;use core::marker::PhantomData; /// A configfs subsystem.////// This is the top level entrypoint for a configfs hierarchy. To register/// with configfs, embed a field of this type into your kernel module struct.#[pin_data(PinnedDrop)]pub struct Subsystem<Data> {    #[pin]    subsystem: Opaque<bindings::configfs_subsystem>,    #[pin]    data: Data,} // SAFETY: We do not provide any operations on `Subsystem`.unsafe impl<Data> Sync for Subsystem<Data> {} // SAFETY: Ownership of `Subsystem` can safely be transferred to other threads.unsafe impl<Data> Send for Subsystem<Data> {} impl<Data> Subsystem<Data> {    /// Create an initializer for a [`Subsystem`].    ///    /// The subsystem will appear in configfs as a directory name given by    /// `name`. The attributes available in directory are specified by    /// `item_type`.    pub fn new(        name: &'static CStr,        item_type: &'static ItemType<Subsystem<Data>, Data>,        data: impl PinInit<Data, Error>,    ) -> impl PinInit<Self, Error> {        try_pin_init!(Self {            subsystem <- pin_init::init_zeroed().chain(                |place: &mut Opaque<bindings::configfs_subsystem>| {                    // SAFETY: We initialized the required fields of `place.group` above.                    unsafe {                        bindings::config_group_init_type_name(                            &mut (*place.get()).su_group,                            name.as_char_ptr(),                            item_type.as_ptr(),                        )                    };                     // SAFETY: `place.su_mutex` is valid for use as a mutex.                    unsafe {                        bindings::__mutex_init(                            &mut (*place.get()).su_mutex,                            kernel::optional_name!().as_char_ptr(),                            kernel::static_lock_class!().as_ptr(),                        )                    }                    Ok(())                }            ),            data <- data,        })        .pin_chain(|this| {            crate::error::to_result(                // SAFETY: We initialized `this.subsystem` according to C API contract above.                unsafe { bindings::configfs_register_subsystem(this.subsystem.get()) },            )        })    }} #[pinned_drop]impl<Data> PinnedDrop for Subsystem<Data> {    fn drop(self: Pin<&mut Self>) {        // SAFETY: We registered `self.subsystem` in the initializer returned by `Self::new`.        unsafe { bindings::configfs_unregister_subsystem(self.subsystem.get()) };        // SAFETY: We initialized the mutex in `Subsystem::new`.        unsafe { bindings::mutex_destroy(&raw mut (*self.subsystem.get()).su_mutex) };    }} /// Trait that allows offset calculations for structs that embed a/// `bindings::config_group`.////// Users of the configfs API should not need to implement this trait.////// # Safety////// - Implementers of this trait must embed a `bindings::config_group`./// - Methods must be implemented according to method documentation.pub unsafe trait HasGroup<Data> {    /// Return the address of the `bindings::config_group` embedded in [`Self`].    ///    /// # Safety    ///    /// - `this` must be a valid allocation of at least the size of [`Self`].    unsafe fn group(this: *const Self) -> *const bindings::config_group;     /// Return the address of the [`Self`] that `group` is embedded in.    ///    /// # Safety    ///    /// - `group` must point to the `bindings::config_group` that is embedded in    ///   [`Self`].    unsafe fn container_of(group: *const bindings::config_group) -> *const Self;} // SAFETY: `Subsystem<Data>` embeds a field of type `bindings::config_group`// within the `subsystem` field.unsafe impl<Data> HasGroup<Data> for Subsystem<Data> {    unsafe fn group(this: *const Self) -> *const bindings::config_group {        // SAFETY: By impl and function safety requirement this projection is in bounds.        unsafe { &raw const (*(*this).subsystem.get()).su_group }    }     unsafe fn container_of(group: *const bindings::config_group) -> *const Self {        // SAFETY: By impl and function safety requirement this projection is in bounds.        let c_subsys_ptr = unsafe { container_of!(group, bindings::configfs_subsystem, su_group) };        let opaque_ptr = c_subsys_ptr.cast::<Opaque<bindings::configfs_subsystem>>();        // SAFETY: By impl and function safety requirement, `opaque_ptr` and the        // pointer it returns, are within the same allocation.        unsafe { container_of!(opaque_ptr, Subsystem<Data>, subsystem) }    }} /// A configfs group.////// To add a subgroup to configfs, pass this type as `ctype` to/// [`crate::configfs_attrs`] when creating a group in [`GroupOperations::make_group`].#[pin_data]pub struct Group<Data> {    #[pin]    group: Opaque<bindings::config_group>,    #[pin]    data: Data,} impl<Data> Group<Data> {    /// Create an initializer for a new group.    ///    /// When instantiated, the group will appear as a directory with the name    /// given by `name` and it will contain attributes specified by `item_type`.    pub fn new(        name: CString,        item_type: &'static ItemType<Group<Data>, Data>,        data: impl PinInit<Data, Error>,    ) -> impl PinInit<Self, Error> {        try_pin_init!(Self {            group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {                let place = v.get();                let name = name.to_bytes_with_nul().as_ptr();                // SAFETY: It is safe to initialize a group once it has been zeroed.                unsafe {                    bindings::config_group_init_type_name(place, name.cast(), item_type.as_ptr())                };                Ok(())            }),            data <- data,        })    }} // SAFETY: `Group<Data>` embeds a field of type `bindings::config_group`// within the `group` field.unsafe impl<Data> HasGroup<Data> for Group<Data> {    unsafe fn group(this: *const Self) -> *const bindings::config_group {        Opaque::cast_into(            // SAFETY: By impl and function safety requirements this field            // projection is within bounds of the allocation.            unsafe { &raw const (*this).group },        )    }     unsafe fn container_of(group: *const bindings::config_group) -> *const Self {        let opaque_ptr = group.cast::<Opaque<bindings::config_group>>();        // SAFETY: By impl and function safety requirement, `opaque_ptr` and        // pointer it returns will be in the same allocation.        unsafe { container_of!(opaque_ptr, Self, group) }    }} /// # Safety////// `this` must be a valid pointer.////// If `this` does not represent the root group of a configfs subsystem,/// `this` must be a pointer to a `bindings::config_group` embedded in a/// `Group<Parent>`.////// Otherwise, `this` must be a pointer to a `bindings::config_group` that/// is embedded in a `bindings::configfs_subsystem` that is embedded in a/// `Subsystem<Parent>`.unsafe fn get_group_data<'a, Parent>(this: *mut bindings::config_group) -> &'a Parent {    // SAFETY: `this` is a valid pointer.    let is_root = unsafe { (*this).cg_subsys.is_null() };     if !is_root {        // SAFETY: By C API contact,`this` was returned from a call to        // `make_group`. The pointer is known to be embedded within a        // `Group<Parent>`.        unsafe { &(*Group::<Parent>::container_of(this)).data }    } else {        // SAFETY: By C API contract, `this` is a pointer to the        // `bindings::config_group` field within a `Subsystem<Parent>`.        unsafe { &(*Subsystem::container_of(this)).data }    }} struct GroupOperationsVTable<Parent, Child>(PhantomData<(Parent, Child)>); impl<Parent, Child> GroupOperationsVTable<Parent, Child>where    Parent: GroupOperations<Child = Child>,    Child: 'static,{    /// # Safety    ///    /// `this` must be a valid pointer.    ///    /// If `this` does not represent the root group of a configfs subsystem,    /// `this` must be a pointer to a `bindings::config_group` embedded in a    /// `Group<Parent>`.    ///    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a    /// `Subsystem<Parent>`.    ///    /// `name` must point to a null terminated string.    unsafe extern "C" fn make_group(        this: *mut bindings::config_group,        name: *const kernel::ffi::c_char,    ) -> *mut bindings::config_group {        // SAFETY: By function safety requirements of this function, this call        // is safe.        let parent_data = unsafe { get_group_data(this) };         let group_init = match Parent::make_group(            parent_data,            // SAFETY: By function safety requirements, name points to a null            // terminated string.            unsafe { CStr::from_char_ptr(name) },        ) {            Ok(init) => init,            Err(e) => return e.to_ptr(),        };         let child_group = <Arc<Group<Child>> as InPlaceInit<Group<Child>>>::try_pin_init(            group_init,            flags::GFP_KERNEL,        );         match child_group {            Ok(child_group) => {                let child_group_ptr = child_group.into_raw();                // SAFETY: We allocated the pointee of `child_ptr` above as a                // `Group<Child>`.                unsafe { Group::<Child>::group(child_group_ptr) }.cast_mut()            }            Err(e) => e.to_ptr(),        }    }     /// # Safety    ///    /// If `this` does not represent the root group of a configfs subsystem,    /// `this` must be a pointer to a `bindings::config_group` embedded in a    /// `Group<Parent>`.    ///    /// Otherwise, `this` must be a pointer to a `bindings::config_group` that    /// is embedded in a `bindings::configfs_subsystem` that is embedded in a    /// `Subsystem<Parent>`.    ///    /// `item` must point to a `bindings::config_item` within a    /// `bindings::config_group` within a `Group<Child>`.    unsafe extern "C" fn drop_item(        this: *mut bindings::config_group,        item: *mut bindings::config_item,    ) {        // SAFETY: By function safety requirements of this function, this call        // is safe.        let parent_data = unsafe { get_group_data(this) };         // SAFETY: By function safety requirements, `item` is embedded in a        // `config_group`.        let c_child_group_ptr = unsafe { container_of!(item, bindings::config_group, cg_item) };        // SAFETY: By function safety requirements, `c_child_group_ptr` is        // embedded within a `Group<Child>`.        let r_child_group_ptr = unsafe { Group::<Child>::container_of(c_child_group_ptr) };         if Parent::HAS_DROP_ITEM {            // SAFETY: We called `into_raw` to produce `r_child_group_ptr` in            // `make_group`.            let arc: Arc<Group<Child>> = unsafe { Arc::from_raw(r_child_group_ptr.cast_mut()) };             Parent::drop_item(parent_data, arc.as_arc_borrow());            arc.into_raw();        }         // SAFETY: By C API contract, we are required to drop a refcount on        // `item`.        unsafe { bindings::config_item_put(item) };    }     const VTABLE: bindings::configfs_group_operations = bindings::configfs_group_operations {        make_item: None,        make_group: Some(Self::make_group),        disconnect_notify: None,        drop_item: Some(Self::drop_item),        is_visible: None,        is_bin_visible: None,    };     const fn vtable_ptr() -> *const bindings::configfs_group_operations {        &Self::VTABLE    }} struct ItemOperationsVTable<Container, Data>(PhantomData<(Container, Data)>); impl<Data> ItemOperationsVTable<Group<Data>, Data>where    Data: 'static,{    /// # Safety    ///    /// `this` must be a pointer to a `bindings::config_group` embedded in a    /// `Group<Parent>`.    ///    /// This function will destroy the pointee of `this`. The pointee of `this`    /// must not be accessed after the function returns.    unsafe extern "C" fn release(this: *mut bindings::config_item) {        // SAFETY: By function safety requirements, `this` is embedded in a        // `config_group`.        let c_group_ptr = unsafe { kernel::container_of!(this, bindings::config_group, cg_item) };        // SAFETY: By function safety requirements, `c_group_ptr` is        // embedded within a `Group<Data>`.        let r_group_ptr = unsafe { Group::<Data>::container_of(c_group_ptr) };         // SAFETY: We called `into_raw` on `r_group_ptr` in        // `make_group`.        let pin_self: Arc<Group<Data>> = unsafe { Arc::from_raw(r_group_ptr.cast_mut()) };        drop(pin_self);    }     const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {        release: Some(Self::release),        allow_link: None,        drop_link: None,    };     const fn vtable_ptr() -> *const bindings::configfs_item_operations {        &Self::VTABLE    }} impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {    const VTABLE: bindings::configfs_item_operations = bindings::configfs_item_operations {        release: None,        allow_link: None,        drop_link: None,    };     const fn vtable_ptr() -> *const bindings::configfs_item_operations {        &Self::VTABLE    }} /// Operations implemented by configfs groups that can create subgroups.////// Implement this trait on structs that embed a [`Subsystem`] or a [`Group`].#[vtable]pub trait GroupOperations {    /// The child data object type.    ///    /// This group will create subgroups (subdirectories) backed by this kind of    /// object.    type Child: 'static;     /// Creates a new subgroup.    ///    /// The kernel will call this method in response to `mkdir(2)` in the    /// directory representing `this`.    ///    /// To accept the request to create a group, implementations should    /// return an initializer of a `Group<Self::Child>`. To prevent creation,    /// return a suitable error.

Lines 1–500 of 1047.