MIT 6.828 操作系统课程系列10 mmap#

linux的mmap函数#

https://www.man7.org/linux/man-pages/man2/mmap.2.html
https://en.wikipedia.org/wiki/Mmap

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); mmap创建文件/设备到内存的映射。把fd偏移offset处,映射到addr。映射长度至少为length。
addr参数可不传,让函数返回实际映射地址。如果传了addr,addr只是作为一个hint。实际地址以返回值为准。
返回的地址都是对齐的。

prot可为PROT_EXEC/PROT_READ/PROT_WRITE/PROT_NONE

flag较多

  • MAP_ANONYMOUS
    匿名映射。不用提供fd和offset。

  • MAP_SHARED
    共享映射。对此映射的修改,对于其他映射到此区域的进程可见。
    如果和fd关联,也会更新其文件。

  • MAP_PRIVATE
    cow映射。本地修改对于其他进程不可见,也不会更新关联的文件。

https://www.man7.org/linux/man-pages/man2/msync.2.html
msync

// uwsgi中的例子
// 创建进程间共享内存
uwsgi.shared = (struct uwsgi_shared *) uwsgi_calloc_shared(sizeof(struct uwsgi_shared));
    uwsgi_malloc_shared
        void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

uwsgi的mmap。创建匿名共享映射,直接做成类似malloc一个uwsgi_shared。然各个进程共享。

virtual memory#

https://en.wikipedia.org/wiki/Virtual_memory

内容挺多。大概看看看课程的lecture17视频。

他把mmap/页表/vma这些内容归为virtual memory。建议阅读的论文https://www.cs.princeton.edu/~appel/papers/vmpup.pdf

作为外行听到的虚拟内存,一般是指把硬盘之类充当内存来用(windows有个配置)。
实际是指一个更大的概念,覆盖存储管理/地址管理等一系列内容。

写代码#

  • 最后一个lab了,胜利就在眼前。mmap涉及的内容比较杂,还是需要一点点耐心实现各种规则。

  • 必须搞懂文件系统的流程和结构。打开文件的流程,根据path得到inode,分配file和fd,关联,返回fd。

  • 文件的实际内容在其inode的addrs里,由一串磁盘block号组成,block可位于磁盘的任何位置,不一定是连续的。

  • 写文件时看offset落在addrs的位置,找到对应的磁盘block,写磁盘。

  • 复习lab3页表相关

  • mmap需要做一个虚拟地址va返回给用户,从va开始,指定长度length。之间的连续地址需要映射到文件的block。

  • 根据prot设置读/写/执行权限。

  • 根据flags决定更新行为。
    MAP_SHARED为共享。一个进程改了数据,其他进程都能看到。并且要更新文件。
    MAP_PRIVATE为私有。

  • 每个mmap映射维护一条数据(结构体),每个进程要维护好自己的所有映射数据。

  • 地址怎么生成?如果直接按sz来,删除时会出现,后续fork时不好处理。
    可做成一个固定位置,像TRAPFRAME那样,更容易处理。

  • 创建映射时处理好PTE的flag,使读写走page fault。在trap里读对应的文件block。这样实现lazy分配。

  • 对地址的操作和文件offset的处理类似。

  • 基本测试是先往文件里写1.5page的数据。然后创建mmap,读地址上的数据检查是否和写文件时数据数据一致。

  • 如果文件是read only,禁止PROT_WRITE的mmap。

  • munmap删除映射。测试中都是按页对齐来unmap,不用考虑复杂情况。可删除两头的部分映射,不会出现从中间打个洞。
    如果是MAP_SHARED,需要把修改过的页更新到文件。

  • mmap后如果unlink删除文件?如果又创建一个文件再写入,可能把mmap的数据篡改。
    需要处理文件和inode的引用计数,hold住数据。

  • exit时删除映射。

  • fork时要复制维护的mmap数据,做地址映射。参考uvmcopy。

  • trap里处理mmap,要区分是否mmap导致。如果不是要正常kill,否则usertests会失败。


到此整个课程结束。对os的基本流程有了一定了解。可以开始动手做一个自己的os了。