xref: /linux/samples/rust/rust_configfs.rs (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Rust configfs sample.
4 
5 use kernel::alloc::flags;
6 use kernel::configfs;
7 use kernel::configfs::configfs_attrs;
8 use kernel::new_mutex;
9 use kernel::page::PAGE_SIZE;
10 use kernel::prelude::*;
11 use kernel::sync::Mutex;
12 
13 module! {
14     type: RustConfigfs,
15     name: "rust_configfs",
16     authors: ["Rust for Linux Contributors"],
17     description: "Rust configfs sample",
18     license: "GPL",
19 }
20 
21 #[pin_data]
22 struct RustConfigfs {
23     #[pin]
24     config: configfs::Subsystem<Configuration>,
25 }
26 
27 #[pin_data]
28 struct Configuration {
29     message: &'static CStr,
30     #[pin]
31     bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
32 }
33 
34 impl Configuration {
35     fn new() -> impl PinInit<Self, Error> {
36         try_pin_init!(Self {
37             message: c"Hello World\n",
38             bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
39         })
40     }
41 }
42 
43 impl kernel::InPlaceModule for RustConfigfs {
44     fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
45         pr_info!("Rust configfs sample (init)\n");
46 
47         // Define a subsystem with the data type `Configuration`, two
48         // attributes, `message` and `bar` and child group type `Child`. `mkdir`
49         // in the directory representing this subsystem will create directories
50         // backed by the `Child` type.
51         let item_type = configfs_attrs! {
52             container: configfs::Subsystem<Configuration>,
53             data: Configuration,
54             child: Child,
55             attributes: [
56                 message: 0,
57                 bar: 1,
58             ],
59         };
60 
61         try_pin_init!(Self {
62             config <- configfs::Subsystem::new(
63                 c"rust_configfs", item_type, Configuration::new()
64             ),
65         })
66     }
67 }
68 
69 #[vtable]
70 impl configfs::GroupOperations for Configuration {
71     type Child = Child;
72 
73     fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<Child>, Error>> {
74         // Define a group with data type `Child`, one attribute `baz` and child
75         // group type `GrandChild`. `mkdir` in the directory representing this
76         // group will create directories backed by the `GrandChild` type.
77         let tpe = configfs_attrs! {
78             container: configfs::Group<Child>,
79             data: Child,
80             child: GrandChild,
81             attributes: [
82                 baz: 0,
83             ],
84         };
85 
86         Ok(configfs::Group::new(name.try_into()?, tpe, Child::new()))
87     }
88 }
89 
90 #[vtable]
91 impl configfs::AttributeOperations<0> for Configuration {
92     type Data = Configuration;
93 
94     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
95         pr_info!("Show message\n");
96         let data = container.message.to_bytes();
97         page[0..data.len()].copy_from_slice(data);
98         Ok(data.len())
99     }
100 }
101 
102 #[vtable]
103 impl configfs::AttributeOperations<1> for Configuration {
104     type Data = Configuration;
105 
106     fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
107         pr_info!("Show bar\n");
108         let guard = container.bar.lock();
109         let data = guard.0.as_slice();
110         let len = guard.1;
111         page[0..len].copy_from_slice(&data[0..len]);
112         Ok(len)
113     }
114 
115     fn store(container: &Configuration, page: &[u8]) -> Result {
116         pr_info!("Store bar\n");
117         let mut guard = container.bar.lock();
118         guard.0[0..page.len()].copy_from_slice(page);
119         guard.1 = page.len();
120         Ok(())
121     }
122 }
123 
124 // `pin_data` cannot handle structs without braces.
125 #[pin_data]
126 struct Child {}
127 
128 impl Child {
129     fn new() -> impl PinInit<Self, Error> {
130         try_pin_init!(Self {})
131     }
132 }
133 
134 #[vtable]
135 impl configfs::GroupOperations for Child {
136     type Child = GrandChild;
137 
138     fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandChild>, Error>> {
139         // Define a group with data type `GrandChild`, one attribute `gc`. As no
140         // child type is specified, it will not be possible to create subgroups
141         // in this group, and `mkdir`in the directory representing this group
142         // will return an error.
143         let tpe = configfs_attrs! {
144             container: configfs::Group<GrandChild>,
145             data: GrandChild,
146             attributes: [
147                 gc: 0,
148             ],
149         };
150 
151         Ok(configfs::Group::new(
152             name.try_into()?,
153             tpe,
154             GrandChild::new(),
155         ))
156     }
157 }
158 
159 #[vtable]
160 impl configfs::AttributeOperations<0> for Child {
161     type Data = Child;
162 
163     fn show(_container: &Child, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
164         pr_info!("Show baz\n");
165         let data = c"Hello Baz\n".to_bytes();
166         page[0..data.len()].copy_from_slice(data);
167         Ok(data.len())
168     }
169 }
170 
171 // `pin_data` cannot handle structs without braces.
172 #[pin_data]
173 struct GrandChild {}
174 
175 impl GrandChild {
176     fn new() -> impl PinInit<Self, Error> {
177         try_pin_init!(Self {})
178     }
179 }
180 
181 #[vtable]
182 impl configfs::AttributeOperations<0> for GrandChild {
183     type Data = GrandChild;
184 
185     fn show(_container: &GrandChild, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
186         pr_info!("Show grand child\n");
187         let data = c"Hello GC\n".to_bytes();
188         page[0..data.len()].copy_from_slice(data);
189         Ok(data.len())
190     }
191 }
192