Files
erofs-freebsd-out-tree/docs/architecture.md
T
2026-08-13 10:44:59 +02:00

10 KiB
Raw Blame History

repo22 架构设计

设计目标

repo22 提供尽量贴近 Linux fs/erofs 职责划分的 FreeBSD 15 只读实现,同时对 FreeBSD vnode、GEOM、pager、dev_t 和 NFS FID 语义做 必要适配。

核心原则

  1. Linux 对齐:函数命名、文件组织、代码排序尽可能匹配 Linux 版本
  2. 最小抽象:避免不必要的封装层
  3. 安全优先:保留 repo19 的所有安全修复
  4. 可维护性:便于社区维护和与上游同步

文件组织

src/
├── super.c          - 超级块、挂载、VFS 集成
├── inode.c          - inode 读取和 vnode 管理
├── data.c           - 数据块映射和解压缩
├── namei.c          - 路径查找(二分搜索)
├── dir.c            - 目录遍历和输出
├── xattr.c          - 扩展属性和 ACL
├── erofs_vnops.c    - VFS vnode 操作实现
├── decompressor.c   - 压缩配置解析和统一调度
├── lz4.c            - FreeBSD 有界 LZ4 后端
├── decompressor_lzma.c    - MicroLZMA 后端
├── decompressor_deflate.c - DEFLATE 后端
├── decompressor_zstd.c    - 可选 ZSTDIO 后端
├── zmap.c           - 压缩逻辑块映射
├── zdata.c          - 压缩数据读取
├── internal.h       - 内存结构和内部 API
├── erofs_fs.h       - 磁盘格式定义
├── xattr.h          - 扩展属性接口
└── erofs_defs.h     - 常量定义

分层架构

┌─────────────────────────────────────┐
│  VFS 层 (FreeBSD kernel)            │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│  VFS 接口层                          │
│  - erofs_vnops.c                    │
│  - super.c (mount/unmount/root)     │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│  文件系统逻辑层                      │
│  - inode.c (erofs_read_inode)       │
│  - namei.c (erofs_namei)            │
│  - dir.c (erofs_readdir_block)      │
│  - xattr.c (erofs_getxattr)         │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│  数据访问层                          │
│  - data.c (erofs_map_blocks)        │
│  - data.c (erofs_read_data)         │
│  - zmap.c / zdata.c                 │
│  - decompressor.c (z_erofs_decompress) │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│  块 I/O 层                           │
│  - erofs_bread/erofs_brelse         │
└─────────────────────────────────────┘

核心数据结构

erofs_mount (内存中的文件系统状态)

struct erofs_mount {
    struct mount *mnt;           // FreeBSD mount 结构
    struct vnode *devvp;         // 块设备 vnode
    struct g_consumer *cp;       // GEOM consumer
    
    uint32_t block_size;         // 块大小
    uint64_t root_nid;           // 根目录 NID
    uint32_t feature_compat;     // 特性标志
    uint32_t feature_incompat;
    
    struct erofs_sb_lz4_info lz4;     // LZ4 参数
    struct erofs_deviceslot *devs;    // 设备表
    struct erofs_xattr_prefix_item *xattr_prefixes;  // xattr 前缀表
};

erofs_node (内存中的 inode)

struct erofs_node {
    struct vnode *vnode;         // 关联的 vnode
    uint64_t nid;                // 节点 ID
    uint64_t size;               // 文件大小
    uint8_t datalayout;          // 数据布局类型
    
    // 压缩相关
    uint8_t z_algorithmformat;
    uint8_t z_lclusterbits;
    
    // Chunk-based 相关
    uint16_t chunkformat;
    uint8_t chunkbits;
    
    // Fragment 相关
    uint32_t fragmentoff;
    bool fragment;
};

关键实现细节

1. 数据布局支持

支持 4 种数据布局:

  • FLAT_PLAIN: 连续块
  • FLAT_INLINE: 最后一个逻辑块位于 inode metadata block 内,且受声明 image/metabox bounds 约束
  • CHUNK_BASED: 固定大小 chunk,支持稀疏文件
  • COMPRESSED: 可变大小压缩 cluster

2. 压缩算法

支持 4 种压缩算法及未压缩 transform:

  • LZ4 (LZ4HC)
  • LZMA
  • DEFLATE
  • ZSTD
  • 未压缩

3. 高级特性

  • ztailpacking: 压缩文件尾部内联
  • fragments: 已验证的 fragment-backed 压缩文件与 metabox carrier
  • ⚠️ dedupe: 仅声明已验证的 fragment/partial-reference 形式,不宣称 覆盖所有未来编码
  • xattr_prefixes: 共享 xattr 前缀表
  • device_table: 多设备支持
  • metabox: 每 inode 元数据盒

4. 安全机制

repo22 的边界策略:

  • 所有指针操作前检查边界
  • 所有算术运算检查溢出
  • 所有分配检查大小合理性
  • 递归深度限制
  • 设备 ID 和块地址验证

与 Linux 版本的差异

对照基线

