操作系统-mmap

张开发
2026/6/4 15:05:19 15 分钟阅读
操作系统-mmap
传统IO读写原理核心概念传统的IO模型是基于显式系统调用与内核缓冲的,也就是说我们在调用时必须明确告诉内核需要多少字节,存放在哪个内存地址,但是我们都知道用户空间和内核空间是隔离的,不能直接传输数据,就需要拷贝。数据流向这里以read(fd,buf,n)为例来介绍在xv6系统中,发生系统调用之后会有哪些过程:1. CPU会从用户态陷入内核态在这个阶段主要有3个过程:a.程序执行 ecall 指令,CPU从用户态切换到内核态b. 保存用户的寄存器 trapframe,然后跳转到内核里面的 sys_read 函数c. 内核会根据文件描述符 fd,在进程的打开文件表中找到对应的struct file,这个结构体中维护了当前文件的读写偏移量 off2. 文件系统层与 Buffer Cache内核不会直接把数据从磁盘读取到用户缓冲区buffer,而是根据前面介绍过的page cache 机制a. 内核根据文件的 inode和当前的偏移量 off 计算出数据位于磁盘的哪些 Block 上b. 去查询 Buffer Cachei. 内核首先检查这些 Block 是否已经在内核空间的内存(Buffer Cache/Page Cache)里了ii. 如果缓存命中(Hit)则直接使用内核缓存中的数据;如果缓存没命中Miss,内核会驱动磁盘控制器通过DMA的方式将数据从磁盘读取到内核空间的 Buffer(此时进程休眠,等待磁盘IO)3. 由于内核空间和用户空间隔离,而且此时数据位于内核空间(struct buf),所以内核需要将数据拷贝给用户态内核调用 copyout (xv6)或 copy_to_user(Linux),将数据从 内核Buffer 逐字节(或逐字)拷贝到用户传入的 buf 物理地址上,最后更新struct file中的off以便下次读取4. 系统调用返回读取后的字节数,恢复用户寄存器,CPU切换回用户模式但是写入数据 write(fd,buf,n)的流程有一些区别 ::1. 数据首先从 用户 Buffer 拷贝到 内核 Buffer(Page Cache)2. 写回策略:。为了性能,write 调用通常在数据仅仅到达内核Cache 后就立即返回成功。。数据并没有立刻写入磁盘!此时该Cache块被标记为Dirty(脏)。。异步落盘:稍后(由定时器或sync调用触发),磁盘驱动程序才会把Dirty Block真正写入磁盘硬件。缺点分析Mmapmmap(memory map)是一种内存映射文件方法,是虚拟内存空间与文件系统之间的桥梁。在类Unix系统中,它允许将文件或设备映射到进程的地址空间中。核心数据结构记录哪段虚拟内存映射到哪个文件的哪一个部分核心功能函数mmap 主要涉及了三个关键部分的修改和扩充,分别是系统调用、缺页中断处理、解除映射。传统IO与mmap的对比Lab第一步“搭建环境”定义VMA结构体并定义一个进程支持多少个mmap映射区域并将其添加到proc结构体中。VMA记录每个进程mmap了哪些文件映射到了哪些虚拟地址长度等信息。第二步实现sys_mmap系统调用。不做IO操作不分配物理内存只找到一个空闲的VMA槽位决定映射到哪一块虚拟地址并且增加文件引用次数1.遍历当前进程的 VMA 数组找一个空闲的槽位valid 0。2。给这段映射选一个未被使用的虚拟地址区间。3.用p-sz当前进程堆的大小作为映射的起始地址然后增加p-sz,类似于sbrk第三步假如程序访问mmap返回的地址时没有映射物理页此时会触发Page fault我们要在usertrap中捕获他进行分配内存读文件映射页表a. 处理 Load\Store Page Faultb. 遍历VMA数组,看故障地址 stval 是否在某个有效的VMA区间内c. 分配一页物理内存,计算文件偏移量,调用readi 读取数据d. 使用 mappages 将物理页映射到虚拟地址第四步实现sys_munmap,解除映射与写回调用munmap或进程退出时,需要移除映射。如果是MAP_SHARED,必须检查“脏位”(Dirty Bit),将修过的数据写回文件。主要的逻辑是:a. 利用walk函数找到页表项PTE如果PTE中标志位PTE_D为1说明修改过需要写到磁盘b. 写回数据,解除这部分页表,更新v-addr和v-length,最后v-valid0 并fileclose首先先定义PTE_D这个标志位第五步细节fork时子进程也要复制父进程的VMA信息而且要增加对应文件的引用次数exit需要munmap所有的有效VMA

更多文章