Raid

如何恢復崩潰的 IMSM raid5 陣列

  • June 3, 2021

描述

我有一個包含 6 個 SSD 驅動器的 IMSM RAID 5 陣列。幾個月前其中一個驅動器發生故障,我還無法更換它。(是的,我知道我有時很懶惰。請不要評判我。)但我已經從 RAID 中刪除了它。

然而,昨天另一個驅動器似乎發生了故障。陣列不組裝。由於即使是 BIOS 也無法建構 RAID,所以我無法啟動任何東西。仔細檢查後,它看起來驅動器很好。我可以訪問它並使用 dd 進行備份。但現在開始似乎有一個MBR記錄。也許某些程序用 MBR 表覆蓋了 RAID 超級塊?如果是這種情況,數據應該仍然存在。我只需要能夠告訴mdadm正確的元數據。當我想到它時,第一個據稱“失敗”的驅動器可能也發生了同樣的事情。因為它仍然是可讀的。但當時我並沒有費心去調查。

儘管如此,我現在正試圖找到一種方法來重新組裝數組以訪問其數據(如果可能的話)。我知道塊大小、驅動器的確切順序和 RAID 級別。這些資訊不應該足夠嗎?

一些資訊

我做的第一件事是使用dd(命名sd[a-e].backup)創建剩餘 5 個驅動器的映像。我還使用--examine並保存了輸出檢查了所有驅動器。您可以閱讀此 gist中的輸出。正如您在其中看到的那樣,mdadm 讀取 MBR 標頭sdb並繼續到下一個驅動器,而沒有檢測到任何 RAID 資訊。但是,對於所有其他驅動器,mdadm 會列印正確的元數據。當我們在做的時候,這裡是輸出cat /proc/mdstat

Personalities:
md127 : inactive sda[3](S) sdd[2](S) sde[1](S) sdc[0](S)
     13049 blocks super external:imsm

unused devices: <none>

我試過的

  • 顯然我試圖“關閉並再次打開”:
# mdadm --stop /dev/md127
mdadm: stopped /dev/md127
# mdadm --assemble /dev/md0 /dev/sdb missing /dev/sda /dev/sdc /dev/sde /dev/sdd
mdadm: Cannot assemble mbr metadata on /dev/sdb
mdadm: /dev/sdb has no superblock - assembly aborted
# mdadm --assemble --scan

在最後一次呼叫 mdadm 之後,/proc/mdstat再次看起來與上面的輸出相同。

然後我創建了只讀循環設備:

# losetup --show -rf /mnt/backup/sdX.backup
[...]
# losetup -a
/dev/loop1: [...] (/mnt/backup/sda.backup)
/dev/loop2: [...] (/mnt/backup/sdb.backup)
/dev/loop3: [...] (/mnt/backup/sdc.backup)
/dev/loop4: [...] (/mnt/backup/sdd.backup)
/dev/loop5: [...] (/mnt/backup/sde.backup)
  • 接下來我嘗試使用--build它,因為它不需要任何超級塊資訊,並且可以手動提供所有元數據:
# mdadm --build /dev/md0 --raid-devices=6 --level=5 --chunk=32 /dev/loop2 missing /dev/loop1 /dev/loop3 /dev/loop5 /dev/loop4
mdadm: Raid level 5 not permitted with --build

但顯然我不允許--build在 5 級 RAID 的上下文中使用。

  • 接下來我嘗試使用--assemble但不使用有關 RAID 的 OROM 資訊。
# IMSM_NO_PLATFORM=1 mdadm --assemble /dev/md0 /dev/loop2 missing /dev/loop1 /dev/loop3 /dev/loop5 /dev/loop4
mdadm: Cannot assemble mbr metadata on /dev/loop2
mdadm: /dev/loop2 has no superblock - assembly aborted

我猜那太容易了。我可以以某種方式告訴 mdadm 假設這loop2是該陣列中的第一個設備並使用來自其他驅動器的元數據嗎?

  • 我會嘗試的最後一件事是將循環設備重新安裝為讀寫並重新創建數組。但是我發現的所有例子(比如這個這個) 假設數組是用 mdadm 創建的。但事實並非如此。它最初是由 BIOS 中的實用程序創建的,具有 ISM 或 Intel Rapid Storage 格式。我想我必須對它有更詳細的了解,比如佈局或數據偏移。我不確定 IMSM 的預設設置是什麼,或者我在哪裡可以找到它們。但更重要的是,我擔心 mdadm 的元數據格式比 IMSM 使用更多的空間和更大的超級塊,並且在保存元數據時會覆蓋數據。也許也可以使用 IMSM 重新創建陣列?或者也許可以在外部儲存元數據。長話短說,我不知道如何使用 mdadm 手動重新創建 IMSM 陣列。

