假设我有一个 128GB 大小的磁盘。该磁盘仅使用了 12GB。磁盘的 116GB 是包含全零 (0x00) 的空白空间。
我想拍摄磁盘的精确快照,以便将来可以按照当前状态精确重建它。为了节省压缩图像的空间,我将通过快速压缩算法(如lz4
或 )将其传递zstd
。
我可以使用 或类似的工具来完成此操作dd
,pv
如下所示:
pv /dev/sdb | lz4 > disk.image.lz4
现在我有一个磁盘映像文件,大小约为 10GB,但实际上包含完整的 128GB 映像,其中包含零 - 零只是被压缩了。
现在我想把这个图像写回磁盘。我自然可以这样做:
lz4 -d -c disk.image.lz4 > /dev/sdb
然而,这里的问题是,将图像写回磁盘可能需要很长时间,因为它将所有内容写回磁盘 - 甚至是零。
假设以下两件事之一:要么我不关心副本上曾经为零的块是否仍然为零,要么如果它是 SSD,我可能只是blkdiscard
在写入图像之前丢弃 SSD 上的所有块,实际上在几秒钟内将磁盘清零。
问题:有没有一种工具可以逐块读取源图像,检测零点,并且简单地跳过在输出设备上写入这些块?
例如,如果我们使用 1MB 块,我理想的工具将读取 1MB 数据,检查是否全部为 0x00,如果不是,则将其写入目标上的相同位置。如果该块确实全是 0x00,则完全跳过写入。
这就是为什么这将是一个优势:
- 将所有块写入目标磁盘可能需要很长时间。特别是当我们使用大小 >2TB 但仅包含相对少量实际数据的旋转硬盘时。
- 当驱动器中只有相对较小的部分可能包含我们关心的数据时,用完 SSD 写入周期将 0x00 写入整个驱动器是相当浪费的。
- 由于图像在写入时被解压缩,因此不会对源设备强加任何额外的读取 I/O。
我正在考虑编写一个简单的工具来完成此任务(如果它尚不存在),但如果已经有一种方法可以做到这一点,那么它是什么?
编辑:为了提供更多细节,一个示例用例是备份包含激活的软件许可证的硬盘分区。根据激活方案,简单的文件副本甚至文件系统感知的分区映像都不太可能正确恢复。 (例如,如果授权方案将数据存储在未分配的空间中、文件表中故意标记为坏的扇区(即使它们不是坏扇区)、NTFS 上的 MFT 本身中等)。因此,需要对所有非全零的内容进行逐位复制,以确保恢复分区仍会产生有效的许可证。
答案1
对于未压缩的(可能本身是稀疏的)源文件,只需使用 (GNU)cp --sparse=always sourcefile /dev/sdX
就足够了:
--sparse=WHEN
控制稀疏文件的创建。见下文
默认情况下,通过粗略启发式检测稀疏源文件,并且相应的目标文件也变得稀疏。这就是 所选择的行为
--sparse=auto
。指定--sparse=always
只要 SOURCE 文件包含足够长的零字节序列就创建稀疏 DEST 文件。用于--sparse=never
禁止创建稀疏文件。
创建稀疏文件只需通过查找而不是写入来完成。在块设备上,这正是 OP 所寻求的(双关语)。
同样也lz4
有稀疏的支持:
--[no-]sparse
稀疏模式支持(默认:在文件上启用,在标准输出上禁用)
lz4 -d -c --sparse disk.image.lz4 > /dev/sdX
这也可以工作(可能甚至不必指定--sparse
),但会首先警告有关覆盖文件的信息:
lz4 -d --sparse /tmp/src.img.lz4 /dev/sdX
最后,对于其他情况(GNU?)dd
本身支持稀疏:
sparse
尝试寻找而不是写入全 NUL 输出块
lz4 -d -c disk.image.lz4 | dd conv=sparse of=/dev/sdX
(我可能还会设置bs=
类似于 SSD 擦除块大小的大小,可能约为 1M,而不是保留默认的 512 字节)。
答案2
是的 - 看看 Clonezilla。
它不会将文件系统中未使用的未使用部分复制到备份映像(或磁盘的未分配部分)。但是如果你的数据稀疏 文件文件系统将其视为一个大分配,那么无论内容如何,它都将被视为一大分配。
Clonezilla 还通过压缩程序传递选定的输出,有很多可供选择,包括并行 gzip。
如果您有某种“原始”磁盘访问权限,那么您可以读取或写入您喜欢的内容,但您必须发明一种方法来指示丢失的零块在哪里。您可以以压缩方式存储文件,“即时”解压缩。我相信 20 多年前就有一款 DOS 产品可以做到这一点;它不太擅长处理错误。