Dd

將圖像寫入磁碟但不寫入源圖像中包含全零的扇區?

  • July 9, 2021

想像一下,我有一個 128GB 大小的磁碟。在這個磁碟上,只使用了 12GB。116GB 的磁碟是包含全零 (0x00) 的空白空間。

我想拍攝磁碟的精確快照,以便將來可以在目前狀態下準確地重建它。為了節省壓縮圖像中的空間,我將通過快速壓縮算法(如lz4or )傳遞它zstd

我可以使用或類似的工具來做到這一點,如下所示ddpv

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 字節)。

引用自:https://unix.stackexchange.com/questions/657566