struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)函數:css
功能:給定一個屬於某個進程的虛擬地址,要求找到其所屬的區間以及相應的vma_area_struct結構;所找到的區間只要知足結束地址大於虛擬地址addr便可html
參數:具體的哪一個進程mm_struct下;虛擬地址node
流程:先驗證mm_struct中的mmap_cache(最近訪問區),若不符合再從AVL樹開始搜索,若沒有AVL樹則從mmap線性隊列開始數據結構
源碼:app
1: /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
2: struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
3: {
4: struct vm_area_struct *vma = NULL;
5:
6: if (mm) {
7: /* Check the cache first. */
8: /* (Cache hit rate is typically around 35%.) */
9: vma = mm->mmap_cache;//先從最近使用的vma_area_struct開始查找
10: if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {//若不在最近使用的vma_area_struct中,則從AVL樹或者線性隊列中搜索
11: if (!mm->mmap_avl) {
12: /* Go through the linear list. */
13: vma = mm->mmap;//線性隊列開始,此線性隊列是按照地址從低往高處排列的
14: while (vma && vma->vm_end <= addr)
15: vma = vma->vm_next;
16: } else {
17: /* Then go through the AVL tree quickly. */
18: struct vm_area_struct * tree = mm->mmap_avl;
19: vma = NULL;
20: for (;;) {
21: if (tree == vm_avl_empty)
22: break;
23: if (tree->vm_end > addr) {
24: vma = tree;
25: if (tree->vm_start <= addr)
26: break;
27: tree = tree->vm_avl_left;
28: } else
29: tree = tree->vm_avl_right;
30: }
31: }
32: if (vma)
33: mm->mmap_cache = vma;//設置mm_struct中的mmap_cache爲最近訪問的虛擬區
34: }
35: }
36: return vma;
37: }
void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)函數:函數
功能:將一個虛擬區間插入到一個進程mm_struct中去ui
參數:所要插入的mm_struct;虛擬區間atom
源碼:spa
1: void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
2: {
3: lock_vma_mappings(vmp);
4: spin_lock(¤t->mm->page_table_lock);
5: __insert_vm_struct(mm, vmp);
6: spin_unlock(¤t->mm->page_table_lock);
7: unlock_vma_mappings(vmp);
8: }
1: /* Insert vm structure into process list sorted by address
2: * and into the inode's i_mmap ring. If vm_file is non-NULL
3: * then the i_shared_lock must be held here.
4: */
5: void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
6: {
7: struct vm_area_struct **pprev;
8: struct file * file;
9:
10: if (!mm->mmap_avl) {//若沒有AVL樹,則將按地址從低往高選擇將新區間插入到線性隊列mm->mmap中去
11: pprev = &mm->mmap;
12: while (*pprev && (*pprev)->vm_start <= vmp->vm_start)
13: pprev = &(*pprev)->vm_next;
14: } else {//有AVL樹,則調整此區間在AVL樹中的位置,同時調整liner que
15: struct vm_area_struct *prev, *next;
16: avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
17: pprev = (prev ? &prev->vm_next : &mm->mmap);
18: if (*pprev != next)
19: printk("insert_vm_struct: tree inconsistent with list\n");
20: }
21: vmp->vm_next = *pprev;
22: *pprev = vmp;
23:
24: mm->map_count++; //vvm個數加1
25: if (mm->map_count >= AVL_MIN_MAP_COUNT && !mm->mmap_avl)//對於一個mm_struct來講,只有vvm個數超過AVL_MIN_MAP_COUNT,纔會創建AVL樹
26: build_mmap_avl(mm);
27:
28: file = vmp->vm_file;
29: if (file) {//若此新區是與文件映射有關,則有相關處理:
30: struct inode * inode = file->f_dentry->d_inode;
31: struct address_space *mapping = inode->i_mapping;
32: struct vm_area_struct **head;
33:
34: if (vmp->vm_flags & VM_DENYWRITE)
35: atomic_dec(&inode->i_writecount);
36:
37: head = &mapping->i_mmap;
38: if (vmp->vm_flags & VM_SHARED)
39: head = &mapping->i_mmap_shared;
40:
41: /* insert vmp into inode's share list */
42: if((vmp->vm_next_share = *head) != NULL)
43: (*head)->vm_pprev_share = &vmp->vm_next_share;
44: *head = vmp;
45: vmp->vm_pprev_share = head;
46: }
47: }