简体   繁体   English

删除文件后的 mmap()

[英]mmap() after deleting the file

I was told, that mmap() might be in trouble, if someone deletes the original file.有人告诉我,如果有人删除原始文件, mmap() 可能会遇到麻烦。 I was wondering if that really happens.我想知道这是否真的发生了。 So i created some little test-program.所以我创建了一些小测试程序。 I am using linux.我正在使用 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;
}

Whenever i delete the file - after the open() operation - it doesn't have negative impact to then mmap().每当我删除文件时 - 在 open() 操作之后 - 它不会对 mmap() 产生负面影响。 I can still acess the data in the test program.我仍然可以访问测试程序中的数据。 When i delete the file right after close(), but before mmap(), it works.当我在 close() 之后但在 mmap() 之前删除文件时,它可以工作。 I can also still see the old file in the /proc/[pid]/fd/ area:我还可以在 /proc/[pid]/fd/ 区域看到旧文件:

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

The rest of the program works.程序的其余部分有效。

Even when i delete the file after the close() it still succeeds to access the mmap() data.即使我在 close()之后删除文件它仍然可以成功访问 mmap() 数据。 However in both cases, after the close() i cannot see the但是在这两种情况下,close() 之后我都看不到

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

anymore.了。 (btw: where is then noted, that this file "still exists somehow"?) (顺便说一句:然后注意到,这个文件“仍然以某种方式存在”?)

So is it the opposite, that it is guaranteed, that mmap() will still be able to operate on the data, even if the file was manually deleted (in a shell or by some other process)?那么是否相反,可以保证 mmap() 仍然能够对数据进行操作,即使文件被手动删除(在 shell 中或由其他某个进程)?

Here's what's happening.这就是正在发生的事情。

The first thing to check is首先要检查的是

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

Note the inode number of the file is 65.注意文件的 inode 号是 65。

On starting the program, here's what it has in its lsof output (apart from other entries not relevant to the current discourse)在启动程序时,这是它在lsof输出中的内容(除了与当前讨论无关的其他条目)

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

This is a result of the open() that's been done.这是已完成的open()的结果。 Note that the inode number is the same as the other file.请注意,inode 编号与其他文件相同。 The open() has increased the ref count on the same inode. open()增加了同一 inode 上的引用计数。 Also, note that REG indicates a regular file.另外,请注意REG表示常规文件。

Now if the file is deleted (using rm etc.), here's what the lsof looks like现在,如果文件被删除(使用rm等),这就是lsof样子

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

This is expected since the file that was opened has been deleted but the handle that to its inode still is open in the process.这是意料之中的,因为打开的文件已被删除,但其 inode 的句柄在此过程中仍处于打开状态。

Moving on to the mmap, and here's the lsof output转到 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)

Now there's another new entry but note that this is of type DEL which indicates (lifting from lsof man page):现在有另一个新条目,但请注意,这是DEL类型,表示(从lsof手册页中提取):

''DEL'' for a Linux map file that has been deleted; ''DEL'' 表示已删除的 Linux 地图文件;

Since lsof can't stat the original file anymore, it puts this mapping as DEL with no size of course, yet note that the inode number still remains the same ie 65.由于lsof无法再统计原始文件,因此它将此映射作为DEL放置,当然没有大小,但请注意 inode 编号仍然保持不变,即 65。

Now after close() has been called on the fd here's what lsof shows现在在 fd 上调用close()之后,这是lsof显示的内容

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

Note that the (deleted) entry is gone since that fd to a REG file has been closed and now only the mmap'd memory remains.请注意, (deleted)条目已消失,因为REG文件的 fd 已关闭,现在仅保留了 mmap 的内存。

After munmap() this entry too is gone (no more references to /tmp/demo-file.dat and finally the program ends.munmap()这个条目也消失了(不再引用/tmp/demo-file.dat ,最后程序结束。

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

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