RK3588 kernel-6.1 fs/ext4/ext4_jbd2.c 与 JBD2 对接层分析

RK3588 kernel-6.1 fs/ext4/ext4_jbd2.c 与 JBD2 对接层分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/ext4_jbd2.cext4 ↔ jbd2 的运行时胶水层,约 392 行)
  • 配套声明与宏、事务额度、回调、ext4_handle_valid 等:**ext4_jbd2.h**(本文件大量逻辑依赖其中的宏与 inline)

2. 代码作用(一句话)

ext4_jbd2.c 把 ext4 的元数据修改统一接到 JBD2:开启/结束事务、在「无日志 / fast commit 回放」下用伪 handle** 走同一套 API;封装 get_write_access / get_create_access / dirty_metadata / forget,并在启用 metadata_csum 时为缓冲块挂 jbd2 triggers;同时处理日志已中止整盘只读块设备异步写失败 等边界,保证崩溃一致性与错误可恢复路径一致。**


3. 解决了什么问题

问题 ext4_jbd2.c 中的处理方式
ext4 与 jbd2 API 分散、错误路径不统一 集中实现 __ext4_journal_* / __ext4_forget / __ext4_handle_dirty_metadata,上层通过 ext4_jbd2.h 宏传入 __FILE__/__LINE__ 便于定位
无外部 journal 或 fast commit 回放仍需同一控制流 EXT4_FC_REPLAY 或无 s_journalext4_get_nojournal():用 current->journal_info引用计数(伪装 handle_t *),ext4_handle_valid 据此区分真/假 handle
日志已在后台 abort(如 commit 线程 I/O 错) ext4_journal_check_start:若 is_journal_abortedext4_abort 把整个 FS 只读拉齐,返回 -EROFS,避免在已坏日志上继续提交脏元数据
强制关机 / 只读挂载 ext4_forced_shutdown → -EIOsb_rdonly → -EROFS;并对 SB_FREEZE_COMPLETEWARN_ON
释放块后日志里仍可能重放旧内容(重放死元数据) __ext4_forget:在 ordered/writeback + 元数据或应对 data 记日志 时走 jbd2_journal_revokefull data journal 或非记日志数据块用 jbd2_journal_forget;无日志则 bforget
元数据校验和在事务提交时需重算 __ext4_journal_get_write_access / get_create_accessext4_has_metadata_csumtrigger_type != EXT4_JTR_NONEjbd2_journal_set_triggers,与 s_journal_triggers[] 协作
块设备曾对元数据 buffer 异步写失败,再读旧页写回导致磁盘不一致 ext4_check_bdev_write_error:比较 mapping->wb_errsbi->s_bdev_wb_err,发现新进错误则 ext4_error_err
事务额度不足 __ext4_journal_ensure_credits:无效 handle 直接 0;否则与 ext4_journal_extend(见头文件)配合补足 buffer / revoke 额度
数据日志模式与 delayed allocation、加密的组合 ext4_inode_journal_mode:无 journal 为 writeback;delalloc 开启时 不对普通文件强行 data journal(避免不支持的组合);加密普通文件 固定 ordered,避免 data journal 语义问题
无 journal 路径上 inode 需同步落盘 __ext4_handle_dirty_metadata:无效 handle 时 mark_buffer_dirty,若 inode_needs_syncsync_dirty_buffer 并检查 EIO

4. 核心函数说明

4.1 ext4_inode_journal_mode

根据 s_journal、挂载 DATA_FLAGS、inode EXT4_INODE_JOURNAL_DATA / EA_INODEDELALLOCIS_ENCRYPTED 等,返回三类模式之一:journal dataorderedwriteback
ext4_should_journal_data 等 inline(在 ext4_jbd2.h)判断 __ext4_forget、额度宏等分支。

4.2 ext4_get_nojournal / ext4_put_nojournal

  • current->journal_info 当作 无符号计数(递增/递减),上限 EXT4_NOJOURNAL_MAX_REF_COUNT
  • ext4_handle_valid(计数值小于阈值视为“假 handle”)配对,使 无日志 代码不必遍地 if (journal)

