描述

描述

描述

我有一个包含 6 个 SSD 驱动器的 IMSM RAID 5 阵列。其中一个驱动器几个月前出现故障,我还无法更换它。 (是的,我知道我有时很懒。请不要评判我。)但我已经将其从 RAID 中删除了。

然而昨天另一个驱动器似乎出现了故障。数组未组装。因为即使 BIOS 也无法构建 RAID,我无法启动任何东西。仔细检查后发现驱动器似乎没有问题。我可以访问它并使用 dd 进行备份。但现在好像一开始就有MBR记录。也许某个进程用 MBR 表覆盖了 RAID 超级块?如果是这种情况,数据应该仍然存在。我只需要能够说出mdadm正确的元数据。当我想到这一点时,同样的事情可能也发生在第一个据称“失败”的驱动器上。因为它仍然可读。但当时我并没有费心去调查。

尽管如此,我现在正在尝试找到一种方法来重新组装数组以访问其数据(如果可能)。我知道块大小、驱动器的确切顺序以及 RAID 级别。这些信息难道还不够吗?

一些信息

dd我做的第一件事是使用(named )创建剩余 5 个驱动器的映像sd[a-e].backup。我还使用检查了所有驱动器--examine并保存了输出。您可以读取输出这个要点。正如您所看到的,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 中的实用程序创建的,具有 IMSM 或 Intel 快速存储格式。我想我必须对它有更详细的了解,例如布局或数据偏移。我不确定 IMSM 的默认设置是什么,也不知道在哪里可以找到它们。但更重要的是,我担心 mdadm 的元数据格式比 IMSM 使用更多的空间和更大的超级块,并且在保存元数据时会覆盖数据。也许也可以使用 IMSM 重新创建阵列?或者也许可以将元数据存储在外部。长话短说,我不知道如何使用 mdadm 手动重新创建 IMSM 阵列。

StackExchange 上的其他问题

  • 我知道这个问题。但我不确定这是否可以应用于我的情况,因为我使用的是具有不同超级块(如果有的话)的 IMSM。
  • 我也读过这个问题。但是它处理的是 RAID 0,而答案建议使用--build不适用于 RAID 5 的。
  • 我也知道这个。但--force不适用于我的情况,因为有问题的驱动器不仅被标记为故障或不同步。我再次不确定应该如何使用 IMSM 专门重新创建阵列。

答案1

尤里卡 - 简介

所以我找到了如何再次访问我的数据。不幸的是我无法使用重新创建数组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是您的硬盘驱动器。替换sdXsdasdb等。输出文件of=/path/to/backups/sdX.img指向要写入的图像。再次sdX适当更换。status=progress只是告诉 GNU 版本的 dd 将当前进度打印到 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 个足以启动阵列。如果您不知道足够驱动器的确切插槽号,您可以尝试使用不同的排列,直到此方法成功。

这意味着我的驱动器以及循环设备的正确顺序是:

投币口 驾驶 循环装置
主引导记录 (0) /dev/sdb /dev/循环2
1 丢失的 -
2 /dev/sda /dev/循环1
3 /dev/sdc /dev/loop3
4 /dev/sde /dev/loop5
5 /dev/sdd /dev/loop4

最后要弄清楚的是布局。不幸的是,mdadm我们没有提供任何相关信息。然而当我们看看Intel 的 RAID 定义看起来 RAID 5 的布局总是不对称的。我不确定 IMSM 阵列是否可以配置不同的布局,但对我来说似乎不太可能。如果这一切都不适合您,那么您可以尝试不同的布局。看一看在源代码中阅读有关其他布局的更多信息。

以下是 IMSM 支持的所有 RAID 级别的概述。 dmsetup 关键字将在下一章中使用。

RAID级别 布局 dmsetup 语法
0 不适用 突袭0
1 不适用 突袭1
5 左不对称 突袭5_la
10 默认(无 1E 或复制) 突袭10

如果您无法从任何驱动器收集任何元数据,那么您必须猜测值和/或尝试不同的组合。作为帮助,IMSM 支持以下不同模式:

信息 可能的值
RAID 级别 0、1、5、10
块尺寸 4 kiB、8 kiB、16 kiB、32 kiB、64 kiB、128 kiB

对于起始扇区和大小,如果您不确定,最好假设为零,并且阵列中最小驱动器的大小乘以非奇偶校验驱动器的数量。您可以通过发出以下命令来获取驱动器的扇区大小:

blockdev --getsize /dev/sdX

如果您的数据实际上并非从零开始,您仍然可以稍后通过以下方式获得正确的偏移量搜索分区头或者甚至可以通过搜索文件系统

使用 dmsetup 组装阵列

不幸的是,当您使用时,无法手动提供元数据mdadm。唯一的例外是可以使用的 RAID 级别 0 和 1--build:

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

由于我们在这里运气不佳,因此我们需要使用不同的工具。因此我们将使用它来dmsetup代替。dmsetup是创建映射到真实驱动器或其他源的虚拟硬盘驱动器的命令。这些映射由多个部分组成,每个部分可以映射到不同的驱动器。在我们的例子中,我们只需要一个部分,并且我们将映射到一个 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(即只读)模式浏览所有文件。需要noload的是阻止 ext4 执行写操作

现在我们最后将使用 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不再抱怨尺寸不匹配。

相关内容