RK3588 kernel-6.1 fs/ext4/orphan.c 孤儿 inode 处理分析

RK3588 kernel-6.1 fs/ext4/orphan.c 孤儿 inode 处理分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/orphan.c
  • 磁盘与内存概念:超级块 s_last_orphan单链表头)、可选 orphan_file feature专用 s_orphan_file_inum 文件内多块槽位)、**内存链表 s_orphan + s_orphan_lock
  • 协作:ext4_jbd2(事务、EXT4_JTR_ORPHAN_FILE)、super.c(挂载/卸载、ext4_init_orphan_info/ext4_release_orphan_info)、inode.cext4_orphan_gettruncateevict 路径上 add/del

2. 代码作用(一句话)

**orphan.c 维护「崩溃后仍须收尾的 inode」:**对已 unlink 但仍被打开、或 大截断跨事务 的 inode,在 有 journal 时把它们 登记到盘上老式 s_last_orphan + 盘上 i 链表新式 orphan 文件槽位),以便 ext4_orphan_cleanup下次 rw 挂载删无链接 inode按记录尺寸截断仍有链接 inode;正常关闭/截断完成时 ext4_orphan_del 从盘上与内存链表移除。


3. 两套盘上表示

机制 盘上结构 内存标记
经典孤儿链表 es->s_last_orphan 指向链表头;每个 inode 盘上 i_links_count 邻域的 next 指针NEXT_ORPHAN)链成单链表 list_head i_orphan 挂在 sbi->s_orphan
orphan 文件(feature) s_orphan_file_inum 指向普通 inode,其数据块为 __le32 ino 槽数组 + 块尾 ext4_orphan_block_tail(magic、checksum) EXT4_STATE_ORPHAN_FILE + i_orphan_idx(线性下标)

ext4_orphan_add:若 s_orphan_info.of_blocks != 0ext4_orphan_file_add;仅当返回 -ENOSPC回退 超级块链表路径(不扩 orphan 文件,避免每件 orphan 操作预留过多 credits)。


4. 解决了什么问题

问题 处理方式
崩溃时文件已 unlink 仍被 FD 占用,须最终释放数据与 inode 进 orphan 表;恢复时 i_nlink==0ext4_process_orphaniput 触发真正删除
截断很大,跨多个已提交事务,中途崩溃导致元数据与数据不一致 截断过程中把 inode 挂 orphan;恢复时 i_nlink!=0truncate_inode_pages + ext4_truncate 收到 i_size/i_disksize 已记录的安全目标
超级块只存一个链表头,高并发 unlink 争用同一块磁盘中超级块/头 inode orphan 文件:多块、按 CPU 简单散列选起始块 atomic_dec_if_positive(ob_free_entries) 找空槽,cmpxchg 占槽,减少 所有 orphan 都改 s_last_orphan 的热点(槽满仍回退链表
orphan 文件块损坏难检测 块尾 magicmetadata_csumext4_orphan_file_block_csum_verify;jbd2 ext4_orphan_file_block_trigger 写时更新 tail checksum
内存与盘上链表一致性 ext4_orphan_add:改 sb 或前驱 inodeNEXT_ORPHAN + ext4_handle_dirty_metadata;失败则从 内存 i_orphan 摘除(注释:避免卸载 panic
ext4_orphan_del 无 handle(错误路径) list_del_init 更新 内存链表跳过 盘上更新
只读挂载但需要清孤儿 ext4_orphan_cleanup临时清 SB_RDONLYCONFIG_QUOTA 下必要时 开 quotaoff
文件系统带错/只读设备 只读 bdev未知 rocompat跳过EXT4_ERROR_FS 时策略性 s_last_orphan跳过恢复(见代码分支)
卸载释放 orphan 文件缓冲 ext4_release_orphan_infobrelseob_bhkfree(of_binfo)

5. 主要函数摘要

5.1 ext4_orphan_add / ext4_orphan_del

  • 前提s_journal 存在 且 inode 正常;无 journal 直接 0(无孤儿恢复契约)。
  • 加锁约定:注释 须在 i_rwsem 下调用I_NEW/I_FREEING 例外)。
  • del:若 EXT4_STATE_ORPHAN_FILEext4_orphan_file_del(清槽、atomic_inc(ob_free_entries));否则链表路径上 可能是 sb 头或前驱 inode 改写 next

5.2 ext4_process_orphan

  • dquot_initialize
  • i_nlink > 0加锁截断页缓存ext4_truncate;失败 ext4_orphan_del(NULL, ...) 清内存链防泄漏
  • i_nlink == 0:计数为 delete
  • iput(inode):触发 实际 evict/释放

5.3 ext4_orphan_cleanup

  • s_last_orphanorphan 文件块数 皆为 0 则返回
  • es->s_last_orphan 循环 ext4_orphan_gets_orphanext4_process_orphan
  • 双重循环orphan 文件 各块非零 ino(设置 EXT4_STATE_ORPHAN_FILEi_orphan_idx
  • 日志:删除/截断数量
  • 恢复 sb->s_flags只读 原样)

5.4 ext4_init_orphan_info

  • feature orphan_fileext4_iget(s_orphan_file_inum),按 i_size 得块数
  • 每块 ext4_bread,校验 tail magicchecksum
  • 统计每块 空槽数atomic_set(ob_free_entries)
  • of_csum_seed 来自 orphan inode 的 i_csum_seed

5.5 ext4_orphan_file_empty

  • 若 feature 未开 返回 1(空)
  • 否则所有块的 ob_free_entries 均等于 每块槽位数(用于 fast commit 等判断,见其它文件调用点)

6. 小结

orphan.c 解决的是 日志文件系统下「逻辑上的删除/截断」与「最终盘上状态」在崩溃边界上的缺口:用 持久化的孤儿集合 记住 哪些 inode 仍需删或收尾截断,并在 挂载恢复幂等地 处理。orphan 文件 是对 经典超级块头链表可扩展、可校验 扩展;空间满透明回退 旧机制。

ext4_orphan_get 实现在其它源文件(通常为 inode.c),orphan_cleanup 依赖其 安全 iget(坏/已删 inode 可中止链表)。

文章互动

阅读 --

留言

0 条留言

正在加载留言…