struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)函数:
功能:给定一个属于某个进程的虚拟地址,要求找到其所属的区间以及相应的vma_area_struct结构;所找到的区间只要满足结束地址大于虚拟地址addr即可
参数:具体的哪个进程mm_struct下;虚拟地址
流程:先验证mm_struct中的mmap_cache(最近访问区),若不符合再从AVL树开始搜索,若没有AVL树则从mmap线性队列开始
源码:
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中去
参数:所要插入的mm_struct;虚拟区间
源码:
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: }