RK3588 kernel-6.1 fs/ext4 源码目录架构详解
本文基于 Linux 6.1 树中 rk3588/kernel-6.1/fs/ext4 目录,从 VFS 注册、内存与磁盘结构、各 .c 文件职责、子系统协作 四个维度给出可对照源码阅读的说明,便于在 RK3588(eMMC/UFS 等块设备上常用 ext4)上做调试与裁剪。
1. 目录与构建
1.1 源文件清单(与 Makefile 一致)
ext4 驱动在 fs/ext4/Makefile 中链接为单一模块对象 ext4.o,由以下 核心 .o 组成(必选):
| 对象 |
源文件 |
主要职责 |
balloc.o |
balloc.c |
传统/compat 块分配、块位图与组内计数(与 mballoc 配合) |
bitmap.o |
bitmap.c |
块组位图、inode 位图读校验与内存侧辅助 |
block_validity.o |
block_validity.c |
系统块区域 rbtree,防止数据块与元数据区重叠 |
dir.o |
dir.c |
目录项(非(htree)线性部分)、readdir、目录块 I/O |
ext4_jbd2.o |
ext4_jbd2.c |
与 JBD2 日志对接:事务、handle、元数据提交 |
extents.o |
extents.c |
extent 树 读写、分裂合并、与 map_blocks 核心逻辑 |
extents_status.o |
extents_status.c |
ES 树:内存中逻辑块→物理/状态的缓存,优化延迟分配与回写 |
file.o |
file.c |
open/read_iter/write_iter/mmap/fallocate、DAX/iomap、ioctl(部分)、O_DIRECT |
fsmap.o |
fsmap.c |
FS_IOC_GETFSMAP 块设备映射查询 |
fsync.o |
fsync.c |
fsync/fdatasync、journal 与 data=ordered 语义 |
hash.o |
hash.c |
目录 htree 哈希(与 namei 配合) |
ialloc.o |
ialloc.c |
inode 分配、inode 位图、组内策略 |
indirect.o |
indirect.c |
非 extent 兼容路径下的间接块映射(老格式) |
inline.o |
inline.c |
内联数据(小文件数据在 inode 内) |
inode.o |
inode.c |
inode 读写、时间戳、ext4_map_blocks、页缓存配合、truncate 协作 |
ioctl.o |
ioctl.c |
ext4_ioctl:标签、feature、group desc、迁移、物理整理等 |
mballoc.o |
mballoc.c |
多块分配器 (mballoc):buddy、预分配、CR 扫描策略 |
migrate.o |
migrate.c |
extent 与 non-extent 间迁移等 |
mmp.o |
mmp.c |
Multi-Mount Protection,防同一设备被并发挂载损坏 |
move_extent.o |
move_extent.c |
EXT4_IOC_MOVE_EXT:块在文件间交换(高级维护) |
namei.o |
namei.c |
路径解析、lookup/create/link/unlink/rename、htree |
page-io.o |
page-io.c |
元数据页/日志相关页写下的 bio 提交封装 |
readpage.o |
readpage.c |
address_space read_folio/readahead 与extent 预读 |
resize.o |
resize.c |
在线扩容:组描述符、位图增长 |
super.o |
super.c |
挂载/卸载、fill_super、super 读写、feature 检查、file_system_type |
symlink.o |
symlink.c |
符号链接 inode 与快/慢路径 |
sysfs.o |
sysfs.c |
sysfs 导出统计与可调参数 |
xattr.o + hurd/trusted/user |
xattr*.c |
扩展属性后端(内部块、trusted、user、hurd) |
fast_commit.o |
fast_commit.c |
快速提交:增量 journal 路径 |
orphan.o |
orphan.c |
orphan 文件/链表:崩溃恢复时截断已删仍打开的 inode |
按 Kconfig 条件编译:
acl.o:POSIX ACL(CONFIG_EXT4_FS_POSIX_ACL)
xattr_security.o:SELinux 等安全标(CONFIG_EXT4_FS_SECURITY)
verity.o:fsverity(CONFIG_FS_VERITY)
crypto.o:fscrypt 加密(CONFIG_FS_ENCRYPTION)
inode-test.o:KUnit(CONFIG_EXT4_KUNIT_TESTS)
头文件要点:ext4.h(超级块/inode 内存结构、宏与内联)、ext4_extents.h、ext4_jbd2.h、mballoc.h、xattr.h、acl.h、fsmap.h、truncate.h。
1.2 Kconfig 依赖
CONFIG_EXT4_FS 会 select JBD2、CRC16、CRYPTO、CRYPTO_CRC32C、FS_IOMAP 等;可选 EXT4_USE_FOR_EXT2 在禁用独立 ext2 驱动时用 ext4 同时注册 ext2。详见 fs/ext4/Kconfig。
2. VFS 注册与挂载路径
2.1 file_system_type
super.c 中定义 ext4 文件类型并注册:
1 2 3 4 5 6 7 8
| static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, .name = "ext4", .init_fs_context = ext4_init_fs_context, .parameters = ext4_param_specs, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, };
|
init_fs_context:挂载参数解析(fs_context_operations:parse_param、get_tree、reconfigure、free)。
get_tree:典型为 get_tree_bdev(fc, ext4_fill_super)(6.1 新挂载 API)。
kill_sb:通用 kill_block_super(super.c 释放块设备与 super)。
同一文件中还注册 ext3;在 EXT4Use_FOR_EXT2 且未编 ext2 时可注册 ext2 别名。
2.2 模块初始化顺序(子系统就绪)
ext4_init_fs() 中顺序(摘自 super.c 尾部逻辑):
ratelimit → ext4_init_es(extent status)→ ext4_init_pending → ext4_init_post_read_processing → ext4_init_pageio → ext4_init_system_zone → ext4_init_sysfs → ext4_init_mballoc → init_inodecache → fast commit dentry cache → 注册 ext3/ext2 → register_filesystem(&ext4_fs_type)。
卸载时按相反顺序撤销。理解此顺序有助于排查 初始化失败 时哪一步返回错误。
2.3 锁顺序(官方注释)
super.c 文件头给出 ext4 在 缺页、缓冲写、truncate、DIO、writepages 上的锁依赖,调试死锁时应优先对照:
1 2 3 4 5 6 7 8 9 10 11
| * Lock ordering * * page fault path: * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) -> transaction start * -> page lock -> i_data_sem (rw) * * buffered write path: * sb_start_write -> i_mutex -> mmap_lock * sb_start_write -> i_mutex -> transaction start -> page lock -> * i_data_sem (rw) * ... (truncate / direct IO / writepages)
|
3. 核心数据结构(内存与磁盘)
3.1 struct ext4_inode_info
每个 VFS struct inode 通过 EXT4_I(inode) 得到 ext4_inode_info,挂载在 inode 尾部 vfs_inode。要点(见 ext4.h):
i_data[]:未转换的 15 项传统块指针(与 extent 共存时代的兼容/起点)。
i_block_group:inode 所在块组,用于 局部性分配。
i_disksize vs i_size:i_disksize 表示 盘上 已提交长度,truncate 与恢复关键。
i_data_sem:截断与 get_block/extent 修改之间的串行。
i_es_tree / i_es_lock:extent status 缓存树。
i_prealloc_*:mballoc 预分配 链表与锁。
i_fc_*:fast commit 跟踪。
xattr_sem:扩展属性与数据写分离锁。
jinode:JBD2 对该 inode 的附加信息。
3.2 struct ext4_sb_info
EXT4_SB(sb) 指向 per-mount 的超级块运行态:s_es 指向磁盘 super 在 buffer_head 中的镜像;s_journal、s_mount_opt(s)、mballoc 的 s_group_info/s_mb_*、s_es_shrinker、quota/fscrypt/dax 等均在此。细节字段见 ext4.h 中 struct ext4_sb_info(篇幅长,适合按需 grep)。
3.3 磁盘布局(概念)
- 超级块 + 块组描述符表 + 每块组:块位图、inode 位图、inode 表、数据区。
- extent:大部分现代 ext4 文件用 extent B+ 树 描述
(logical block → physical block, len)。
- bigalloc:cluster(多 block 为分配单位),宏
EXT4_CLUSTER_* 在 ext4.h。
- journal:默认 JBD2,
ext4_jbd2.c 包装 start_commit、ext4_journal_get_write_access 等。
4. 子系统协作(数据路径)
4.1 块映射总线:ext4_map_blocks(inode.c)
用户读写、缺页、get_block 最终都汇聚到 逻辑块 → 物理块 映射:
- 查/更新 extent 树(
extents.c);
- 参考 extent status(
extents_status.c)避免重复扫描、支持 DELALLOC;
- 延迟分配:可先只更新 ES 与 inode,稍后 mballoc 落地;
- 未写 extent: unwritten 标记,回写后转换。
4.2 块分配:mballoc.c + balloc.c
- mballoc 为主路径:按 buddy、per-group 信息、prealloc 做高性能分配;
- balloc 补充位图读写、计数维护及与老接口的衔接。
4.3 日志:ext4_jbd2.c + ext4_jbd2.h
- 元数据块通过 journal 先行记录 再写原位;
data=ordered / writeback / journal 等 data 模式影响 数据块 与日志顺序;
- fast_commit(
fast_commit.c)在支持的配置上减少全事务开销。
4.4 目录与 Htree:namei.c + dir.c + hash.c
namei.c:VFS inode_operations 的 lookup/mkdir/...、rename 复杂路径;
dir.c:目录块 格式、readdir;
hash.c:htree 哈希与冲突处理。
4.5 页缓存与 I/O:readpage.c、file.c、page-io.c、fsync.c
- 缓冲 I/O:
address_space_operations 在 inode.c/readpage.c 等分散设置;
file.c:iomap/dax、ext4_iomap_ops、Direct I/O、fallocate;
page-io.c:下层 bio 提交与日志相关的页写出;
fsync.c:保证 journal + 脏页序。
4.6 扩展属性与安全:xattr*.c、acl.c、xattr_security.c
xattr.c:EA 与 inode、块存储格式;
acl.c:POSIX ACL 与 generic_acl 桥接;
xattr_security.c:安全模块使用的 xattr 名空间。
4.7 运维与特性:ioctl.c、resize.c、mmp.c、sysfs.c
ioctl.c:在线 resize 协助、feature 操作、组参数、物理丢弃/搬迁等 EXT4_IOC_*;
resize.c:扩容时增长 group desc、位图;
mmp.c:多挂载防护周期写块;
sysfs.c:导出 mballoc 等统计与参数。
4.8 仅当配置开启
crypto.c:fscrypt: per-file/目录密钥、块内加密;
verity.c:merkle 树校验只读内容;
verity 与 dax(s_daxdev 在 ext4_sb_info):读路径旁路页缓存需与 extent/一致性小心配合。
5. 整体数据流简图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 用户 read/write/mmap | V VFS (file_operations / address_space) | v file.c / inode.c / readpage.c | v ext4_map_blocks + extents + extents_status | +--> mballoc/balloc (新块) | v page cache / bio 或 iomap DIO | v ext4_jbd2 (+ fast_commit) 元数据顺序 | v 块设备 (eMMC/UFS/NVMe/...)
|
6. RK3588 相关注意点
- 根文件系统 / userdata:RK 方案常见 ext4 + f2fs;ext4 多用于 boot、vendor、system 等只读/读写分区。
- 性能与磨损:关注
barrier/nobarrier(随内核演进注意语义变化)、journal_async_commit、delalloc、挂载选项与存储控制器 cache;MMP 在生产上避免双挂同卷。
- 裁剪:若不需要 ACL/security/verity/encryption,可在
Kconfig 关掉对应选项以减小 ext4 模块体积。
- 调试:
CONFIG_EXT4_DEBUG、tracepoints(CREATE_TRACE_POINTS + trace/events/ext4.h)、sysfs 统计。
7. 推荐阅读顺序(读源码)
super.c:ext4_fill_super、ext4_parse_param、ext4_reconfigure、feature 与错误处理。
ext4.h:ext4_inode_info、ext4_sb_info、ext4_map_blocks。
inode.c:ext4_map_blocks、dirty 与 writeback 交互。
extents.c + extents_status.c:现代 ext4 的核心。
mballoc.c + balloc.c:分配策略。
ext4_jbd2.c + fast_commit.c:一致性与性能。
namei.c + dir.c:目录与 rename。
file.c:mmap/DIO/fallocate。
- 按需:
resize.c、ioctl.c、orphan.c、mmp.c。
8. 小结
fs/ext4 是完整的 fourth extended 实现:在 VFS 层注册为块设备文件系统,通过 ext4_sb_info / ext4_inode_info 维护挂载与 inode 状态;extent + extent status + mballoc + JBD2(及 fast commit) 构成现代数据与元数据路径;namei/dir/hash 负责命名空间;xattr/acl/security/verity/crypto 提供策略与保密完整性;resize/ioctl/sysfs/mmp/orphan 覆盖工程与可靠性需求。上述与 Makefile 中 .o 列表一一对应,可按表索骥阅读。
文档对应内核树路径:rk3588/kernel-6.1/fs/ext4/。生成位置:linuxDoc/fs/ext4/。