繁体   English   中英

删除文件后的 mmap()

[英]mmap() after deleting the file

有人告诉我,如果有人删除原始文件, mmap() 可能会遇到麻烦。 我想知道这是否真的发生了。 所以我创建了一些小测试程序。 我正在使用 linux。

#include <iostream>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int, char**)
{
    char const * const fileName = "/tmp/demo-file.dat";
    size_t size;

    {
        struct stat st;
        stat(fileName, &st);
        size = st.st_size;
    }

    int fd = open(fileName, O_RDWR);
    if (fd == -1)
    {
        std::cout << "open() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
        return (-1);
    }
    else
    {
        std::cout << "open() done (ok)" << std::endl;
    }

    for (int i = 20; i > 0; --i)
    {
        std::cout << "file open()'ed, wait #" << i << " seconds before mmap()" << std::endl;
        sleep(1);
    }

    void *data = mmap((void*)0L, size, PROT_READ, MAP_SHARED, fd, (off_t)0);
    if (data == (void*)-1)
    {
        std::cout << "mmap() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
    }
    else
    {
        std::cout << "mmap() done (ok)" << std::endl;
    }

    for (int i = 20; i > 0; --i)
    {
        std::cout << "going to close() socket in #" << i << " seconds" << std::endl;
        sleep (1);
    }

    close(fd);

    for (int i = 30; i > 0; --i)
    {
        std::cout << "going to umap() files in #" << i << " seconds (still accessing the data)" << std::endl;
        for (unsigned int x = 0; x < size; ++x)
        {
            char cp = *(char*) (data + x);
            (void) cp;
        }
        sleep(1);
    }

    munmap(data, size);

    for (int i = 30; i > 0; --i)
    {
        std::cout << "going to terminate #" << i << " seconds" << std::endl;
        sleep(1);
    }

    return 0;
}

每当我删除文件时 - 在 open() 操作之后 - 它不会对 mmap() 产生负面影响。 我仍然可以访问测试程序中的数据。 当我在 close() 之后但在 mmap() 之前删除文件时,它可以工作。 我还可以在 /proc/[pid]/fd/ 区域看到旧文件:

lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)

程序的其余部分有效。

即使我在 close()之后删除文件它仍然可以成功访问 mmap() 数据。 但是在这两种情况下,close() 之后我都看不到

lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)

了。 (顺便说一句:然后注意到,这个文件“仍然以某种方式存在”?)

那么是否相反,可以保证 mmap() 仍然能够对数据进行操作,即使文件被手动删除(在 shell 中或由其他某个进程)?

这就是正在发生的事情。

首先要检查的是

$ls -i /tmp/demo-file.dat
65 /tmp/demo-file.dat

注意文件的 inode 号是 65。

在启动程序时,这是它在lsof输出中的内容(除了与当前讨论无关的其他条目)

a.out   29271 zoso    3u   REG   0,21        5       65 /tmp/demo-file.dat

这是已完成的open()的结果。 请注意,inode 编号与其他文件相同。 open()增加了同一 inode 上的引用计数。 另外,请注意REG表示常规文件。

现在,如果文件被删除(使用rm等),这就是lsof样子

a.out   29271 zoso    3u   REG   0,21        5       65 /tmp/demo-file.dat (deleted)

这是意料之中的,因为打开的文件已被删除,但其 inode 的句柄在此过程中仍处于打开状态。

转到 mmap,这是lsof输出

a.out   29271 zoso  DEL    REG   0,21                65 /tmp/demo-file.dat
a.out   29271 zoso    3u   REG   0,21        5       65 /tmp/demo-file.dat (deleted)

现在有另一个新条目,但请注意,这是DEL类型,表示(从lsof手册页中提取):

''DEL'' 表示已删除的 Linux 地图文件;

由于lsof无法再统计原始文件,因此它将此映射作为DEL放置,当然没有大小,但请注意 inode 编号仍然保持不变,即 65。

现在在 fd 上调用close()之后,这是lsof显示的内容

a.out   29271 zoso  DEL    REG   0,21                65 /tmp/demo-file.dat

请注意, (deleted)条目已消失,因为REG文件的 fd 已关闭,现在仅保留了 mmap 的内存。

munmap()这个条目也消失了(不再引用/tmp/demo-file.dat ,最后程序结束。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM