RK3588 kernel-6.1 fs/ext4/indirect.c 传统间接块映射分析

RK3588 kernel-6.1 fs/ext4/indirect.c 传统间接块映射分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/indirect.c未启用 extent 时 inode 内 i_data[]直接块 + 一/二/三级间接 树:查找、分配、截断、打洞
  • 调用方:inode.cext4_map_blocks(无 EXT4_INODE_EXTENTS 时走 ext4_ind_map_blocks)、截断与 punch hole 路径
  • 不覆盖:extent 树(见 extents.c

2. 代码作用(一句话)

indirect.c 实现 classic ext2 式 「inode 根部指针 + 多级间接块」:把逻辑块号 ext4_block_to_path 解析为各级索引,ext4_get_branch** 读链;若缺块且允许创建则 ext4_alloc_branch 分配元数据与数据块并 ext4_splice_branch 挂回树;ext4_ind_truncate / ext4_ind_remove_space 通过 ext4_find_shared + ext4_free_branches / ext4_free_data 回收子树并配合日记。** 全程依赖 i_data_semext4_jbd2。**


3. 解决了什么问题

问题 处理方式
无 extent 时如何把逻辑块映射到物理块 ext4_ind_map_blocks:路径深度 + ext4_get_branch;命中则尽量 向前合并连续指针first_block + count)扩大 m_len
逻辑块号超出三间接可表示范围 ext4_block_to_path:越界 ext4_warningdepth=0
间接块中指针越界或损坏 ext4_get_branchkey > ext4_blocks_count-EFSCORRUPTED;读盘后 ext4_check_indirect_blockref
分配新链时崩溃中间态 注释:先分配整条链再 splice,失败则 ext4_alloc_branchext4_free_blocks 释放,不从未完成链可达,减少恢复复杂度
块分配局部性 ext4_find_near:向左找最近已分配块 → 否则靠近 间接块本体 → 否则 ext4_inode_to_goal_block(同组 + PID 着色减少并发冲突);ext4_find_goal 截断到 32 位物理块上限
单次创建需要多少数据块(跨 indirect 边界) ext4_blks_to_allocateblocks_to_boundary(来自 ext4_block_to_path
bigalloc 与非 extent 不兼容 ext4_ind_map_blocks 创建路径:ext4_has_feature_bigalloc-EFSCORRUPTED(须 extent)
截断到更短 i_size ext4_ind_truncateext4_es_remove_extent 同步 ES 树;i_disksize = i_sizeext4_find_shared 找与 最后一个保留块 共享的路径,只释放 尾部;再按 offsets[0] 逐级 ext4_free_branches 拆掉 整棵一级/二级/三级 子树
punch hole(中间挖洞) ext4_ind_remove_space:对 [start,end)同层深度 / 跨层 情况,组合 ext4_find_sharedext4_free_branches,与 ext4_punch_hole 衔接
日记事务额度估算 ext4_ind_trans_blocks~N/每块指针数 + 4(上界经验公式)
事务重启与 i_data_sem 死锁 ext4_ind_trunc_restart_fn / ext4_ind_truncate_ensure_credits:与 extents.cext4_ext_trunc_restart_fn 同类——放下 i_data_semext4_discard_preallocations

4. 核心数据结构:Indirect

1
2
3
4
5
typedef struct {
__le32 *p;
__le32 key;
struct buffer_head *bh;
} Indirect;
  • p:当前层 指向下一层块号的槽位(inode 内或某间接块 buffer)。
  • key:该槽位上的 块号(le32)
  • bh:本层若为间接块则非 NULL。

ext4_get_branchinode->i_data 起沿 offsets[] 填充 chain[],遇 0 指针 返回 残缺链 供分配。


5. 分配路径概要

  1. ext4_block_to_pathdepthoffsetsblocks_to_boundary
  2. ext4_get_branch → 若完整:映射成功(可扫连续块)。
  3. 无 CREATE:按 子树空洞大小m_len(hole)
  4. CREATEindirect_blks = 从断点到叶子还差几层元数据;ext4_alloc_branchext4_new_meta_blocks 建中间层、ext4_mb_new_blocks 建数据;ext4_splice_branch 写回父指针、更新 i_blocks 等。
  5. delallocEXT4_GET_BLOCKS_DELALLOC_RESERVEext4_da_update_reserve_space

6. 锁定约定(与注释一致)

  • 仅查找down_read(i_data_sem)
  • 可能分配down_write(i_data_sem)(由 inode.c 在调用 ext4_ind_map_blocks 前保证)。

7. 小结

indirect.c 是 ext4 对 传统 bitmap+i_block[] 布局 的完整实现;现代默认 extent 文件 主要走 extents.c,本文件仍用于 未转换的老布局、特殊场景或 tests。阅读 ext4_map_blocks 时:EXT4_INODE_EXTENTS 置位 → extent 路径否则 → ext4_ind_map_blocks。与 s_bitmap_maxbytesfile.c/truncate 与本文 max_block)共同约束 非 extent 文件最大逻辑长度

文章互动

阅读 --

留言

0 条留言

正在加载留言…