mmap(): 如果底层文件发生变化(缩小),会发生什么?

6
如果使用mmap()内存映射文件,但随后底层文件缩小很多,如果访问了已经从文件中删减的内存偏移量,会发生什么?
3个回答

4

IBM表示,如果在mmap()之后映射文件的大小减小,尝试引用文件末尾之外的内容是未定义的,可能会导致MCH0601异常。

如果mmap()函数完成后文件的大小增加,则原始文件末尾之外的整个页面将无法通过映射访问。

SingleUnixSpecification中也有同样的说法:http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html

如果映射文件的大小由于对映射文件的其他操作而发生更改,则对应于添加或删除文件部分的映射区域的引用的影响是未指定的

'

'undefined'或'unspecified'的意思是 - 操作系统允许开始格式化磁盘或其他内容。最可能的情况是SIGSEGV会终止您的应用程序。

'

1
我认为这是一种情况,其中未定义行为可能会导致运行到操作系统错误,从而导致数据丢失:http://lwn.net/Articles/357767/ - ninjalj
1
@osgx 在Linux上,它是一个SIGBUS信号。 - Matthew Hall

1

这取决于您给mmap什么标志,手册页面如下:

MAP_SHARED 共享此映射。对映射的更新对于映射此文件的其他进程是可见的,并传递到底层文件。实际上,直到调用msync(2)或munmap()才可能更新文件。

MAP_PRIVATE 创建一个私有的写时复制映射。对映射的更新对于映射同一文件的其他进程不可见,并且不会传递到底层文件。未指定在mmap()调用之后对文件所做的更改是否在映射区域中可见。

因此,对于MAP_PRIVATE,无论如何,每个编写器都有一个“私有”副本。(但只有在发生变异操作时才会复制)。

我认为如果您使用MAP_SHARED,则不允许其他进程以写权限打开该文件。但这只是猜测。

编辑:ninjalj是正确的,即使您使用MAP_SHARED,文件也可以被修改。


2
你为什么会这样想呢?映射文件本质上只是支持文件的共享内存而已。如果你需要保护,可以使用信号量/进程级互斥或一些无锁算法。 - ninjalj
@ninjalj:看来你是对的。我是从读者/写者问题的角度考虑的(最多1个写者或1个以上的读者,但永远不会同时存在)。显然,曾经有一个标志可以获得我所考虑的行为,但由于它能够被用于本地DoS攻击而被删除了。 - Evan Teran

-1

根据man页面,当您尝试访问对于当前文件映射来说太大的地址时,mmap会返回EINVAL错误。

"dnotify"和"inotify"是Linux内核中当前的文件更改通知服务。它们可能会通知mmap子系统文件的更改。


1
如果在返回mmap之后文件变短了怎么办?这时就没有机会从mmap调用中获得错误信息了。 - osgx
我刚刚尝试使用stat计算文件的大小,我将文件映射到内存中,打印出整个内容,睡眠5秒钟(同时删除了几行),然后再次打印出整个内容,使用stat变量(未修改自原始stat调用),它正常工作,并打印出压缩的内容。 - Gearoid Murphy
Gearoid Murphy,这非常不可靠,因为它取决于Linux磁盘缓存(页面缓存)使用情况和映射类型。 - osgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接