本文共 3755 字,大约阅读时间需要 12 分钟。
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)
SYSCALL_DEFINE6(mmap_pgoff ksys_mmap_pgoff vm_mmap_pgoff do_mmap // A .得到 虚拟地址空间 addr = get_unmapped_area // 1. file->f_op->get_unmapped_area // 2. shmem_get_unmapped_area // 3. current->mm->get_unmapped_area // 这里面得到 虚拟地址空间 // 得到 固定虚拟地址空间的方法 // 参数 addr 以页为单位,即4KB对其 // MAP_FIXED 会得到固定的虚拟地址空间. // 如果调用前被占用,则解占用 // MAP_FIXED_NOREPLACE 也会得到固定的虚拟地址空间// 如果调用前辈占用,则return fail addr = mmap_region * populate = 0; vma_merge vma = kmem_cache_zalloc //... vma 成员的填充 call_mmap(file, vma); // B. 得到物理地址空间 // C. 建立虚拟地址空间到物理地址空间的映射 file->f_op->mmap(file, 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_faultfile->f_op->mmap 按道理应该完成以下事情 // B. 得到物理地址空间 // C. 建立虚拟地址空间到物理地址空间的映射但是实际上分为以下三种情况 1.在file->f_op->mmap前已经分配了物理内存,file->f_op->mmap 只做了映射 // MAP_SHARED 不会引起异常 // MAP_PRIVATE 导致 映射的物理页没有 写权限,写内存会导致异常 2.file->f_op->mmap 申请了物理内存, 并做了映射 // MAP_SHARED 不会引起异常 // MAP_PRIVATE 导致 映射的物理页没有 写权限,写内存会导致异常 3.file->f_op->mmap 没有申请物理内存,没有做映射,而是在 file->f_op->mmap 中设置了 vma->ops = &my_file_mmap // MAP_SHARED // 在访问地址时会导致内存访问异常, 流程中会回调vma->ops//即 my_file_mmap // my_file_mmap 中 完成 申请 物理内存 // 异常其他流程中 会 做 映射 // MAP_PRIVATE // 在访问地址时会导致内存访问异常, 流程中会调用 do_anonymous_page
VM_LOCKED 设置后,也会到调用 异常流程中调用的主要函数handle_mm_fault -> __handle_mm_fault -> handle_pte_fault -> do_anonymous_page
缺页异常 并不对应 一种异常(armv6有7个异常)而是 对应 几种因为访问内存的产生的错误 // 是一种软件上的叫法,架构无关这种错误会让 cpu(对应armv6) 产生 data abort 异常访存(访问存储器) 时发生异常,armv6 会 1.设置 FSR // Fault Status Register 存储失效的相关信息(包括存储访问所属区域和访问类型) 2.设置 FAR // Fault Address Register 存储访问失效的虚拟地址 3.进入 data abort 异常 3.1 设置处理器模式为 ABT异常模式__vectors_start vector_dabt __dabt_usr/__dabt_svc dabt_helper v7_early_abort mrc c5 // 读 c5 mrc c6 // 读 c6 do_DataAbort fsr_info[0...4] do_page_fault // 缺页异常 的 核心函数 A 针对 匿名页面缺页异常 do_anoymous_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
具体流程handle_mm_fault __handle_mm_fault handle_pte_fault do_anonymous_page page = alloc_zeroed_user_highpage_movable page_add_new_anon_rmap(page, vma, vmf->address, false); lru_cache_add_inactive_or_unevictable(page, vma);
SYSCALL_DEFINE1(brk find_vma do_brk_flags get_unmapped_area vma_merge vma = vm_area_alloc 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 成员的值
参考 mmap 的过程2
转载地址:http://pjigi.baihongyu.com/