RK3588 kernel-6.1 fs/ext4/file.c 普通文件 VFS 层分析

RK3588 kernel-6.1 fs/ext4/file.c 普通文件 VFS 层分析

1. 分析范围

  • rk3588/kernel-6.1/fs/ext4/file.c普通文件file_operations / 部分 inode_operations 配套、读写、mmap、open/release、llseek)
  • 强依赖:iomap.cext4_iomap_opsext4_iomap_overwrite_opsext4_iomap_report_ops)、inode.cext4_map_blocks)、extents.c(未写区转换等)

2. 代码作用(一句话)

file.c 把 ext4 常规文件接到 Linux VFS:在 forced shutdown、加密、verity、DAX 等前提下分流 缓冲读/写iomap_dio_rw 直读直写** 与 DAX;用 i_rwsem 共享/独占inode_dio_wait 协调 未对齐 DIO、扩展写、unwritten extent 填洞 的安全性;open 里采样挂载路径写超块、挂 journal inodemmap 区分 DAX 大页缺页 与普通 filemap_fault / ext4_page_mkwrite。**


3. 解决了什么问题

问题 file.c 中的处理方式
直 I/O 与特性组合(对齐、inline、加密等) ext4_should_use_dio:用 ext4_dio_alignment 判定;不成立则清 IOCB_DIRECTgeneric_file_read_iter,或写路径走 ext4_buffered_write_iter,保持 「不适用 DIO 时回落缓冲」 的历史语义
错对齐 DIO + unwritten extent 填洞并发 注释 ext4_unaligned_io同一块上两路 dio_zero 可能互清零。做法:未对齐 DIO 必须独占 i_rwsem,且 inode_dio_wait 串行化在途 DIO
扩展写 DIO 与 i_size / i_disksize / orphan 扩展写前 ext4_orphan_addext4_dio_write_end_ioext4_convert_unwritten_extents;仅在超过当前 disk/逻辑 sizeext4_handle_inode_extension;失败 ext4_inode_extension_cleanup + ext4_truncate_failed_write
纯覆盖写可减少锁竞争 ext4_overwrite_ioext4_map_blocks(..., 0)** 判断是否已映射且非洞;覆盖路径可走 **共享 i_rwsem** + **ext4_iomap_overwrite_ops`
DIO 只完成部分长度 末尾 ext4_buffered_write_iter 吃剩余 iov_iter,再 filemap_write_and_wait_range + invalidate_mapping_pages,尽量保持 「要么全 DIO 要么语义一致」
非 extent(bitmap)布局的最大文件 ext4_generic_write_checksEXT4_INODE_EXTENTS 未置时用 s_bitmap_maxbytes 截断 iov_iter
不可变文件 IS_IMMUTABLE → -EPERM
关闭文件时把延迟分配落盘 / 释放预分配 ext4_release_fileEXT4_STATE_DA_ALLOC_CLOSEext4_alloc_da_blocks;最后一个写者且无 i_reserved_data_blocksext4_discard_preallocations
管理员排查「盘从哪挂载过」 ext4_sample_last_mounted:首次写挂载采样 d_path 写入 s_last_mounted(带日志与校验和)
journal ordered 模式与写 fd ext4_file_open 写打开时 ext4_inode_attach_jinode
SEEK_HOLE / SEEK_DATA ext4_llseekiomap_seek_hole / iomap_seek_data + ext4_iomap_report_ops
maxbytes 随布局变化 ext4_llseek:无 EXTENTS 标志用 s_bitmap_maxbytes,否则 s_maxbytes
DAX 共享映射写 vs COW ext4_dax_huge_fault:仅 VM_SHARED 真写ext4_journal_start;避免只读挂载上无意义 journal 失败

4. 核心组件

4.1 ext4_file_read_iter

  • ext4_forced_shutdown → -EIO
  • DAXext4_dax_read_iterdax_iomap_rw
  • IOCB_DIRECText4_dio_read_iteriomap_dio_rw(..., ext4_iomap_ops);否则 generic_file_read_iter

4.2 ext4_buffered_write_iter

  • IOCB_NOWAIT → -EOPNOTSUPP(缓冲路径)
  • inode_lock + ext4_write_checks(内含 ext4_generic_write_checksfile_modified
  • generic_perform_write + generic_write_sync

4.3 ext4_dio_write_iter

  • 初判 未对齐可能扩展独占锁;否则先 共享锁
  • ext4_dio_write_checks:扩展写 extend=true;若 共享锁下需要改安全配置、扩展、或非覆盖写 → 升级为 独占 并重算
  • 扩展写ext4_orphan_add(短事务)
  • iomap_dio_rw:覆盖用 ext4_iomap_overwrite_ops未对齐或扩展IOMAP_DIO_FORCE_WAIT
  • ext4_dio_write_ops.end_iounwritten → ext4_convert_unwritten_extents;按需 ext4_handle_inode_extension

4.4 ext4_file_write_iter

三分流:forced shutdownDAXDIRECT缓冲

4.5 DAX 写路径(CONFIG_FS_DAX

ext4_dax_write_iterext4_write_checks → orphan(若越 i_disksize)→ dax_iomap_rwext4_handle_inode_extension / cleanup

4.6 ext4_file_mmap

  • daxdev_mapping_supported:不支持 MAP_SYNC 等则 -EOPNOTSUPP
  • DAXext4_dax_vm_opsVM_HUGEPAGE);否则 ext4_file_vm_opsfilemap_fault / ext4_page_mkwrite

4.7 ext4_file_open / ext4_release_file

  • openext4_sample_last_mountedfscrypt_file_openfsverity_file_open、写打开 attach jinodeFMODE_NOWAIT | FMODE_BUF_RASYNCdquot_file_open
  • release:DA 块刷盘、预分配丢弃;若存在 is_dxprivate_dataext4_htree_free_dir_info(多数普通文件不命中;与 htree 私有数据生命周期相关的兜底)

4.8 ext4_file_operations / ext4_file_inode_operations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const struct file_operations ext4_file_operations = {
.llseek = ext4_llseek,
.read_iter = ext4_file_read_iter,
.write_iter = ext4_file_write_iter,
.iopoll = iocb_bio_iopoll,
.unlocked_ioctl = ext4_ioctl,
// ...
.mmap = ext4_file_mmap,
.mmap_supported_flags = MAP_SYNC,
.open = ext4_file_open,
.release = ext4_release_file,
.fsync = ext4_sync_file,
// ...
.fallocate = ext4_fallocate,
};

const struct inode_operations ext4_file_inode_operations = {
.setattr = ext4_setattr,
.getattr = ext4_file_getattr,
// ...
.fiemap = ext4_fiemap,
// ...
};

5. 小结

file.c 不负责盘上 extent/块分配细节(在 inode.c / extents.c / iomap.c),而是 VFS 入口策略:何时 DIO/DAX/缓冲、如何 加锁与 orphan 以保证 ext4 直写 + unwritten + 延迟块 组合下的正确性,并挂载 加密、verity、OSyncError、配额、seek 洞/数据。阅读 write(2)/read(2)/mmap 在 ext4 上的行为时,应与本文件及 ext4_iomap_* 实现对照。

文章互动

阅读 --

留言

0 条留言

正在加载留言…