将稀疏文件就地转换为非稀疏文件

将稀疏文件就地转换为非稀疏文件

在Linux上,给定一个稀疏文件,如何使其成为非稀疏文件?
可以用复制cp --sparse=never ...,但是如果文件是10G,而洞是2G(即分配的空间是8G),如何让文件系统分配剩余的2G而不将原始8G复制到新文件?

答案1

从表面上看,这很简单dd

dd if=sparsefile of=sparsefile conv=notrunc bs=1M

它读取整个文件,并将全部内容写回其中。

为了只写入孔本身,您首先必须确定这些孔在哪里。您可以使用 或 来做到这filefrag一点hdparm

文件片段:

# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1048575:  187357696.. 188406271: 1048576:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188406272: last,eof
sparsefile: 2 extents found

高清参数:

# hdparm --fibmap sparsefile

sparsefile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0 1498861568 1507250175    8388608
  6442450944 1605633024 1614021631    8388608

正如您所说,这个示例文件的10G大小有一个2G孔。它有两个范围,第一个覆盖0-1048575,第二个覆盖1572864-2621439,这意味着该洞是1048576-1572864(以4k大小的块为单位,如所示filefrag)。显示的信息hdparm是相同的,只是显示不同(第一个范围覆盖8388608从 0 开始的 512 字节扇区,因此它是0-4294967295字节,因此漏洞以4294967296-6442450944字节为单位。

请注意,如果存在任何碎片,您可能会显示更多的范围。不幸的是,这两个命令都没有直接显示漏洞,而且我不知道有哪个命令可以这样做,因此您必须从显示的逻辑偏移量中推断出它。

现在,可以通过添加适当的(相同)/值和来填充如上所示的该1048576-1572864洞。请注意,它已适应使用上面使用的扇区。 (对于,您必须调整查找/跳过/计数值以反映大小的块)。ddseekskipcountbs=4kfilefragbs=1M1M

dd if=sparsefile of=sparsefile conv=notrunc \
   bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))

虽然您可以填补漏洞而/dev/zero不是读取文件本身的漏洞(这也只会产生零),但无论如何读取都会更安全,sparsefile这样万一偏移量错误,您就不会损坏数据。

在较新版本的 中GNU dd,您可以坚持使用更大的块大小并以字节为单位指定所有值:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
   iflag=skip_bytes,count_bytes oflag=seek_bytes \
   seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))

filefrag运行后:

# sync
# filefrag -e sparsefile 
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1572863:  187357696.. 188930559: 1572864:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188930560: last,eof
sparsefile: 2 extents found

由于碎片化,它仍然是两个范围。然而,逻辑偏移量表明,这次没有空洞,因此文件不再稀疏。

当然,这个dd解决方案是非常手动的方法。如果您定期需要此功能,那么编写一个小程序来填补此类空白将很容易。如果它已经作为标准工具存在,那我还没有听说过。


毕竟有一个工具fallocate似乎在某种程度上是有效的:

fallocate -l $(stat --format="%s" sparsefile) sparsefile

然而,最后在 XFS 的情况下,虽然它确实为该文件分配了物理区域,但实际上并没有将其清零。filefrag显示已分配但未写入的范围。

   2:        3..      15:    7628851..   7628863:     13:    7629020: unwritten

如果目的是能够直接从块设备读取正确的数据,那么这还不够好。它只保留将来写入所需的存储空间。

相关内容