os/fs/tmpfs/
inode.rs

1//! Tmpfs Inode 实现
2//!
3//! TmpfsInode 直接管理物理帧,无需经过 BlockDevice 层
4
5use alloc::collections::BTreeMap;
6use alloc::string::{String, ToString};
7use alloc::sync::{Arc, Weak};
8use alloc::vec::Vec;
9
10use crate::config::PAGE_SIZE;
11use crate::mm::address::{ConvertablePaddr, PageNum, UsizeConvert};
12use crate::mm::frame_allocator::{FrameTracker, alloc_frame};
13use crate::sync::{Mutex, SpinLock};
14use crate::uapi::time::TimeSpec;
15use crate::vfs::{DirEntry, FileMode, FsError, Inode, InodeMetadata, InodeType};
16
17/// Tmpfs Inode 实现
18///
19/// 文件数据直接存储在物理页中,按需分配
20pub struct TmpfsInode {
21    /// Inode 元数据
22    metadata: SpinLock<InodeMetadata>,
23
24    /// 文件数据页(稀疏存储)
25    /// 索引:页号 (offset / PAGE_SIZE)
26    /// 值:物理帧 (None 表示空洞)
27    data: Mutex<Vec<Option<Arc<FrameTracker>>>>,
28
29    /// 父目录(弱引用,避免循环引用)
30    parent: Mutex<Weak<TmpfsInode>>,
31
32    /// 子节点(仅对目录有效)
33    children: Mutex<BTreeMap<String, Arc<TmpfsInode>>>,
34
35    /// Tmpfs 统计信息(共享引用)
36    stats: Arc<Mutex<TmpfsStats>>,
37
38    /// 指向自身的弱引用(用于 lookup "." 和作为子节点的父节点)
39    self_ref: Mutex<Weak<TmpfsInode>>,
40}
41
42/// Tmpfs 统计信息
43#[derive(Debug, Clone)]
44pub struct TmpfsStats {
45    /// 已分配的总页数
46    pub allocated_pages: usize,
47
48    /// 最大允许的页数(0 表示无限制)
49    pub max_pages: usize,
50
51    /// 下一个 inode 编号
52    pub next_inode_no: usize,
53}
54
55impl TmpfsInode {
56    /// 创建新的 tmpfs inode(通用构造函数)
57    pub fn new(
58        inode_no: usize,
59        inode_type: InodeType,
60        mode: FileMode,
61        parent: Weak<TmpfsInode>,
62        stats: Arc<Mutex<TmpfsStats>>,
63    ) -> Arc<Self> {
64        let now = TimeSpec::now();
65
66        // 清除文件类型位,只保留权限位和特殊位
67        let mode = mode & !FileMode::S_IFMT;
68
69        // 根据 inode_type 设置正确的文件类型位
70        let mode = match inode_type {
71            InodeType::Directory => mode | FileMode::S_IFDIR,
72            InodeType::File => mode | FileMode::S_IFREG,
73            InodeType::Symlink => mode | FileMode::S_IFLNK,
74            InodeType::CharDevice => mode | FileMode::S_IFCHR,
75            InodeType::BlockDevice => mode | FileMode::S_IFBLK,
76            InodeType::Fifo => mode | FileMode::S_IFIFO,
77            InodeType::Socket => mode | FileMode::S_IFSOCK,
78        };
79
80        let metadata = InodeMetadata {
81            inode_no,
82            inode_type,
83            mode,
84            uid: 0,
85            gid: 0,
86            size: 0,
87            atime: now,
88            mtime: now,
89            ctime: now,
90            nlinks: if inode_type == InodeType::Directory {
91                2
92            } else {
93                1
94            }, // 目录默认2(.和..)
95            blocks: 0,
96            rdev: 0, // 设备节点会在 mknod 时设置
97        };
98
99        Arc::new(Self {
100            metadata: SpinLock::new(metadata),
101            data: Mutex::new(Vec::new()),
102            parent: Mutex::new(parent),
103            children: Mutex::new(BTreeMap::new()),
104            stats,
105            self_ref: Mutex::new(Weak::new()),
106        })
107    }
108
109    /// 创建根目录
110    pub fn new_root(stats: Arc<Mutex<TmpfsStats>>) -> Arc<Self> {
111        let stats_guard = stats.lock();
112        let inode_no = stats_guard.next_inode_no;
113        drop(stats_guard);
114
115        let mut stats_guard = stats.lock();
116        stats_guard.next_inode_no += 1;
117        drop(stats_guard);
118
119        let root = Self::new(
120            inode_no,
121            InodeType::Directory,
122            FileMode::S_IRUSR
123                | FileMode::S_IWUSR
124                | FileMode::S_IXUSR
125                | FileMode::S_IRGRP
126                | FileMode::S_IXGRP
127                | FileMode::S_IROTH
128                | FileMode::S_IXOTH,
129            Weak::new(),
130            stats,
131        );
132
133        // 设置自引用
134        *root.self_ref.lock() = Arc::downgrade(&root);
135
136        root
137    }
138
139    /// 分配新的 inode 编号
140    fn alloc_inode_no(&self) -> usize {
141        let mut stats = self.stats.lock();
142        let inode_no = stats.next_inode_no;
143        stats.next_inode_no += 1;
144        inode_no
145    }
146
147    /// 检查是否有足够的空间分配新页
148    fn can_alloc_pages(&self, num_pages: usize) -> bool {
149        let stats = self.stats.lock();
150        if stats.max_pages == 0 {
151            return true; // 无限制
152        }
153        stats.allocated_pages + num_pages <= stats.max_pages
154    }
155
156    /// 增加已分配页数
157    fn inc_allocated_pages(&self, num: usize) {
158        let mut stats = self.stats.lock();
159        stats.allocated_pages += num;
160    }
161
162    /// 减少已分配页数
163    fn dec_allocated_pages(&self, num: usize) {
164        let mut stats = self.stats.lock();
165        stats.allocated_pages = stats.allocated_pages.saturating_sub(num);
166    }
167
168    /// 更新访问时间
169    fn update_atime(&self) {
170        let mut meta = self.metadata.lock();
171        meta.atime = TimeSpec::now();
172    }
173
174    /// 更新修改时间
175    fn update_mtime(&self) {
176        let mut meta = self.metadata.lock();
177        let now = TimeSpec::now();
178        meta.mtime = now;
179        meta.ctime = now;
180    }
181
182    fn reserve_page(&self) -> Result<(), FsError> {
183        let mut stats = self.stats.lock();
184        if stats.max_pages != 0 && stats.allocated_pages >= stats.max_pages {
185            return Err(FsError::NoSpace);
186        }
187        stats.allocated_pages += 1;
188        Ok(())
189    }
190
191    fn cancel_page_reservation(&self) {
192        self.dec_allocated_pages(1);
193    }
194}
195
196impl Inode for TmpfsInode {
197    fn metadata(&self) -> Result<InodeMetadata, FsError> {
198        Ok(self.metadata.lock().clone())
199    }
200
201    fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, FsError> {
202        let meta = self.metadata.lock();
203
204        if meta.inode_type != InodeType::File {
205            return Err(FsError::IsDirectory);
206        }
207
208        if offset >= meta.size {
209            return Ok(0);
210        }
211
212        let read_size = buf.len().min(meta.size - offset);
213        drop(meta);
214
215        let mut bytes_read = 0;
216        let data = self.data.lock();
217
218        while bytes_read < read_size {
219            let page_index = (offset + bytes_read) / PAGE_SIZE;
220            let page_offset = (offset + bytes_read) % PAGE_SIZE;
221            let read_len = (PAGE_SIZE - page_offset).min(read_size - bytes_read);
222
223            // 如果页不存在,返回 0
224            if page_index >= data.len() || data[page_index].is_none() {
225                buf[bytes_read..bytes_read + read_len].fill(0);
226            } else {
227                // 通过内核直接映射读取
228                let frame = data[page_index].as_ref().unwrap();
229                let kernel_vaddr = frame.ppn().start_addr().to_vaddr();
230
231                unsafe {
232                    core::ptr::copy_nonoverlapping(
233                        (kernel_vaddr.as_usize() + page_offset) as *const u8,
234                        buf[bytes_read..].as_mut_ptr(),
235                        read_len,
236                    );
237                }
238            }
239
240            bytes_read += read_len;
241        }
242
243        self.update_atime();
244        Ok(bytes_read)
245    }
246
247    fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, FsError> {
248        let meta = self.metadata.lock();
249
250        if meta.inode_type != InodeType::File {
251            return Err(FsError::IsDirectory);
252        }
253
254        drop(meta);
255
256        let mut data = self.data.lock();
257        let mut bytes_written = 0;
258
259        while bytes_written < buf.len() {
260            let page_index = (offset + bytes_written) / PAGE_SIZE;
261            let page_offset = (offset + bytes_written) % PAGE_SIZE;
262            let write_len = (PAGE_SIZE - page_offset).min(buf.len() - bytes_written);
263
264            // 确保 Vec 足够大
265            if page_index >= data.len() {
266                data.resize(page_index + 1, None);
267            }
268
269            // 按需分配物理帧
270            if data[page_index].is_none() {
271                if self.reserve_page().is_err() {
272                    return Err(FsError::NoSpace);
273                }
274
275                match alloc_frame() {
276                    Some(frame) => {
277                        data[page_index] = Some(Arc::new(frame));
278                    }
279                    None => {
280                        // 如果物理帧分配失败,回滚预留的页面计数
281                        self.cancel_page_reservation();
282                        return Err(FsError::NoSpace);
283                    }
284                }
285            }
286
287            // 通过内核直接映射写入
288            let frame = data[page_index].as_ref().unwrap();
289            let kernel_vaddr = frame.ppn().start_addr().to_vaddr();
290
291            unsafe {
292                core::ptr::copy_nonoverlapping(
293                    buf[bytes_written..].as_ptr(),
294                    (kernel_vaddr.as_usize() + page_offset) as *mut u8,
295                    write_len,
296                );
297            }
298
299            bytes_written += write_len;
300        }
301
302        drop(data);
303
304        // 更新文件大小和时间
305        let mut meta = self.metadata.lock();
306        meta.size = meta.size.max(offset + bytes_written);
307        meta.blocks = (meta.size + 511) / 512; // 以 512B 为单位
308        drop(meta);
309
310        self.update_mtime();
311        Ok(bytes_written)
312    }
313
314    fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, FsError> {
315        let meta = self.metadata.lock();
316        if meta.inode_type != InodeType::Directory {
317            return Err(FsError::NotDirectory);
318        }
319        drop(meta);
320
321        let children = self.children.lock();
322
323        // 处理特殊目录项
324        if name == "." {
325            // 返回自身
326            let self_weak = self.self_ref.lock();
327            if let Some(self_arc) = self_weak.upgrade() {
328                return Ok(self_arc as Arc<dyn Inode>);
329            }
330            return Err(FsError::IoError); // 不应该发生
331        } else if name == ".." {
332            let parent = self.parent.lock();
333            if let Some(parent_arc) = parent.upgrade() {
334                return Ok(parent_arc as Arc<dyn Inode>);
335            }
336            // 根目录的 ".." 指向自己
337            let self_weak = self.self_ref.lock();
338            if let Some(self_arc) = self_weak.upgrade() {
339                return Ok(self_arc as Arc<dyn Inode>);
340            }
341            return Err(FsError::IoError); // 不应该发生
342        }
343
344        children
345            .get(name)
346            .cloned()
347            .map(|inode| inode as Arc<dyn Inode>)
348            .ok_or(FsError::NotFound)
349    }
350
351    fn create(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
352        let meta = self.metadata.lock();
353        if meta.inode_type != InodeType::Directory {
354            return Err(FsError::NotDirectory);
355        }
356        drop(meta);
357
358        let mut children = self.children.lock();
359
360        // 检查是否已存在
361        if children.contains_key(name) {
362            return Err(FsError::AlreadyExists);
363        }
364
365        // 创建新的 inode
366        let inode_no = self.alloc_inode_no();
367
368        // 获取自身的弱引用作为父节点
369        let parent_weak = self.self_ref.lock().clone();
370
371        let new_inode = TmpfsInode::new(
372            inode_no,
373            InodeType::File,
374            mode,
375            parent_weak,
376            self.stats.clone(),
377        );
378
379        // 设置新文件的自引用
380        *new_inode.self_ref.lock() = Arc::downgrade(&new_inode);
381
382        children.insert(String::from(name), new_inode.clone());
383        drop(children);
384
385        self.update_mtime();
386
387        Ok(new_inode as Arc<dyn Inode>)
388    }
389
390    fn mkdir(&self, name: &str, mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
391        let meta = self.metadata.lock();
392        if meta.inode_type != InodeType::Directory {
393            return Err(FsError::NotDirectory);
394        }
395        drop(meta);
396
397        let mut children = self.children.lock();
398
399        // 检查是否已存在
400        if children.contains_key(name) {
401            return Err(FsError::AlreadyExists);
402        }
403
404        // 创建新的目录 inode
405        let inode_no = self.alloc_inode_no();
406
407        // 获取自身的弱引用作为父节点
408        let parent_weak = self.self_ref.lock().clone();
409
410        let new_inode = TmpfsInode::new(
411            inode_no,
412            InodeType::Directory,
413            mode,
414            parent_weak,
415            self.stats.clone(),
416        );
417
418        // 设置新目录的自引用
419        *new_inode.self_ref.lock() = Arc::downgrade(&new_inode);
420
421        children.insert(String::from(name), new_inode.clone());
422        drop(children);
423
424        // 更新父目录的 nlinks(子目录的 .. 指向父目录)
425        let mut meta = self.metadata.lock();
426        meta.nlinks += 1;
427        drop(meta);
428
429        self.update_mtime();
430
431        Ok(new_inode as Arc<dyn Inode>)
432    }
433
434    fn unlink(&self, name: &str) -> Result<(), FsError> {
435        let meta = self.metadata.lock();
436        if meta.inode_type != InodeType::Directory {
437            return Err(FsError::NotDirectory);
438        }
439        drop(meta);
440
441        let mut children = self.children.lock();
442
443        // 检查是否存在
444        let child = children.get(name).ok_or(FsError::NotFound)?;
445
446        // 检查是否是目录
447        let child_meta = child.metadata.lock();
448        if child_meta.inode_type == InodeType::Directory {
449            return Err(FsError::IsDirectory);
450        }
451        drop(child_meta);
452
453        // 获取该 inode 的已分配页数
454        let child_data = child.data.lock();
455        let allocated = child_data.iter().filter(|f| f.is_some()).count();
456        drop(child_data);
457
458        // 删除
459        children.remove(name);
460        self.dec_allocated_pages(allocated);
461        self.update_mtime();
462
463        Ok(())
464    }
465
466    fn rmdir(&self, name: &str) -> Result<(), FsError> {
467        let meta = self.metadata.lock();
468        if meta.inode_type != InodeType::Directory {
469            return Err(FsError::NotDirectory);
470        }
471        drop(meta);
472
473        let mut children = self.children.lock();
474
475        // 检查是否存在
476        let child = children.get(name).ok_or(FsError::NotFound)?;
477
478        // 检查是否是目录
479        let child_meta = child.metadata.lock();
480        if child_meta.inode_type != InodeType::Directory {
481            return Err(FsError::NotDirectory);
482        }
483        drop(child_meta);
484
485        // 检查目录是否为空
486        let child_children = child.children.lock();
487        if !child_children.is_empty() {
488            return Err(FsError::DirectoryNotEmpty);
489        }
490        drop(child_children);
491
492        // 删除
493        children.remove(name);
494
495        // 更新父目录的 nlinks
496        let mut meta = self.metadata.lock();
497        meta.nlinks = meta.nlinks.saturating_sub(1);
498        drop(meta);
499
500        self.update_mtime();
501
502        Ok(())
503    }
504
505    fn readdir(&self) -> Result<Vec<DirEntry>, FsError> {
506        let meta = self.metadata.lock();
507        if meta.inode_type != InodeType::Directory {
508            return Err(FsError::NotDirectory);
509        }
510        let inode_no = meta.inode_no;
511        drop(meta);
512
513        let children = self.children.lock();
514        let mut entries = Vec::new();
515
516        // 添加 "." 和 ".."
517        entries.push(DirEntry {
518            name: String::from("."),
519            inode_no,
520            inode_type: InodeType::Directory,
521        });
522
523        let parent = self.parent.lock();
524        let parent_inode_no = if let Some(parent_arc) = parent.upgrade() {
525            parent_arc.metadata.lock().inode_no
526        } else {
527            inode_no // 根目录的 ".." 指向自己
528        };
529        drop(parent);
530
531        entries.push(DirEntry {
532            name: String::from(".."),
533            inode_no: parent_inode_no,
534            inode_type: InodeType::Directory,
535        });
536
537        // 添加子项
538        for (name, child) in children.iter() {
539            let child_meta = child.metadata.lock();
540            entries.push(DirEntry {
541                name: name.clone(),
542                inode_no: child_meta.inode_no,
543                inode_type: child_meta.inode_type,
544            });
545        }
546
547        Ok(entries)
548    }
549
550    fn truncate(&self, new_size: usize) -> Result<(), FsError> {
551        let mut meta = self.metadata.lock();
552
553        if meta.inode_type != InodeType::File {
554            return Err(FsError::IsDirectory);
555        }
556
557        let old_size = meta.size;
558
559        if new_size < old_size {
560            // 缩小:释放多余的页
561            let new_page_count = (new_size + PAGE_SIZE - 1) / PAGE_SIZE;
562            let old_page_count = (old_size + PAGE_SIZE - 1) / PAGE_SIZE;
563
564            let mut data = self.data.lock();
565
566            // 计算要释放的页数
567            let pages_to_free = data[new_page_count..old_page_count.min(data.len())]
568                .iter()
569                .filter(|f| f.is_some())
570                .count();
571
572            data.truncate(new_page_count);
573            drop(data);
574
575            self.dec_allocated_pages(pages_to_free);
576        }
577
578        meta.size = new_size;
579        meta.blocks = (new_size + 511) / 512;
580        drop(meta);
581
582        self.update_mtime();
583        Ok(())
584    }
585
586    fn sync(&self) -> Result<(), FsError> {
587        // tmpfs 完全在内存中,无需同步
588        Ok(())
589    }
590
591    fn as_any(&self) -> &dyn core::any::Any {
592        self
593    }
594
595    fn symlink(&self, name: &str, target: &str) -> Result<Arc<dyn Inode>, FsError> {
596        // 检查当前节点是否为目录
597        let meta = self.metadata.lock();
598        if meta.inode_type != InodeType::Directory {
599            return Err(FsError::NotDirectory);
600        }
601        drop(meta);
602
603        // 检查文件名是否已存在
604        let children = self.children.lock();
605        if children.contains_key(name) {
606            return Err(FsError::AlreadyExists);
607        }
608        drop(children);
609
610        // 分配新的 inode 编号
611        let mut stats = self.stats.lock();
612        let inode_no = stats.next_inode_no;
613        stats.next_inode_no += 1;
614        drop(stats);
615
616        // 创建符号链接 inode (默认权限 0o777)
617        let symlink_inode = TmpfsInode::new(
618            inode_no,
619            InodeType::Symlink,
620            FileMode::from_bits_truncate(0o777),
621            Arc::downgrade(&self.self_ref.lock().upgrade().unwrap()),
622            self.stats.clone(),
623        );
624
625        // 将目标路径写入符号链接文件的数据中
626        let target_bytes = target.as_bytes();
627        if let Err(e) = symlink_inode.write_at(0, target_bytes) {
628            return Err(e);
629        }
630
631        // 添加到父目录
632        self.children
633            .lock()
634            .insert(name.to_string(), symlink_inode.clone());
635
636        // 更新父目录的修改时间
637        self.metadata.lock().mtime = TimeSpec::now();
638
639        Ok(symlink_inode as Arc<dyn Inode>)
640    }
641
642    fn link(&self, _name: &str, _target: &Arc<dyn Inode>) -> Result<(), FsError> {
643        // TODO: 实现硬链接支持
644        Err(FsError::NotSupported)
645    }
646
647    fn rename(
648        &self,
649        _old_name: &str,
650        _new_parent: Arc<dyn Inode>,
651        _new_name: &str,
652    ) -> Result<(), FsError> {
653        // TODO: 实现重命名支持
654        Err(FsError::NotSupported)
655    }
656
657    fn set_times(&self, atime: Option<TimeSpec>, mtime: Option<TimeSpec>) -> Result<(), FsError> {
658        let mut metadata = self.metadata.lock();
659        if let Some(atime) = atime {
660            metadata.atime = atime;
661        }
662        if let Some(mtime) = mtime {
663            metadata.mtime = mtime;
664        }
665        Ok(())
666    }
667
668    fn readlink(&self) -> Result<String, FsError> {
669        // 检查是否为符号链接
670        let meta = self.metadata.lock();
671        if meta.inode_type != InodeType::Symlink {
672            return Err(FsError::InvalidArgument);
673        }
674        let size = meta.size;
675        drop(meta);
676
677        // 读取符号链接的目标路径
678        if size == 0 {
679            return Ok(String::new());
680        }
681
682        let mut buf = alloc::vec![0u8; size];
683        let bytes_read = self.read_at(0, &mut buf)?;
684
685        // 转换为字符串
686        String::from_utf8(buf[..bytes_read].to_vec()).map_err(|_| FsError::InvalidArgument)
687    }
688
689    fn mknod(&self, name: &str, mode: FileMode, dev: u64) -> Result<Arc<dyn Inode>, FsError> {
690        // 检查当前节点是否为目录
691        let meta = self.metadata.lock();
692        if meta.inode_type != InodeType::Directory {
693            return Err(FsError::NotDirectory);
694        }
695        drop(meta);
696
697        // 检查文件名是否已存在
698        let mut children = self.children.lock();
699        if children.contains_key(name) {
700            return Err(FsError::AlreadyExists);
701        }
702
703        // 从 mode 提取文件类型
704        let inode_type = if mode.contains(FileMode::S_IFCHR) {
705            InodeType::CharDevice
706        } else if mode.contains(FileMode::S_IFBLK) {
707            InodeType::BlockDevice
708        } else if mode.contains(FileMode::S_IFIFO) {
709            InodeType::Fifo
710        } else {
711            // mknod 只支持特殊文件
712            return Err(FsError::InvalidArgument);
713        };
714
715        // 分配新的 inode 号
716        let inode_no = self.alloc_inode_no();
717
718        // 获取父节点的弱引用
719        let parent_weak = self.self_ref.lock().clone();
720
721        // 创建新的 inode
722        let new_inode =
723            TmpfsInode::new(inode_no, inode_type, mode, parent_weak, self.stats.clone());
724
725        // 设置设备号 与 自引用
726        new_inode.metadata.lock().rdev = dev;
727        *new_inode.self_ref.lock() = Arc::downgrade(&new_inode);
728
729        // 添加到父目录的子节点
730        children.insert(String::from(name), new_inode.clone());
731        drop(children);
732
733        self.update_mtime();
734
735        Ok(new_inode as Arc<dyn Inode>)
736    }
737
738    fn chmod(&self, _mode: FileMode) -> Result<(), FsError> {
739        Err(FsError::NotSupported)
740    }
741
742    fn chown(&self, _uid: u32, _gid: u32) -> Result<(), FsError> {
743        Err(FsError::NotSupported)
744    }
745}