Skip to content

构建新虚拟文件系统axvfs #343

@Josen-B

Description

@Josen-B

https://github.com/arceos-hypervisor/axvfs

设计目标

创建一个统一、通用、功能完整的 VFS,要求:

​ ✅ 支持相对路径操作(通过文件/目录句柄)

​ ✅ 提供完整的元数据接口

​ ✅ 支持软链接和硬链接

​ ✅ 解决并发访问问题

​ ✅ 通用性:三个平台都能方便接入

​ ✅ 简洁性:接口设计清晰,易于实现

结合 axfs_vfsaxfs-ng-vfs,实现统一的虚拟文件系统 axvfs,具有标准通用的接口,arceos,starry和axvisor 分别实现对应的 api 层接入 axvfs

Image

对文件或路径的操作依然通过std进入arceos_api,然后下层的实现是一套统一的实现方案。

如果有对于starry或axvisor特有的结构或接口,可以通过feature (monolithic & hypervisor)控制。

代码结构

axvfs/
├── Cargo.toml
├── README.md          # 使用指南
└── src/
    ├── file_handle.rs # 文件句柄
    ├── dir_handle.rs  # 目录句柄
    ├── types.rs       # 核心类型
    ├── traits.rs      # Trait 定义
    ├── path.rs        # 路径操作
    ├── mount.rs       # 挂载管理
    └── lib.rs         # 主库文件

核心模块设计

1. 核心类型 (types.rs)

定义文件系统的基础类型:

// 节点类型
pub enum NodeType {
    RegularFile, Directory, Symlink,
    CharDevice, BlockDevice, Fifo, Socket
}

// 权限模式 (POSIX 风格)
pub struct NodePermission: u16 {
    OWNER_READ, OWNER_WRITE, OWNER_EXEC,
    GROUP_READ, GROUP_WRITE, GROUP_EXEC,
    OTHER_READ, OTHER_WRITE, OTHER_EXEC,
    SET_UID, SET_GID, STICKY
}

// 完整元数据
pub struct Metadata {
    device: u64,           // 设备 ID
    inode: u64,            // inode 号
    nlink: u64,            // 硬链接计数
    mode: NodePermission,  // 权限
    node_type: NodeType,   // 节点类型
    uid: u32,              // 所有者用户 ID
    gid: u32,              // 所有者组 ID
    size: u64,             // 大小
    block_size: u64,       // 块大小
    blocks: u64,           // 分配的块数
    rdev: DeviceId,        // 设备 ID(特殊文件)
    atime: Duration,       // 访问时间
    mtime: Duration,       // 修改时间
    ctime: Duration,       // 状态改变时间
}

2. 核心 Trait (traits.rs)

FilesystemOps Trait

文件系统操作接口:

pub trait FilesystemOps: Send + Sync {
    fn name(&self) -> &str;                           // 文件系统名称
    fn statfs(&self) -> VfsResult<FileSystemInfo>;    // 文件系统统计
    fn sync(&self) -> VfsResult<()>;                  // 同步
    fn mount(&self, mount_point: &str) -> VfsResult<()>; // 挂载
    fn unmount(&self) -> VfsResult<()>;               // 卸载
    fn root(&self) -> Arc<dyn VnodeOps>;              // 根目录
}

VnodeOps Trait

虚拟节点操作接口:

pub trait VnodeOps: Send + Sync + Any {
    // 基本信息
    fn filesystem(&self) -> &Arc<dyn FilesystemOps>;
    fn inode(&self) -> u64;
    fn node_type(&self) -> NodeType;
    fn metadata(&self) -> VfsResult<Metadata>;
    fn set_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
    fn parent(&self) -> VfsResult<Option<Arc<dyn VnodeOps>>>;
    fn sync(&self, data_only: bool) -> VfsResult<()>;

    // 文件操作
    fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize>;
    fn write_at(&self, offset: u64, buf: &[u8]) -> VfsResult<usize>;
    fn truncate(&self, size: u64) -> VfsResult<()>;

    // 目录操作
    fn lookup(&self, name: &str) -> VfsResult<Arc<dyn VnodeOps>>;
    fn create(&self, name: &str, node_type: NodeType, mode: NodePermission)
        -> VfsResult<Arc<dyn VnodeOps>>;
    fn remove(&self, name: &str) -> VfsResult<()>;
    fn link(&self, name: &str, target: &Arc<dyn VnodeOps>) -> VfsResult<()>;
    fn unlink(&self, name: &str) -> VfsResult<()>;
    fn symlink(&self, name: &str, target: &str) -> VfsResult<()>;
    fn readlink(&self) -> VfsResult<String>;
    fn rename(&self, old_name: &str, new_dir: &Arc<dyn VnodeOps>, new_name: &str)
        -> VfsResult<()>;
    fn readdir(&self, offset: usize, sink: &mut dyn DirEntrySink) -> VfsResult<usize>;
    fn mkdir(&self, name: &str, mode: NodePermission) -> VfsResult<Arc<dyn VnodeOps>>;
    fn rmdir(&self, name: &str) -> VfsResult<()>;
}

3. 文件/目录句柄 (file_handle.rs, dir_handle.rs)

FileHandle

