|
| 1 | +--- |
| 2 | +sidebar_position: 2 |
| 3 | +--- |
| 4 | + |
| 5 | +# 组件设计 |
| 6 | + |
| 7 | +## 组件概述 |
| 8 | +AxFS(ArceOS File System)是 AxVisor 虚拟化平台的核心文件系统组件,负责为操作系统内核和应用提供统一的文件系统访问接口。它作为虚拟化环境中的存储抽象层,支持多种文件系统类型(Ext4、FAT32、RAMFS等),并为用户空间提供类POSIX的文件操作API。 |
| 9 | + |
| 10 | +主要职责为: |
| 11 | + |
| 12 | +1. **统一文件系统抽象**:为不同类型的底层文件系统提供统一的VFS(虚拟文件系统)接口 |
| 13 | +2. **多文件系统支持**:支持Ext4、FAT32、内存文件系统等多种文件系统并行运行 |
| 14 | +3. **挂载点管理**:管理多文件系统的挂载和卸载,提供统一的命名空间 |
| 15 | +4. **路径解析**:提供路径解析、规范化和跨挂载点查找功能 |
| 16 | +5. **权限控制**:基于能力的访问控制机制,确保文件操作的安全性 |
| 17 | +6. **设备抽象**:为块设备提供统一接口,支持从GPT分区表动态发现和挂载分区 |
| 18 | + |
| 19 | + |
| 20 | +## 核心概念 |
| 21 | + |
| 22 | +### VFS 抽象 |
| 23 | + |
| 24 | +AXFS 基于外部 crate `axfs_vfs` 提供的 VFS 抽象: |
| 25 | + |
| 26 | +```rust |
| 27 | +// 文件系统操作接口 |
| 28 | +pub trait VfsOps { |
| 29 | + fn root_dir(&self) -> VfsNodeRef; |
| 30 | + fn mount(&self, mount_point: &str, parent: VfsNodeRef) -> VfsResult<()>; |
| 31 | + fn umount(&self) -> VfsResult<()>; |
| 32 | +} |
| 33 | + |
| 34 | +// 文件/目录节点操作接口 |
| 35 | +pub trait VfsNodeOps { |
| 36 | + fn get_attr(&self) -> VfsResult<VfsNodeAttr>; |
| 37 | + fn lookup(self: Arc<Self>, path: &str) -> VfsResult<VfsNodeRef>; |
| 38 | + fn create(&self, path: &str, ty: VfsNodeType) -> VfsResult; |
| 39 | + fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize>; |
| 40 | + fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult<usize>; |
| 41 | + // ... |
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | +**设计要点**: |
| 46 | +- 所有文件系统必须实现 `VfsOps` trait |
| 47 | +- 所有文件/目录节点必须实现 `VfsNodeOps` trait |
| 48 | +- 返回类型为 `Arc<dyn VfsNodeOps>`,支持动态分发 |
| 49 | + |
| 50 | +### 挂载点管理 |
| 51 | + |
| 52 | +根文件系统通过 `RootDirectory` 统一管理多个挂载点: |
| 53 | + |
| 54 | +```rust |
| 55 | +pub struct RootDirectory { |
| 56 | + main_fs: Arc<dyn VfsOps>, // 主文件系统 |
| 57 | + mounts: Vec<MountPoint>, // 挂载点列表 |
| 58 | +} |
| 59 | + |
| 60 | +struct MountPoint { |
| 61 | + path: String, // 挂载点路径 |
| 62 | + fs: Arc<dyn VfsOps>, // 挂载的文件系统 |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +**设计要点**: |
| 67 | +- 主文件系统 (`main_fs`) 通常是第一个挂载的分区或 ramfs |
| 68 | +- 路径解析时优先匹配最长前缀的挂载点 |
| 69 | +- 当前目录跟踪 (`CURRENT_DIR_PATH`,`CURRENT_DIR`) |
| 70 | + |
| 71 | +### 设备抽象 |
| 72 | + |
| 73 | +块设备通过 `Disk` 和 `Partition` 两层抽象: |
| 74 | + |
| 75 | +```rust |
| 76 | +// 完整磁盘设备 |
| 77 | +pub struct Disk { |
| 78 | + block_id: u64, // 当前块号 |
| 79 | + offset: usize, // 块内偏移 |
| 80 | + dev: Arc<Mutex<AxBlockDevice>>, // 底层块设备 |
| 81 | +} |
| 82 | + |
| 83 | +// 分区设备(磁盘切片) |
| 84 | +pub struct Partition { |
| 85 | + inner: Arc<Disk>, // 关联的磁盘 |
| 86 | + start_lba: u64, // 起始 LBA |
| 87 | + end_lba: u64, // 结束 LBA |
| 88 | +} |
| 89 | + |
| 90 | +impl Partition { |
| 91 | + pub fn new(disk: Arc<Disk>, start_lba: u64, size_bytes: u64) -> Self { ... } |
| 92 | + pub fn read_one(&mut self, buf: &mut [u8]) -> DevResult<usize> { ... } |
| 93 | + pub fn write_one(&mut self, buf: &[u8]) -> DevResult<usize> { ... } |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +**设计要点**: |
| 98 | +- `Partition` 复用 `Disk` 实现,通过 LBA 偏移转发 |
| 99 | +- 统一 `read_one` / `write_one` 接口 |
| 100 | +- 512 字节块大小对齐 |
| 101 | + |
| 102 | +### 分区扫描与检测 |
| 103 | + |
| 104 | +通过 GPT 分区表解析和文件系统魔数识别: |
| 105 | + |
| 106 | +```rust |
| 107 | +pub fn scan_gpt_partitions(disk: &mut Disk) -> AxResult<Vec<PartitionInfo>> { |
| 108 | + // 1. 尝试解析 GPT |
| 109 | + match parse_gpt_partitions(disk) { |
| 110 | + Ok(partitions) if !partitions.is_empty() => return Ok(partitions), |
| 111 | + Ok(_) => { /* 尝试 MBR */ } |
| 112 | + Err(_) => { /* 尝试 MBR */ } |
| 113 | + } |
| 114 | + // 2. 解析 MBR |
| 115 | + parse_mbr_partitions(disk) |
| 116 | +} |
| 117 | + |
| 118 | +pub enum FilesystemType { |
| 119 | + Fat, // FAT32/FAT16 |
| 120 | + Ext4, // ext4/ext3/ext2 |
| 121 | + Unknown, |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +**检测策略**: |
| 126 | +1. 读取分区前几个扇区 |
| 127 | +2. 识别 FAT32 (0xEB, 0xAA, 0x55) 和 ext4 (0x53, 0xEF) 魔数 |
| 128 | +3. 填充 `PartitionInfo.filesystem_type` |
| 129 | + |
| 130 | +### OpenOptions 配置 |
| 131 | + |
| 132 | +文件打开选项通过 `OpenOptions` 结构体配置: |
| 133 | + |
| 134 | +```rust |
| 135 | +pub struct OpenOptions { |
| 136 | + read: bool, // 可读 |
| 137 | + write: bool, // 可写 |
| 138 | + append: bool, // 追加模式 |
| 139 | + truncate: bool, // 截断(清空)文件 |
| 140 | + create: bool, // 文件不存在则创建 |
| 141 | + create_new: bool, // 强制创建新文件(已存在则失败) |
| 142 | + _custom_flags: i32, // 系统特定标志 |
| 143 | + _mode: u32, // 文件权限模式 |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +**权限模型**: |
| 148 | +- 基于 `cap_access` crate 的能力令牌 |
| 149 | +- 打开时捕获令牌、后续操作验证权限 |
| 150 | + |
| 151 | + |
| 152 | +## API 设计 |
| 153 | + |
| 154 | +### 高级 API (api/) |
| 155 | + |
| 156 | +提供 `std::fs` 风格的接口: |
| 157 | + |
| 158 | +```rust |
| 159 | +// 文件操作 |
| 160 | +pub fn read(path: &str) -> io::Result<Vec<u8>> |
| 161 | +pub fn read_to_string(path: &str) -> io::Result<String> |
| 162 | +pub fn write(path: &str, contents: C) -> io::Result<()> |
| 163 | +pub fn metadata(path: &str) -> io::Result<Metadata> |
| 164 | + |
| 165 | +// 目录操作 |
| 166 | +pub fn read_dir(path: &str) -> io::Result<ReadDir> |
| 167 | +pub fn create_dir(path: &str) -> io::Result<()> |
| 168 | +pub fn remove_dir(path: &str) -> io::Result<()> |
| 169 | +pub fn remove_file(path: &str) -> io::Result<()> |
| 170 | + |
| 171 | +// 路径操作 |
| 172 | +pub fn canonicalize(path: &str) -> io::Result<String> |
| 173 | +pub fn current_dir() -> io::Result<String> |
| 174 | +pub fn set_current_dir(path: &str) -> io::Result<()> |
| 175 | +``` |
| 176 | + |
| 177 | +### 低级 API (fops.rs) |
| 178 | + |
| 179 | +提供带权限的文件操作: |
| 180 | + |
| 181 | +```rust |
| 182 | +pub struct File { |
| 183 | + node: WithCap<VfsNodeRef>, // 带权限令牌的节点 |
| 184 | + is_append: bool, |
| 185 | + offset: u64, |
| 186 | +} |
| 187 | + |
| 188 | +impl File { |
| 189 | + pub fn open(path: &str) -> io::Result<Self>; |
| 190 | + pub fn create(path: &str) -> io::Result<Self>; |
| 191 | + pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>; |
| 192 | + pub fn write(&mut self, buf: &[u8]) -> io::Result<usize>; |
| 193 | + pub fn seek(&mut self, pos: SeekFrom) -> io::Result<u64>; |
| 194 | +} |
| 195 | + |
| 196 | +pub struct Directory { |
| 197 | + node: WithCap<VfsNodeRef>, |
| 198 | + entry_idx: usize, |
| 199 | +} |
| 200 | + |
| 201 | +impl Directory { |
| 202 | + pub fn open(path: &str) -> io::Result<Self>; |
| 203 | + pub fn read_entry(&mut self) -> io::Result<Option<DirEntry>>; |
| 204 | +} |
| 205 | +``` |
| 206 | + |
| 207 | + |
| 208 | +## 组件依赖 |
| 209 | + |
| 210 | + |
| 211 | +axfs 尽量保证对其他组件较少的依赖程度,仅依赖于 axdriver、axio、axfs_vfs 等核心组件,且其他组件的依赖关系尽量简单,以降低组件之间的耦合度,提高系统的可维护性和可扩展性。大部分依赖库为自主开发,部分依赖库为第三方开源通用库。 |
| 212 | + |
| 213 | +### 自主依赖库 |
| 214 | +- axdriver:提供统一的设备驱动抽象层,为块设备提供标准化的接口,是文件系统与硬件设备之间的桥梁 |
| 215 | + |
| 216 | +- axdriver_block:提供块设备驱动接口,支持块设备的读写操作 |
| 217 | + |
| 218 | +- axio:输入输出抽象层,提供统一的I/O操作接口,支持内存分配 |
| 219 | + |
| 220 | +- axfs_vfs:虚拟文件系统层,提供统一的文件系统抽象接口,支持多种文件系统的挂载和操作 |
| 221 | + |
| 222 | +- fatfs:FAT文件系统具体实现,提供对FAT32文件系统的支持 |
| 223 | + |
| 224 | +- rsext4:ext4文件系统的具体实现,提供对ext4文件系统的读写等功能的支持 |
| 225 | + |
| 226 | +- axfs_ramfs:内存文件系统,提供基于内存的文件系统实现,用于临时文件存储 |
| 227 | + |
| 228 | +- axerrno:提供统一的错误处理机制,定义文件系统操作中的错误类型和处理方式 |
| 229 | + |
| 230 | +## 第三方通用库 |
| 231 | + |
| 232 | +- cap_access:提供能力访问控制,管理文件系统访问权限 |
| 233 | + |
| 234 | +- lazyinit:提供延迟初始化机制,优化系统启动性能,按需初始化 |
| 235 | + |
| 236 | +- spin:提供自旋锁实现,在多核环境下保护共享数据 |
| 237 | + |
| 238 | +- log:提供日志记录功能,记录文件系统操作和调试信息 |
0 commit comments