RK3588 kernel-6.1 fs/ext4/resize.c 在线扩容(resize)分析

RK3588 kernel-6.1 fs/ext4/resize.c 在线扩容(resize)分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/resize.c挂载状态下扩大 ext4 卷:superblock块组描述符(GDT)位图与 inode 表meta_bg 转换备份超级块/GDT
  • 用户态入口:ioctl.cEXT4_IOC_GROUP_EXTENDEXT4_IOC_GROUP_ADDEXT4_IOC_RESIZE_FS;均配合 ext4_resize_begin/ext4_resize_end 与能力 CAP_SYS_RESOURCE

不在此文件范围内离线 shrink缩小已用块数;注释与代码均明确 在线收缩不支持


2. 代码作用(一句话)

resize.c 在 jbd2 事务内(及受控的预置阶段事务中)把 底层块设备末端 对应的新空间 纳入已有 ext4:要么 只拉长最后一个块组ext4_group_extend),要么 按块组追加ext4_group_add** / ext4_flex_group_add),要么 ext4_resize_fs 自动循环 _extend + 批量 flex 组;当 resize_inode 预留的 GDT 槽位用尽转为 meta_bg 布局ext4_convert_meta_bg);并通过 update_backups 维护 稀疏超级块/GDT 备份;用 ext4_kvfree_array_rcu 等在 扩大 s_group_desc 等 RCU 可见数组 后安全释放旧指针。**


3. 解决了什么问题

问题 resize.c 中的处理方式
磁盘/LUN 扩大后文件系统仍只有旧容量 在线更新 s_blocks_count/s_free_blocks_count(及 per-group 结构),使 mballoc/分配路径 能用新块
只做「最后一组补满」的应急路径 ext4_group_extend:要求当前 逻辑末尾不在块组边界last != 0),否则需 GROUP_ADD/RESIZE_FS;适合 remount,resize=不依赖预留 GDT 的场景(注释说明)
新增整块组(含位图、inode 表、备份元数据) ext4_group_add:校验 ext4_new_group_dataverify_group_input:位图/itb 与 GDT 重叠、越界、最后一块可读等),扩 flex_bg/groupinfo,再 ext4_flex_group_add
一次加多组、控制内存与日记压力 ext4_resize_fsext4_setup_next_flex_gd + alloc_flex_gdflex 大小批量;MAX_RESIZE_BG 等限制;约 每 10 秒打进度日志
GDT 块数量随块组增加而增长 ext4_add_new_descsadd_new_gdbEXT4_RESIZE_INO 的双间接树 抠出预留 GDT 块;或 add_new_gdb_meta_bgmeta_bg 下挂新描述符块
预留 GDT 用完仍要继续涨 ext4_resize_fs:先 缩小目标 n_blocks_count 到预留能撑住的最大组数ext4_convert_meta_bg 开启 meta_bg释放 resize inode 占用的元数据块,再 带着原目标大小 retry
resize_inodemeta_bg 互斥 ext4_resize_fs:若两者同时 feature 置位则 -EINVAL(不一致布局)
JBD 难以整事务回滚 注释反复强调:在改盘前尽量做完所有可能失败检查add_new_gdb 等路径 先 verify 再改 dind
扩容与并发访问 ext4_resize_beginEXT4_FLAGS_RESIZING-EBUSY 互斥);sparse_super2非主超级块挂载EXT4_ERROR_FS拒绝扩容
bigalloc 边界 ext4_resize_fsn_blocks_count 向下对齐 cluster,避免 半 cluster 不可用语义
内核侧数据结构随组数变长 ext4_alloc_flex_bg_arrayext4_mb_alloc_groupinfo;旧数组 ext4_kvfree_array_rcu RCU 后再 kvfree
新组块位图与 inode 表初始化 setup_new_flex_group_blocks复制 GDT 备份zeroout inode 表bclean 位图set_flexbg_block_bitmap 在位图中 标记元数据占用
元数据 checksum ext4_setup_new_descs / ext4_set_bitmap_checksums 等写 组描述符与位图校验(与 ext4_has_group_desc_csum 等配合)
EXT4_IOC_RESIZE_FS 结束后统计 ext4_resize_end(..., true)ext4_update_overhead 刷新 overhead/free_clusters

4. 主要入口与协作关系

