RK3588 kernel-6.1 fs/ext4/move_extent.c 在线 extent 迁移(defrag)分析
1. 分析范围
rk3588/kernel-6.1/fs/ext4/move_extent.c(EXT4_IOC_MOVE_EXT:e4defrag等工具触发的 两文件间逻辑区间与底层块映射交换)- 协作:
extents.c中的ext4_swap_extents、ioctl.c(命令分发与 bigalloc/DAX 拒绝)、inode.c(ext4_get_block)
2. 代码作用(一句话)
在 同一 superblock、均为 extent 普通文件 且 非 data=journal / 非加密 等前提下,ext4_move_extents** 按 原文件逻辑块范围 遍历 extent,逐 页 调用 move_extent_per_page:加日记 → 双文件页锁 → 若仍为 unwritten 可仅 ext4_swap_extents;否则 把原页数据读 uptodate → filemap_release_folio 尝试丢旧映射 → ext4_swap_extents 交换两文件在该区间的物理映射 → ext4_get_block + block_commit_write 把旧数据写回 原 inode 上新的物理块 → ext4_jbd2_inode_add_write;失败时 repair_branches 尝试 再 swap 回去 以防元数据与数据不一致。**
3. 解决了什么问题
| 问题 | 处理方式 |
|---|---|
| 大文件 extent 碎片严重,顺序读性能差 | 用户态用 卷上空白 donor 文件 预占位,再通过 move extent 把 原文件某段 映射 换到 donor 已持有的连续物理区,从而减少碎片(在线 defrag 核心思路之一) |
两 inode 同时改 i_data_sem 死锁 |
ext4_double_down_write_data_sem:按 inode 指针地址顺序 加锁;ext4_double_up_write_data_sem 按 orig/donor 实参顺序 释放(与加锁顺序配对) |
与 journal_start、页fault、read_folio 交叉死锁 |
进入 move_extent_per_page 的事务后 抬起 i_data_sem(注释 a/b),只用 页锁 与 extent 路径.serialize |
| unwritten extent 在换映射前被其它路径初始化 | 持页锁后 mext_check_coverage 再扫一遍;若 已非全 unwritten 则走 数据拷贝路径(mext_page_mkuptodate)而非纯 swap |
swap 成功但 block_commit_write 失败 |
repair_branches:再 ext4_swap_extents 试图复原;若仍失败 ext4_error_inode_block |
ENOSPC / 缓冲区被 journal 钉住 -EBUSY |
ext4_should_retry_alloc、jbd2_journal_force_commit_nested 后 重试 |
| 非法参数与安全 | mext_check_arguments:仅 extent、同 FS、regular、非 swapfile、donor 非 immutable/append/suid 组合限制、逻辑起点按页对齐、len 按 EOF 截断 |
| 与 DIO、截断并发 | 外层 lock_two_nondirectories、inode_dio_wait、ext4_double_down_write_data_sem 包住整段循环 |
| 预分配与旧 goal 干扰 | 循环结束后若 moved_len!=0:ext4_discard_preallocations 对 orig/donor |
不支持(由 ioctl.c/ext4_move_extents 组合):bigalloc、DAX、data=journaling、fscrypt(本文件内 IS_ENCRYPTED 检查)。
4. 调用链简图
1 | ioctl: EXT4_IOC_MOVE_EXT |
5. 与 ext4_swap_extents 的关系
move_extent.c 负责 页级 I/O、日记额度、锁升降序;extents.c 的 ext4_swap_extents 在 事务 handle 下 改写两棵 extent 树 中对应逻辑区间的 物理指针(并处理 脏元数据)。两者必须 一致使用,分析实现时需 extents.c 对照阅读。
6. 小结
move_extent.c 实现 内核级「换腱接骨」:在 不扩大用户可见文件布局语义 的前提下,交换两段文件的块映射并保证数据落到新映射上,供 e4defrag 做 online defrag。正确性依赖 extent 类型再检查、失败回滚 swap 与 jbd2 inode ranged write 标记。
若需补充 用户态 e4defrag 典型步骤( donor 分配策略等),属于 工具链文档,超出本内核文件范围。
正在加载留言…