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