Linux Kernel/文件页反向映射

按文件页区间查找相关进程映射

Linux 用增强红黑树索引文件映射的页偏移区间,反向查找与一个 folio 相交的 VMA。

v6.12内存管理核验 2026-10-12
相关概念

工程问题#

同一文件的不同范围可以映射到多个进程。回收或迁移文件页时,需要找出可能映射这些页的 VMA;逐个扫描文件的全部映射会把无关区间也带入处理。

实际实现#

address_space.i_mmap 以 VMA 的文件页偏移区间建立 interval tree,节点额外保存整棵子树的最大结束偏移。rmap_walk_file 将 folio 转为闭区间,搜索时结合区间起点排序与子树最大终点排除不相交分支,再调用 rmap_one 处理候选 VMA。

处理流程#

  1. 用 vm_pgoff 和 VMA 页数确定文件页偏移闭区间
  2. 以区间起点排序,在红黑树节点维护子树最大终点
  3. 将 folio 的起始偏移及页数换算为待查闭区间
  4. 遍历相交 VMA,换算虚拟地址后交给反向映射回调

源码片段#

固定版本 · 原文摘录
mm/interval_tree.cv6.12 · L13–L25
查看原文件
13static inline unsigned long vma_start_pgoff(struct vm_area_struct *v)14{15	return v->vm_pgoff;16}1718static inline unsigned long vma_last_pgoff(struct vm_area_struct *v)19{20	return v->vm_pgoff + vma_pages(v) - 1;21}2223INTERVAL_TREE_DEFINE(struct vm_area_struct, shared.rb,24		     unsigned long, shared.rb_subtree_last,25		     vma_start_pgoff, vma_last_pgoff, /* empty */, vma_interval_tree)
vma_start_pgoff / vma_last_pgoff / INTERVAL_TREE_DEFINE

VMA 的起止键来自文件页偏移,shared.rb_subtree_last 是子树最大终点;宏将这些字段绑定到增强红黑树。

mm/rmap.cv6.12 · L2685–L2701
查看原文件
2685lookup:2686	vma_interval_tree_foreach(vma, &mapping->i_mmap,2687			pgoff_start, pgoff_end) {2688		unsigned long address = vma_address(vma, pgoff_start,2689			       folio_nr_pages(folio));26902691		VM_BUG_ON_VMA(address == -EFAULT, vma);2692		cond_resched();26932694		if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))2695			continue;26962697		if (!rwc->rmap_one(folio, vma, address, rwc->arg))2698			goto done;2699		if (rwc->done && rwc->done(folio))2700			goto done;2701	}
rmap_walk_file

遍历与 folio 文件页区间相交的 VMA,先换算虚拟地址,再执行 rmap_one;这段调用证明 interval tree 直接用于文件页反向映射。

include/linux/interval_tree_generic.hv6.12 · L88–L106
查看原文件
88		if (node->ITRB.rb_left) {				      \89			ITSTRUCT *left = rb_entry(node->ITRB.rb_left,	      \90						  ITSTRUCT, ITRB);	      \91			if (start <= left->ITSUBTREE) {			      \92				/*					      \93				 * Some nodes in left subtree satisfy Cond2.  \94				 * Iterate to find the leftmost such node N.  \95				 * If it also satisfies Cond1, that's the     \96				 * match we are looking for. Otherwise, there \97				 * is no matching interval as nodes to the    \98				 * right of N can't satisfy Cond1 either.     \99				 */					      \100				node = left;				      \101				continue;				      \102			}						      \103		}							      \104		if (ITSTART(node) <= last) {		/* Cond1 */	      \105			if (start <= ITLAST(node))	/* Cond2 */	      \106				return node;	/* node is leftmost match */  \
INTERVAL_TREE_DEFINE · _subtree_search

只有左子树最大终点不小于查询起点时才进入该子树;随后检验当前节点两端是否相交。查询依赖区间增强信息,而不只是普通键值查找。

依次展示区间定义、反向映射调用和子树剪枝。完整函数还包括锁获取、调度让出及停止条件,摘录未将它们视为树本身提供的能力。

收益与取舍#

工程分析

带来的收益

  • 查询可以跳过最大终点仍小于待查起点的整棵子树
  • 一个文件页范围可以返回多个进程中的候选 VMA,而不局限于单个包含区间

付出的代价

  • 每个节点增加区间增强字段;插入、删除和旋转需要维护子树最大终点
  • 区间命中只是候选映射,具体页表状态仍由回调检查;还需要 folio 锁和 i_mmap 读锁保护

可比较的选择

线性扫描文件的全部 VMA结构更简单,但每次查询都要检查无关映射;映射数量增多时扫描成本上升。

版本与适用范围#

对应 Linux v6.12 的 rmap_walk_file。键是同一文件内的页偏移,不是进程虚拟地址;与 mm_struct.mm_mt 管理进程 VMA 的 Maple Tree 是不同索引。回调可以提前结束,区间相交不保证页表当前仍存在映射。

参考来源#

源码、官方文档与原始论文
01
linux · vma_start_pgoff / vma_last_pgoff / INTERVAL_TREE_DEFINE

mm/interval_tree.c · vma_start_pgoff / vma_last_pgoff / INTERVAL_TREE_DEFINE

源码v6.12
02
linux · rmap_walk_file

mm/rmap.c · rmap_walk_file

源码v6.12
03
linux · INTERVAL_TREE_DEFINE · _subtree_search

include/linux/interval_tree_generic.h · INTERVAL_TREE_DEFINE · _subtree_search

源码v6.12
19 个匹配案例