扔掉脏的写时复制页面

时间:2014-06-23 01:12:48

标签: linux mmap

有没有办法可以通过MAP_PRIVATE创建写时复制映射,写一些数据(即弄脏一些页面),然后丢弃我的更改,没有使用munmap和re -mmaping?目标是为给定的映射维护相同的虚拟地址(如果我取消映射并再次映射同一文件,则无法保证发生这种情况),但要立即丢弃我的所有COW更改。

我的理解是,尝试通过提示地址并使用MAP_FIXED标志重新映射空间可能会产生这种效果;但是,我不确定我对MAP_FIXED文档的解释是否正确,或者是否保证了这种行为。

引用mmap(2)docs:

If the memory region specified by addr and len overlaps pages of any existing
mapping(s), then the overlapped part of the existing mapping(s) will be 
discarded.

"丢弃"在这种情况下意味着任何COW页面都将被丢弃,相应页面的新读取将出错并反映磁盘上的更改?

2 个答案:

答案 0 :(得分:3)

如果执行与现有映射重叠的mmap操作,Linux内核将会对现有映射的重叠部分进行调整,就好像首先对它们进行了unmap一样。因此,例如,如果您将帧缓冲区映射到共享库,那么该内存现在与共享库无关;它指向帧缓冲区。

来自已删除映射的基础页面对象与映射无关:页面是引用计数对象。当两个地图共享同一页面的视图时,这仅仅是由于在不同视图中“安装”了相同的页面。当页面变脏,然后取消映射时,这不会创建依赖关系,从而必须在新映射之前写出脏页面;在原始脏页(例如,文件支持的共享映射的一部分)被刷新之前,虚拟内存已经可以重新分配给新映射(例如一块图形帧缓冲区)。

关于丢弃映射:我认为你不能这样做。也就是说,如果你有一个应该将脏页面刷新到底层文件的映射,你就不能写入那个内存然后快速unmap它(或mmap一些东西)希望写作永远不会完成。在Linux的madvise API中,MAP_REMOVE操作似乎相关,但根据手册页,它似乎仅适用于tmpfsshmfs。我认为阻止写入发生的唯一方法是做一个历史悠久的仪式,称为“潜水电源开关”。

有一种方法可以映射文件对象,使得不会传播更改:即MAP_PRIVATE(与MAP_SHARED相反)。例如,MAP_PRIVATE之类的调试器需要gdb,它需要能够将断点放入可执行文件或共享库中,而不会将陷阱指令放入每个可执行文件或库的每个实例中。正在运行的进程(以及磁盘上的副本!)。

如果你有MAP_PRIVATE修改过的部分,并且你取消它(或那些部分)或在它们之上映射某些东西,我相信它们将被丢弃。这些页面应该是写入时复制的,因此使它们变脏的过程应该只保留一个参考。当它们被取消映射时,它们的引用计数降为零,因为它们是私有页面,所以它们会被删除。

答案 1 :(得分:1)

即使在复制后,虚拟地址仍保持不变。只有物理地址发生变化(以及相关的内存映射页面寄存器)。

在进程写入页面后,撤消它已经太晚了。复制发生在第一次写入存储区域期间。