当一个新区域被加到进程的地址空间时,内核会检查它是否可以与一个或多个现存区域合并,vma_merge()函数在可能的情况下,将一个新区域与周边区域进行合并。参数:
mm:新区域所属的进程地址空间
prev:在地址上紧接着新区域的前面一个vma
addr:新区域的起始地址
end:新区域的结束地址
vm_flags:新区域的标识集
anon_vma:新区域所属的匿名映射
file:新区域映射的文件
pgoff:新区域映射文件的偏移
policy:和NUMA相关
-
struct vm_area_struct *vma_merge(struct mm_struct *mm,
-
struct vm_area_struct *prev, unsigned long addr,
-
unsigned long end, unsigned long vm_flags,
-
struct anon_vma *anon_vma, struct file *file,
-
pgoff_t pgoff, struct mempolicy *policy)
-
{
-
pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
-
struct vm_area_struct *area, *next;
-
-
-
-
-
-
if (vm_flags & VM_SPECIAL)
-
return NULL;
-
-
if (prev)
-
next = prev->vm_next;
-
else
-
next = mm->mmap;
-
area = next;
-
-
-
-
if (next && next->vm_end == end)
-
next = next->vm_next;
-
-
-
-
-
-
-
-
-
if (prev && prev->vm_end == addr &&
-
mpol_equal(vma_policy(prev), policy) &&
-
can_vma_merge_after(prev, vm_flags,
-
anon_vma, file, pgoff)) {
-
-
-
-
-
-
if (next && end == next->vm_start &&
-
mpol_equal(policy, vma_policy(next)) &&
-
can_vma_merge_before(next, vm_flags,
-
anon_vma, file, pgoff+pglen) &&
-
is_mergeable_anon_vma(prev->anon_vma,
-
next->anon_vma)) {
-
-
vma_adjust(prev, prev->vm_start,
-
next->vm_end, prev->vm_pgoff, NULL);
-
} else
-
vma_adjust(prev, prev->vm_start,
-
end, prev->vm_pgoff, NULL);
-
return prev;
-
}
-
-
-
-
-
-
if (next && end == next->vm_start &&
-
mpol_equal(policy, vma_policy(next)) &&
-
can_vma_merge_before(next, vm_flags,
-
anon_vma, file, pgoff+pglen)) {
-
if (prev && addr < prev->vm_end)
-
vma_adjust(prev, prev->vm_start,
-
addr, prev->vm_pgoff, NULL);
-
else
-
vma_adjust(area, addr, next->vm_end,
-
next->vm_pgoff - pglen, NULL);
-
return area;
-
}
-
-
return NULL;
-
}
vma_adjust会执行具体的合并调整操作
-
void vma_adjust(struct vm_area_struct *vma, unsigned long start,
-
unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert)
-
{
-
struct mm_struct *mm = vma->vm_mm;
-
struct vm_area_struct *next = vma->vm_next;
-
struct vm_area_struct *importer = NULL;
-
struct address_space *mapping = NULL;
-
struct prio_tree_root *root = NULL;
-
struct file *file = vma->vm_file;
-
struct anon_vma *anon_vma = NULL;
-
long adjust_next = 0;
-
int remove_next = 0;
-
-
if (next && !insert) {
-
-
if (end >= next->vm_end) {
-
-
-
-
-
again: remove_next = 1 + (end > next->vm_end);
-
end = next->vm_end;
-
anon_vma = next->anon_vma;
-
importer = vma;
-
} else if (end > next->vm_start) {
-
-
-
-
-
-
adjust_next = (end - next->vm_start) >> PAGE_SHIFT;
-
anon_vma = next->anon_vma;
-
importer = vma;
-
} else if (end < vma->vm_end) {
-
-
-
-
-
-
adjust_next = - ((vma->vm_end - end) >> PAGE_SHIFT);
-
anon_vma = next->anon_vma;
-
importer = next;
-
}
-
}
-
-
if (file) {
-
mapping = file->f_mapping;
-
if (!(vma->vm_flags & VM_NONLINEAR))
-
root = &mapping->i_mmap;
-
spin_lock(&mapping->i_mmap_lock);
-
if (importer &&
-
vma->vm_truncate_count != next->vm_truncate_count) {
-
-
-
-
-
importer->vm_truncate_count = 0;
-
}
-
-
-
if (insert) {
-
insert->vm_truncate_count = vma->vm_truncate_count;
-
-
-
-
-
-
-
__vma_link_file(insert);
-
}
-
}
-
-
-
-
-
-
if (vma->anon_vma && (insert || importer || start != vma->vm_start))
-
anon_vma = vma->anon_vma;
-
if (anon_vma) {
-
spin_lock(&anon_vma->lock);
-
-
-
-
-
-
if (importer && !importer->anon_vma) {
-
importer->anon_vma = anon_vma;
-
__anon_vma_link(importer);
-
}
-
}
-
-
if (root) {
-
flush_dcache_mmap_lock(mapping);
-
vma_prio_tree_remove(vma, root);
-
if (adjust_next)
-
vma_prio_tree_remove(next, root);
-
}
-
-
-
vma->vm_start = start;
-
vma->vm_end = end;
-
vma->vm_pgoff = pgoff;
-
if (adjust_next) {
-
next->vm_start += adjust_next << PAGE_SHIFT;
-
next->vm_pgoff += adjust_next;
-
}
-
-
if (root) {
-
if (adjust_next)
-
vma_prio_tree_insert(next, root);
-
vma_prio_tree_insert(vma, root);
-
flush_dcache_mmap_unlock(mapping);
-
}
-
-
if (remove_next) {
-
-
-
-
-
__vma_unlink(mm, next, vma);
-
if (file)
-
__remove_shared_vm_struct(next, file, mapping);
-
if (next->anon_vma)
-
__anon_vma_merge(vma, next);
-
} else if (insert) {
-
-
-
-
-
-
__insert_vm_struct(mm, insert);
-
-
}
-
-
if (anon_vma)
-
spin_unlock(&anon_vma->lock);
-
if (mapping)
-
spin_unlock(&mapping->i_mmap_lock);
-
-
if (remove_next) {
-
if (file) {
-
fput(file);
-
if (next->vm_flags & VM_EXECUTABLE)
-
removed_exe_file_vma(mm);
-
}
-
mm->map_count--;
-
mpol_put(vma_policy(next));
-
kmem_cache_free(vm_area_cachep, next);
-
-
-
-
-
-
if (remove_next == 2) {
-
next = vma->vm_next;
-
goto again;
-
}
-
}
-
-
validate_mm(mm);
-
}
insert_vm_struct()函数用于插入一块新区域
-
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;
-
}
-
-
-
-
-
__vma = find_vma_prepare(mm,vma->vm_start,&prev,&rb_link,&rb_parent);
-
if (__vma && __vma->vm_start < vma->vm_end)
-
return -ENOMEM;
-
if ((vma->vm_flags & VM_ACCOUNT) &&
-
security_vm_enough_memory_mm(mm, vma_pages(vma)))
-
return -ENOMEM;
-
vma_link(mm, vma, prev, rb_link, rb_parent);
-
return 0;
-
}
-
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)
-
{
-
struct address_space *mapping = NULL;
-
-
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);
-
-
-
__vma_link(mm, vma, prev, rb_link, rb_parent);
-
__vma_link_file(vma);
-
-
anon_vma_unlock(vma);
-
if (mapping)
-
spin_unlock(&mapping->i_mmap_lock);
-
-
mm->map_count++;
-
validate_mm(mm);
-
}
阅读(4466) | 评论(0) | 转发(0) |