linux記憶體管理之使用者態記憶體管理以及mmap
阿新 • • 發佈:2019-02-10
分配一個新的線性區
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);