RK3588 kernel-6.1 fs/ext4/inode.c 分析
1. 分析范围
rk3588/kernel-6.1/fs/ext4/inode.c(约 6300+ 行,ext4 inode 生命周期与块映射的核心枢纽)- 不替代子模块细节:extent / indirect / inline / xattr / quota 等仍要以对应
.c文件 为准;inode.c负责 编排、锁、日记额度、VFS 回调入口
2. 代码作用(一句话)
inode.c 实现 盘上 inode 与内存 inode/ext4_inode_info 的同步:__ext4_iget** 读 inode 表、校验 inode 校验和 与 非法/已删 inode 规则;ext4_map_blocks 在 extent 状态树 与 ext4_ext_map_blocks/ext4_ind_map_blocks 之间搭桥并维护 i_data_sem;ext4_setattr/ext4_truncate/ext4_evict_inode 处理 截断、orphan、unlink 回收;ext4_write_inode/ext4_mark_iloc_dirty 对接 回写与 journal;并包含 延迟分配(delalloc)、get_block/iomap 辅助、inode 标志与 jbd2 jinode 等大量横切逻辑。**
3. 解决了什么问题
| 问题 | inode.c 中的处理方式 |
|---|---|
| 逻辑块如何映射到物理块(extent / indirect 统一入口) | ext4_map_blocks:非 FC_REPLAY 时先 ext4_es_lookup_extent;未创建则 i_data_sem 读锁 下 只读映射;EXT4_GET_BLOCKS_CREATE 等则 写锁 再 ext4_ext_map_blocks / ext4_ind_map_blocks;新映射 ext4_es_insert_extent;EXT4_GET_BLOCKS_ZERO 时 ext4_issue_zeroout;check_block_validity 防越界 |
| 从磁盘装入 VFS inode | __ext4_iget:iget_locked、__ext4_get_inode_loc_noinmem、extra_isize / metadata_csum / i_size / i_flags 检查;死 inode(nlink==0) 与 配额 inode 号 等边界;ext4_find_inline_data_nolock、extent 树初始化、unlock_new_inode |
| 截断与崩溃恢复 | ext4_truncate:inline 先 ext4_inline_data_truncate;ext4_orphan_add;i_data_sem 写 + ext4_ext_truncate / ext4_ind_truncate;注释说明 orphan + 重放 语义 |
| 删除文件的最后阶段 | ext4_evict_inode:i_nlink!=0 分支处理 data=journal 下页缓存与 jbd2;i_nlink==0:ordered truncate、journal start、快 symlink 清 i_data、ext4_truncate、ext4_xattr_delete_inode、ext4_free_inode;失败路径 orphan 清理;fast commit 与 i_fc_list 的 ineligible 标记 |
chown/chmod/截断属性 |
ext4_setattr:immutable/append、fscrypt/fsverity、配额 dquot_transfer;ATTR_SIZE:ordered 数据、DIO wait、layout、orphan、i_disksize 与截断(长注释说明与页刷盘的顺序约束) |
回写 super 的 write_inode |
有 journal:WB_SYNC_ALL 且非 for_sync 时 ext4_fc_commit(..., i_sync_tid);无 journal:取 iloc、sync_dirty_buffer |
| 延迟分配簇预留 | ext4_da_update_reserve_space、ext4_da_get_block_prep、ext4_alloc_da_blocks、ext4_da_release_space 等(与 mballoc、ES 树 协作) |
| 页缓存与块设备 | ext4_get_block / ext4_get_block_unwritten、ext4_bread_batch、ext4_walk_page_buffers、ext4_set_aops(对 address_space_operations 赋值) |
| 打洞、部分块清零 | ext4_punch_hole、ext4_zero_partial_blocks、ext4_update_disksize_before_punch |
| DAX / lease / mmap 冲突 | ext4_break_layouts |
| ordered journal 需要跟踪 inode 数据事务 | ext4_inode_attach_jinode |
| inode 元数据校验和 | ext4_inode_csum_verify / ext4_inode_csum_set(ext4_mark_iloc_dirty 路径写回时设置) |
| 扩大 inode extra 区域 | ext4_expand_extra_isize |
| 切换 inode 的 data journal 标志 | ext4_change_inode_journal_flag |
| 估算事务块数 | ext4_writepage_trans_blocks、ext4_chunk_trans_blocks |
4. 模块结构(阅读地图)
1 | inode.c(逻辑分组) |
5. ext4_map_blocks 要点(与 extents.c / indirect.c / extents_status.c 的分界)
ext4_es_lookup_extent:命中 written/unwritten/delayed/hole 则直接填map(CACHED_NOWAIT可早退)。- 只查盘上树:读
i_data_sem,extent →ext4_ext_map_blocks(..., create=0),否则ext4_ind_map_blocks(..., create=0);若有结果则 写 ES(混合 delayed 标记逻辑)。 - 创建 / 转换 unwritten:清
m_flags,写i_data_sem,再 create=flags 调 ext/ind。 - 新块:可选 zeroout 后再
ext4_es_insert_extent。 - 释放写锁 前
out_sem处理错误码。
6. __ext4_iget 要点
- 非法 ino(保留 quota/orphan_file、越界等)→
-EFSCORRUPTED/-ESTALE。 - 已缓存:
check_igot_inode做一致性断言。 i_extra_isize、负i_size、dir_index 与 INDEX 标志不兼容 metadata_csum 等 → 损坏。- 填充 uid/gid/projid、nlink、i_flags、i_blocks ACL 块、inline、extent、symlink 等后
unlock_new_inode。
7. 小结
inode.c 是 ext4 的 「中心调度」:把 VFS、日志、块分配、extent/indirect/inline、ES 缓存、orphan、配额、加密/verity 连成可断言的序。深入 某一算法(例如 extent 插入)应进入 extents.c;深入 iget 之后的 raw 字段解析 可对照 ext4.h 中 struct ext4_inode。
阅读顺序建议:ext4_map_blocks → ext4_truncate/ext4_setattr(ATTR_SIZE) → __ext4_iget → ext4_evict_inode,再按需下钻 delalloc 与 ext4_set_aops 相关符号。
正在加载留言…