RK3588 kernel-6.1 fs/ext4/fsmap.c 与 fs/ext4/fsync.c 分析

RK3588 kernel-6.1 fs/ext4/fsmap.cfs/ext4/fsync.c 分析

1. 分析范围

文件 作用定位
fs/ext4/fsmap.c FS_IOC_GETFSMAP(getfsmap)在 ext4 上的实现:把盘上 物理块区间 归类为 所有者(空闲 / 固定元数据 / 日志 /「未知」缝隙等) 并返回给用户态
fs/ext4/fsync.c fsync / fdatasync / msync 触发的 ext4_sync_file:先刷 用户数据页,再按 是否启用 journal、data 模式 提交元数据(含 fast commit 路径),必要时 blkdev_issue_flush

通用 VFS 的 linux/fs/fsync.c(如 do_fsync)不在本分析范围内;用户所问的 fsync.cext4 子目录下的实现


2. fsmap.c:代码作用(一句话)

块组 buddy / 空闲查询ext4_mballoc_query_range)与 预先枚举的固定元数据块列表(超级块、GDT、位图、inode 表等)之间做 物理地址序上的归并,通过 ext4_getfsmap_helper 输出连续的 fsmap/ext4_fsmap 记录(含 洞状「未知所有者」 区间);支持 数据设备 + 外置 journal 设备 两段 handler,并对 大簇(bigalloc) 以簇为单位查询后再换算成块区间。


3. fsmap.c:解决了什么问题

问题 处理方式
用户态需要「整块设备上谁占了哪一段」的物理视图(调试、迁移、审计、xfs_io fsmap 等) 实现 ext4_getfsmap,对接 struct fsmap_headformatter 回调,填 fmh_entries / fmh_oflags
空闲区来自 mballoc,元数据位置来自组描述符 固定元数据ext4_getfsmap_find_fixed_metadata 聚合成 有序链表;每个块组对 空闲簇ext4_mballoc_query_rangeext4_getfsmap_datadev_helper,与 gfi_next_fsblk 同步推进,中间 空隙EXT4_FMR_OWN_UNKNOWN 报告
块组边界处空闲 extent 断裂 gfi_lastfree:块组末尾的 free extent 暂存,与下一组 邻接则合并,否则先 ext4_getfsmap_helper 吐出
外置 journal 占用独立设备 ext4_getfsmap_logdev:在 设备号匹配查询起点为物理 0 时,构造一条 EXT4_FMR_OWN_LOGj_blk_offset / j_total_len 的合成记录
用户态用字节、内核 ext4 用文件系统块 ext4_fsmap_from_internal / ext4_fsmap_to_internals_blocksize_bits 换算
跨调用分页遍历 fmh_keys低 key 可带非零 fmr_lengthext4_getfsmap 将其 折到 dkeys[0].fmr_physical += length,避免重复返回同一段
仅统计映射条数而不拷贝缓冲区 fmh_count == 0ext4_getfsmap_helper 只增 fmh_entries,用于 计数模式

所有者常量(节选,见 fs/ext4/fsmap.h):EXT4_FMR_OWN_FREEUNKNOWNFS(超级块等静态元数据)、GDT / RESV_GDT / BLKBM / INOBM / INODESLOG


4. fsmap.c:核心流程摘要

  1. ext4_getfsmap:校验 fmh_iflags设备号s_bdevs_journal_bdev);组装 handlers[]排序,逐设备调 gfd_fn
  2. ext4_getfsmap_datadev:把 keys 裁到 [s_first_data_block, blocks_count);对每个相关 块组 设置 gfi_low / gfi_high(簇边界);ext4_mballoc_query_range空闲;最后用 gfi_last=true 再跑一次 helper 收口尾部缝隙。
  3. ext4_getfsmap_helper:跳过 低于起始 key 的记录;rec_fsblk > gfi_next_fsblk 时先 填 UNKNOWN 间隙;再输出 当前记录;维护 gfi_next_fsblk;支持 信号中断返回 -EINTR

5. fsync.c:代码作用(一句话)

ext4_sync_file只读/FS_ABORTED/强制关机 等早退之后,先 file_write_and_wait_range 刷数据页;无日志走 sync_mapping_buffers + sync_inode_metadata + 新目录项链上的父目录同步;有日志且非 data=journalext4_fsync_journalext4_fc_commit(按 datasync 选用 i_datasync_tidi_sync_tid);data=journalext4_force_commit;最后按 barrier / journal 情况 可能 blkdev_issue_flush,并 检查 writeback 错误序号


6. fsync.c:解决了什么问题

问题 处理方式
无日志时新建文件只靠回写,崩溃窗口大 ext4_sync_parent:沿 EXT4_STATE_NEWENTRY dentry 链 向上 sync_mapping_buffers + sync_inode_metadata,把 新建路径上的目录 尽快落盘
有 journal 时 fsync 与事务 TID 对齐 ext4_fsync_journal:提交 包含该 inode 已记录更改的事务(通过 i_sync_tid / i_datasync_tid),并纳入 fast commitext4_fc_commit
data=journal 时数据在 journal 里 依赖 ext4_force_commit文件数据随事务 处理(注释说明 filemap_fdatawait 可能遇到 commit 弄脏的页,但块已在日志中)
设备乱序写需要屏障 needs_barrier无 journalBARRIER 挂载journal 带 JBD2_BARRIER 且当前 commit 未带 data barrierblkdev_issue_flush
静默写失败 file_check_and_advance_wb_err
只读挂载与 EXT4_MF_FS_ABORTED sb_rdonly + mount flag 返回 -EROFS

7. fsync.c:函数关系简图

1
2
3
4
5
6
7
8
9
10
ext4_sync_file
├─ file_write_and_wait_range
├─ 无 s_journal → ext4_fsync_nojournal
│ ├─ sync_mapping_buffers
│ ├─ sync_inode_metadata(视 datasync 与 I_DIRTY_*)
│ └─ ext4_sync_parent(NEWENTRY 链)
├─ data journal → ext4_force_commit
└─ else → ext4_fsync_journal → ext4_fc_commit(journal, commit_tid)
└─ blkdev_issue_flush(若 needs_barrier)
└─ file_check_and_advance_wb_err

8. 小结

  • fsmap.c 面向 「物理块 → 类别/所有者」整卷查询,与 mballoc、组描述符、外置日志 紧耦合,是 Oracle getfsmap / xfs_io 生态在 ext4 上的后端。
  • fsync.c 面向 与应用契约的持久化数据先等页缓存元数据(及可选 fast commit)再等 journal,并处理 无日志目录新建barrier/写错

分析 ioctl 入口时可在 ext4_ioctl.c 中搜索 FS_IOC_GETFSMAP/ext4_getfsmap;分析 fsync 与 fast commit 细节可对照 fast_commit.cext4_jbd2.h 中的 ext4_update_inode_fsync_trans

文章互动

阅读 --

留言

0 条留言

正在加载留言…