[英]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.