StackExchange 上的其他問題

  • 我知道這個問題。但是我不確定這是否可以應用於我的情況,因為我使用的是具有不同超級塊(如果有的話)的 IMSM。
  • 我也讀過這個問題。但是它處理 RAID 0,答案建議使用--build不適用於 RAID 5 的。
  • 我也知道這個。但--force不適用於我的情況,因為有問題的驅動器不僅被標記為失敗或不同步。我再次不確定我應該如何專門使用 IMSM 重新創建陣列。

尤里卡 - 簡介

所以我發現瞭如何再次訪問我的數據。不幸的是,我無法使用mdadm. 問題是使用 IMSM 我必須先創建一個容器。但容器不接受失去的設備。我需要所有原來的 6 個硬碟驅動器,但我現在只有 5 個。我也不能使用任何虛擬硬碟驅動器,因為它們需要連接到 RAID 控制器。此外,我不確定mdadm創建卷後是否或如何開始同步驅動器。但是我找到了一種涉及dmsetup. 我可以再次訪問我的所有文件。

在執行驅動器的多個備份以使用它們時,我還意識到不再屬於陣列的一個驅動器有時會因 IO 錯誤而失敗。我仍然能夠進行備份,因為這些錯誤僅在大約每三次呼叫dd. 我推測一旦發生其中一個 IO 錯誤,驅動器可能會被 IMSM 踢出陣列,並且其所有元數據都被刪除。

我還意識到這個驅動器是陣列中的第一個。由於我有一個 GPT 表,並且由於數組的數據從第一個扇區開始,因此它以 MBR 開頭也是合乎邏輯的。所以驅動器的超級扇區沒有被 MBR 覆蓋。它一直都在。

讀取數據

我試圖在這裡提供一個逐步解決方案,解釋該過程中使用的所有命令。希望這會幫助那裡的人。

(可選)備份所有驅動器

這不是絕對必要的。特別是因為我們稍後會使用只讀循環設備。但是,在我的儲存解決方案發生重大故障後,我特別偏執。所以我盡量避免使用實際數據。除此之外,使用備份文件表明這種方法根本不需要原始硬碟驅動器或 BIOS。您只需要一個 dd 圖像。如果您跳過本節,請確保在下一節中將循環設備真正創建為只讀,否則您可能會面臨數據變得更加退化並可能永遠失去的風險。

不過這裡是備份硬碟的命令。您可能已經熟悉 dd。但是,如果您沒有為陣列中的每個硬碟驅動器執行此命令:

# dd if=/dev/sdX of=/path/to/backups/sdX.img status=progress
# dd if=/dev/sdY of=/path/to/backups/sdY.img status=progress
# [...]

輸入文件if=/dev/sdX是您的硬碟。替換sdXsda,sdb等。輸出文件of=/path/to/backups/sdX.img指向要寫入的圖像。再次適當更換sdXstatus=progress只是告訴 dd 的 GNU 版本將目前進度列印到 stderr。

創建循環設備

接下來我們將創建循環設備。如果我們使用備份圖像,它可以確保它們被辨識為塊文件。雖然這可能不是必需的。但無論如何,它確保圖像只會被讀取,因為我們使用的是只讀標誌-r

# losetup --show -rf /path/to/backups/sdX.img
# losetup --show -rf /path/to/backups/sdY.img
[...]
  • -r: 只讀取文件,不寫入
  • -f:使用循環設備的下一個可用編號,這樣我們就不必自己猜測了。
  • --show:列印-f實際選擇的名稱。這通常非常有用。儘管無論如何我們都會在下一步中列印這些值。

為了更好地了解我們剛剛創建的循環設備,我們可以使用以下命令:

# losetup -a
/dev/loop1: [2129]:251265027 (/path/to/backups/sdX.img)
/dev/loop2: [2129]:251265027 (/path/to/backups/sdY.img)
[...]

嘗試記住哪個循環設備屬於哪個圖像。

收集一些元數據

接下來我們需要了解一些有關 RAID 的資訊。具體來說,我們需要找出 RAID 從哪個扇區開始(尤其是在矩陣 RAID 的情況下),它跨越多少個扇區,它的塊大小和佈局是什麼,以及驅動器以什麼順序添加到陣列中。

如果至少有一個驅動器仍然是陣列的一部分並且附加了元數據,那麼您可以使用它來檢索大部分需要的資訊。sdX在仍屬於陣列的驅動器上執行以下命令:

