10 KiB
repo22 架构设计
设计目标
repo22 提供尽量贴近 Linux fs/erofs 职责划分的 FreeBSD 15
只读实现,同时对 FreeBSD vnode、GEOM、pager、dev_t 和 NFS FID 语义做
必要适配。
核心原则
- Linux 对齐:函数命名、文件组织、代码排序尽可能匹配 Linux 版本
- 最小抽象:避免不必要的封装层
- 安全优先:保留 repo19 的所有安全修复
- 可维护性:便于社区维护和与上游同步
文件组织
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 适配)
- 内存分配:使用
malloc(..., M_EROFS, ...)而非kmalloc() - 块 I/O:通过 GEOM consumer 和 FreeBSD vnode/buffer 接口读取 provider
- VFS 接口:
erofs_vnops.c实现 FreeBSDvop_vector,不照搬 Linuxinode_operations、folio 或 iomap 接口 - 错误约定:内核入口返回正的 FreeBSD errno;Linux 负 errno 或
ERR_PTR仅作为算法对照,不能机械移植 - 压缩后端:BSD 调度器跨编译单元调用
internal.h中的简单后端 API; Linux 使用struct z_erofs_decompressor和不同的内存/页面生命周期 - LZ4 文件职责:BSD 保留独立
lz4.c有界解码器;Linux LZ4 路径位于decompressor.c并依赖 Linux 内核 LZ4/page API - 平台特性:Linux
sysfs.c、fileio.c、fscache.c、ishare.c和zutil.c没有无条件对应物,不为文件外观引入空包装 - 构建架构:当前只验证 FreeBSD 15 amd64,Makefile 明确拒绝其他
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_*
函数排序(每个文件)
- 辅助函数(static)
- 核心逻辑函数
- VFS 接口函数
- 模块注册/清理(仅 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.c 和 test_inode.c 只重复了测试文件中的公式,并未调用
内核生产解析路径,其中 inode harness 还引用过已删除的磁盘字段。它们已退役,
不得作为 feature 验证证据。superblock、inode、pager 和错误路径必须使用
TC*.md 中的确定性镜像,经 FreeBSD 内核模块实际挂载或访问验证。
集成测试
仓库根目录遗留的 test_all_decompress.sh 和 test_chunk_based.sh 包含其他
repo 的硬编码路径,不能作为 repo22 的测试入口或验收证据。受支持的验证方式是
直接执行 tests/TC*.md 中记录的 FreeBSD 15 内核步骤,并将命令、errno、哈希和
清理状态写入 tests/results/manual/ 下的日期报告。
VM 测试
- 挂载真实镜像
- 文件读取验证
- 性能基准测试
维护指南
同步上游 Linux 变更
- 选定明确的 Linux
fs/erofs快照;当前工作区基线为/work/dev-src-linux/fs/erofs - 逐文件识别修改,不假设两个实现共享提交历史
- 检查是否为磁盘格式变更(
erofs_fs.h)或 Linux 专属 VFS/page API - 只移植语义上适用的算法,并保留 FreeBSD errno、锁、GEOM 和 vnode 约定
- 运行双配置构建、模块加载和真实镜像挂载测试
添加新特性
- 在
erofs_fs.h添加磁盘格式定义 - 在
internal.h添加内存结构 - 实现解析逻辑(data.c/inode.c)
- 添加确定性 fixture 和对应的
TC*.md内核测试 - 更新文档
性能考虑
- 零拷贝:直接从缓冲区缓存读取
- 延迟加载:仅在需要时读取 inode 元数据
- 缓存友好:利用 FreeBSD 的 vnode 缓存
- 批量操作:目录读取一次性处理多个条目
已知限制
- 不支持写操作(只读文件系统)
- 不支持 FUSE 模式
- 构建和运行时验证目前仅覆盖 FreeBSD 15 amd64
- 不实现 Linux file-backed、fscache、page-cache sharing 或 sysfs 控制面