RK3588 kernel-6.1 fs/ext4/namei.c 路径解析与目录元数据操作分析

RK3588 kernel-6.1 fs/ext4/namei.c 路径解析与目录元数据操作分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/namei.c目录 inode 的 VFS inode_operationslookup / create / link / unlink / symlink / mkdir / rmdir / mknod / tmpfile / rename,以及 目录块读写、htree 增删分裂、目录项校验和 等底层支撑)
  • dir.creaddir、线性/dx 路径)、inline.c(内联目录项增删转普通目录)、hash.cext4_htree_fill_tree遍历填充)、xattr.c/acl.clistxattr/get_acl 等透传)的协作

分工提示dir.c 文档已覆盖 大目录按 hash 遍历f_pos 编码;本文重点在 「写名字」:如何在磁盘目录结构里 查找、插入、删除、改名,以及 htree 随写入而分裂、升层


2. 代码作用(一句话)

namei.c 实现 ext4 目录层名空间操作:通过 ext4_read_dirblock索引块 / 叶子块 预期做 一致性校验与元数据 CRCext4_lookup/ext4_get_parent** 解析 目录项 → ext4_igetext4_add_entry 统一 内联目录htree线性目录,必要时 make_indexed_dir 把单块目录 提升为索引目录ext4_dx_add_entry/do_split 在叶子满或索引满时 分裂叶子或分裂/升高索引ext4_delete_entry/__ext4_unlink 合并 rec_len 回收槽位;ext4_rename/ext4_cross_rename/ext4_rename2jbd2 事务 内完成 换名、目录 .. 维护、白化(whiteout)、fast commit 跟踪或置为不合格;并向 VFS 导出 ext4_dir_inode_operations


3. 解决了什么问题

问题 namei.c 中的处理方式
按路径打开/创建需要「在目录里找名字」 ext4_lookup_entry/ext4_find_entry(含 htree dx_probe 与线性扫描);ext4_lookup 校验 inum、加密上下文(目录与目标子项)、d_splice_alias
.. 与父 dentry 解析 ext4_get_parent:查找 .. 项并 ext4_iget
超大目录 O(n) 插入 索引目录ext4_dx_add_entry 按 hash 落到叶子;叶子满 do_split;索引项满则 分裂索引块indirect_levels++ 升层(受 ext4_dir_htree_level 限制)
单块目录长高后首次建索引 make_indexed_dir:把原块改为 dx root,分配新叶子等(与 ext4_add_entry 中「仅一块且无 dx 回退」路径衔接)
htree 损坏时能否继续用 ext4_dx_add_entry 失败且返回 ERR_BAD_DX_DIR无 metadata_csum 时可 ext4_clear_inode_flag(EXT4_INODE_INDEX) 回退线性(有风险);有 checksumEFSCORRUPTED,避免 silent 损坏
目录块读错类型 / 洞 / 越界 __ext4_read_dirblockblocki_size首块非洞期望 INDEX 却读到叶子ext4_error_inode;索引块 CRCext4_dx_csum_verify);叶子 目录尾 CRC(与 ext4_dirblock_csum_* 协作)
目录无限膨胀 ext4_append:可选 s_max_dir_size_kb 限制 i_size
fscrypt / casefold 文件名 fscrypt_is_nokey_namefscrypt_prepare_*ext4_fname_setup_*ext4_ci_compare;casefold 下 negative dentrylookup 缓存 策略(d_invalidate / 查找失败 不缓存
删除目录项后空间碎片 ext4_generic_delete_entry:与前项 合并 rec_len清空 inode/name
重命名与目录链接计数、.. ext4_rename_dir_prepare/ext4_rename_dir_finishext4_update_dx_flag;跨目录移动目录时 ext4_inc_count/ext4_dec_count
overlay 等需要的 RENAME_WHITEOUT ext4_whiteout_for_renameext4_setent 把原项改成 whiteout inode,失败 ext4_resetent
RENAME_EXCHANGE ext4_cross_rename:双方向 ext4_setent
rename 目录与 fast commit ext4_fc_mark_ineligible(EXT4_FC_REASON_RENAME_DIR)(回放尚不能正确处理 .. 改写);非目录 rename 则 __ext4_fc_track_link/unlink/create
内联目录与普通目录形态切换 ext4_try_add_inline_entryext4_delete_inline_entry;rename 时 inline → blockforce_reread 避免删项时还按旧形态解释缓冲
sticky 位与「目录项 inode 与 dentry 不一致」 注释说明:须用 de->inoded_inode 比对,防 cwd 被删后同名占位 等竞态

4. 核心流程摘要

4.1 目录块读取与校验类型

  • dirblock_type_tEITHER / INDEX / DIRENT / DIRENT_HTREE,告知 __ext4_read_dirblock 期望值,用于 区分索引块与叶子选择性做强校验(避免空叶子被误判为索引块时误验索引 CRC)。
  • ext4_read_dirblock 为带 调用点 的封装,便于 ext4_error_inode(..., func, line, ...) 定位。

4.2 添加目录项:ext4_add_entry

  1. ext4_fname_setup_filename(加密名、casefold 等)。
  2. ext4_has_inline_data(dir)ext4_try_add_inline_entry;成功则返回。
  3. is_dx(dir)ext4_dx_add_entry;失败则按是否 metadata_csum 决定 降级或报错
  4. 否则 块号 0…blocks-1add_dirent_to_buf-ENOSPC单块 + dir_index featuremake_indexed_dir
  5. 仍满则 ext4_append 新目录块再 add_dirent_to_buf
  6. 成功则 ext4_set_inode_state(..., EXT4_STATE_NEWENTRY)

4.3 htree 写路径:ext4_dx_add_entry

  • dx_probe 定位帧栈;读 叶子 DIRENT_HTREE
  • 叶子 add_dirent_to_bufENOSPC索引项满分裂索引增加 indirect_levels;否则 do_split 分裂叶子dx_make_map/dx_sort_map 均分条目),再在目标叶 add_dirent_to_buf
  • restart重新 dx_probe,因索引路径已变。
  • ext4_delete_entry:先尝试 inline 路径,再 ext4_journal_get_write_access + ext4_generic_delete_entry + ext4_dirblock_csum_set + ext4_handle_dirty_dirblock
  • __ext4_unlinkext4_find_entry 与 inode 校验;事务内删项;drop_nlinki_nlink==0 ext4_orphan_addfast commit ext4_fc_track_unlink(带 dentry 时)。

