11.Lab Ten —— mmap

内存映射文件(Memory-Mapped File)是一种将文件内容映射到进程的虚拟地址空间的技术,使得文件的内容可以像内存一样被访问。

通过内存映射文件,可以高效地访问和操作文件内容

首先切换到mmap分支

复制代码
git checkout mmap
make clean
  1. 在Makefile中添加 $U/_mmaptest,同时添加mmap和munmap系统调用的声明定义,包括kernel/syscall.h, kernel/syscall.c, user/usys.pluser/user.h.

2.在 kernel/proc.h 中定义VMA结构体及数组

VMA存储了mmap-ed的信息,当一个进程调用mmap后,kernel会将已经mmap的信息记录到进程的一个VMA数组中(一次mmap对应一个VMA),strcut proc中有一个vma_pool字段存储所有的VMA,是一个固定大小的数组,当在mmap需要存储一个VMA时,就是从vma_pool中找一个空闲的位置并将VMA放进去

MAX_VMA_POOL定义为16

VMA结构体字段含义:

  • used:表明VMA是否已经使用,用于在vma_pool中寻空闲位置

  • addr:在内存中映射的内存地址

  • length:映射的大小

  • prot:mmap参数中的权限

  • flags:mmap参数中的flags

  • offset:mmap参数中的offset,一般恒为0

  • f:要映射的文件

3.在kernel/proc.c中的allocproc函数(分配新的进程结构体)中增加对vma_pool的初始化

4.在kernel/proc.c中实现vma_pool中分配和释放VMA的逻辑vma_alloc和vma_fre,同时将函数放到defs.h中

  1. 实现sys_mmap()逻辑(有关mmap的系统调用已经在最开始设置好)

调用system call传入参数,检查权限,然后从vma_pool中分配一个空的vma位置,将其填充mmap的相关信息

6.实现sys_munmap()逻辑

解析调用system call的参数,在vma_pool中找到munmap的内存地址所对应的VMA,根据VMA的信息,将修改数据回写到文件中,然后更新VMA的信息,同时如果发现当初mmap的内存全部munmap,那就释放VMA

cpp 复制代码
int
munmap_impl(uint64 addr, int length)
{
  struct proc *p = myproc();

  // 在 vma pool 中找到 addr 对应的 vma
  struct VMA *vma = 0;
  int i;
  for (i = 0; i < MAX_VMA_POOL; i++) {
    vma = p->vma_pool + i;
    if (vma->used == 1 && addr >= vma->addr && (addr + length) < (vma->addr + vma->length)) {
      break;
    }
  }
  if (i > MAX_VMA_POOL) {
    return -1;
  }
  // 根据 vma 的信息,将数据回写入文件中
  uint64 begin_addr = addr;
  uint64 end_addr = addr + length;
  if (vma->flags == MAP_SHARED && vma->f->writable) {
    uint64 cur_addr = begin_addr;
    while (cur_addr < end_addr) {
      int sz = end_addr - cur_addr >= PGSIZE? PGSIZE: end_addr - cur_addr;
      begin_op();
      ilock(vma->f->ip);
      if (writei(vma->f->ip, 1, cur_addr, cur_addr - vma->addr, sz) != sz) {
        return -1;
      }
      iunlock(vma->f->ip);
      end_op();
      uvmunmap(p->pagetable, cur_addr, 1, 1);
      cur_addr += PGSIZE;
    }
  }
  // 完成回写后,更新 vma 中的信息
  //如果头部的取消映射,那么前面length地址长度的空间都无效了,所以需要+length
  if (addr == vma->addr) {  // 说明 addr 是 mmap 内存的头部
    vma->addr += length;
    vma->length -= length;
    //如果不是头部而是尾部,那其实对vma的起始位置没有影响,直接长度减减即可
  } else if (addr + length == vma->addr + vma->length) { // 说明 addr 是 mmap 的尾部
    vma->length -= length;
  }
  // 如果 mmap 的内存全部被 munmmap,那需要释放 vma 以及对 file 的引用
  if (vma->length == 0 && vma->used == 1) {
    filedup(vma->f);
    vma->used = 0;
  }
  return 0;
}


uint64 sys_munmap(void){
  uint64 addr;
  int length;
  if(argaddr(0,&addr) < 0 || argint(1,&length) < 0){
    return -1;
  }
  return (uint64) munmap_impl(addr,length);
}

7.在kernel/trap.c中的usertrap增加对page fault的处理,因为mmap只是分配了虚拟内存,并没有分配物理内存,当用户访问mmap的内存时会产生page fault,所以需要分配实际的物理内存

同时因为实现了COW,也就是mmap的内存是lazy allocation的,那么虚拟内存不一定有对应的物理内存,就需要修改kernel/vm.c中的uvmcopyuvmunmap

8.修改exit(kernel/proc.c)和fork(kernel/proc.c)

exit应当释放当前进程全部的mmap-ed的内存区域

fork应当让子进程拥有与父进程相同的mmaped

可以发现这里exit使用了munmap_impl函数,那么需要将该函数放到kernel/defs.h当中

测试

相关推荐
用户Taobaoapi201440 分钟前
淘宝商品列表查询 API 接口详解
大数据
涛思数据(TDengine)2 小时前
taosd 写入与查询场景下压缩解压及加密解密的 CPU 占用分析
大数据·数据库·时序数据库·tdengine
DuDuTalk2 小时前
DuDuTalk接入DeepSeek,重构企业沟通数字化新范式
大数据·人工智能
大数据追光猿2 小时前
Qwen 模型与 LlamaFactory 结合训练详细步骤教程
大数据·人工智能·深度学习·计算机视觉·语言模型
Elastic 中国社区官方博客2 小时前
使用 Elastic-Agent 或 Beats 将 Journald 中的 syslog 和 auth 日志导入 Elastic Stack
大数据·linux·服务器·elasticsearch·搜索引擎·信息可视化·debian
对许4 小时前
Hadoop的运行模式
大数据·hadoop·分布式
星星点点洲4 小时前
【RAG】RAG 系统的基本搭建流程(ES关键词检索示例)
python·elasticsearch
天空卫士4 小时前
AI巨浪中的安全之舵:天空卫士助力人工智能落地远航
大数据·人工智能·安全·网络安全·数据安全
@@@wang6 小时前
搜索引擎(基于java在线文档)
搜索引擎
SelectDB技术团队6 小时前
云原生时代的架构革新,Apache Doris 存算分离如何实现弹性与性能双重提升
大数据·数据库·云原生·doris·存算分离