xref: /DragonOS/kernel/src/filesystem/devpts/mod.rs (revision 2709e017d0d216d61b2caed3c7286459de7794c7)
1 use core::sync::atomic::{AtomicU32, Ordering};
2 
3 use alloc::{
4     collections::BTreeMap,
5     string::{String, ToString},
6     sync::{Arc, Weak},
7     vec::Vec,
8 };
9 use ida::IdAllocator;
10 use system_error::SystemError;
11 use unified_init::macros::unified_init;
12 
13 use crate::{
14     driver::{
15         base::device::{
16             device_number::{DeviceNumber, Major},
17             IdTable,
18         },
19         tty::{
20             pty::unix98pty::NR_UNIX98_PTY_MAX,
21             tty_device::{PtyType, TtyDevice, TtyType},
22         },
23     },
24     filesystem::vfs::{core::do_mount_mkdir, syscall::ModeType, FileType},
25     init::initcall::INITCALL_FS,
26     libs::spinlock::{SpinLock, SpinLockGuard},
27     time::PosixTimeSpec,
28 };
29 
30 use super::vfs::{
31     core::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata,
32 };
33 
34 const DEV_PTYFS_MAX_NAMELEN: usize = 16;
35 
36 #[allow(dead_code)]
37 const PTY_NR_LIMIT: usize = 4096;
38 
39 #[derive(Debug)]
40 pub struct DevPtsFs {
41     /// 根节点
42     root_inode: Arc<LockedDevPtsFSInode>,
43     pts_ida: IdAllocator,
44     pts_count: AtomicU32,
45 }
46 
47 impl DevPtsFs {
48     pub fn new() -> Arc<Self> {
49         let root_inode = Arc::new(LockedDevPtsFSInode::new());
50         let ret = Arc::new(Self {
51             root_inode,
52             pts_ida: IdAllocator::new(1, NR_UNIX98_PTY_MAX as usize),
53             pts_count: AtomicU32::new(0),
54         });
55 
56         ret.root_inode.set_fs(Arc::downgrade(&ret));
57 
58         ret
59     }
60 
61     pub fn alloc_index(&self) -> Result<usize, SystemError> {
62         self.pts_ida.alloc().ok_or(SystemError::ENOSPC)
63     }
64 }
65 
66 impl FileSystem for DevPtsFs {
67     fn root_inode(&self) -> Arc<dyn IndexNode> {
68         self.root_inode.clone()
69     }
70 
71     fn info(&self) -> super::vfs::FsInfo {
72         return FsInfo {
73             blk_dev_id: 0,
74             max_name_len: DEV_PTYFS_MAX_NAMELEN,
75         };
76     }
77 
78     fn as_any_ref(&self) -> &dyn core::any::Any {
79         self
80     }
81 
82     fn name(&self) -> &str {
83         "devpts"
84     }
85 
86     fn super_block(&self) -> super::vfs::SuperBlock {
87         todo!()
88     }
89 }
90 
91 #[derive(Debug)]
92 pub struct LockedDevPtsFSInode {
93     inner: SpinLock<PtsDevInode>,
94 }
95 
96 impl LockedDevPtsFSInode {
97     pub fn new() -> Self {
98         Self {
99             inner: SpinLock::new(PtsDevInode {
100                 fs: Weak::new(),
101                 children: Some(BTreeMap::new()),
102                 metadata: Metadata {
103                     dev_id: 0,
104                     inode_id: generate_inode_id(),
105                     size: 0,
106                     blk_size: 0,
107                     blocks: 0,
108                     atime: PosixTimeSpec::default(),
109                     mtime: PosixTimeSpec::default(),
110                     ctime: PosixTimeSpec::default(),
111                     file_type: FileType::Dir,
112                     mode: ModeType::from_bits_truncate(0o777),
113                     nlinks: 1,
114                     uid: 0,
115                     gid: 0,
116                     raw_dev: DeviceNumber::default(),
117                 },
118             }),
119         }
120     }
121 
122     pub fn set_fs(&self, fs: Weak<DevPtsFs>) {
123         self.inner.lock().fs = fs;
124     }
125 }
126 
127 #[derive(Debug)]
128 pub struct PtsDevInode {
129     fs: Weak<DevPtsFs>,
130     children: Option<BTreeMap<String, Arc<TtyDevice>>>,
131     metadata: Metadata,
132 }
133 
134 impl PtsDevInode {
135     pub fn children_unchecked(&self) -> &BTreeMap<String, Arc<TtyDevice>> {
136         self.children.as_ref().unwrap()
137     }
138 
139     pub fn children_unchecked_mut(&mut self) -> &mut BTreeMap<String, Arc<TtyDevice>> {
140         self.children.as_mut().unwrap()
141     }
142 }
143 
144 impl IndexNode for LockedDevPtsFSInode {
145     fn open(
146         &self,
147         _data: SpinLockGuard<FilePrivateData>,
148         _mode: &super::vfs::file::FileMode,
149     ) -> Result<(), SystemError> {
150         Ok(())
151     }
152 
153     fn metadata(&self) -> Result<super::vfs::Metadata, SystemError> {
154         let inode = self.inner.lock();
155         let metadata = inode.metadata.clone();
156 
157         return Ok(metadata);
158     }
159 
160     fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> {
161         // TODO: 回收
162         Ok(())
163     }
164 
165     fn read_at(
166         &self,
167         _offset: usize,
168         _len: usize,
169         _buf: &mut [u8],
170         _data: SpinLockGuard<FilePrivateData>,
171     ) -> Result<usize, system_error::SystemError> {
172         todo!()
173     }
174 
175     fn write_at(
176         &self,
177         _offset: usize,
178         _len: usize,
179         _buf: &[u8],
180         _data: SpinLockGuard<FilePrivateData>,
181     ) -> Result<usize, system_error::SystemError> {
182         todo!()
183     }
184 
185     fn fs(&self) -> alloc::sync::Arc<dyn super::vfs::FileSystem> {
186         self.inner.lock().fs.upgrade().unwrap()
187     }
188 
189     fn as_any_ref(&self) -> &dyn core::any::Any {
190         todo!()
191     }
192 
193     fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, system_error::SystemError> {
194         let info = self.metadata()?;
195         if info.file_type != FileType::Dir {
196             return Err(SystemError::ENOTDIR);
197         }
198 
199         let mut keys: Vec<String> = Vec::new();
200         keys.push(String::from("."));
201         keys.push(String::from(".."));
202         keys.append(
203             &mut self
204                 .inner
205                 .lock()
206                 .children_unchecked()
207                 .keys()
208                 .cloned()
209                 .collect(),
210         );
211 
212         return Ok(keys);
213     }
214 
215     fn create_with_data(
216         &self,
217         name: &str,
218         file_type: FileType,
219         _mode: super::vfs::syscall::ModeType,
220         _data: usize,
221     ) -> Result<Arc<dyn IndexNode>, SystemError> {
222         if file_type != FileType::CharDevice {
223             return Err(SystemError::ENOSYS);
224         }
225 
226         let mut guard = self.inner.lock();
227 
228         if guard.children_unchecked_mut().contains_key(name) {
229             return Err(SystemError::EEXIST);
230         }
231 
232         let fs = guard.fs.upgrade().unwrap();
233 
234         let result = TtyDevice::new(
235             name.to_string(),
236             IdTable::new(name.to_string(), None),
237             TtyType::Pty(PtyType::Pts),
238         );
239 
240         let mut metadata = result.metadata()?;
241 
242         metadata.mode.insert(ModeType::S_IFCHR);
243         metadata.raw_dev =
244             DeviceNumber::new(Major::UNIX98_PTY_SLAVE_MAJOR, name.parse::<u32>().unwrap());
245 
246         result.set_metadata(&metadata)?;
247 
248         guard
249             .children_unchecked_mut()
250             .insert(name.to_string(), result.clone());
251 
252         fs.pts_count.fetch_add(1, Ordering::SeqCst);
253 
254         Ok(result)
255     }
256 
257     fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, SystemError> {
258         let guard = self.inner.lock();
259 
260         if let Some(dev) = guard.children_unchecked().get(name) {
261             Ok(dev.clone() as Arc<dyn IndexNode>)
262         } else {
263             Err(SystemError::ENOENT)
264         }
265     }
266 
267     fn unlink(&self, name: &str) -> Result<(), SystemError> {
268         let mut guard = self.inner.lock();
269         guard.children_unchecked_mut().remove(name);
270         Ok(())
271     }
272 }
273 
274 #[unified_init(INITCALL_FS)]
275 #[inline(never)]
276 pub fn devpts_init() -> Result<(), SystemError> {
277     // 创建 devptsfs 实例
278     let ptsfs: Arc<DevPtsFs> = DevPtsFs::new();
279 
280     do_mount_mkdir(ptsfs, "/dev/pts").expect("Failed to mount DevPtsFS");
281     kinfo!("DevPtsFs mounted.");
282 
283     Ok(())
284 }
285