3.Lab-10 mmap
Lab: mmap (hard)
一、要求
- 只要求实现mmap功能的子集,即对文件进行内存映射
mmap说明
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
- 
map:成功时, 返回map的虚拟地址,失败时返回 `0xffffffffffffffff``
- 
addr:内存映射的起始地址,通常设置为NULL,内核自行决定文件映射到的虚拟地址,本次Lab中addr始终为零
- 
len:要映射的字节数,可能与文件长度不同
- 
prot: 内存映射模式:可读、可写、或可执行可以假定 prot是PROT_READ或PROT_WRITE或两者都是
- 
flags:- 
MAP_SHARED:对映射内存的修改应写回文件
- 
MAP_PRIVATE:修改无需写回文件
- 
不需要实现其他 flags
 
- 
- 
fd:要映射的文件描述符
- 
offset:文件映射的起始位置,通常为文件的偏移量,单位为字节,本次Lab始终为零
如果映射同一个 MAP_SHARED 文件的进程不共享物理页面,这是可以接受的。
munmap说明
int munmap(void *addr, size_t len);
- 
移除指定地址范围内的 mmap映射。
- 
如果内存被修改,并且映射模式为 MAP_SHARED,则应先将修改写入文件。
- 
一个 munmap调用可能只覆盖mmap区域的一部分,但可以假定它将在开始处、结束处或整个区域取消映射(但不会在区域中间打一个“洞”)。比如map了0到10,unmap的区域可能是[0,x]、[x, 10],或者[0,10],但不会是[x,y]\((x,y \in (0,10))\) 
一些提示
- 
在 UPROGS中添加_mmaptest,并添加mmap和munmap系统调用,以便能够编译user/mmaptest.c。目前,只需让mmap和munmap返回错误。kernel/fcntl.h中定义了PROT_READ等。运行mmaptest,它将在第一次mmap调用时失败。
- 
懒填充页表:mmap不应分配物理内存或读取文件。应在usertrap的页面错误处理中完成这些操作,就像copy-on-write LAB中一样。之所以要懒加载,是为了确保map 大文件时能够快速完成,并且mmap一个大于物理内存的文件也是可能的。 - 
这里的map 大文件能够快速完成: - 因为无需真正读取,而只是记录,所以mmap系统调用返回的快
- 之后发生缺页中断时,因为是懒加载,所以每次只读取需要的文件内容,无需全部读取,所以速度也很快
 
- 
mmap一个大于物理内存的文件: 和COW一样,因为只读取需要的页,所以可mmap一个大于物理内存的文件 
 
- 
- 
跟踪mmap的元数据,定义一个结构体VMA保存mmap的元数据。记录虚拟内存范围的地址、长度、权限、文件等。由于xv6没有内核内存分配器,可声明一个固定大小的元数据数组VMAS,大小为16即可。 
- 
实现mmap:在进程的地址空间中找到一个未使用的区域来映射文件,并在进程的VMA数组中添加一个VMA。VMA应包含一个指向映射文件的struct file的指针;mmap应该增加文件的引用计数,以便在关闭文件时结构体不会消失(提示:filedup)。运行mmaptest:第一次mmap应该成功,但随后访问mmap区域的内存将会出现页面错误并使mmaptest终止。 
- 
当访问map区域内存时,会发生缺页异常, 添加代码:申请一个新页,将相关文件的4096字节读入该页,并将其映射到用户地址空间。 使用readi读取文件,它接受文件偏移量参数,用于读取正确的位置(必须对传递给readi的inode进行lock\unlock)。正确设置页面的权限。 运行mmaptest;它应该能够运行到第一个munmap。 
- 
实现munmap:找到地址范围对应的VMA并取消映射(提示:使用uvmunmap)。如果munmap移除了先前mmap的所有页面,它应该减少相应struct file的引用计数。如果取消映射的页面已被修改并且文件映射为MAP_SHARED,则应将页面写回文件(参考:filewrite)。
- 
理想情况下,只需写回脏页。RISC-V PTE中的 脏位(D)表示页面是否被修改。不过,mmaptest并不检查非脏页面是否没有被写回;因此,可以不查看D位,全写回页面。
- 
修改 exit,当exit时,应取消map的区域,就像调用了munmap一样。
- 
修改 fork,以确保子进程和父进程有相同的Map区域。不要忘记为VMA的struct file增加引用计数。在子进程的页面错误处理程序中,可以分配一个新的物理页面,而不是与父进程共享页面。后者会更酷,但它需要更多的实现工作。运行mmaptest;
三、代码地址
https://github.com/INnoVationv2/xv6-labs-2023/commit/4b0cf67a16ffe29e53b3774175ce32a78190156a
 
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号