mmap原理及流程(kernel 4.1版本)
by HappySeeker
背景
最近在分析问题时,遇到了mmap fb设备失败问题,顺便看了下4.1版本内核中的mmap相关流程,以前看过老版本的,有些忘记了,这里权当记录,供后续参考。
mmap是什么?
相信做过Linux开发的兄弟都或多或少用过,或者听说过mmap,但可能并不完全了解mmap的作用。
mmap字面上是内存映射的意思,听起来比较抽象,其用法有很多,但总结起来,主要是如下两个用途:
- 将文件内容映射到进程用户态的虚拟地址空间中,如此,进程就可以通过读写相应的虚拟地址空间内容,而直接读写相应文件中的内容。如此映射最大的好处是,进程可以直接从用户态访问文件中的数据,而不需要用户态和内核态之间的内存拷贝操作(正常流程下,如果想要向文件中写数据,需要将数据从用户态拷贝到内核态,然后再从内核态写入文件),相当于少了一次内存拷贝操作,这也是人们常说的零拷贝技术之一。当然,这里的文件不限于普通文件,Unix环境中,一切皆文件嘛,这里的文件完全可能是特殊文件,比如设备文件,那相应的mmap操作就需要单独的驱动实现了。
- 分配内存。当mmap中传入的fd为空时,其作用就是分配内存,类似于malloc(其实malloc的glibc实现中就使用了mmap来分配内存),俗称“匿名映射”,匿名的意思就是fd为空,名字很抽象,本质不复杂:就是在进程的虚拟地址空间中分配一段虚拟内存(用vma表示),物理内存在缺页异常中分配,并修改相应页表。
mmap基本原理
如前面所述,mmap主要有两种用途,其中第一种用途分两种情况(普通文件和特殊文件),这里分别描述相关原理:
1.普通文件的mmap基本原理为:每个文件(file)都定义了相应的文件操作数据结构(file_operations),该结构中定义了mmap操作,比如ext3文件系统文件对应的文件操作为:ext3_file_operations
,对应的mmap操作接口为:generic_file_mmap
。generic_file_mmap
中就是创建(或查找利用现有的)vma,然后设置相应的成员,包括缺页异常对应的处理钩子,最后返回相应的虚拟地址。当进程访问(写)相应的虚拟地址时,硬件会触发缺页异常(因为相应的页表项还没有创建),此时会进入缺页异常流程(do_page_fault
),然后会进入之前设置的缺页异常钩子,该钩子会触发文件系统的写入操作,最终会将数据写入到文件中。
2.特殊文件(以设备文件为例)的mmap的基本原理与上述普通文件类似,主要差别在于:其定义的文件操作不同,对应的接口不同;其实现取决于具体的驱动,流程与普通文件实现可以完全不同,这里不详述。
3.匿名映射的基本原理:由于没有具体的fd,没有对应的文件,匿名映射没有对应的文件操作,其流程比较直接,主要还是创建(或查找利用现有的)vma,然后设置相应的成员,返回相应的虚拟地址。当进程访问(写)相应的虚拟地址时,硬件会触发缺页异常(因为相应的页表项还没有创建),此时会进入缺页异常流程(do_page_fault
),然后会进入匿名映射对应的流程,主要就是为虚拟地址范围创建相应的页表,本质上,就是分配了相应的物理内存。
代码流程
mmap流程
mmap有相应的系统调用接口,从系统调用开始的大致流程如下(代码不是很好找,需要仔细看看):
SYSCALL_DEFINE6(mmap_pgoff, ...
sys_mmap_pgoff
SYSCALL_DEFINE6(mmap_pgoff, ...
vm_mmap_pgoff
do_mmap_pgoff
mmap_region
file->f_op->mmap() //不同文件(驱动)自己定义的mmap钩子,比如ext3文件系 统对应为`generic_file_mmap`
文件缺页异常流程
do_page_fault
__do_page_fault
handle_pte_fault
__handle_mm_fault
handle_pte_fault
do_fault
do_shared_fault
__do_fault
vma->vm_ops->fault() //文件系统或驱动注册的缺页异常钩子,如ext4文件对应为filemap_fault
匿名映射缺页异常流程
do_page_fault
__do_page_fault
handle_pte_fault
__handle_mm_fault
handle_pte_fault
do_anonymous_page
mk_pte //创建页表项
set_pte_at
Subscribe via RSS