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