##進程地址空間 find_vma()
find_vma()功能是查找給定地址的最鄰近區,是尋找合適的線性地址空間至關重要的函數。find_vma()函數有兩個參數:進程內存描述符的地址mm和線性地址addr。查找線性區的vm_end字段大於addr的第一個線性區的位置,並返回這個線性區描述符的地址;如果沒有這樣的線性區存在,就返回-個NULL指針。
補充:
內核用兩個數據結構表示進程地址空間: struct mm_struct(內存描述符) 和 struct vm_area_struct(線性區描述符) 表示。
struct mm_struct 記錄進程地址空間有關的全部信息,進程描述符struct task_struct中mm字段指向屬於自己的mm_struct(內存描述符)。
struct vm_area_struct 記錄進程使用每個線性區以及線性區的屬性。內核中用兩種數據結構組織每個進程所使用的線性區----鏈表和紅黑樹,這樣做的好處是加快查找的速度。struct mm_struct中mmap 和 mm_rb字段分別存放其鏈表頭和紅黑樹根結點。
/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
struct rb_node *rb_node;
struct vm_area_struct *vma;
/* Check the cache first. */
vma = vmacache_find(mm, addr);
if (likely(vma))
return vma;
/* 查找第一個vm_end字段大於addr的線性區 */
rb_node = mm->mm_rb.rb_node;
while (rb_node) {
struct vm_area_struct *tmp;
tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
if (tmp->vm_end > addr) {
vma = tmp;
if (tmp->vm_start <= addr)
break;
rb_node = rb_node->rb_left;
} else
rb_node = rb_node->rb_right;
}
/*
* vmacache_update : 將新得到的vma緩衝到struct task_struct中vmacache數組中,
* 提高下次查找的命中率.
* 原因 : 程序中引用地址的局部性使下面這種情況出現的可能性很大,如果檢查的最後一個
* 線性地址屬於某一給定的線性區,那麼下一個要前差的線性地址也屬於這個線性區。
*/
if (vma)
vmacache_update(addr, vma);
return vma;
}
EXPORT_SYMBOL(find_vma)