RK3588 kernel-6.1 fs/ext4/dir.c 目录与遍历机制分析

RK3588 kernel-6.1 fs/ext4/dir.c 目录与遍历机制分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/dir.c
  • namei.clookup/create/rename 等)、hash.cext4_htree_fill_tree 等 htree 填充)、inline.cext4_read_inline_dir)、inode.cext4_map_blocks)的协作

2. 代码作用(一句话)

dir.c 实现 ext4 目录的文件层行为readdir/getdents 遍历(含 htree 哈希目录 与非索引线性目录)、目录项格式合法性校验目录块校验和加密目录名解密后上报inline 目录 回退,以及 ext4_dir_operations(含 llseek/release/ioctl/fsync);大目录通过 ext4_dx_readdir哈希序 缓存到红黑树再 dir_emit,避免纯字节线性扫全块。


3. 解决了什么问题

问题 dir.c 中的处理方式
大目录 readdir 过慢 启用 htreeEXT4_INODE_INDEX 等)时走 ext4_dx_readdir:按 major/minor hash 批量装入 fname 红黑树,顺序 dir_emit;与 hash.c 协作
目录项损坏导致越界/错 inode __ext4_check_dir_entry:检查 rec_len、对齐、与 name_len 关系、不越出 buffer、inode 不超过 s_inodes_count;失败 ext4_error_*
telldir/seekdir 在哈希目录下的语义 ext4_dir_llseekhtreef_pos 表示哈希空间hash2pos/pos2maj_hash/pos2min_hash),兼容 32/64 位 APIFMODE_32BITHASH/FMODE_64BITHASH(如 NFS)
目录块静默损坏 读块后 ext4_dirblock_csum_verify,失败则报错并跳块
加密目录展示明文名 fscrypt_fname_disk_to_usr + dir_emitcasefold 时用条目内 hash/minor_hash
小目录 inline 数据 ext4_read_inline_dir,无则回退映射块
htree 元数据异常 ext4_dx_readdir 若返回 ERR_BAD_DX_DIR:无 metadata_csum 时可 ext4_clear_inode_flag(INDEX) 回退线性读(有风险,仅旧场景)
并发改目录导致 f_pos 悬垂 inode_eq_iversion/inode_query_iversion:目录改变时从块内重扫对齐 offset
fsck/一致性扫描 ext4_check_all_de:对整块顺序校验所有 ext4_dir_entry_2

4. 核心组件

4.1 is_dx_dir

ext4_has_feature_dir_index 前提下,满足 其一 则视为可走目录索引路径:

  • inode 置 EXT4_INODE_INDEX;或
  • 逻辑上仅 1 个目录块i_size == 1 block);或
  • inline data 目录(可能参与转换路径)。

具体 htree 读由 hash.c 等与 ext4_dx_readdir 衔接。

4.2 __ext4_check_dir_entry / is_fake_dir_entry

  • 假项. / ..(名长 1–2 且为点);或 EXT4_FT_DIR_CSUM 校验占位项 —— 不参与最小 ext4_dir_rec_len(1, dir) 的严格名规则(用 fake 分支)。
  • 正常项则按 dircasefold 下的最小记录长度等检查。

返回 0 表示合法1 表示有问题(与历史上 ext2 返回值语义相反,注释已说明)。

4.3 ext4_readdir(非 dx 或 dx 失败回退后的线性路径)

主要步骤:

  1. fscrypt_prepare_readdir(加密目录)。
  2. is_dx_dir:先试 ext4_dx_readdir;仅当 ERR_BAD_DX_DIR 时再尝试清 INDEX 标志并走线性。
  3. ext4_read_inline_dir 处理 inline。
  4. 加密时准备 fscrypt_fname 缓冲。
  5. ctx->pos ext4_map_blocks 定位目录数据块,readaheadext4_bread 读块。
  6. 目录块校验和set_buffer_verified
  7. iversion 不一致时从块头重扫 rec_len 对齐 offset
  8. 循环 ext4_check_dir_entry + dir_emit;洞(err==0)则推进 ctx->posdir_relax_shared 用于并发下让出。