4.5 创建类操作(节选)

  • ext4_create/ext4_mknod/ext4_tmpfileext4_new_inode_start_handle + ext4_add_entry(或 tmpfile 不建目录项),设置 ext4_file_inode_operationsext4_special_inode_operations
  • ext4_mkdirext4_new_inode_start_handle + ext4_init_new_dir./..)+ ext4_add_entryext4_dir_inode_operations
  • ext4_symlinkfscrypt_prepare_symlink;短链可走 fast symlink;长链 ext4_init_symlink_block 写数据块;加密则 ext4_encrypted_symlink_inode_operations

4.6 ext4_rename2ext4_rename / ext4_cross_rename

  • fscrypt_prepare_rename
  • RENAME_EXCHANGEext4_cross_rename
  • 否则 ext4_renamequotaext4_find_entryjournal_start、目录则 empty_dir/EMLINK 检查、ext4_setent/ext4_add_entry、删旧项、更新 ctime/nlink/orphanwhiteout 回滚路径。

5. 与 ext4_dir_inode_operations 的对应关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const struct inode_operations ext4_dir_inode_operations = {
.create = ext4_create,
.lookup = ext4_lookup,
.link = ext4_link,
.unlink = ext4_unlink,
.symlink = ext4_symlink,
.mkdir = ext4_mkdir,
.rmdir = ext4_rmdir,
.mknod = ext4_mknod,
.tmpfile = ext4_tmpfile,
.rename = ext4_rename2,
.setattr = ext4_setattr,
.getattr = ext4_getattr,
.listxattr = ext4_listxattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
.fiemap = ext4_fiemap,
.fileattr_get = ext4_fileattr_get,
.fileattr_set = ext4_fileattr_set,
};

目录 inode 的 setattr/getattr/xattr/acl 等在其它文件中实现,经此表挂到 目录 上。


6. 小结

namei.c 是 ext4 「名字 ↔ inode」 的枢纽:读目录块时防呆与校验写目录时维护线性与 htree 两种形态(含 分裂与索引升高),并把 POSIX 语义(link 计数、目录 ..、加密与白化、journaling/fast commit)落到 事务化的目录项更新 上。深入 htree 读侧与 readdir 请结合 dir.c/hash.c 文档;内联目录 细节见 inline 相关源码与 rk3588-kernel-6.1-ext4-inline内联数据与内联目录分析.md

文章互动

阅读 --

留言

0 条留言

正在加载留言…