【问题标题】:mmap(): what happens if underlying file changes (shrinks)?mmap():如果底层文件更改(缩小)会发生什么?
【发布时间】:2011-10-16 02:07:20
【问题描述】:

如果您使用 mmap() 对文件进行内存映射,但底层文件会更改为更小的大小。如果您访问从文件中删除的内存偏移量会怎样?

【问题讨论】:

    标签: c++ linux mmap


    【解决方案1】:

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

    “dnotify”和“inotify”是Linux内核中当前的文件更改通知服务。 据推测,他们会通知 mmap 子系统文件的更改。

    【讨论】:

    • 如果在返回 mmap 后文件变短了怎么办? mmap 调用不会出错。
    • 我刚试过用stat计算文件的大小,我映射文件,打印出全部内容,休眠5秒(同时我删除了几行)并打印出整个再次使用 stat 变量(未修改我原来的 stat 调用)的内容,它工作正常,并打印出合同内容。
    • Gearoid Murphy,这很不可靠,因为它取决于 linux 磁盘缓存(页面缓存)的使用情况和映射类型。
    【解决方案2】:

    IBM 表示未定义 http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Fmmap.htm

    如果映射文件的大小在 mmap() 之后减小,则尝试超出文件末尾的引用未定义,并可能导致 MCH0601 异常。

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

    SingleUnixSpecification中也是这么说的:http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html

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

    “未定义”或“未指定”表示 - 允许操作系统开始格式化磁盘或任何东西。最有可能的是 SIGSEGV 杀死您的应用程序。

    【讨论】:

    • 我会说这是 UB 可能会导致 uo 遇到导致数据丢失的操作系统错误的一种情况:lwn.net/Articles/357767
    • @osgx 在 Linux 上,它是 SIGBUS
    【解决方案3】:

    这取决于你给 mmap 的标志,手册页:

    MAP_SHARED 共享此映射。对映射的更新可见 映射此文件的其他进程,并被执行到 底层文件。在 msync(2) 之前,该文件可能不会真正更新 或 munmap() 被调用。

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

    所以对于MAP_PRIVATE,没关系,每个作者实际上都有一个“私人”副本。 (虽然它只是在发生变异操作时才复制)。

    我会认为如果您使用MAP_SHARED,那么将不允许其他进程以写入权限打开文件。但这是一个猜测。

    编辑:ninjalj 是对的,即使你mmapMAP_SHARED 也可以修改文件。

    【讨论】:

    • 你为什么会这样想?毕竟,映射文件只不过是文件支持的共享内存。如果您想要保护,请使用信号量/进程级互斥锁或一些无锁算法。
    • @ninjalj:看来你是对的。我在考虑读者/作者问题(最多 1 个作者或 1 个以上的读者,但绝不会两者兼而有之)。显然,曾经有一个标志来获取我正在考虑的行为,但它被删除了,因为它能够用于本地 DoS 攻击。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 2011-08-24
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    相关资源
    最近更新 更多