支持位置跟踪的文件描述符:

pub struct FileHandle {
    vnode: Vnode,                      // 关联的 vnode
    offset: AtomicU64,                 // 当前位置(原子操作,并发安全)
    flags: OpenFlags,                  // 打开标志
    id: u64,                          // 句柄 ID
}

impl FileHandle {
    pub fn read(&self, buf: &mut [u8]) -> VfsResult<usize>;
    pub fn write(&self, buf: &[u8]) -> VfsResult<usize>;
    pub fn seek(&self, offset: i64, whence: u8) -> VfsResult<u64>;
    pub fn truncate(&self, size: u64) -> VfsResult<()>;
    pub fn sync(&self, data_only: bool) -> VfsResult<()>;
}

DirHandle

支持相对路径操作的目录描述符:

pub struct DirHandle {
    vnode: Vnode,                      // 关联的目录 vnode
    offset: AtomicU64,                 // 读取位置
    id: u64,
}

impl DirHandle {
    // 相对路径操作
    pub fn lookup(&self, name: &str) -> VfsResult<Vnode>;
    pub fn create_file(&self, name: &str, mode: NodePermission)
        -> VfsResult<Vnode>;
    pub fn create_dir(&self, name: &str, mode: NodePermission)
        -> VfsResult<Vnode>;
    pub fn readdir(&self) -> VfsResult<Vec<DirEntry>>;
    pub fn symlink(&self, name: &str, target: &str) -> VfsResult<()>;
    pub fn readlink(&self, name: &str) -> VfsResult<String>;
    pub fn rename(&self, old_name: &str, new_dir: &DirHandle, new_name: &str)
        -> VfsResult<()>;
}

相对路径示例

// openat 等价操作
fn sys_openat(dirfd: i32, path: &str, flags: OpenFlags) -> VfsResult<i32> {
    let vnode = if path.starts_with('/') {
        // 绝对路径
        mount_mgr.lookup(Path::new(path))?
    } else {
        // 相对路径 - 使用 dir_handle
        let dir_handle = dir_table.get(dirfd as usize)?;
        dir_handle.lookup(path)?
    };
    Ok(file_table.insert(FileHandle::new(vnode, flags)?)? as i32)
}

4. 路径操作 (path.rs)

完整的路径解析和操作功能:

pub struct Path {
    inner: str,
}

pub struct PathBuf {
    inner: String,
}

impl Path {
    pub fn components(&self) -> Components;
    pub fn parent(&self) -> Option<&Path>;
    pub fn file_name(&self) -> Option<&str>;
    pub fn join(&self, path: &Path) -> PathBuf;
    pub fn normalize(&self) -> PathBuf;  // 处理 . 和 ..
    pub fn is_absolute(&self) -> bool;
}

5. 挂载管理 (mount.rs)

管理多个文件系统的挂载和路径解析:

pub struct MountManager {
    mounts_by_device: Mutex<BTreeMap<u64, Arc<MountPoint>>>,
    mounts_by_path: Mutex<BTreeMap<String, Arc<MountPoint>>>,
    root_mount: Mutex<Option<Arc<MountPoint>>>,
}

impl MountManager {
    pub fn set_root(&self, filesystem: Arc<dyn FilesystemOps>) -> VfsResult<()>;
    pub fn mount(&self, mount_path: &Path, filesystem: Arc<dyn FilesystemOps>)
        -> VfsResult<Arc<MountPoint>>;
    pub fn unmount(&self, mount_path: &Path) -> VfsResult<()>;
    pub fn resolve_mount(&self, path: &Path) -> VfsResult<Arc<MountPoint>>;
    pub fn lookup(&self, path: &Path) -> VfsResult<Vnode>;
    pub fn statfs(&self, path: &Path) -> VfsResult<FileSystemInfo>;
    pub fn build_path(&self, mount: &MountPoint, vnode: &Vnode) -> VfsResult<PathBuf>;
}

关键实现:

  • resolve_mount(): 查找最长匹配的挂载点
  • lookup(): 解析路径到 vnode,支持挂载点跨越
  • build_path(): 从 vnode 向上遍历构建完整路径,用于目录句柄的相对路径操作

6. 文件表和目录表 (file_handle.rs, dir_handle.rs)

管理打开的文件和目录描述符:

pub struct FileTable {
    handles: Mutex<Vec<Option<Arc<FileHandle>>>>,
}

impl FileTable {
    pub fn new() -> Self;
    pub fn insert(&self, file: FileHandle) -> VfsResult<usize>;
    pub fn get(&self, fd: usize) -> VfsResult<Arc<FileHandle>>;
    pub fn remove(&self, fd: usize) -> VfsResult<()>;
}

pub struct DirTable {
    handles: Mutex<Vec<Option<Arc<DirHandle>>>>,
}

impl DirTable {
    pub fn new() -> Self;
    pub fn insert(&self, dir: DirHandle) -> VfsResult<usize>;
    pub fn get(&self, fd: usize) -> VfsResult<Arc<DirHandle>>;
    pub fn remove(&self, fd: usize) -> VfsResult<()>;
}

特性:

  • 线程安全的句柄管理
  • 支持 fd 分配和释放
  • 支持句柄克隆和共享

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions