进程地址空间 insert_vm_struct
2016-06-02 20:16
337 查看
进程地址空间 insert_vm_struct()
insert_vm_struct() 在线性区对象链表和内存描述符的红黑树中插入一个vm_area_struct结构。这个函数使用两个参数:mm 指定进程内存描述符的地址,vma指定要插入的vm_area_struct对象的地址。其基本思路:利用find_vma_links()寻找出将要插入的结点位置,其前驱结点和其父结点。
利用__vma_link_list()和__vma_link_rb()将结点分别插入链表和红黑树中,vma_link()是其前端函数。注意在__vma_link_rb()利用vma_gap_update()更新vm_area_struct中rb_subtree_gap字段。该字段在get_unmapped_area中已有介绍,加快了寻找满足条件的vma。
若线性区用于文件映射,那么利用__vma_link_file()处理。这里暂不讨论。
线性区计数加一。
实际代码如下:
/*
Insert vm structure into process list sorted by address
and into the inode’s i_mmap tree. If vm_file is non-NULL
then i_mmap_rwsem is taken here.
*/
int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma)
{
/*
* rb_link : 保存的是将入插入的位置指针的指针
* pre : 保存的是指向rb_link的前驱结点的指针
* rb_parent : 保存的是指向rb_link的父结点的指针
*/
struct vm_area_struct *prev;
struct rb_node **rb_link, *rb_parent;
if (find_vma_links(mm, vma->vm_start, vma->vm_end, &prev, &rb_link, &rb_parent)) return -ENOMEM; if ((vma->vm_flags & VM_ACCOUNT) && security_vm_enough_memory_mm(mm, vma_pages(vma))) return -ENOMEM; /* The vm_pgoff of a purely anonymous vma should be irrelevant until its first write fault, when page's anon_vma and index are set. But now set the vm_pgoff it will almost certainly end up with (unless mremap moves it elsewhere before that first wfault), so /proc/pid/maps tells a consistent story. By setting it to reflect the virtual start address of the vma, merges and splits can happen in a seamless way, just using the existing file pgoff checks and manipulations. Similarly in do_mmap_pgoff and in do_brk. */ if (vma_is_anonymous(vma)) { BUG_ON(vma->anon_vma); vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT; } vma_link(mm, vma, prev, rb_link, rb_parent); return 0; }
find_vma_links : 利用双重指针将插入的位置,插入结点的前驱位置和插入结点的父结点位置保存在对应的双重指针的变量中,返回到上级函数中。
static int find_vma_links(struct mm_struct *mm, unsigned long addr, unsigned long end, struct vm_area_struct **pprev, struct rb_node ***rb_link, struct rb_node **rb_parent) { struct rb_node **__rb_link, *__rb_parent, *rb_prev; __rb_link = &mm->mm_rb.rb_node; rb_prev = __rb_parent = NULL; while (*__rb_link) { struct vm_area_struct *vma_tmp; __rb_parent = *__rb_link; vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb); if (vma_tmp->vm_end > addr) { /* Fail if an existing vma overlaps the area */ /* 判断新生成的vma区是否和已有vma重合 */ if (vma_tmp->vm_start < end) return -ENOMEM; __rb_link = &__rb_parent->rb_left; } else { rb_prev = __rb_parent; __rb_link = &__rb_parent->rb_right; } } *pprev = NULL; if (rb_prev) *pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb); *rb_link = __rb_link; *rb_parent = __rb_parent; return 0; }
相关文章推荐
- UNIX内核概述-进程地址空间
- 进程地址空间 find_vma()
- 地址空间(独立、共用)
- linux内核--进程地址空间(三)
- Linux面试之进程地址空间
- linux内存相关整理--为了看swap的问题
- linux系统之_进程及内存管理的前世今生
- Linux内核之进程地址空间
- 内存描述符mm_struct浅析
- Linux进程地址空间
- 进程的地址空间:TEXT,DATA,BSS,HEAP,STACK
- Linux进程地址空间学习总结
- 如何用十条命令在一分钟内检查Linux服务器性能
- Xamarin.Forms之Frame布局
- Java基础知识
- hdoj-1040-As Easy As A+B
- C++ and the Perils of Double-Checked Locking
- Android总结篇系列:Android广播机制
- 计算球体积
- css做带三角边框