將圖像寫入磁碟但不寫入源圖像中包含全零的扇區?
想像一下,我有一個 128GB 大小的磁碟。在這個磁碟上,只使用了 12GB。116GB 的磁碟是包含全零 (0x00) 的空白空間。
我想拍攝磁碟的精確快照,以便將來可以在目前狀態下準確地重建它。為了節省壓縮圖像中的空間,我將通過快速壓縮算法(如
lz4
or )傳遞它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 本身內等)。因此,需要逐位複制並非全為零的所有內容,以確保恢復分區仍會產生有效的許可證。
對於未壓縮的(並且可能本身是稀疏的)源文件,只需使用 (GNU)
cp --sparse=always sourcefile /dev/sdX
就足夠了:
--sparse=WHEN
控制稀疏文件的創建。見下文
預設情況下,稀疏的 SOURCE 文件由粗略的啟發式檢測,相應的 DEST 文件也變得稀疏。那是 選擇的行為
--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 字節)。