1. 程式人生 > >linux記憶體管理之使用者態記憶體管理以及mmap

linux記憶體管理之使用者態記憶體管理以及mmap

分配一個新的線性區

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);