| // SPDX-License-Identifier: GPL-2.0 | |
| //! Rust configfs sample. | |
| use kernel::alloc::flags; | |
| use kernel::configfs; | |
| use kernel::configfs::configfs_attrs; | |
| use kernel::new_mutex; | |
| use kernel::page::PAGE_SIZE; | |
| use kernel::prelude::*; | |
| use kernel::sync::Mutex; | |
| module! { | |
| type: RustConfigfs, | |
| name: "rust_configfs", | |
| authors: ["Rust for Linux Contributors"], | |
| description: "Rust configfs sample", | |
| license: "GPL", | |
| } | |
| #[pin_data] | |
| struct RustConfigfs { | |
| #[pin] | |
| config: configfs::Subsystem<Configuration>, | |
| } | |
| #[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)), | |
| }) | |
| } | |
| } | |
| impl kernel::InPlaceModule for RustConfigfs { | |
| fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> { | |
| pr_info!("Rust configfs sample (init)\n"); | |
| // Define a subsystem with the data type `Configuration`, two | |
| // attributes, `message` and `bar` and child group type `Child`. `mkdir` | |
| // in the directory representing this subsystem will create directories | |
| // backed by the `Child` type. | |
| let item_type = configfs_attrs! { | |
| container: configfs::Subsystem<Configuration>, | |
| data: Configuration, | |
| child: Child, | |
| attributes: [ | |
| message: 0, | |
| bar: 1, | |
| ], | |
| }; | |
| try_pin_init!(Self { | |
| config <- configfs::Subsystem::new( | |
| c"rust_configfs", item_type, Configuration::new() | |
| ), | |
| }) | |
| } | |
| } | |
| #[vtable] | |
| impl configfs::GroupOperations for Configuration { | |
| type Child = Child; | |
| fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<Child>, Error>> { | |
| // Define a group with data type `Child`, one attribute `baz` and child | |
| // group type `GrandChild`. `mkdir` in the directory representing this | |
| // group will create directories backed by the `GrandChild` type. | |
| let tpe = configfs_attrs! { | |
| container: configfs::Group<Child>, | |
| data: Child, | |
| child: GrandChild, | |
| attributes: [ | |
| baz: 0, | |
| ], | |
| }; | |
| Ok(configfs::Group::new(name.try_into()?, tpe, Child::new())) | |
| } | |
| } | |
| #[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.to_bytes(); | |
| 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(()) | |
| } | |
| } | |
| // `pin_data` cannot handle structs without braces. | |
| #[pin_data] | |
| struct Child {} | |
| impl Child { | |
| fn new() -> impl PinInit<Self, Error> { | |
| try_pin_init!(Self {}) | |
| } | |
| } | |
| #[vtable] | |
| impl configfs::GroupOperations for Child { | |
| type Child = GrandChild; | |
| fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandChild>, Error>> { | |
| // Define a group with data type `GrandChild`, one attribute `gc`. As no | |
| // child type is specified, it will not be possible to create subgroups | |
| // in this group, and `mkdir`in the directory representing this group | |
| // will return an error. | |
| let tpe = configfs_attrs! { | |
| container: configfs::Group<GrandChild>, | |
| data: GrandChild, | |
| attributes: [ | |
| gc: 0, | |
| ], | |
| }; | |
| Ok(configfs::Group::new( | |
| name.try_into()?, | |
| tpe, | |
| GrandChild::new(), | |
| )) | |
| } | |
| } | |
| #[vtable] | |
| impl configfs::AttributeOperations<0> for Child { | |
| type Data = Child; | |
| fn show(_container: &Child, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { | |
| pr_info!("Show baz\n"); | |
| let data = c"Hello Baz\n".to_bytes(); | |
| page[0..data.len()].copy_from_slice(data); | |
| Ok(data.len()) | |
| } | |
| } | |
| // `pin_data` cannot handle structs without braces. | |
| #[pin_data] | |
| struct GrandChild {} | |
| impl GrandChild { | |
| fn new() -> impl PinInit<Self, Error> { | |
| try_pin_init!(Self {}) | |
| } | |
| } | |
| #[vtable] | |
| impl configfs::AttributeOperations<0> for GrandChild { | |
| type Data = GrandChild; | |
| fn show(_container: &GrandChild, page: &mut [u8; PAGE_SIZE]) -> Result<usize> { | |
| pr_info!("Show grand child\n"); | |
| let data = c"Hello GC\n".to_bytes(); | |
| page[0..data.len()].copy_from_slice(data); | |
| Ok(data.len()) | |
| } | |
| } |