xref: /DragonOS/kernel/src/filesystem/sysfs/group.rs (revision 06d5e247267cb65b84a80f219853ccd0f384b16e)
1 use core::intrinsics::unlikely;
2 
3 use alloc::{string::ToString, sync::Arc};
4 
5 use crate::{
6     driver::base::kobject::KObject,
7     filesystem::{
8         kernfs::{callback::KernInodePrivateData, KernFSInode},
9         sysfs::{dir::SysKernDirPriv, sysfs_instance, SysFSKernPrivateData},
10         vfs::{syscall::ModeType, IndexNode},
11     },
12     kwarn,
13     libs::casting::DowncastArc,
14     syscall::SystemError,
15 };
16 
17 use super::{AttributeGroup, SysFS};
18 
19 impl SysFS {
20     /// 在sysfs中,为指定的kobject的属性组创建文件夹
21     pub fn create_groups(
22         &self,
23         kobj: &Arc<dyn KObject>,
24         groups: &[&'static dyn AttributeGroup],
25     ) -> Result<(), SystemError> {
26         return self.do_create_groups(kobj, groups, false);
27     }
28 
29     fn do_create_groups(
30         &self,
31         kobj: &Arc<dyn KObject>,
32         groups: &[&'static dyn AttributeGroup],
33         update: bool,
34     ) -> Result<(), SystemError> {
35         for i in 0..groups.len() {
36             let group = groups[i];
37             if let Err(e) = self.do_create_group(kobj, group, update) {
38                 for j in (0..=i).rev() {
39                     self.remove_group(kobj, groups[j]).ok();
40                 }
41                 return Err(e);
42             }
43         }
44         return Ok(());
45     }
46 
47     fn do_create_group(
48         &self,
49         kobj: &Arc<dyn KObject>,
50         group: &'static dyn AttributeGroup,
51         update: bool,
52     ) -> Result<(), SystemError> {
53         // kobj的inode必须存在
54         let kobj_inode = kobj.inode().ok_or(SystemError::EINVAL)?;
55 
56         if group.attrs().is_empty() {
57             return Err(SystemError::EINVAL);
58         }
59 
60         let parent_inode: Arc<KernFSInode>;
61         if group.name().is_some() {
62             if update {
63                 // 如果是更新,那么group的name必须存在
64                 parent_inode = kobj_inode
65                     .find(group.name().unwrap())
66                     .map_err(|_| SystemError::EINVAL)?
67                     .downcast_arc()
68                     .unwrap();
69             } else {
70                 let private_data = KernInodePrivateData::SysFS(SysFSKernPrivateData::Dir(
71                     SysKernDirPriv::new(kobj.clone()),
72                 ));
73                 parent_inode = kobj_inode
74                     .add_dir(
75                         group.name().unwrap().to_string(),
76                         ModeType::S_IRWXU | ModeType::S_IRUGO | ModeType::S_IXUGO,
77                         Some(private_data),
78                         None,
79                     )
80                     .map_err(|e| {
81                         if e == SystemError::EEXIST {
82                             self.warn_duplicate(&kobj_inode, group.name().unwrap());
83                         }
84                         e
85                     })?;
86             }
87         } else {
88             parent_inode = kobj_inode.clone();
89         }
90 
91         if let Err(e) = self.group_create_files(parent_inode.clone(), kobj, group, update) {
92             if group.name().is_some() {
93                 parent_inode.remove_recursive();
94             }
95             return Err(e);
96         }
97 
98         return Ok(());
99     }
100 
101     /// 从一个kobject中移除一个group
102     ///
103     /// This function removes a group of attributes from a kobject.  The attributes
104     /// previously have to have been created for this group, otherwise it will fail.
105     ///
106     /// ## 参数
107     ///
108     /// - `kobj` - 要移除group的kobject
109     /// - `group` - 要移除的group
110     ///
111     ///
112     pub fn remove_group(
113         &self,
114         kobj: &Arc<dyn KObject>,
115         group: &'static dyn AttributeGroup,
116     ) -> Result<(), SystemError> {
117         let inode = kobj.inode().unwrap();
118         let parent_inode: Arc<KernFSInode>;
119         if let Some(name) = group.name() {
120             parent_inode = inode
121                 .find(name)
122                 .map_err(|e| {
123                     kwarn!("sysfs group '{name}' not found for kobject {kobj:?}");
124                     e
125                 })?
126                 .downcast_arc()
127                 .unwrap();
128         } else {
129             parent_inode = inode;
130         }
131 
132         self.group_remove_files(&parent_inode, group);
133 
134         if group.name().is_some() {
135             parent_inode.remove_recursive();
136         }
137 
138         return Ok(());
139     }
140 
141     /// 创建属性组的文件
142     ///
143     /// ## 参数
144     ///
145     /// - `parent` - 属性组的父文件夹
146     /// - `kobj` - 属性组所属的kobject
147     /// - `group` - 属性组
148     /// - `update` - 当前是否正在更新属性
149     ///
150     /// https://opengrok.ringotek.cn/xref/linux-6.1.9/fs/sysfs/group.c#34
151     fn group_create_files(
152         &self,
153         parent: Arc<KernFSInode>,
154         kobj: &Arc<dyn KObject>,
155         group: &'static dyn AttributeGroup,
156         update: bool,
157     ) -> Result<(), SystemError> {
158         let mut e = Ok(());
159         for attr in group.attrs() {
160             let mut mode = attr.mode();
161 
162             // 由于我们在更新的时候,可能会更改visibility和permissions,所以需要先删除再创建
163             if update {
164                 parent.remove(attr.name()).ok();
165             }
166             if let Some(mt) = group.is_visible(kobj.clone(), *attr) {
167                 mode = mt;
168                 // 当前属性不可见,跳过
169                 if mode.is_empty() {
170                     continue;
171                 }
172             }
173 
174             if unlikely((mode.bits() & (!0o644)) != 0) {
175                 kwarn!(
176                     "Attribute '{name}' has invalid mode 0{mode:o}",
177                     name = attr.name(),
178                     mode = mode
179                 );
180             }
181 
182             mode = ModeType::from_bits_truncate(mode.bits() & 0o644);
183             e = sysfs_instance().add_file_with_mode(&parent, *attr, mode);
184             if e.is_err() {
185                 break;
186             }
187         }
188 
189         if let Err(e) = e {
190             self.group_remove_files(&parent, group);
191             return Err(e);
192         }
193 
194         return Ok(());
195     }
196 
197     fn group_remove_files(&self, _parent: &Arc<KernFSInode>, _group: &'static dyn AttributeGroup) {
198         todo!("group_remove_files")
199     }
200 }
201