4.3 ext4_journal_check_start

jbd2_journal_start 类操作前统一检查:强制关机只读已冻结日志 abort。失败则不让新事务开始,避免错误扩大。

4.4 __ext4_journal_start_sb / __ext4_journal_stop

  • start:校验通过后,有 journal 且非 FC_REPLAYjbd2__journal_start(带 GFP_NOFS、类型、调用行号等);否则 假 handle
  • stop:假 handle 走 ext4_put_nojournal;真 handle jbd2_journal_stop,合并 handle->h_err 与 stop 返回值,错误走 __ext4_std_error

4.5 __ext4_journal_start_reserved

对已 jbd2 预留额度 的 handle 再 jbd2_journal_start_reserved;若 ext4_journal_check_start 失败则 jbd2_journal_free_reserved 并返回错误指针。

4.6 __ext4_journal_ensure_credits

若当前 buffer credits / revoke credits 不够目标值,计算差额并 ext4_journal_extend(扩展事务占位)。

4.7 ext4_journal_abort_handle

printk 错误上下文后 jbd2_journal_abort_handle,用于 get_*_access / forget / dirty 等失败路径,避免在已失败事务上继续误用。

4.8 ext4_check_bdev_write_error

__ext4_journal_get_write_access 里,若 bh->b_bdev->bd_super 存在,则检查该 bdev 映射上的 写回错误序号,防止脏元数据页与磁盘真相割裂时再次写盘扩大损坏。

4.9 __ext4_journal_get_write_access

  1. 可选 ext4_check_bdev_write_error
  2. 有效 handle:jbd2_journal_get_write_access,失败则 abort handle
  3. 按需 jbd2_journal_set_triggers(metadata checksum)

4.10 __ext4_forget

释元数据或数据块时的日志语义核心

  • 无有效 handlebforget(bh)
  • journal data 模式,或 数据块且不该 journal datajbd2_journal_forget(注释:V1 superblock 不支持 revoke 等历史原因)
  • 否则(元数据,或应对 data journal 的数据):jbd2_journal_revoke(blocknr, bh),失败 ext4_error
  • bh 可为 NULL:仅撤销 journal 中仍存在的块号记录

4.11 __ext4_journal_get_create_access

新分配块的 jbd2_journal_get_create_access + 与写访问相同的 trigger 逻辑。

4.12 __ext4_handle_dirty_metadata

  • 有效 handlejbd2_journal_dirty_metadata,设置 buffer_meta / prio / uptodate;异常时 abort 并 ext4_error_inode(或 pr_err 无 inode)
  • 无效 handlemark_buffer_dirty(_inode);若 inode_needs_sync 则同步写 buffer 并检查 I/O 错误

5. 与 ext4_jbd2.h 的分工(阅读代码时建议一起看)

内容 位置
ext4_journal_start / ext4_journal_stop 等宏 ext4_jbd2.h
ext4_handle_validext4_journal_extendext4_journal_restart 头文件 inline
事务块数估算宏EXT4_SINGLEDATA_TRANS_BLOCKS 等) 头文件
ext4_journal_callback_add 与 commit 后回调 头文件
本文件 上述行为的 .c 实现体(start/stop/forget/dirty/get_access/ensure_credits 与 inode journal modebdev 写错检测

6. 小结

**ext4_jbd2.c** 自身不包含完整日志布局或 recovery 实现(那是 jbd2 与 ext4 super/inode 挂载路径的职责),它负责:在 ext4 元数据路径上正确调用 JBD2(journal_start / get_*_access / dirty_metadata / stop 等)、在有无 journal 下统一抽象、在释放块时选择 revoke/forget、在 metadata checksum 下挂 commit 前触发器、并把 I/O/abort 类失败收敛为 ext4 错误处理。阅读任意 ext4_journal_* / ext4_forget / ext4_handle_dirty_metadata 调用点时,应以本文件与 ext4_jbd2.h 为权威语义说明。

文章互动

阅读 --

留言

0 条留言

正在加载留言…