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

测试

相关推荐
孤水寒月7 分钟前
Git忽略文件.gitignore
git·elasticsearch
田猿笔记7 分钟前
Typesense:开源的高速搜索引擎
搜索引擎
LKAI.7 小时前
搭建Elastic search群集
linux·运维·elasticsearch·搜索引擎
WTT00119 小时前
2024楚慧杯WP
大数据·运维·网络·安全·web安全·ctf
云云32113 小时前
怎么通过亚矩阵云手机实现营销?
大数据·服务器·安全·智能手机·矩阵
新加坡内哥谈技术13 小时前
苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架
大数据·人工智能·语言模型
Data-Miner14 小时前
经典案例PPT | 大型水果连锁集团新零售数字化建设方案
大数据·big data
lovelin+v1750304096614 小时前
安全性升级:API接口在零信任架构下的安全防护策略
大数据·数据库·人工智能·爬虫·数据分析
道一云黑板报15 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes