1. Motivation
EROFS(Enhanced Read-Only File System)是 Linux 内核中的高性能只读文件系统,现已被 Android(system 分区默认格式)、containerd(erofs snapshotter,OCI 镜像 +erofs 层)、openEuler 等广泛采用。它以 4KiB 块为粒度压缩,与 SquashFS(128KiB 块)相比:
- 压缩/解压粒度小,随机读取开销低,更适合容器与微虚拟机场景(如 Firecracker 只读 rootfs);
- 支持 tail-packing 内联(小文件尾部数据直接内联在 inode 之后,零额外块占用);
- 支持 chunk-based 去重寻址(容器镜像层共享数据块)。
DragonOS 需要一个可靠的只读文件系统作为 rootfs / 容器镜像层 / 最小镜像的载体。本项目直接复用开源社区已有的纯 Rust 实现 erofs-rs(erofs-sys crate,no_std),在 DragonOS 内核中实现 VFS 适配层,最小化新代码量。
2. On-Disk Format
EROFS 镜像(v1)由以下区域组成。所有整数为小端。Superblock 位于设备偏移 1024 字节处,共 128 字节。
参考:linux-6.6.21/fs/erofs/erofs_fs.h(磁盘格式权威定义)、erofs-rs/erofs-sys/src/superblock.rs(解析实现)。
┌───────────────────────────────────────────────────────────┐
│ Superblock 128 字节 @ offset 1024,magic 0xE0F5 │
│ magic / checksum / feature_compat / blkszbits / │
│ root_nid / inos / build_time / blocks / meta_blkaddr / │
│ xattr_blkaddr / uuid / feature_incompat / extra_devices │
├───────────────────────────────────────────────────────────┤
│ Device Table 可选(多设备镜像,erofs_deviceslot 128B) │
├───────────────────────────────────────────────────────────┤
│ Data Blocks 文件数据区(compressed / uncompressed) │
├───────────────────────────────────────────────────────────┤
│ Inode Table nid = meta_blkaddr*blksz + nid*32 │
│ Compact 32B | Extended 64B(槽位固定 32B)│
├───────────────────────────────────────────────────────────┤
│ Directory Blocks 目录块(见下) │
├───────────────────────────────────────────────────────────┤
│ Shared Xattr Area 可选(共享 xattr 前缀/条目) │
└───────────────────────────────────────────────────────────┘
Inode 格式(erofs_fs.h 中 erofs_inode_compact / erofs_inode_extended,解析见 erofs-rs/erofs-sys/src/inode.rs):
i_format(u16)位域:bit 0 = 版本(0=Compact 32B,1=Extended 64B);bit 1-3 = 数据布局(datalayout):
| 值 |
布局 |
说明 |
| 0 |
FLAT_PLAIN |
平坦数据块(i_u = 起始块地址) |
| 1 |
COMPRESSED_FULL |
全压缩(非紧凑索引) |
| 2 |
FLAT_INLINE |
平坦 + 尾部数据内联在 inode 后 |
| 3 |
COMPRESSED_COMPACT |
紧凑压缩索引 |
| 4 |
CHUNK_BASED |
分块索引寻址(支持多设备/去重) |
Compact inode 无时间戳(继承 superblock 的 build_time),uid/gid 16 位,文件最大 4GiB;Extended 有 i_mtime、32 位 uid/gid、u64 文件大小。
目录格式(erofs_fs.h 中 erofs_dirent,解析见 erofs-rs/erofs-sys/src/dir.rs):
每个目录块头部为定长的 DirentDesc 数组(12 字节/条:nid: u64 + nameoff: u16 + file_type: u8 + reserved: u8),文件名从块尾部倒序存放,nameoff 指向名字起始位置。
┌──────────┬──────────┬─────────┬──────────┬─────────┐
│ Dirent 0 │ Dirent 1 │ ... │ name.. │ name.. │
│ 12B │ 12B │ ... │ (倒序) │ (倒序) │
└──────────┴──────────┴─────────┴──────────┴─────────┘
3. Core Structs
erofs-rs 侧(erofs-sys crate,直接复用,不修改)
ImageFileSystem<B>(erofs-sys/src/superblock/file.rs)— 镜像文件系统的核心实现:
pub struct ImageFileSystem<B> where B: FileBackend {
backend: B, // 数据后端(DragonOS 侧提供)
infixes: Vec<XAttrInfix>, // xattr 长前缀表
sb: SuperBlock, // 解析后的 superblock
device_info: DeviceInfo, // 设备表(多设备镜像)
}
impl ImageFileSystem<B> {
pub fn try_new(backend: B) -> PosixResult<Self>; // 从 offset 1024 读并解析 superblock
}
SuperBlock(superblock.rs)— blksz() / blocks() / inos() / root_nid(pub)/ build_time(pub),内部提供 iloc(nid)(inode 槽位定位)、blk_access()(跨块边界访问)。
InodeInfo(inode.rs)— 磁盘 inode 的统一内存表示,enum { Compact(..), Extended(..) },提供 file_size() / inode_type() / inode_perm() / spec() / nlink() / uid() / gid() / mtime()。spec() 把 i_u 联合体解析为 Spec::{RawBlk(u32), Chunk(ChunkFormat), Device(u32), CompressedBlocks(u32)}。通过 InodeInfo::try_from((&dyn FileSystem<I>, Nid)) 从磁盘读取。
DirentDesc / Dirent(dir.rs)— 目录条目:nid: u64、file_type: u8、dirname() -> &[u8]。
DragonOS 侧(新增,kernel/src/filesystem/erofs/)
/// 块设备适配器:把 DragonOS BlockDevice 变成 erofs-sys 的 Source
pub struct BlockDevSource { dev: Arc<dyn BlockDevice> }
/// 新类型包装,绕过孤儿规则为 UncompressedBackend 实现 FileBackend
pub(crate) struct BlockDevBackend(UncompressedBackend<BlockDevSource>);
/// 文件系统实例
pub struct ErofsFileSystem {
inner: ImageFileSystem<BlockDevBackend>, // erofs-sys 核心
root_inode: Arc<ErofsInode>,
inode_cache: RwLock<BTreeMap<Nid, (InodeId, Weak<ErofsInode>)>>, // nid → inode 缓存
blk_dev: Arc<dyn BlockDevice>, // 持有设备,防止卸载
next_ino: AtomicUsize, // DragonOS InodeId 分配器
}
/// VFS inode
pub struct ErofsInode {
info: InodeInfo, // erofs-sys 解析结果
ino: InodeId, // DragonOS inode id
nid: Nid,
fs: Weak<ErofsFileSystem>, // 回指(Weak 防循环引用)
}
/// 内部桥接:临时构造,实现 erofs-sys 的 Inode trait,用于调用 mapped_iter 等
pub(crate) struct ErofsSysInode { info: InodeInfo, nid: Nid, xattrs: XAttrSharedEntries }
4. Core Traits That Must Be Implemented
只需实现 erofs-sys 的 3 个 trait(约 400 行),其余复用 ImageFileSystem;再实现 DragonOS VFS 的 3 个 trait 完成接入。
4.1 erofs-sys trait(kernel/src/filesystem/erofs/)
impl Source for BlockDevSource(source.rs)— 任意字节偏移读取:
impl Source for BlockDevSource {
fn fill(&self, data: &mut [u8], _device_id: i32, offset: Off) -> PosixResult<u64> {
// 1. 字节偏移 → LBA:blk = offset / LBA_SIZE, off_in_blk = offset % LBA_SIZE
// 2. 整扇区读取:dev.read_at_sync(blk, blk_count, &mut raw_buf)
// 3. 从扇区缓冲区拷贝 data.len() 字节到目标,返回实际拷贝数
}
}
impl Backend/FileBackend for BlockDevBackend(fs.rs)— 透传 fill 到 UncompressedBackend<BlockDevSource>(新类型是必须的:FileBackend 的 blanket impl 是 impl<T: Source> FileBackend for UncompressedBackend<T>,孤儿规则要求在自己的 crate 里包一层)。
impl Inode for ErofsSysInode(inode.rs)— 提供 info() / nid() / xattrs_shared_entries(),调用 erofs-sys 方法时从 ErofsInode 栈上临时构造,零堆分配。
4.2 DragonOS VFS trait
impl MountableFileSystem for ErofsFileSystem(挂载入口,参照 ext4/filesystem.rs:1438 的 Ext4MountData 模式):
register_mountable_fs!(ErofsFileSystem, EROFSFSMAKER, "erofs");
pub struct ErofsMountData { gendisk: Arc<GenDisk> }
impl FileSystemMakerData for ErofsMountData { fn as_any(&self) -> &dyn Any { self } }
impl MountableFileSystem for ErofsFileSystem {
fn make_fs_with_flags(data: Option<&dyn FileSystemMakerData>, mount_flags: MountFlags)
-> Result<Arc<dyn FileSystem + 'static>, SystemError> {
// 1. downcast 得到 ErofsMountData → gendisk → BlockDevice
// 2. let backend = BlockDevBackend(UncompressedBackend::new(BlockDevSource::new(dev)));
// 3. let inner = ImageFileSystem::try_new(backend)?; // 解析 superblock
// 4. 读取根 inode:let root_info = InodeInfo::try_from((&inner, sb.root_nid))?;
// 5. Arc::new_cyclic 构造 ErofsFileSystem(root_inode 持 Weak<fs>)
// 6. 挂载完成后 forget(mount_guard)(设备生命周期贯穿挂载期)
}
fn make_mount_data(raw_data, source) -> ... {
// 参照 Ext4MountData::from_source:
// user_path_at → 校验 BlockDevice 类型 → vcore::try_find_gendisk(dname)
}
}
impl FileSystem for ErofsFileSystem(fs.rs):
| 方法 |
实现 |
root_inode() |
返回缓存好的 root_inode |
name() |
"erofs" |
super_block() |
从 inner.superblock() 映射:Magic::from_bits_truncate(0xE0F5)、bsize/frsize = blksz()、blocks、files = inos();bfree/bavail/ffree = 0(只读) |
sync_fs() |
Ok(())(只读无需同步) |
support_readahead() |
false(无 page cache 后端,压缩数据也无法线性预读) |
impl IndexNode for ErofsInode(inode.rs):
| 方法 |
实现 |
read_at(offset, len, buf) |
fs.inner.mapped_iter(&sys_inode, offset) → 遍历 BufferMapIter 逐块 copy_from_slice,EOF 截断,越界返回 0 |
write_at(..) |
Err(SystemError::EROFS) — 只读 |
metadata() |
InodeInfo → Metadata(mode、size、uid/gid、mtime、nlink、file_type;Compact inode 的 mtime 用 sb.build_time 推导) |
find(name) / find_bytes(name) |
fill_dentries 回调中匹配名字 → 命中后 get_or_create_inode(nid) 并停止遍历 |
list_entries() |
fill_dentries 回调中收集全部 DirectoryEntry |
open() / close() / flush_file() |
空操作(只读,无状态) |
读路径数据流(read() 系统调用):
ErofsInode::read_at(offset, len, buf)
└─ fs.inner.mapped_iter(&sys_inode, offset) // erofs-sys:逻辑→物理映射
└─ TempBufferMapIter::try_yield(map) // 按 Map 逐段读取
└─ backend.fill(&mut block, 0, map.physical_start)
└─ BlockDevSource::fill(...) // 字节偏移 → 扇区对齐
└─ BlockDevice::read_at_sync(lba, count, buf) // virtio-blk 等
4.3 文件布局(新增代码)
kernel/src/filesystem/
└── erofs/ ★ 新建
├── mod.rs # pub mod fs / inode / source / errno
├── errno.rs # erofs_sys::Errno → SystemError 映射(EPERM/ENOENT/EIO/...,fallback EIO)
├── fs.rs # ErofsFileSystem + BlockDevBackend + MountableFileSystem
├── inode.rs # ErofsInode + ErofsSysInode + impl IndexNode
└── source.rs # BlockDevSource + impl erofs_sys::data::Source
kernel/Cargo.toml:
erofs-sys = { path = "../../erofs-rs/erofs-sys" } # 相对路径引用;不走 CONFIG_EROFS_FS 内核模式
kernel/src/filesystem/mod.rs:
pub mod erofs;
kernel/src/filesystem/vfs/mod.rs:
Magic 枚举新增 EROFS_MAGIC = 0xE0F5 # 参照现有 FAT_MAGIC/EXT4 等变体
5. Dependency: erofs-sys
- 纯 Rust
no_std:#![no_std] + extern crate alloc,无 FFI、无 C 依赖,可直接编译进 DragonOS 内核
- 可运行:FUSE 版已可运行,Linux 内核 Rust-for-Linux 亦计划采用;接入成本远低于自行维护磁盘格式解析。
- 接入面小:磁盘格式解析(superblock/inode/dir/xattr)、地址映射(flat/chunk/内联)、迭代器全部由 erofs-sys 提供,DragonOS 只写适配层。
编译模式:不设 CONFIG_EROFS_FS=y,走 extern crate alloc 路径,erofs-sys 作为普通 path 依赖。
6. Limitations(阶段一范围)
| 限制 |
说明 |
| 仅未压缩镜像 |
使用 UncompressedBackend;lz4 等压缩镜像(mkfs.erofs -z lz4)阶段一不支持。压缩支持见下「阶段二:压缩支持」(需在 erofs-rs 补齐) |
| 无 xattr |
as_sys_inode() 的 XAttrSharedEntries 为空;getxattr/listxattr VFS 回调不实现(Linux 参考 xattr.c) |
| 单设备 |
device_id 参数忽略,不支持多设备镜像(extra_devices > 0 时挂载应报错拒绝) |
| 无 mmap / page cache |
page_cache() 返回 None,map_pages/fault 走默认;只读 FS 影响有限 |
| 无 readahead |
support_readahead() = false;数据按需解压/读取 |
| inode 缓存无上限 |
BTreeMap<Nid, Weak<..>> 不主动淘汰;阶段二可加 LRU(参照 Linux inode.c 的 inode cache 语义) |
阶段二:压缩支持(需在 erofs-rs 补齐)
erofs-rs 目前仅有 UncompressedBackend(compression.rs 只有占位枚举、map.rs 的 MAP_ENCODED 常量已定义但无实现),压缩读取需要在 erofs-rs 中补齐:
- 压缩索引解析:COMPRESSED_FULL / COMPRESSED_COMPACT 两种 layout 的物理簇索引解析(逻辑块 → 压缩簇),对应 Linux
zmap.c(z_erofs_map_blocks_iter);
CompressedBackend:读物理簇 → 解压 → 输出解压后数据,MapIter 增加 MAP_ENCODED 路径(对应 Linux zdata.c 的 z_erofs_decompress);
- 解压器抽象:按 superblock
available_compr_algs 位图分派(对应 Linux decompressor.c),挂载时对不支持的算法明确拒绝(EUCLEAN/ENOTSUP)。
解压器选用 ruzstd:
(a) Widely adopted (57,012,877 all-time downloads);
(b) Pure-Rust implementation (no FFI / no C library);
(c) Full no_std support;
(d) Focused on decompression (compression available but limited) —— EROFS 只需要解压,恰好匹配。
注:EROFS 原生算法为 LZ4(默认)/ LZMA(5.16+)/ DEFLATE(6.6+),Zstandard 是 Linux 6.10+ 新增(6.6.21 中尚不存在)。采用 ruzstd 即走 zstd 压缩簇路线:测试镜像用 mkfs.erofs -z zstd 生成,DragonOS 由此直接获得 zstd 压缩能力;阶段二后续可再按需补 lz4 解压器。
阶段二其他候选:chunk-based 去重文件、mmap、xattr、多设备。
7. Testing
7.1 集成测试
# 镜像准备(erofs-utils)
mkdir -p /tmp/erofs_root/subdir
echo "hello from erofs!" > /tmp/erofs_root/hello.txt
mkfs.erofs erofs.img /tmp/erofs_root/ # 阶段一:未压缩镜像
mkfs.erofs -z zstd erofs-zstd.img /tmp/erofs_root/ # 阶段二:zstd 压缩镜像(ruzstd)
7.2 dunitest
参照 user/apps/tests/dunitest/ ext4 测例模式,新增 erofs_basic.cc(gtest),覆盖 mount/stat/statfs/open+read/readdir/readlink/write→EROFS。内核侧 #[cfg(test)] 单测覆盖 superblock 解析。
7.3 erofs-sys 自身
cd erofs-rs && cargo test
8. 验收标准
参考
- EROFS 官方文档:https://erofs.docs.kernel.org/en/latest/
- 磁盘格式(Linux 6.6.21):
linux-6.6.21/fs/erofs/erofs_fs.h;挂载/解析参考 super.c、inode.c、data.c、dir.c、namei.c;压缩(阶段二)参考 zmap.c、zdata.c、decompressor.c
- erofs-rs:
erofs-sys/src/{superblock, inode, dir, map, data, operations}.rs
- DragonOS 接入参考:
kernel/src/filesystem/ext4/(挂载模式)、tools/run-qemu.sh(挂盘)、user/apps/tests/dunitest/(测例模式)
1. Motivation
EROFS(Enhanced Read-Only File System)是 Linux 内核中的高性能只读文件系统,现已被 Android(system 分区默认格式)、containerd(erofs snapshotter,OCI 镜像
+erofs层)、openEuler 等广泛采用。它以 4KiB 块为粒度压缩,与 SquashFS(128KiB 块)相比:DragonOS 需要一个可靠的只读文件系统作为 rootfs / 容器镜像层 / 最小镜像的载体。本项目直接复用开源社区已有的纯 Rust 实现 erofs-rs(
erofs-syscrate,no_std),在 DragonOS 内核中实现 VFS 适配层,最小化新代码量。2. On-Disk Format
EROFS 镜像(v1)由以下区域组成。所有整数为小端。Superblock 位于设备偏移 1024 字节处,共 128 字节。
参考:
linux-6.6.21/fs/erofs/erofs_fs.h(磁盘格式权威定义)、erofs-rs/erofs-sys/src/superblock.rs(解析实现)。Inode 格式(
erofs_fs.h中erofs_inode_compact/erofs_inode_extended,解析见erofs-rs/erofs-sys/src/inode.rs):i_format(u16)位域:bit 0 = 版本(0=Compact 32B,1=Extended 64B);bit 1-3 = 数据布局(datalayout):i_u= 起始块地址)Compact inode 无时间戳(继承 superblock 的
build_time),uid/gid 16 位,文件最大 4GiB;Extended 有i_mtime、32 位 uid/gid、u64 文件大小。目录格式(
erofs_fs.h中erofs_dirent,解析见erofs-rs/erofs-sys/src/dir.rs):每个目录块头部为定长的
DirentDesc数组(12 字节/条:nid: u64+nameoff: u16+file_type: u8+reserved: u8),文件名从块尾部倒序存放,nameoff指向名字起始位置。3. Core Structs
erofs-rs 侧(
erofs-syscrate,直接复用,不修改)ImageFileSystem<B>(erofs-sys/src/superblock/file.rs)— 镜像文件系统的核心实现:SuperBlock(superblock.rs)—blksz()/blocks()/inos()/root_nid(pub)/build_time(pub),内部提供iloc(nid)(inode 槽位定位)、blk_access()(跨块边界访问)。InodeInfo(inode.rs)— 磁盘 inode 的统一内存表示,enum { Compact(..), Extended(..) },提供file_size()/inode_type()/inode_perm()/spec()/nlink()/uid()/gid()/mtime()。spec()把i_u联合体解析为Spec::{RawBlk(u32), Chunk(ChunkFormat), Device(u32), CompressedBlocks(u32)}。通过InodeInfo::try_from((&dyn FileSystem<I>, Nid))从磁盘读取。DirentDesc/Dirent(dir.rs)— 目录条目:nid: u64、file_type: u8、dirname() -> &[u8]。DragonOS 侧(新增,
kernel/src/filesystem/erofs/)4. Core Traits That Must Be Implemented
只需实现 erofs-sys 的 3 个 trait(约 400 行),其余复用
ImageFileSystem;再实现 DragonOS VFS 的 3 个 trait 完成接入。4.1 erofs-sys trait(
kernel/src/filesystem/erofs/)impl Source for BlockDevSource(source.rs)— 任意字节偏移读取:impl Backend/FileBackend for BlockDevBackend(fs.rs)— 透传fill到UncompressedBackend<BlockDevSource>(新类型是必须的:FileBackend的 blanket impl 是impl<T: Source> FileBackend for UncompressedBackend<T>,孤儿规则要求在自己的 crate 里包一层)。impl Inode for ErofsSysInode(inode.rs)— 提供info()/nid()/xattrs_shared_entries(),调用 erofs-sys 方法时从ErofsInode栈上临时构造,零堆分配。4.2 DragonOS VFS trait
impl MountableFileSystem for ErofsFileSystem(挂载入口,参照ext4/filesystem.rs:1438的Ext4MountData模式):impl FileSystem for ErofsFileSystem(fs.rs):root_inode()root_inodename()"erofs"super_block()inner.superblock()映射:Magic::from_bits_truncate(0xE0F5)、bsize/frsize = blksz()、blocks、files = inos();bfree/bavail/ffree = 0(只读)sync_fs()Ok(())(只读无需同步)support_readahead()false(无 page cache 后端,压缩数据也无法线性预读)impl IndexNode for ErofsInode(inode.rs):read_at(offset, len, buf)fs.inner.mapped_iter(&sys_inode, offset)→ 遍历BufferMapIter逐块copy_from_slice,EOF 截断,越界返回 0write_at(..)Err(SystemError::EROFS)— 只读metadata()InodeInfo→Metadata(mode、size、uid/gid、mtime、nlink、file_type;Compact inode 的 mtime 用sb.build_time推导)find(name)/find_bytes(name)fill_dentries回调中匹配名字 → 命中后get_or_create_inode(nid)并停止遍历list_entries()fill_dentries回调中收集全部DirectoryEntryopen()/close()/flush_file()读路径数据流(
read()系统调用):4.3 文件布局(新增代码)
5. Dependency: erofs-sys
no_std:#![no_std]+extern crate alloc,无 FFI、无 C 依赖,可直接编译进 DragonOS 内核编译模式:不设
CONFIG_EROFS_FS=y,走extern crate alloc路径,erofs-sys作为普通 path 依赖。6. Limitations(阶段一范围)
UncompressedBackend;lz4 等压缩镜像(mkfs.erofs -z lz4)阶段一不支持。压缩支持见下「阶段二:压缩支持」(需在 erofs-rs 补齐)as_sys_inode()的XAttrSharedEntries为空;getxattr/listxattrVFS 回调不实现(Linux 参考xattr.c)device_id参数忽略,不支持多设备镜像(extra_devices > 0时挂载应报错拒绝)page_cache()返回None,map_pages/fault走默认;只读 FS 影响有限support_readahead() = false;数据按需解压/读取BTreeMap<Nid, Weak<..>>不主动淘汰;阶段二可加 LRU(参照 Linuxinode.c的 inode cache 语义)阶段二:压缩支持(需在 erofs-rs 补齐)
erofs-rs 目前仅有
UncompressedBackend(compression.rs只有占位枚举、map.rs的MAP_ENCODED常量已定义但无实现),压缩读取需要在 erofs-rs 中补齐:zmap.c(z_erofs_map_blocks_iter);CompressedBackend:读物理簇 → 解压 → 输出解压后数据,MapIter增加MAP_ENCODED路径(对应 Linuxzdata.c的z_erofs_decompress);available_compr_algs位图分派(对应 Linuxdecompressor.c),挂载时对不支持的算法明确拒绝(EUCLEAN/ENOTSUP)。解压器选用 ruzstd:
(a) Widely adopted (57,012,877 all-time downloads);
(b) Pure-Rust implementation (no FFI / no C library);
(c) Full no_std support;
(d) Focused on decompression (compression available but limited) —— EROFS 只需要解压,恰好匹配。
阶段二其他候选:chunk-based 去重文件、mmap、xattr、多设备。
7. Testing
7.1 集成测试
7.2 dunitest
参照
user/apps/tests/dunitest/ext4 测例模式,新增erofs_basic.cc(gtest),覆盖 mount/stat/statfs/open+read/readdir/readlink/write→EROFS。内核侧#[cfg(test)]单测覆盖 superblock 解析。7.3 erofs-sys 自身
cd erofs-rs && cargo test8. 验收标准
mount -t erofs /dev/vdX /mnt/erofs成功,umount成功;read_at跨块、EOF 截断、尾部内联 FLAT_INLINE);list_entries、find、符号链接);metadata/statfs返回正确的 mode/size/uid/gid/mtime 与 magic 0xE0F5;EROFS;多设备镜像挂载被明确拒绝(EUCLEAN/ENOTSUP),不 panic;(阶段一)压缩镜像同样被明确拒绝;erofs_basic全绿;mkfs.erofs -z zstd压缩镜像可正常挂载与读取,未压缩镜像不受影响;含不支持算法的镜像被明确拒绝。参考
linux-6.6.21/fs/erofs/erofs_fs.h;挂载/解析参考super.c、inode.c、data.c、dir.c、namei.c;压缩(阶段二)参考zmap.c、zdata.c、decompressor.cerofs-sys/src/{superblock, inode, dir, map, data, operations}.rskernel/src/filesystem/ext4/(挂载模式)、tools/run-qemu.sh(挂盘)、user/apps/tests/dunitest/(测例模式)