在linux内核中如果一个page被多个虚拟地址(虚拟页)映射,我们可以通过Rmap Walk机制对该page的所有vma进行遍历。
1、try_to_unmap函数入口
int try_to_unmap(struct page *page, enum ttu_flags flags)
{
int ret;
struct rmap_walk_control rwc = {
.rmap_one = try_to_unmap_one,
.arg = &rp,
.done = page_not_mapped,
.file_nonlinear = try_to_unmap_nonlinear,
.anon_lock = page_lock_anon_vma_read,
};
ret = rmap_walk(page, &rwc);
return ret;
}
2、匿名页面的反向映射
struct rmap_walk_control中的rmap_one实现是try_to_unmap_one,最终调用page_remove_rmap()和page_cache_release()来断开PTE映射关系。
- 获取页面page->mapping指向的anon_vma数据结构,并申请一个读者锁
- 遍历anon_vma->rb_root红黑树中的AVC,从AVC得到相应的VMA。
- 实际的断开用户PTE页表项操作
static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc)
{
struct anon_vma *anon_vma;
pgoff_t pgoff;
struct anon_vma_chain *avc;
int ret = SWAP_AGAIN;
anon_vma = rmap_walk_anon_lock(page, rwc);
if (!anon_vma)
return ret;
pgoff = page_to_pgoff(page);
anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
struct vm_area_struct *vma = avc->vma;
unsigned long address = vma_address(page, vma);
if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
continue;
ret = rwc->rmap_one(page, vma, address, rwc->arg);
if (ret != SWAP_AGAIN)
break;
if (rwc->done && rwc->done(page))
break;
cond_resched();
}
anon_vma_unlock_read(anon_vma);
return ret;
}
参考: