【微信群问题讨论】我想请教一下,有木有人实现或者了解过sparse file在文件系统层面里中是如何支持空洞的?
本文是原「蜗窝讨论区」的历史存档(2017-07-17),来自版块「Linux kernel技术问答」,共 1 帖。讨论区已停止服务,此处仅供查阅。
技术讨论主题:我想请教一下,有木有人实现或者了解过sparse file在文件系统层面里中是如何支持空洞的?是如何用metadata追踪这些空洞的呢?
讨论的过程和结果如下:
1、怎么形成file hole呢?
形成空洞的方法是这样的:首先是创建一个空文件,然后用truncate或者seek命令强制将当前文件指针移动到一个地方,例如1G处,然后在1G处随便写一些数据,这样会形成一个1G的空洞。
2、用户层面读一个文件中的空洞会怎么样?
当对文件中的空洞进行读操作的时候,会返回全0。因此,你想要复制一个包含空洞文件的时候需要小心,由于空洞文件的读操作,会返回全0,在向新文件写的时候,实际上是执行了0写入,但是文件系统不可能去判断数据是否为非0,一旦有数据写入,就会真的写入物理磁盘,这时是不会形成空洞的。例如:cp命令会调ioctl(FIBMAP)下到内核,再到文件系统注册的bmap函数来确认,这个函数会告诉cp,到底是空洞,还是文件结束,如果是空洞,cp会有对应的处理,也会跳成空洞,scp没有这个跳过过程,会把你的空洞全部补0。
3、为何读空洞会返回0呢?
这和内核中的read_page操作相关。一般用户空间对文件发起read操作的时候,首先会在page cache中找,如果没有则发起磁盘操作。而在read_page函数会把磁盘上没有记录的block所对应的page中全部填充0。因此,读空洞就返回全0了。
4、如果写入文件时候 空洞的部分不是一页的整数倍 怎么处理呢?
文件系统是按照file block来组织数据的,因此,对于一个1M的空洞,如果多次跳着写,每次写一个字节a,如果将跨度包含多个块,中间的块仍然是洞,但那一个字节所在的块剩下的blovksize-1会被填充0。之所以如此是因为当我们对空洞写的时候,首先会找到对应的page,如果是空洞,那么其实的数据全0,然后写入这个字节a,然后系统在适当的时候,当把这个page写入磁盘,这时候page中有啥就写啥。
