页缓存与写回机制与实现详解
源码路径:
rk3588/kernel-6.1/mm/filemap.c、readahead.c、page-writeback.c、backing-dev.c、truncate.c
内核版本:Linux 6.1(RK3588)
文档目录:linuxDoc/mm/
目录
一、原理
1.1 Page Cache 角色
页缓存缓存 文件数据 的物理页,使:
- 读:优先内存命中,减少块设备 I/O
- 写:先改缓存页,异步 写回(writeback) 到存储
- mmap:文件映射直接 fault 到 cache 中的 folio
同一文件 inode 对应 struct address_space,其 i_pages(xarray)索引 offset → folio。
1.2 Folio(Linux 6.1)
folio 表示一个或多个连续 page 的缓存单元(尤其 THP、大块 I/O),filemap.c 路径以 folio 为中心,legacy API 经 folio-compat.c 适配。
1.3 预读(Readahead)
顺序读检测 访问模式,提前将后续页读入 cache,隐藏磁盘延迟。
1.4 写回与脏页
修改 mapped 或 write() 路径使页 置脏;pdflush/bdi writeback 线程在脏页比例或 sync 时写回设备。
backing_dev 限制每设备的 inflight 写与脏页占比,防止内存被脏页占满。
二、实现方式
2.1 文件映射缺页:filemap_fault()
filemap.c ~3191:
- 根据
vmf->pgoff在mapping->i_pages查找 folio - 未命中:
pagecache_get_read/filemap_read_folio读盘 - 可能
lock_page,返回VM_FAULT_RETRY - 安装 PTE,
folio_mark_accessed
与 __handle_mm_fault 中文件 VMA 的 vm_ops->fault 衔接。
2.2 缓冲读:filemap_read / generic_file_read_iter
- 按 offset 查找或分配 cache folio
- 未 uptodate 则提交 bio 读盘
- 拷贝到用户 iov
2.3 预读:readahead.c
page_cache_sync_readahead/ondemand_readahead- 根据
file->f_ra(struct file_ra_state)维护预读窗口 readahead_expand扩大窗口;force_page_cache_ra强制预读
2.4 脏页与写回:page-writeback.c
| 步骤 | 说明 |
|---|---|
| 置脏 | folio_mark_dirty → __mark_inode_dirty |
| 聚合 | inode 挂到 bdi->wb 链表 |
| 写回 | wb_writeback / write_cache_pages |
| 完成 | folio_end_writeback,清除 dirty |
balance_dirty_pages:进程写超过 dirty_ratio 时节流。
2.5 backing-dev.c
每个块设备/文件系统注册 struct backing_dev_info:
max_ratio、dirty_bandwidth等- cgroup writeback 关联(
CONFIG_CGROUP_WRITEBACK)
2.6 truncate.c
文件缩小或删除时 truncate_inode_pages:从 xarray 摘除 folio,若映射存在则通过 rmap unmap(见 06 文档)。
2.7 workingset 交互
频繁回收的 cache 页 refault 由 workingset.c 统计,影响 vmscan 对文件页的回收积极性(见 07 文档)。
三、关键数据结构与接口
| 结构/API | 说明 |
|---|---|
struct address_space |
i_pages、host inode、a_ops |
filemap_fault |
mmap 读 fault |
filemap_read |
缓冲读 |
folio_mark_dirty |
标脏 |
sync(2) / fsync |
触发写回 |
a_ops 常用:read_folio、writepages、dirty_folio、migrate_folio。
四、RK3588 平台说明
- 编解码 读配置文件/码流 走 page cache;大文件顺序读可调
fadvise(SEQ)(fadvise.c)。 - dmabuf / GEM 不一定经过传统 page cache,但 VFS 层媒体仍可能用 shmem(见 12 文档)。
- eMMC/UFS 慢时 dirty 内存高 会触发回收与写回竞争,表现为编码卡顿与
NR_WRITEBACK升高。
五、调试与观测
| 手段 | 说明 |
|---|---|
/proc/meminfo Cached/Dirty/Writeback |
缓存与写回量 |
echo w > /proc/sys/vm/drop_caches |
丢弃 cache(调试用) |
fiemap / sync |
写回行为 |
trace:filemap tracepoints。
附录:源码索引
| 主题 | 文件 | 约略行号 |
|---|---|---|
| filemap_fault | filemap.c | 3191 |
| readahead | readahead.c | 全文 |
| writeback | page-writeback.c | 全文 |
| backing dev | backing-dev.c | 全文 |
正在加载留言…