int*_*ect 5 linux filesystems mmap memory-mapped-files ext4
我本质上正在寻找相当于 ext4 的mremap().
我有一个大的mmap()文件,我在其中分配数组,并且数组需要增长。因此,我想让第一个数组在当前位置变大,并移动文件和地址空间中的所有其他数组以腾出空间。
如果这只是匿名内存,mremap()只要我插入整数个内存页面,我就可以在恒定时间内移动整个页面。但这是一个磁盘支持的文件,因此数据需要在文件和内存中移动。
我实际上不想在物理磁盘上读取然后重写整个数据块。我希望数据保留在磁盘上的物理扇区中,并引导文件系统调整文件元数据以在需要额外空间的地方插入新扇区。如果我必须将插入保持为与文件系统相关的磁盘扇区大小的某个倍数,那很好。如果我最终不得不复制 O(N) 扇区或范围引用来为插入的范围腾出空间,那也没关系。我只是不想为了在 4 GB 文件中间插入一个块而将 2 GB 数据移入和移回磁盘。
如何通过操作文件元数据来完成高效插入?Linux 中是否确实公开了用于此目的的通用 API?或者如果文件系统碰巧是 ext4 就可以工作?write()在适当的情况下,在内存映射文件中给定源地址的调用是否会减少到我想要的那种有效移位?
是否有一个 C 或 C++ API 函数,其语义是“从这里复制字节到那里,并将源代码保留为未定义的值”,我应该调用该函数,以防将来将此优化添加到标准库和内核中?
我考虑过总是在文件末尾分配新页面,并将它们映射到内存中的正确位置。但是当我重新加载文件时,我需要找到某种方法来重建这一系列映射。此外,缩小数据结构将是一个不小的问题。那时,我将编写一个数据库页面管理器。
我想我实际上可能已经弄清楚了。
我去寻找“linux make a file稀疏”,这让我在Unix & Linux Stack Exchange上找到了这个答案,其中提到了fallocate命令行工具。该fallocate工具有一个--dig-holes选项,可以将文件中可以用孔表示的部分变成孔。
然后我去寻找“fallocate digholes”来了解它是如何工作的,我得到了手册fallocate页。我注意到它还提供了一种插入某种尺寸的孔的方法:
-i, --insert-range
Insert a hole of length bytes from offset, shifting existing
data.
Run Code Online (Sandbox Code Playgroud)
如果命令行工具可以做到这一点,Linux 也可以做到,所以我深入研究了 Fallocate 的源代码,您可以在 Github 上找到它:
case 'i':
mode |= FALLOC_FL_INSERT_RANGE;
break;
Run Code Online (Sandbox Code Playgroud)
看起来该工具通过使用 Linux 4.1 中添加的标志调用Linux 特定函数fallocate来完成廉价的孔插入(以及所有其他文件数据的移动)。该标志不适用于所有文件系统,但它确实适用于 ext4,并且它正是我想要的:调整文件元数据以在某个点有效地释放文件偏移空间中的一些空间。fallocate()FALLOC_FL_INSERT_RANGE
我并不清楚它如何与当前内存映射页面交互,但我认为我可以使用它。