您的位置:首页 > 其它

进程地址空间 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息