前提
mmap 和 brk 通过封装 A 和 B , 完成了 对 用户空间虚拟物理内存的管理
代码流程
mm/mmap.c:190:SYSCALL_DEFINE1(brk, unsigned long, brk)
mm/mmap.c:1641:SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
mm/mmap.c:2953:SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len)
可以这么讲, brk 类似于 mmap数据流中的一种:"私有匿名映射"
而mmap共有 四种用途
mmap 的过程1
SYSCALL_DEFINE6(mmap_pgoff
ksys_mmap_pgoff
vm_mmap_pgoff
do_mmap
addr = get_unmapped_area
A.1 针对文件xx映射 get_area = file->f_op->get_unmapped_area
A.2 针对匿名共享映射 get_area = shmem_get_unmapped_area;
A.3 针对匿名私有映射 get_area = current->mm->get_unmapped_area;
A.4 return addr = get_area(file, addr, len, pgoff, flags);
addr = mmap_region
* populate = 0;
vma_merge
vma = kmem_cache_zalloc
if(file){
call_mmap(file, vma);
}else if (VM_SHARED){
shmem_zero_setup(vma);
}else{
vma_set_anonymous(vma);
}
vma_link(mm, vma, prev, rb_link, rb_parent);
----------------------------------------------------以下是 马上申请物理地址空间和建立映射的情况
if (!IS_ERR_VALUE(addr) && ((vm_flags & VM_LOCKED) || (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
*populate = len;
if (populate) mm_populate
__mm_populate
populate_vma_page_range
__get_user_pages
find_extend_vma
follow_page_mask
faultin_page
handle_mm_fault
get_area = file->f_op->get_unmapped_area
file->f_op->mmap 按道理应该完成以下事情
但是实际上分为以下三种情况
1.在file->f_op->mmap前已经分配了物理内存,file->f_op->mmap 只做了映射
2.file->f_op->mmap 申请了物理内存, 并做了映射
3.file->f_op->mmap 没有申请物理内存,没有做映射,而是在 file->f_op->mmap 中设置了 vma->vm_ops= &my_file_mmap
1. 申请物理地址空间
2. 建立虚拟地址空间到物理地址空间的映射
get_area = shmem_get_unmapped_area;
current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags);
shmem_zero_setup(vma);
shmem_kernel_file_setup("dev/zero", size, vma->vm_flags);
vma->vm_ops = &shmem_vm_ops;
get_area = current->mm->get_unmapped_area;
vma_set_anonymous(vma);
vma->vm_ops = NULL;
mmap 的过程2 访存异常
VM_LOCKED 设置后,也会到调用 异常流程中调用的主要函数
handle_mm_fault -> __handle_mm_fault -> handle_pte_fault -> do_anonymous_page
缺页异常 并不对应 一种异常(armv6有7个异常)
而是 对应 几种因为访问内存的产生的错误
这种错误会让 cpu(对应armv6) 产生 data abort 异常
访存(访问存储器) 时发生异常,armv6 会
1.设置 FSR
2.设置 FAR
3.进入 data abort 异常
3.1 设置处理器模式为 ABT异常模式
__vectors_start
vector_dabt
__dabt_usr/__dabt_svc
dabt_helper
v7_early_abort
mrc c5
mrc c6
do_DataAbort
fsr_info[0...4]
do_page_fault
__do_page_fault
handle_mm_fault
__handle_mm_fault
handle_pte_fault
handle_pte_fault
if (!vmf->pte) {
if (vma_is_anonymous(vmf->vma))
return do_anonymous_page(vmf);
else
return do_fault(vmf);
}
if (!pte_present(vmf->orig_pte))
return do_swap_page(vmf);
if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))
return do_numa_page(vmf);
if (vmf->flags & FAULT_FLAG_WRITE) {
if (!pte_write(entry))
return do_wp_page(vmf);
entry = pte_mkdirty(entry);
}
handle_pte_fault 解析
A 针对 匿名页面缺页异常 do_anonymous_page
有虚拟地址,没有映射,没有物理地址
应用场景 : malloc
B 针对 文件映射缺页异常 do_fault (下分 do_read_fault do_cow_fault do_shared_fault,三个函数都调用 __do_fault,__do_fault中调用vma->vm_ops->fault)
有虚拟地址,没有映射,没有物理地址
mmap(驱动mmap中没有申请物理空间和映射)之后,访存 发生异常
应用场景:mmap读文件内容
动态库映射
C 针对 写时复制缺页异常 do_wp_page
有虚拟地址,有映射(页表为只读),有物理地址
应用场景:fork的COW
D 针对 swap 缺页异常 do_swap_page
有虚拟地址, 有映射,有物理地址,物理页被换出
应用场景:为了节省内存,物理页面从内存被换出到硬盘,现在需要换入
针对 ... 缺页异常 do_numa_page
do_fault
do_read_fault
__do_fault
vma->vm_ops->fault()
do_cow_fault
__do_fault
vma->vm_ops->fault()
do_shared_fault
__do_fault
vma->vm_ops->fault()
do_fault
do_read_fault
do_cow_fault
do_shared_fault
do_anonymous_page
pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),vma->vm_page_prot));
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
或
page = alloc_zeroed_user_highpage_movable
pte_alloc
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
do_wp_page
针对写时复制, wp_page_copy
针对可写并且共享的普通映射页面,wp_page_shared
针对可写并且共享的特殊映射页面,wp_pfn_shared
针对可以复用的页面,wp_page_resume
brk 的过程1
SYSCALL_DEFINE1(brk
if (brk <= mm->brk) {mm->brk = brk;}
find_vma
do_brk_flags
get_unmapped_area
vma_merge
vma = vm_area_alloc
vma_set_anonymous
vma_link(mm, vma, prev, rb_link, rb_parent);
----------------------------------------------------以下是 马上申请物理地址空间和建立映射的情况
mm_populate
__mm_populate
populate_vma_page_range
__get_user_pages
find_extend_vma
follow_page_mask
faultin_page
handle_mm_fault
其中会(申请的话,增加)(释放的话,降低) mm_struct 的 brk 成员的值
brk 的过程2
mmap 的过程2 访存异常 中的
1. 主体流程
2. 分体流程 匿名私有映射