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当中

测试

相关推荐
数智顾问6 小时前
【73页PPT】美的简单高效的管理逻辑(附下载方式)
大数据·人工智能·产品运营
和科比合砍81分6 小时前
ES模块(ESM)、CommonJS(CJS)和UMD三种格式
大数据·elasticsearch·搜索引擎
瓦哥架构实战7 小时前
从 Prompt 到 Context:LLM OS 时代的核心工程范式演进
大数据
weixin_lynhgworld7 小时前
盲盒抽卡机小程序系统开发:以技术创新驱动娱乐体验升级
大数据·盲盒·抽谷机
TDengine (老段)9 小时前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
悟乙己9 小时前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
东哥说-MES|从入门到精通10 小时前
Mazak MTF 2025制造未来参观总结
大数据·网络·人工智能·制造·智能制造·数字化
盟接之桥10 小时前
盟接之桥说制造:在安全、确定与及时之间,构建品质、交期与反应速度的动态平衡
大数据·运维·安全·汽车·制造·devops
链上日记11 小时前
STC携手VEX发起全球首个碳资产RWA生态,泰国峰会即将引爆绿色金融
大数据
用户Taobaoapi201411 小时前
京东商品列表API(JD.item_search)
大数据·数据挖掘·数据分析