分配一个新的线性区
do_mmap
=>ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
=>len = PAGE_ALIGN(len);
=>addr = get_unmapped_area(file, addr, len, pgoff, flags);//找到一个空闲的线性区
=>get_area = current->mm->get_unmapped_area;
=>addr = get_area(file, addr, len, pgoff, flags);//mm->get_unmapped_area = arch_get_unmapped_area;
=>addr = PAGE_ALIGN(addr);
=>vma = find_vma(mm, addr);
=>注意,vma && vma->vm_end > addr 的优先级是 > 更高,可以理解成 (vma && (vma->vm_end > addr))
=>通过红黑树查找
full_search://for循环的含义:探测找到空闲并且满足大小的空间,用于后续分配新的vma
for (vma = find_vma(mm, addr); ; vma = vma->vm_next)
if (!vma || addr + len <= vma->vm_start)//到vma链表尾部或者在链表找到合适的空位置,参考文章《内存学习3 vma研究》http://mp.blog.csdn.net/mdeditor/index/79157302
mm->free_area_cache = addr + len;
return addr;
addr = vma->vm_end;//这个addr不合适,挪一个位置继续探测
=>error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
=>security_ops->file_mmap (file, reqprot, prot, flags, addr, addr_only);
=>mmap_region(file, addr, len, flags, vm_flags, pgoff, accountable);
=>vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
=>vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);//真正分配vma的地方
vma->vm_mm = mm;
vma->vm_start = addr;
vma->vm_end = addr + len;
vma->vm_flags = vm_flags;
vma->vm_page_prot = protection_map[vm_flags &
(VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
vma->vm_pgoff = pgoff;
=>if (file)
vma->vm_file = file;
get_file(file);
error = file->f_op->mmap(file, vma);
=>addr = vma->vm_start;
pgoff = vma->vm_pgoff;
vm_flags = vma->vm_flags;
=>vma_link(mm, vma, prev, rb_link, rb_parent);//将新的vma加入链表和红黑树里面,里面很复杂,可以牵出一头牛
=>if (vm_flags & VM_LOCKED)//如果不锁存的话届时缺页中断分配页框和刷新页表
mm->locked_vm += len >> PAGE_SHIFT;
make_pages_present(addr, addr + len);//分配页框和刷新页表
=>vma = find_vma(current->mm, addr);
=>ret = get_user_pages(current, current->mm, addr, len, write, 0, NULL, NULL);
分配了线性区之后只是空头支票,没有干货,当访问内存的时候的时候要走入缺页中断
另外一个与分配线性区类似的是malloc,调用do_brk
do_brk
=>if (security_vm_enough_memory(len >> PAGE_SHIFT)) //len >> PAGE_SHIFT 把len转换成pages作为参数,
=>security_ops->vm_enough_memory(current->mm, pages);
=>selinux_vm_enough_memory
=>__vm_enough_memory//判断物理内存是否够用,是否能申请下len大小的空间,这个函数貌似很有用,后续好好研究一下
=>vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
=>vma->vm_mm = mm;
vma->vm_start = addr;
vma->vm_end = addr + len;
vma->vm_pgoff = pgoff;
vma->vm_flags = flags;
vma->vm_page_prot = protection_map[flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
=>vma_link(mm, vma, prev, rb_link, rb_parent);
=>make_pages_present(addr, addr + len);
参考文章
linux底层内存管理–用户空间的分级分配系统以及懒惰的含义
http://blog.csdn.net/liuyuanqing2010/article/details/6680443
linux内存管理之sys_brk实现分析 和 Linux内核分析之缺页中断
http://blog.csdn.net/sadamoo/article/category/1334891