xref: /DragonOS/kernel/src/filesystem/sysfs/file.rs (revision f79998f626801329580c782fd05e36cb2027f474)
1 use core::{intrinsics::unlikely, ops::BitAnd};
2 
3 use alloc::{
4     string::ToString,
5     sync::{Arc, Weak},
6 };
7 use log::warn;
8 use system_error::SystemError;
9 
10 use crate::{
11     driver::base::kobject::KObject,
12     filesystem::{
13         kernfs::{
14             callback::{KernCallbackData, KernFSCallback, KernInodePrivateData},
15             KernFSInode,
16         },
17         sysfs::{SysFSOps, SysFSOpsSupport},
18         vfs::{syscall::ModeType, PollStatus},
19     },
20 };
21 
22 use super::{Attribute, BinAttribute, SysFS, SysFSKernPrivateData};
23 
24 #[derive(Debug)]
25 pub struct SysKernFilePriv {
26     attribute: Option<&'static dyn Attribute>,
27     /// bin attribute和attribute二选一,只能有一个为Some
28     bin_attribute: Option<Arc<dyn BinAttribute>>,
29     /// 当前文件对应的kobject
30     kobj: Weak<dyn KObject>,
31 }
32 
33 impl SysKernFilePriv {
34     pub fn new(
35         kobj: &Arc<dyn KObject>,
36         attribute: Option<&'static dyn Attribute>,
37         bin_attribute: Option<Arc<dyn BinAttribute>>,
38     ) -> Self {
39         if attribute.is_none() && bin_attribute.is_none() {
40             panic!("attribute and bin_attribute can't be both None");
41         }
42         if attribute.is_some() && bin_attribute.is_some() {
43             panic!("attribute and bin_attribute can't be both Some");
44         }
45 
46         let kobj = Arc::downgrade(kobj);
47         return Self {
48             kobj,
49             attribute,
50             bin_attribute,
51         };
52     }
53 
54     #[allow(dead_code)]
55     #[inline]
56     pub fn attribute(&self) -> Option<&'static dyn Attribute> {
57         self.attribute
58     }
59 
60     pub fn callback_read(&self, buf: &mut [u8], offset: usize) -> Result<usize, SystemError> {
61         if let Some(attribute) = self.attribute {
62             // 当前文件所指向的kobject已经被释放
63             let kobj = self.kobj.upgrade().expect("kobj is None");
64             let len = attribute.show(kobj, buf)?;
65             if offset > 0 {
66                 if len <= offset {
67                     return Ok(0);
68                 }
69                 let len = len - offset;
70                 buf.copy_within(offset..offset + len, 0);
71                 buf[len] = 0;
72             }
73             return Ok(len);
74         } else if let Some(bin_attribute) = self.bin_attribute.as_ref() {
75             // 当前文件所指向的kobject已经被释放
76             let kobj = self.kobj.upgrade().expect("kobj is None");
77             return bin_attribute.read(kobj, buf, offset);
78         } else {
79             panic!("attribute and bin_attribute can't be both None");
80         }
81     }
82 
83     pub fn callback_write(&self, buf: &[u8], offset: usize) -> Result<usize, SystemError> {
84         if let Some(attribute) = self.attribute {
85             // 当前文件所指向的kobject已经被释放
86             let kobj = self.kobj.upgrade().expect("kobj is None");
87             return attribute.store(kobj, buf);
88         } else if let Some(bin_attribute) = self.bin_attribute.as_ref() {
89             // 当前文件所指向的kobject已经被释放
90             let kobj = self.kobj.upgrade().expect("kobj is None");
91             return bin_attribute.write(kobj, buf, offset);
92         } else {
93             panic!("attribute and bin_attribute can't be both None");
94         }
95     }
96 }
97 
98 impl SysFS {
99     /// 为指定的kobject创建一个属性文件
100     ///
101     /// ## 参数
102     ///
103     /// - `kobj` 要创建属性文件的kobject
104     /// - `attr` 属性
105     pub fn create_file(
106         &self,
107         kobj: &Arc<dyn KObject>,
108         attr: &'static dyn Attribute,
109     ) -> Result<(), SystemError> {
110         let inode = kobj.inode().ok_or(SystemError::EINVAL)?;
111         return self.add_file_with_mode(&inode, attr, attr.mode());
112     }
113 
114     // https://code.dragonos.org.cn/xref/linux-6.1.9/fs/sysfs/file.c?fi=sysfs_add_file_mode_ns#271
115     pub(super) fn add_file_with_mode(
116         &self,
117         parent: &Arc<KernFSInode>,
118         attr: &'static dyn Attribute,
119         mode: ModeType,
120     ) -> Result<(), SystemError> {
121         let x = parent.private_data_mut();
122         let kobj: Arc<dyn KObject>;
123         if let Some(KernInodePrivateData::SysFS(SysFSKernPrivateData::Dir(dt))) = x.as_ref() {
124             kobj = dt.kobj().unwrap();
125         } else {
126             drop(x);
127             let path = self.kernfs_path(parent);
128             panic!("parent '{path}' is not a dir");
129         }
130         drop(x);
131 
132         let sysfs_ops: &dyn SysFSOps = kobj.kobj_type().unwrap().sysfs_ops().ok_or_else(|| {
133             warn!("missing sysfs attribute operations for kobject: {kobj:?}");
134             SystemError::EINVAL
135         })?;
136 
137         // assume that all sysfs ops are preallocated.
138 
139         let sys_support = sysfs_ops.support(attr);
140 
141         let kern_callback: &'static dyn KernFSCallback;
142         if sys_support.contains(SysFSOpsSupport::ATTR_SHOW)
143             && sys_support.contains(SysFSOpsSupport::ATTR_STORE)
144         {
145             kern_callback = &PreallocKFOpsRW;
146         } else if sys_support.contains(SysFSOpsSupport::ATTR_SHOW) {
147             kern_callback = &PreallocKFOpsReadOnly;
148         } else if sys_support.contains(SysFSOpsSupport::ATTR_STORE) {
149             kern_callback = &PreallocKFOpsWriteOnly;
150         } else {
151             kern_callback = &PreallocKFOpsEmpty;
152         }
153 
154         let sys_priv = SysFSKernPrivateData::File(SysKernFilePriv::new(&kobj, Some(attr), None));
155         let r = parent.add_file(
156             attr.name().to_string(),
157             mode.bitand(ModeType::from_bits_truncate(0o777)),
158             Some(4096),
159             Some(KernInodePrivateData::SysFS(sys_priv)),
160             Some(kern_callback),
161         );
162 
163         if let Err(e) = r {
164             if e == SystemError::EEXIST {
165                 self.warn_duplicate(parent, attr.name());
166             }
167 
168             return Err(e);
169         }
170         return Ok(());
171     }
172 
173     /// 在sysfs中删除某个kobject的属性文件
174     ///
175     /// 如果属性文件不存在,则发出一个警告
176     ///
177     /// ## 参数
178     ///
179     /// - `kobj` 要删除属性文件的kobject
180     /// - `attr` 属性
181     pub fn remove_file(&self, kobj: &Arc<dyn KObject>, attr: &'static dyn Attribute) {
182         let parent = kobj.inode();
183 
184         if let Some(parent) = parent {
185             let r = parent.remove(attr.name());
186             if unlikely(r.is_err()) {
187                 warn!(
188                     "failed to remove file '{}' from '{}'",
189                     attr.name(),
190                     kobj.name()
191                 );
192             }
193         }
194     }
195 
196     /// 在sysfs中,为指定的kobject创建一个动态申请的bin属性文件
197     ///
198     /// ## 参数
199     ///
200     /// - `kobj` 要创建属性文件的kobject
201     /// - `attr` 属性
202     ///
203     /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/sysfs/file.c#558
204     pub fn create_bin_file(
205         &self,
206         kobj: &Arc<dyn KObject>,
207         attr: &Arc<dyn BinAttribute>,
208     ) -> Result<(), SystemError> {
209         let inode = kobj.inode().ok_or(SystemError::EINVAL)?;
210         return self.add_bin_file_with_mode(&inode, attr, attr.mode());
211     }
212 
213     /// 在sysfs中删除某个kobject的bin属性文件
214     ///
215     /// 如果属性文件不存在,则发出一个警告
216     #[allow(dead_code)]
217     pub fn remove_bin_file(&self, kobj: &Arc<dyn KObject>, attr: &Arc<dyn BinAttribute>) {
218         let parent = kobj.inode();
219 
220         if let Some(parent) = parent {
221             let r = parent.remove(attr.name());
222             if unlikely(r.is_err()) {
223                 warn!(
224                     "failed to remove file '{}' from '{}'",
225                     attr.name(),
226                     kobj.name()
227                 );
228             }
229         }
230     }
231 
232     /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/sysfs/file.c#304
233     pub(super) fn add_bin_file_with_mode(
234         &self,
235         parent: &Arc<KernFSInode>,
236         attr: &Arc<dyn BinAttribute>,
237         mode: ModeType,
238     ) -> Result<(), SystemError> {
239         let x = parent.private_data_mut();
240         let kobj: Arc<dyn KObject>;
241         if let Some(KernInodePrivateData::SysFS(SysFSKernPrivateData::Dir(dt))) = x.as_ref() {
242             kobj = dt.kobj().unwrap();
243         } else {
244             drop(x);
245             let path = self.kernfs_path(parent);
246             panic!("parent '{path}' is not a dir");
247         }
248         drop(x);
249 
250         let kern_callback: &'static dyn KernFSCallback;
251         let bin_support = attr.support_battr();
252 
253         if bin_support.contains(SysFSOpsSupport::BATTR_READ)
254             && bin_support.contains(SysFSOpsSupport::BATTR_WRITE)
255         {
256             kern_callback = &PreallocKFOpsRW;
257         } else if bin_support.contains(SysFSOpsSupport::BATTR_READ) {
258             kern_callback = &PreallocKFOpsReadOnly;
259         } else if bin_support.contains(SysFSOpsSupport::BATTR_WRITE) {
260             kern_callback = &PreallocKFOpsWriteOnly;
261         } else {
262             kern_callback = &PreallocKFOpsEmpty;
263         }
264 
265         let sys_priv =
266             SysFSKernPrivateData::File(SysKernFilePriv::new(&kobj, None, Some(attr.clone())));
267         let r = parent.add_file(
268             attr.name().to_string(),
269             mode.bitand(ModeType::from_bits_truncate(0o777)),
270             Some(attr.size()),
271             Some(KernInodePrivateData::SysFS(sys_priv)),
272             Some(kern_callback),
273         );
274 
275         if let Err(e) = r {
276             if e == SystemError::EEXIST {
277                 self.warn_duplicate(parent, attr.name());
278             }
279 
280             return Err(e);
281         }
282         return Ok(());
283     }
284 }
285 
286 #[derive(Debug)]
287 struct PreallocKFOpsRW;
288 
289 impl KernFSCallback for PreallocKFOpsRW {
290     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
291         return Ok(());
292     }
293 
294     fn read(
295         &self,
296         data: KernCallbackData,
297         buf: &mut [u8],
298         offset: usize,
299     ) -> Result<usize, SystemError> {
300         return data.callback_read(buf, offset);
301     }
302 
303     fn write(
304         &self,
305         data: KernCallbackData,
306         buf: &[u8],
307         offset: usize,
308     ) -> Result<usize, SystemError> {
309         return data.callback_write(buf, offset);
310     }
311 
312     #[inline]
313     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
314         return Ok(PollStatus::READ | PollStatus::WRITE);
315     }
316 }
317 
318 #[derive(Debug)]
319 struct PreallocKFOpsReadOnly;
320 
321 impl KernFSCallback for PreallocKFOpsReadOnly {
322     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
323         return Ok(());
324     }
325 
326     fn read(
327         &self,
328         data: KernCallbackData,
329         buf: &mut [u8],
330         offset: usize,
331     ) -> Result<usize, SystemError> {
332         return data.callback_read(buf, offset);
333     }
334 
335     fn write(
336         &self,
337         _data: KernCallbackData,
338         _buf: &[u8],
339         _offset: usize,
340     ) -> Result<usize, SystemError> {
341         return Err(SystemError::EPERM);
342     }
343 
344     #[inline]
345     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
346         return Ok(PollStatus::READ);
347     }
348 }
349 
350 #[derive(Debug)]
351 struct PreallocKFOpsWriteOnly;
352 
353 impl KernFSCallback for PreallocKFOpsWriteOnly {
354     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
355         return Ok(());
356     }
357 
358     fn read(
359         &self,
360         _data: KernCallbackData,
361         _buf: &mut [u8],
362         _offset: usize,
363     ) -> Result<usize, SystemError> {
364         return Err(SystemError::EPERM);
365     }
366 
367     fn write(
368         &self,
369         data: KernCallbackData,
370         buf: &[u8],
371         offset: usize,
372     ) -> Result<usize, SystemError> {
373         return data.callback_write(buf, offset);
374     }
375 
376     #[inline]
377     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
378         return Ok(PollStatus::WRITE);
379     }
380 }
381 
382 #[derive(Debug)]
383 struct PreallocKFOpsEmpty;
384 
385 impl KernFSCallback for PreallocKFOpsEmpty {
386     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
387         return Ok(());
388     }
389 
390     fn read(
391         &self,
392         _data: KernCallbackData,
393         _buf: &mut [u8],
394         _offset: usize,
395     ) -> Result<usize, SystemError> {
396         return Err(SystemError::EPERM);
397     }
398 
399     fn write(
400         &self,
401         _data: KernCallbackData,
402         _buf: &[u8],
403         _offset: usize,
404     ) -> Result<usize, SystemError> {
405         return Err(SystemError::EPERM);
406     }
407 
408     #[inline]
409     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
410         return Ok(PollStatus::empty());
411     }
412 }
413 
414 pub fn sysfs_emit_str(buf: &mut [u8], s: &str) -> Result<usize, SystemError> {
415     let len = if buf.len() > s.len() {
416         s.len()
417     } else {
418         buf.len() - 1
419     };
420     buf[..len].copy_from_slice(&s.as_bytes()[..len]);
421     buf[len] = b'\0';
422     return Ok(len);
423 }
424