# 线性区的底层处理

## 1 查找给定地址的最邻近区

struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
{
struct vm_area_struct *vma = NULL;

if (mm) {
/* Check the cache first. */
/* (Cache hit rate is typically around 35%.) */
vma = mm->mmap_cache;
struct rb_node * rb_node;

rb_node = mm->mm_rb.rb_node;
vma = NULL;

while (rb_node) {
struct vm_area_struct * vma_tmp;

vma_tmp = rb_entry(rb_node,
struct vm_area_struct, vm_rb);

vma = vma_tmp;
break;
rb_node = rb_node->rb_left;
} else
rb_node = rb_node->rb_right;
}
if (vma)
mm->mmap_cache = vma;
}
}
return vma;
}

vma = mm->mmap_cache;
return vma;

rb_node = mm->mm_rb.rb_node;
vma = NULL;
while (rb_node) {
vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
vma = vma_tmp;
break;
rb_node = rb_node->rb_left;
} else
rb_node = rb_node->rb_right;
}

#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define container_of(ptr, type, member) ({   /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

vma_tmp = ({ typeof( ((vm_area_struct *)0)->vm_rb ) *__mptr = (rb_node); /
(type *)( (char *)__mptr - ((size_t) &((vm_area_struct *)0)->vm_rb) );})

struct vm_area_struct *
find_vma_prev(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct **pprev)
{
struct vm_area_struct *vma = NULL, *prev = NULL;
struct rb_node * rb_node;
if (!mm)
goto out;

/* Guard against addr being lower than the first VMA */
vma = mm->mmap;

/* Go through the RB tree quickly. */
rb_node = mm->mm_rb.rb_node;

while (rb_node) {
struct vm_area_struct *vma_tmp;
vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);

rb_node = rb_node->rb_left;
} else {
prev = vma_tmp;
if (!prev->vm_next || (addr < prev->vm_next->vm_end))
break;
rb_node = rb_node->rb_right;
}
}

out:
*pprev = prev;
return prev ? prev->vm_next : vma;
}

static struct vm_area_struct *
find_vma_prepare(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct **pprev, struct rb_node ***rb_link,
struct rb_node ** rb_parent)
{
struct vm_area_struct * vma;
struct rb_node ** __rb_link, * __rb_parent, * rb_prev;

rb_prev = __rb_parent = NULL;
vma = NULL;

struct vm_area_struct *vma_tmp;

vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb);

vma = vma_tmp;
return vma;
} else {
rb_prev = __rb_parent;
}
}

*pprev = NULL;
if (rb_prev)
*pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
*rb_parent = __rb_parent;
return vma;
}

## 2 查找一个与给定的地址区间相重叠的线性区

static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
{
struct vm_area_struct * vma = find_vma(mm,start_addr);

if (vma && end_addr <= vma->vm_start)
vma = NULL;
return vma;
}

## 3 查找一个空闲的地址区间

static inline unsigned long get_unmapped_area(struct file * file, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)

return -ENOMEM;
if (!vma || addr + len <= vma->vm_start)
}
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
return -ENOMEM;
}
if (!vma || addr + len <= vma->vm_start) {
}
}

（2）刚刚扫描过的线性区后面的空闲区没有足够的大小（vma !＝ NULL && vma->vm_start < addr＋len）。此时，继续考虑下一个线性区。

## 4 向内存描述符链表中插入一个线性区

int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
{
struct vm_area_struct * __vma, * prev;
struct rb_node ** rb_link, * rb_parent;

if (!vma->vm_file) {
BUG_ON(vma->anon_vma);
vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT;
}
if (__vma && __vma->vm_start < vma->vm_end)
return -ENOMEM;
return 0;

insert_vm_struct()函数在线性区对象链表和内存描述符的红-黑树中插入一个vm_area_struct结构。这个函数使用两个参数：mm指定进程内存描述符的地址，vmp指定要插入的vm_area_struct对象的地址。线性区对象的vm_start和vm_end字段必定已经初始化过。

static struct vm_area_struct *
find_vma_prepare(struct mm_struct *mm, unsigned long addr,
struct vm_area_struct **pprev, struct rb_node ***rb_link,
struct rb_node ** rb_parent)
{
struct vm_area_struct * vma;
struct rb_node ** __rb_link, * __rb_parent, * rb_prev;

rb_prev = __rb_parent = NULL;    /* rb_prev内部变量表示vma的前一个vm_area_struct结构在树中的位置 */
vma = NULL;

struct vm_area_struct *vma_tmp;

vma_tmp = rb_entry(__rb_parent, struct vm_area_struct, vm_rb);

vma = vma_tmp;
return vma;
} else {
rb_prev = __rb_parent;
}
}

*pprev = NULL;
if (rb_prev)
*pprev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
*rb_parent = __rb_parent;
return vma;
}

static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node **rb_link,
struct rb_node *rb_parent)
{

if (vma->vm_file)
mapping = vma->vm_file->f_mapping;

if (mapping) {
spin_lock(&mapping->i_mmap_lock);
vma->vm_truncate_count = mapping->truncate_count;
}
anon_vma_lock(vma);

anon_vma_unlock(vma);
if (mapping)
spin_unlock(&mapping->i_mmap_lock);

mm->map_count++;
validate_mm(mm);
}
static void
__vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node **rb_link,
struct rb_node *rb_parent)
{
}

1. 在mm->mmap所指向的链表中插入线性区 —— __vma_link_list(mm, vma, prev, rb_parent)：
static inline void
__vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node *rb_parent)
{
if (vma->vm_flags & VM_EXEC)
if (prev) {
vma->vm_next = prev->vm_next;
prev->vm_next = vma;
} else {
mm->mmap = vma;
if (rb_parent)
vma->vm_next = rb_entry(rb_parent,
struct vm_area_struct, vm_rb);
else
vma->vm_next = NULL;
}
}

2. 在红-黑树mm->mm_rb中插入线性区：
void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
struct rb_node **rb_link, struct rb_node *rb_parent)
{
rb_insert_color(&vma->vm_rb, &mm->mm_rb);
}
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;

}
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;

while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent);

if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}

if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}

rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}

if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}

rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}

rb_set_black(root->rb_node);
}

4. 递增mm->map_count计数器（mm->map_count++;）。

• 本文已收录于以下专栏：

举报原因： 您举报文章：线性区的底层处理 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)