有人告诉我,如果有人删除原始文件,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 / area:
中看到旧文件lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)
该计划的其余部分有效。
即使我在关闭()后删除文件,它仍然可以成功访问mmap()数据。 但是在这两种情况下,之后关闭()我看不到
lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)
了。 (顺便说一句:然后注意到,这个文件“仍以某种方式存在”?)
相反,即使文件被手动删除(在shell中或通过其他一些进程),mmap()仍然能够对数据进行操作,这是相反的吗?
答案 0 :(得分:0)
这里发生了什么。
首先要检查的是
$ls -i /tmp/demo-file.dat
65 /tmp/demo-file.dat
请注意文件65的inode编号。
启动程序时,此处有lsof
输出内容(除了与当前话语无关的其他条目)
a.out 29271 ichakrab 3u REG 0,21 5 65 /tmp/demo-file.dat
这是open()
已完成的结果。请注意,inode编号与其他文件相同。 open()
增加了同一inode的引用计数。另请注意,REG
表示常规文件。
现在,如果文件被删除(使用rm
等),这里lsof
看起来像什么
a.out 29271 ichakrab 3u REG 0,21 5 65 /tmp/demo-file.dat (deleted)
这是预料之中的,因为已打开的文件已被删除,但其过程中的句柄仍处于打开状态。
转到mmap,这里是lsof
输出
a.out 29271 ichakrab DEL REG 0,21 65 /tmp/demo-file.dat
a.out 29271 ichakrab 3u REG 0,21 5 65 /tmp/demo-file.dat (deleted)
现在还有另一个新条目,但请注意,此类型为DEL
,表示(从lsof手册页提升):
&#39;&#39; DEL&#39;&#39;对于已删除的Linux映射文件;
由于lsof
不能再对原始文件进行统计,因此它将此映射设置为DEL
,当然没有大小,但请注意,inode编号仍然保持不变,65。< / p>
现在,在fd上调用了close()
之后lsof
显示的内容
a.out 29271 ichakrab DEL REG 0,21 65 /tmp/demo-file.dat
请注意,(deleted)
条目已经消失,因为fd到REG
文件已经关闭,现在只剩下mmap&#39}内存。
munmap()
此条目也消失了(不再引用/tmp/demo-file.dat
,最后程序结束。