反向映射机制与实现详解
源码路径:
rk3588/kernel-6.1/mm/rmap.c、page_vma_mapped.c
内核版本:Linux 6.1(RK3588)
文档目录:linuxDoc/mm/
目录
一、原理
1.1 正向 vs 反向映射
| 方向 | 含义 | 典型用途 |
|---|---|---|
| 正向 | 虚拟地址 → PTE → 物理页 | 进程访问内存 |
| 反向 | 物理页 → 所有映射它的 PTE | 回收、迁移、写回、解除映射 |
无 rmap 时,内核无法知道某 物理页 还被哪些进程映射,不能安全回收或迁移。
1.2 两类映射
匿名页(堆、栈、匿名 mmap):
- 通过
anon_vma/anon_vma_chain挂到相关 VMA - fork 后树状共享 anon_vma
文件页(page cache):
- 通过
address_space->i_mmap(interval tree)记录所有 mmap 该文件的 VMA - 每个 VMA 内再用页表遍历
1.3 锁顺序
rmap.c 文件头定义 MM 全局 锁顺序(mmap_lock → inode/i_mmap → page lock → anon_vma → pte lock → lru_lock)。违反易死锁。
二、实现方式
2.1 遍历映射:page_vma_mapped_walk
page_vma_mapped.c 提供 page_vma_mapped_walk:
- 在指定 VMA 的页表范围内查找 指向目标 pfn 的 PTE
- 支持 THP、PMD 映射等层级
rmap 中 try_to_unmap_one、page_mkclean 等均依赖此 walker。
2.2 匿名 VMA 建立
anon_vma_prepare/__anon_vma_prepare:首次映射匿名页时创建 anon_vmaanon_vma_fork:fork 复制/合并 anon_vma 树anon_vma_init:启动期初始化 slab cache
2.3 解除映射:try_to_unmap
回收路径调用 try_to_unmap(folio, flags):
- 文件页:遍历
mapping->i_mmap中 VMA - 匿名页:遍历
folio_anon_vma(folio)链 - 对每个 VMA 调用
try_to_unmap_one:
1 | static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, |
flags 含 TTU_IGNORE_MNU、TTU_BATCH_FLUSH 等。
2.4 写回与 COW 辅助
| 函数 | 作用 |
|---|---|
page_mkclean |
清除 PTE 写位,用于文件页回收前写回 |
try_to_migrate |
迁移专用 unmap |
page_referenced |
检查 PTE young 位,供回收参考 |
2.5 TLB flush
unmap 后通过 flush_tlb_batched_pending / mmu_notifier 通知架构刷新 TLB。
三、关键数据结构与接口
| 结构/接口 | 说明 |
|---|---|
struct anon_vma |
匿名页反向映射根 |
struct anon_vma_chain |
VMA 与 anon_vma 关联 |
struct address_space.i_mmap |
文件 mmap 区间树 |
try_to_unmap |
回收 unmap |
page_vma_mapped_walk |
PTE 遍历器 |
四、与其它子系统协作
- 07 回收:必须先 unmap 才能释放 file/anon 页
- 09 CMA / migrate:
migrate_pages需 rmap 协助 - 04 缺页:建立映射时注册 anon_vma / i_mmap
五、调试与观测
- 死锁排查:对照
rmap.c锁顺序与持有锁的栈 CONFIG_DEBUG_VM_RB等选项可校验 interval tree
附录:源码索引
| 主题 | 文件 | 约略行号 |
|---|---|---|
| try_to_unmap_one | rmap.c | 1470 |
| anon_vma_init | rmap.c | 459 |
| page_vma_mapped_walk | page_vma_mapped.c | 全文 |
正在加载留言…