# mdadm --examine /dev/sdX
/dev/sdX:
         Magic : Intel Raid ISM Cfg Sig.
       Version : 1.3.00
   Orig Family : aa0b2c12
        Family : 48d867fb
    Generation : 0018f99c
    Attributes : All supported
          UUID : 0312fa14:fa8db3c2:2a76dc3f:299ed5b4
      Checksum : 084869b8 correct
   MPB Sectors : 6
         Disks : 6
  RAID Devices : 1

 Disk02 Serial : S21PNSBG710576N
         State : active
            Id : 00000000
   Usable Size : 488391936 (232.88 GiB 250.06 GB)

Bad Block Management Log:
      Log Size : 2040
     Signature : abadb10c
   Entry Count : 254

[NameOfYourArray]:
          UUID : 24b1e785:14f37ee5:41f6a4ab:d8b89e11
    RAID Level : 5
       Members : 6
         Slots : [__UUUU]
   Failed disk : 1
     This Slot : 2
   Sector Size : 512
    Array Size : 2441959424 (1164.42 GiB 1250.28 GB)
  Per Dev Size : 488392200 (232.88 GiB 250.06 GB)
 Sector Offset : 0
   Num Stripes : 7631124
    Chunk Size : 32 KiB
      Reserved : 0
 Migrate State : idle
     Map State : failed
   Dirty State : clean
    RWH Policy : off

輸出繼續,但您可以忽略其餘部分。上面顯示的輸出產生以下有價值的資訊:

Sector Offset : 0       # Where the data starts
                       # (right at the first sector in my case)
Array Size : 2441959424 # Size of the volume (data) inside the array
Chunk Size : 32 KiB     # Size of a single chunk

您甚至可以確定特定驅動器在陣列中的位置。

This Slot : 2

這意味著這個是陣列中的第三個驅動器。(槽號從零開始。)或者Disk## Serial : [...]也提示槽號:

Disk02 Serial : S21PNSBG710576N

對所有驅動器執行此命令。對於仍然產生有效結果的那些,請記下插槽號。

您可以使用另一個技巧來確定陣列中的第一個驅動器。由於 RAID 是以塊而不是以字節為單位寫入的,因此前 32 kiB 位於第一個驅動器上。第二個驅動器上的第二個 32 kiB 等等。這意味著第一個驅動器應該有足夠的扇區包含分區表的開頭。這意味著開始時應該有一個 MBR(即使您使用 GPT,因為它以保護性 MBR 開始)。mdadm --examine已經告訴您它在沒有元數據時找到了 MBR。但你也可以使用fdisk -l.

就我而言,我能夠通過它們的元數據找出四個驅動器的插槽號。我很幸運,第五個驅動器包含一個 MBR,所以我自動知道它是第一個。6 個驅動器中的 5 個足以啟動陣列。如果您不知道足夠驅動器的確切插槽號,您可以嘗試使用不同的排列,直到此方法成功。

這意味著我的驅動器以及我的循環設備的正確順序是:

最後要弄清楚的是佈局。不幸的是mdadm,我們沒有提供這方面的資訊。然而,當我們查看Intel 的 RAID 定義時,看起來 RAID 5 的佈局總是不對稱的。我不確定 IMSM 陣列是否可以配置為不同的佈局,但對我來說似乎不太可能。如果這一切都不適合您,那麼您可以嘗試不同的佈局。查看原始碼以了解有關其他佈局的更多資訊。

以下是 ISM 支持的所有 RAID 級別的概述。dmsetup 關鍵字將在下一章中使用。

如果您無法從任何驅動器收集任何元數據,那麼您必須猜測值和/或嘗試不同的組合。作為幫助,這些是 IMSM 支持的不同模式:

對於起始扇區和大小,如果您不確定,最好假設為零,並且陣列中最小驅動器的大小乘以非奇偶校驗驅動器的數量。您可以通過發出以下命令來獲取驅動器扇區的大小:

blockdev --getsize /dev/sdX

如果您的數據實際上不是從零開始,您仍然可以稍後通過搜尋分區標頭或什至通過搜尋 filesystems來獲得正確的偏移量。

使用 dmsetup 組裝陣列

不幸的是,當您使用mdadm. 唯一的例外是您可以使用的 RAID 級別 0 和 1--build

mdadm --build /dev/md0 --raid-devices=2 --level=0 --chunk=32 /dev/loop0 /dev/loop1

由於我們在這裡運氣不好,我們需要使用不同的工具。因此,我們將改為使用dmsetupdmsetup是創建映射到真實驅動器或其他源的虛擬硬碟驅動器的命令。這些映射由幾個部分組成,每個部分都可以映射到不同的驅動器。在我們的例子中,我們只需要一個部分,並且我們正在映射到一個 RAID,我們將手動提供其元數據。