4.1 ext4_resize_begin / ext4_resize_end

  • 权限CAP_SYS_RESOURCE,否则 -EPERM
  • 一致性s_reserved_gdt_blocks 非零则须 resize_inode feature主 sb 与 s_first_data_block 对齐(备份超级块挂载则拒绝)
  • 安全EXT4_ERROR_FSsparse_super2 下不允许在线 resize
  • 结束:清除 RESIZINGRESIZE_FS 成功路径 update_backups=true 触发 overhead 更新

4.2 ext4_group_extend

  • 仅处理 最后一个块组内「从当前 o_blocks_countn_blocks_count(或补满本组)」
  • last == 0(已由完整块组边界结尾)→ -EPERM,提示需 GROUP_ADD/在线工具
  • ext4_group_extend_no_check日记 3 credits,改 sb 块总数与 free 计数ext4_group_add_blocks 把新块在位图中标为空闲可用,update_backups(super)

4.3 ext4_group_addEXT4_IOC_GROUP_ADD

  • 只能在尾数追加input->group == s_groups_count
  • 非 sparse新 GDT 落到新块gdb_off==0)时 -EPERM(无法再分稀疏备份)
  • 需要预留时打开 EXT4_RESIZE_INO
  • 分配 flex/mballoc groupinfo 后,以 count=1ext4_flex_group_add

4.4 ext4_resize_fsEXT4_IOC_RESIZE_FS

高层循环(逻辑顺序):

  1. n_blocks_count - 1,确认设备够长;bigalloc 对齐
  2. 禁止缩小;计算目标 最后一组 n_group
  3. resize_inode:检查 GDT 块数是否超过「旧描述符块数 + s_reserved_gdt_blocks」 → 必要时 临时降低 n_blocks_count,记 n_blocks_count_retry
  4. ext4_convert_meta_bg:在 无需再动 resize_inode 或已缩到仅扩组内 的边界上 切换到 meta_bg
  5. 最后一组塞不进 inode 表等元数据回退 n_group 重算(retry
  6. 与当前尾组同组ext4_group_extend_no_check;否则先 补满当前尾组add 为簇/块公式)
  7. while ext4_setup_next_flex_gdext4_alloc_group_tables(用户空间/内核算好的表布局)+ ext4_flex_group_add
  8. 若有 n_blocks_count_retry释放 flex 结构goto retry 扩到用户原定大小

4.5 ext4_flex_group_add

  • 前置setup_new_flex_group_blocks独立大事务:初始化 新组上的 备份 GDT、位图、inode 表 等)
  • 主事务EXT4_HT_RESIZEext4_add_new_descsext4_setup_new_descsext4_update_super(块数、inode 数、flex 计数器、s_overhead_clusters 等)
  • 成功后update_backups超级块备份新增/变更的 GDT 块备份(区分 meta_bg 与 padding)

4.6 ext4_convert_meta_bg

  • 打开 meta_bg feature,从 resize inode 释放 DIND 及所连块ext4_free_blocks),清除 inode 映射
  • 要求:进入时 s_reserved_gdt_blocks 已为 0(否则报错)

5. 与用户态、其它子系统的关系

组件 关系
ioctl.c EXT4_IOC_* 封装 resize_begin/resize_endRESIZE_FS 结束 update_backups=true
balloc.c/mballoc 新块通过 ext4_group_add_blocks、位图 EXT4_BG_BLOCK_UNINIT 等与 簇分配器 一致
super.c superblock checksum、挂载标志
工具链 resize2fs 等通常组合 ioctl设备容量查询本节仅述内核实现

6. 小结

resize.c 解决的是 「块设备变大了,ext4 如何在不卸载的前提下把新末端块变成合法块组并接入 GDT/位图」:涵盖 仅尾组延长用户提供单组几何的 GROUP_ADD、以及 RESIZE_FS 的自动分批与 meta_bg 切换。设计核心是 预留 GDT(resize_inode)或 meta_bg 二选一、日志事务与「先校验再改」、以及 备份超级块/GDT 与 flex/mballoc 元数据扩容 的一致性。

若需对照 组描述符与块组静态布局,可结合 rk3588-kernel-6.1-ext4-balloc块位图与块组辅助分析.md 等文档。

文章互动

阅读 --

留言

0 条留言

正在加载留言…