4.4 htree:fname 树与 ext4_dx_readdir

  • struct fname:存 hash、minor_hash、inode、file_type、name(可变长),挂在 rb_hash 上;哈希碰撞 时用链表 next 串在同一 RB 节点逻辑下(少见)。
  • ext4_htree_store_dirent(可被 hash.c 调用):插入/合并碰撞链;加密目录 树内存放 解密后名ent_name)。
  • ext4_dx_readdir:首次分配 dir_private_info;若 f_pos 被用户改写则 清空树 并重解析 curr_hash;优先吐 extra_fname(上次 dir_emit 缓冲区满 未发完的碰撞链);需要时调 ext4_htree_fill_treehash.c)继续装树。
  • ext4_release_dirext4_htree_free_dir_info 释放整棵树。

4.5 hash2pos / ext4_get_htree_eof

  • f_pos 在 dx 目录中编码 (major_hash, minor_hash),不是单纯字节偏移。
  • EOFEXT4_HTREE_EOF_32BITEXT4_HTREE_EOF_64BIT,取决于 f_mode是否 compat 32 位 syscall

4.6 ext4_check_all_de

工具函数:从 buffer 头到尾按 rec_len 跳转,逐项 ext4_check_dir_entry;指针越过 top-EFSCORRUPTED。供 namei/校验路径 快速扫整块目录项。

4.7 ext4_dir_operations

1
2
3
4
5
6
7
8
const struct file_operations ext4_dir_operations = {
.llseek = ext4_dir_llseek,
.read = generic_read_dir,
.iterate_shared = ext4_readdir,
.unlocked_ioctl = ext4_ioctl,
.fsync = ext4_sync_file,
.release = ext4_release_dir,
};

目录 openfile->f_op 指向此处;iterate_shared 为现代 readdir 接口(与 sharedlock 语义配合)。


5. 数据流示意

1
2
3
4
5
6
7
8
9
10
11
12
13
getdents / readdir
|
v
ext4_readdir
|
+--> is_dx_dir && ext4_dx_readdir(hash 序 + RB 树)
| |
| +--> ext4_htree_fill_tree(hash.c)
|
+--> inline:ext4_read_inline_dir(inline.c)
|
+--> 线性:ext4_map_blocks → ext4_bread
→ dirblock csum → check_dir_entry → dir_emit

6. 与 namei.c / hash.c 的分工

文件 侧重
dir.c 只读列举、目录 file_operations、项格式校验辅助
namei.c lookup / create / unlink / rename、路径解析与目录改写的 inode 语义
hash.c dx 索引块 解析、ext4_htree_fill_tree、改名/插入时 htree 维护

7. RK3588 / 工程注意点

  • 大目录(如海量小文件缓存目录)强烈依赖 htree + dir_index;若磁盘上 htree 损坏且 无 metadata_csum,内核可能 降级清 INDEX(注释称不标脏),应以备份+fsck 为主,勿依赖长期使用降级态。
  • 加密 (fscrypt) 与 casefold 目录会走 dir.c 中额外分支,调试 readdir 异常时核对 密钥与编码
  • ext4_check_dir_entry** 告警** 多指向 磁盘目录块损坏不兼容工具写盘,需 dmesg + fsck

8. 小结

维度 结论
作用 目录 readdir/哈希目录遍历目录项与目录块校验f_pos/llseek 语义ext4_dir_operations
解决问题 大目录性能(htree)、损坏检测、crypt/casefold、inline、与 VFS dir_context 对接

源码:rk3588/kernel-6.1/fs/ext4/dir.c。文档:linuxDoc/fs/ext4/

文章互动

阅读 --

留言

0 条留言

正在加载留言…