但首先我們需要談談數字。正如我們之前確定的那樣,在我的案例中,塊大小為 32 kiB。但是dmsetup需要扇區。在幾乎所有情況下,一個扇區等於 512 字節。如果您想安全起見,可以使用 .檢查扇區大小blockdev --getss /dev/sdX。就我而言,這意味著32 kiB / (512 bytes/sector) = 64 sectors. 我們已經知道扇區數組中數據的大小(即 2441959424)。但有一個問題。我有 6 台設備。對於每個條帶一個奇偶校驗塊,塊的數量必須能被 5 整除。但是扇區的數量不能被 5 整除。在我的情況下,它至少可以被每個塊的扇區數整除。但我什至不確定這是否得到保證。似乎數據在最後一個條帶中途停止。不幸的是 dmsetup 不會容忍這種情況。這意味著我們需要四捨五入到最接近的整數,該整數可以被 5 個驅動器和 64 個扇區整除(根據您的情況調整這些數字)。就我而言,這是:2441959680。這意味著fdisk可能會抱怨驅動器大小錯誤和缺少備份表。但是我們可以通過截斷 dd 圖像來解決這個問題。

現在創建一個文件(例如table.txt),其中一個部分包含一行。

<start> <size> raid <raid layout> 2 <chunk size> nosync <num devices>[ - /dev/loopN|-]*num_devices

首先,您必須給出扇區的起點和大小。下一個參數說這是一個 RAID。有關 RAID 佈局,請參見上一節中的表格。下一個參數中的“2”表示 RAID 的兩個特殊參數。第一個是塊大小。第二個將阻止任何同步。之後,您必須首先給出設備數量,然後為每個設備提供一對元數據和設備路徑來描述您的驅動器。由於我們不想提供任何元數據,因此我們使用破折號來表示。如果設備失去,我們會寫兩個破折號,表示元數據和設備都不可用。如果 RAID 級別允許,建議至少保留一個設備。如果您已經懷疑一個驅動器可能包含錯誤數據,請選擇該驅動器。

例如,在我的情況下,文件看起來像這樣。請注意,缺少第二個設備。

0 2441959680 raid raid5_la 2 64 nosync 6 - /dev/loop2 - - - /dev/loop1 - /dev/loop3 - /dev/loop5 - /dev/loop4

現在執行以下命令來創建一個映射到我們數組的新塊文件:

# dmsetup create sdr /path/to/table.txt

這可能會引發一堆 IO 錯誤。在這種情況下,扇區的大小可能不能被塊大小整除。您可以使用以下命令刪除塊文件以重做最後一步:

# dmsetup remove sdr

現在讓我們看看這個新創建的設備文件。如果你跑

# fdisk -l /dev/mapper/sdr

你應該能夠看到你的分區表。如果您有 GPT 表,請不要擔心會出現的兩個錯誤。大小不匹配和缺少備份表是由於我們為 RAID 選擇的大小太大。

我的看起來像這樣:

Device                     Start        End    Sectors   Size Type
/dev/mapper/sdr-part1       2048     923647     921600   450M Windows recovery environment
/dev/mapper/sdr-part2     923648    1128447     204800   100M EFI System
/dev/mapper/sdr-part3    1128448    1161215      32768    16M Microsoft reserved
/dev/mapper/sdr-part4    1161216  679840003  678678788 323.6G Microsoft basic data
/dev/mapper/sdr-part5  679841792  680902655    1060864   518M Windows recovery environment
/dev/mapper/sdr-part6  680904704 2295472127 1614567424 769.9G Linux filesystem
/dev/mapper/sdr-part7 2295472128 2441957375  146485248  69.9G Linux swap

使用該表中的開始和扇區列,我們甚至可以掛載其中一些分區。請注意,所有數字都在扇區中,需要乘以 512 轉換為字節。

# mount -o ro,noload,loop,offset=348623208448,sizelimit=826658521088 /dev/mapper/sdr /mnt

這意味著我的 Linux 分區現在安裝在 /mnt 上,我可以在ro(即只讀)模式下瀏覽我的所有文件。這是防止 ext4 執行寫操作noload所必需的。

現在最後我們將使用 dd 執行完整備份。

# dd if=/dev/mapper/sdr of=/path/to/backups/raid.img status=progress

還記得我們是如何創建一個略大於應有大小的 RAID 嗎?我們可以利用這個機會通過將圖像截斷到正確的大小來糾正這個錯誤。需要將扇區數轉換為字節數:2441959424*512 = 1250283225088.

# truncate -s 1250283225088 /path/to/backups/raid.img

現在fdisk -l不再抱怨尺寸不匹配了。

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