inverse map页框逆映射
在页回收中,逆映射是一个有意思,并且很有技巧的一个功能.
逆映射:就是从给定的page来找到所有的引用者,特别的是PTE页表项.
有了逆映射就能安心释放指定page了.不然就会杯具了.
逆映射的场景:共享页框最常见的是共享库,C库基本上映射到所有的用户进程了.其次比如共享内存.
**kernel的演进:**
1. 2.4时代是遍历所有的进程要找到此page的引用者的PTE.简单粗暴.
效率上有点弱,功能上还是达到的.
2. 2.5时代改进了,牺牲了空间换效率,为每个页分配一个list来记录引用者.因为每个page都要增加了size空间,其实大部分页是不存在共享的.据说被抱怨.
3. 2.6又改进了,提出所谓的基于对象的方法.
**2种共享页,或者是2种对象**
1. anonymous 匿名页,这个名字其实真取得不好.MAP_PRIVATE, stack * or brk vma (with NULL file)
2. file map 文件映射页.
**page/anon_vma/address_space**
struct page {
union {
atomic_t _mapcount; /* Count of ptes mapped in mms,
};
union {
struct {
struct address_space *mapping; /* If low bit clear, points to
* inode address_space, or NULL.
* If page mapped as anonymous
* memory, low bit is set, and
* it points to anon_vma object:
* see PAGE_MAPPING_ANON below.
*/
};
}
};
struct anon_vma {
spinlock_t lock; /* Serialize access to vma list */
struct list_head head; /* List of private "related" vmas */
};
struct vm_area_struct {
struct mm_struct * vm_mm; /* The address space we belong to. */
/*
* A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
* list, after a COW of one of the file pages. A MAP_SHARED vma
* can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
* or brk vma (with NULL file) can only be in an anon_vma list.
*/
struct list_head anon_vma_node; /* Serialized by anon_vma->lock */
struct anon_vma *anon_vma; /* Serialized by page_table_lock */
};
struct address_space {
struct inode *host; /* owner: inode, block_device */
struct prio_tree_root i_mmap; /* tree of private and shared mappings */
struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
} ;
**页逆映射**
page->mapping[0]来区分是何种对象.
如果是anonymous对象,则mapping指向anon_vma这个对象,这个对象list所有的vma_area_struct.
vma_area_struct->vm_mm->PGD就能找到PTE了.
如果是file对象,则mapping指向file address space对象.这个address_space.i_mmap记录有所进程的共享映射信息vma_area_struct.这个也就能找到所有进程的PTE信息了. 特别要说的是i_mmap是棵优先查找树. over.
**func**
int try_to_unmap(struct page *page, int migration)
{
int ret;
BUG_ON(!PageLocked(page));
if (PageAnon(page))
ret = try_to_unmap_anon(page, migration);
else
ret = try_to_unmap_file(page, migration);
if (!page_mapped(page))
ret = SWAP_SUCCESS;
return ret;
}
try_to_unmap_one()释放一页
{
address = vma_address(page, vma);算出虚拟地址
if (address == -EFAULT)
goto out;
pte = page_check_address(page, mm, address, &ptl);由虚拟地址算出pte
if (!pte)
goto out;
...后续的页表操作 , 略
}