本轮维护逐文件对照工作区中的 /work/dev-src-linux/fs/erofs。该目录是导入的 Linux 7.1-rc1 EROFS 参考快照;对照不依赖 repo22 与 Linux 树具有共同 Git 历史。/work/linux-src/fs/erofs 中对应文件与该精简快照字节一致,但不是本轮 文件映射的依据。

必要差异(FreeBSD 适配)

  1. 内存分配:使用 malloc(..., M_EROFS, ...) 而非 kmalloc()
  2. 块 I/O:通过 GEOM consumer 和 FreeBSD vnode/buffer 接口读取 provider
  3. VFS 接口erofs_vnops.c 实现 FreeBSD vop_vector,不照搬 Linux inode_operations、folio 或 iomap 接口
  4. 错误约定:内核入口返回正的 FreeBSD errnoLinux 负 errno 或 ERR_PTR 仅作为算法对照,不能机械移植
  5. 压缩后端BSD 调度器跨编译单元调用 internal.h 中的简单后端 API; Linux 使用 struct z_erofs_decompressor 和不同的内存/页面生命周期
  6. LZ4 文件职责BSD 保留独立 lz4.c 有界解码器;Linux LZ4 路径位于 decompressor.c 并依赖 Linux 内核 LZ4/page API
  7. 平台特性Linux sysfs.cfileio.cfscache.cishare.czutil.c 没有无条件对应物,不为文件外观引入空包装
  8. 构建架构:当前只验证 FreeBSD 15 amd64Makefile 明确拒绝其他 MACHINE_ARCH

保持一致的部分

  • 静态目录 helper 使用 Linux 名称 find_target_dirent
  • LZMA、DEFLATE、ZSTD 后端使用 Linux 文件名 decompressor_*.c
  • Makefile 先列 metadata/VFS 文件,再列压缩调度、映射和后端文件
  • 跨文件后端声明集中在 internal.h,不在调用方手写 extern
  • erofs_fs.h 的磁盘格式定义和核心目录/映射算法按 Linux 语义核对

代码规范

命名约定

  • 公共函数:erofs_<module>_<action>
  • 静态函数:描述性名称,无固定前缀
  • 宏:EROFS_* 全大写
  • 结构体:struct erofs_*

函数排序(每个文件)

  1. 辅助函数(static
  2. 核心逻辑函数
  3. VFS 接口函数
  4. 模块注册/清理(仅 super.c

错误处理

int erofs_function(...)
{
    int error = 0;
    void *buf = NULL;
    
    // 操作...
    if (条件) {
        error = EINVAL;
        goto fail;
    }
    
    // ...
    return 0;
    
fail:
    if (buf)
        erofs_brelse(buf);
    return error;
}

测试策略

单元测试

不存在受支持的用户态单元测试入口。旧的 src/Makefile.test 从错误目录引用 test_decompress.c,并尝试把内核解压源码按不匹配的用户态 ABI 链接;该入口已 删除,不能作为可运行测试或 feature 验证证据。

旧的 test_super.ctest_inode.c 只重复了测试文件中的公式,并未调用 内核生产解析路径,其中 inode harness 还引用过已删除的磁盘字段。它们已退役, 不得作为 feature 验证证据。superblock、inode、pager 和错误路径必须使用 TC*.md 中的确定性镜像,经 FreeBSD 内核模块实际挂载或访问验证。

集成测试

仓库根目录遗留的 test_all_decompress.shtest_chunk_based.sh 包含其他 repo 的硬编码路径,不能作为 repo22 的测试入口或验收证据。受支持的验证方式是 直接执行 tests/TC*.md 中记录的 FreeBSD 15 内核步骤,并将命令、errno、哈希和 清理状态写入 tests/results/manual/ 下的日期报告。

VM 测试

  • 挂载真实镜像
  • 文件读取验证
  • 性能基准测试

维护指南

同步上游 Linux 变更

  1. 选定明确的 Linux fs/erofs 快照;当前工作区基线为 /work/dev-src-linux/fs/erofs
  2. 逐文件识别修改,不假设两个实现共享提交历史
  3. 检查是否为磁盘格式变更(erofs_fs.h)或 Linux 专属 VFS/page API
  4. 只移植语义上适用的算法,并保留 FreeBSD errno、锁、GEOM 和 vnode 约定
  5. 运行双配置构建、模块加载和真实镜像挂载测试

添加新特性

  1. erofs_fs.h 添加磁盘格式定义
  2. internal.h 添加内存结构
  3. 实现解析逻辑(data.c/inode.c
  4. 添加确定性 fixture 和对应的 TC*.md 内核测试
  5. 更新文档

性能考虑

  • 零拷贝:直接从缓冲区缓存读取
  • 延迟加载:仅在需要时读取 inode 元数据
  • 缓存友好:利用 FreeBSD 的 vnode 缓存
  • 批量操作:目录读取一次性处理多个条目

已知限制

  • 不支持写操作(只读文件系统)
  • 不支持 FUSE 模式
  • 构建和运行时验证目前仅覆盖 FreeBSD 15 amd64
  • 不实现 Linux file-backed、fscache、page-cache sharing 或 sysfs 控制面