前言
mmap 函数经常是和 普通的 bio 进行一个参照对比
mmap 相比于 bio 减少了一次 系统空间 到 用户空间 的拷贝操作
普通的 bio 的流程可以参见这里 从磁盘读取数据到内存的调试
这里 我们来看一下 mmap
测试用例
测试用例如下, 仅仅是一个 mmap 的一个简单的使用
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>#define LEN (10*4096)int main(void) {int fd, loop;char *vadr;if ((fd = open("/dev/mapnopage", O_RDWR)) < 0) {return 0;}vadr = mmap(0, LEN, PROT_READ, MAP_PRIVATE | MAP_LOCKED, fd, 0);for (loop = 0; loop < 2; loop++) {printf("[%-10s----%lx]\n", vadr + 4096 * loop, vadr + 4096 * loop);}}
get_unmapped_area
从上下文可知 file 为 代码中读取的 "mapnopage"
do_mmap 主要有几个阶段, get_unmapped_area 为 获取可用的 mmap 的虚拟内存
mmap_region 为处理真正的映射处理, 初始化 vma->vm_ops
mm_populate 为迭代用户需要的 n 个页面, 然后 产生缺页中断, 然后 基于 vma->vm_ops 来处理缺页中断, 填充页面
如果用户有传入一个合法的 虚拟地址, 直接返回目标的地址
否则从 heap 自顶向下获取可用的 虚拟内存区间
然后就是 找可用的 mmap 映射区, 从 mmap_base 开始向下找, 可用的 vma 映射区
mmap_region
这部分就是 根据可用的 mmap 映射区, 新建 vma, 然后添加到 用户进程中
然后基于 file->f_op->mmap 来处理 vma, 更新 vma->vm_ops 为 对应的文件系统的 vm_ops, 比如这里 "/dev/mapnopage" 对应的 vm_ops 更新为 shmem_vm_ops
mm_populate
循环需要处理的 n 个页面, 主动触发获取 物理页
然后 shmem_fault 会从 pagecache 中获取给定的文件, 给定的偏移 的 page 信息
然后 定时同步到 持久化设备
以上处理的堆栈信息
在 pagecache 中尝试查询
完