Descrição
Eu tenho uma matriz IMSM RAID 5 que contém 6 unidades SSD. Uma das unidades falhou há alguns meses e ainda não consegui substituí-la. (Sim, eu sei que às vezes sou preguiçoso. Por favor, não me julgue.) Mas já o removi do RAID.
Ontem, porém, outra unidade parece ter falhado. A matriz não é montada. Como até o BIOS falha ao construir o RAID, não consigo inicializar nada. Após uma inspeção mais detalhada, parece que a unidade está boa. Posso acessá-lo e fazer backups usando dd. Mas parece ter um registro MBR no início agora. Talvez algum processo tenha substituído o superbloco RAID por uma tabela MBR? Se for esse o caso, os dados ainda devem estar lá. Eu só preciso saber mdadm
os metadados corretos. Quando penso nisso, a mesma coisa pode ter acontecido com a primeira unidade que supostamente "falhou". Uma vez que ainda era legível também. Mas não me preocupei em investigar naquela época.
No entanto, agora estou tentando encontrar uma maneira de remontar o array para acessar seus dados (se possível). Eu sei o tamanho do bloco, a ordem exata das unidades e o nível do RAID. Isso não deveria ser informação suficiente?
Algumas informações
A primeira coisa que fiz foi criar imagens das 5 unidades restantes usando dd
(nomeado sd[a-e].backup
). Também examinei todas as unidades usando --examine
e salvei a saída. Você pode ler a saída emesta essência. Como você pode ver, o mdadm lê o cabeçalho MBR sdb
e prossegue para a próxima unidade sem detectar nenhuma informação RAID. Para todas as outras unidades, o mdadm imprime os metadados corretos. Enquanto estamos nisso, aqui está o resultado decat /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>
O que eu tentei
- Obviamente tentei "desligar e ligar novamente":
# 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
Após a última chamada para mdadm, /proc/mdstat
novamente parece idêntico à saída acima.
Em seguida, criei dispositivos de loop somente leitura:
# 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)
- Em seguida tentei usar
--build
pois não requer nenhuma informação do superbloco e todos os metadados podem ser fornecidos manualmente:
# 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
Mas aparentemente não tenho permissão para usar --build
no contexto de RAIDs de nível 5.
- A próxima coisa que tentei foi usar,
--assemble
mas sem usar, as informações OROM sobre o RAID.
# 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
Isso teria sido muito fácil, eu acho. Posso, de alguma forma, dizer ao mdadm para assumir que esse loop2
é o primeiro dispositivo dessa matriz e usar os metadados das outras unidades?
- A última coisa que eu teria tentado seria remontar os dispositivos de loop como leitura e gravação e recriar o array. No entanto, todos os exemplos que encontrei (como esteouEste) suponha que o array foi criado com mdadm. Mas não foi. Ele foi inicialmente criado por um utilitário no BIOS e possui o formato IMSM ou Intel Rapid Storage. Acho que preciso ter um conhecimento mais detalhado sobre isso, como layout ou deslocamento de dados. Não tenho certeza de quais são os padrões do IMSM ou onde posso encontrá-los. Mas o mais importante é que estou preocupado com o fato de o formato de metadados do mdadm usar mais espaço e um superbloco maior do que o IMSM e sobrescrever os dados ao salvar os metadados. Talvez também seja possível recriar o array usando IMSM? Ou talvez seja possível armazenar os metadados externamente. Resumindo, não tenho ideia de como recriar manualmente um array IMSM com mdadm.
Outras perguntas sobre StackExchange
- Estou ciente deessa questão. Mas não tenho certeza se isso pode ser aplicado à minha situação, pois estou usando o IMSM, que possui superblocos diferentes (se houver).
- Eu também liessa questão. No entanto, trata-se de RAID 0 e a resposta sugere usar
--build
o que não funciona com RAID 5. - Também estou cienteEste. Mas
--force
não é aplicável na minha situação, pois a unidade em questão não está apenas marcada como com falha ou fora de sincronia. E, novamente, não tenho certeza de como devo recriar o array especificamente com o IMSM.
Responder1
Eureka - Introdução
Então descobri como ter acesso aos meus dados novamente. Infelizmente não consegui recriar o array usando mdadm
. O problema é que com o IMSM preciso primeiro criar um contêiner. Mas o contêiner não aceita dispositivos perdidos. Eu precisaria de todos os meus 6 discos rígidos originais, mas só tenho 5 no momento. Também não posso usar discos rígidos virtuais, pois eles precisam estar conectados ao controlador RAID. Além disso, não tenho certeza se ou como mdadm
começaria a sincronizar as unidades assim que eu criasse um volume. No entanto, encontrei uma maneira que envolve dmsetup
. Consigo acessar todos os meus arquivos novamente.
Ao realizar vários backups das unidades para trabalhar com elas, também percebi que a única unidade que não faz mais parte da matriz às vezes falha com erros de E/S. Ainda consegui fazer backups, pois esses erros ocorriam apenas a cada terceira invocação do dd
. Presumo que assim que ocorreu um dos erros de IO, a unidade provavelmente foi expulsa da matriz pelo IMSM e todos os seus metadados foram excluídos.
Também percebi que esta unidade era a primeira da matriz. Como tenho uma tabela GPT e como os dados do array começam no primeiro setor também é lógico que comece com um MBR. Portanto, o supersetor da unidade não foi substituído por um MBR. Sempre esteve lá.
Lendo os dados
Estou tentando dar aqui uma solução passo a passo que explica todos os comandos usados no processo. Espero que isso ajude alguém por aí.
(Opcional) Faça um backup de todas as unidades
Isto não é estritamente necessário. Especialmente porque usaremos dispositivos de loop somente leitura posteriormente. No entanto, estou particularmente paranóico após uma grande falha na minha solução de armazenamento. Portanto, tento evitar ao máximo usar os dados reais. Além disso, o uso dos arquivos de backup mostra que esse método não requer discos rígidos ou BIOS originais. Tudo que você precisa é de uma imagem dd. Se você estiver pulando esta seção, certifique-se de realmente criar os dispositivos de loop na próxima seção como somente leitura ou você corre o risco de que seus dados fiquem ainda mais degradados e sejam perdidos para sempre.
No entanto, aqui está o comando para fazer backup do seu disco rígido. Você já deve estar familiarizado com dd. Mas caso você não execute este comando para cada disco rígido que faz parte do seu array:
# dd if=/dev/sdX of=/path/to/backups/sdX.img status=progress
# dd if=/dev/sdY of=/path/to/backups/sdY.img status=progress
# [...]
O arquivo de entrada if=/dev/sdX
é o seu disco rígido. Substitua sdX
por sda
, sdb
, etc. O arquivo de saída of=/path/to/backups/sdX.img
aponta para a imagem que deve ser gravada. Novamente substitua sdX
adequadamente. status=progress
apenas informa à versão GNU do dd para imprimir o progresso atual no stderr.
Crie dispositivos de loop
A seguir vamos criar dispositivos de loop. Caso estejamos utilizando imagens de backup garante que sejam reconhecidas como arquivo de bloco. Embora isso possa não ser necessário. Mas em qualquer caso garante que a imagem só será lida já que estamos usando a flag somente leitura-r
# losetup --show -rf /path/to/backups/sdX.img
# losetup --show -rf /path/to/backups/sdY.img
[...]
-r
: apenas leia do arquivo, não escreva nele-f
: use o próximo número disponível para o dispositivo de loop para que não tenhamos que adivinhar sozinhos.--show
: imprima o nome que você-f
realmente escolheu. Isso geralmente é bastante útil. Embora estejamos imprimindo esses valores na próxima etapa de qualquer maneira.
Para obter uma boa visão geral dos dispositivos de loop que acabamos de criar, podemos usar o seguinte comando:
# losetup -a
/dev/loop1: [2129]:251265027 (/path/to/backups/sdX.img)
/dev/loop2: [2129]:251265027 (/path/to/backups/sdY.img)
[...]
Tente lembrar qual dispositivo de loop pertence a qual imagem.
Reunindo alguns metadados
Em seguida, precisamos descobrir algumas informações sobre o RAID. Especificamente, precisamos descobrir em qual setor o RAID inicia (especialmente no caso de um RAID de matriz), quantos setores ele abrange, qual é o tamanho e o layout do bloco e em que ordem as unidades foram adicionadas ao array.
Se houver pelo menos uma unidade que ainda faça parte da matriz e tenha metadados anexados, você poderá usá-la para recuperar a maioria das informações necessárias. Execute o seguinte comando em uma unidade sdX
que ainda faz parte da matriz:
# 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
A saída continua, mas você pode ignorar o resto. A saída mostrada acima produz as seguintes informações valiosas:
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
Você pode até determinar onde está essa unidade específica em sua matriz.
This Slot : 2
Isso significa que esta é a terceira unidade da matriz. (O número do slot começa em zero.) Alternativamente, Disk## Serial : [...]
também indica o número do slot:
Disk02 Serial : S21PNSBG710576N
Execute este comando para todas as unidades. Para aqueles que ainda produzem resultados válidos, anote o número do slot.
Há outro truque que você pode usar para determinar a primeira unidade do array. Como o RAID é gravado em blocos e não em bytes, os primeiros 32 KiB residem na primeira unidade. Os segundos 32 kiB na segunda unidade e assim por diante. Isso significa que a primeira unidade deve ter setores suficientes contendo o início da sua tabela de partições. O que significa que deve haver um MBR no início (mesmo quando você estiver usando GPT, pois ele começa com um MBR protetor). mdadm --examine
já informa que encontrou um MBR quando não há metadados. Mas você também pode usar fdisk -l
.
No meu caso, consegui descobrir os números dos slots de quatro unidades por meio de seus metadados. Tive sorte porque a quinta unidade continha um MBR, então soube automaticamente que era a primeira. 5 de 6 unidades são suficientes para iniciar o array. Se você não souber os números exatos de slots de unidades suficientes, poderá tentar usar diferentes permutações até que esse método seja bem-sucedido.
O que significa que a ordem correta das minhas unidades e, portanto, dos meus dispositivos de loop é:
Slot | Dirigir | Dispositivo de loop |
---|---|---|
MBR (0) | /dev/sdb | /dev/loop2 |
1 | ausente | - |
2 | /dev/sda | /dev/loop1 |
3 | /dev/sdc | /dev/loop3 |
4 | /dev/sde | /dev/loop5 |
5 | /dev/sdd | /dev/loop4 |
A última coisa a descobrir é o layout. Infelizmente mdadm
não nos dá nenhuma informação sobre isso. No entanto, quando olhamos paraDefinições de RAID da Intelparece que o layout do RAID 5 é sempre deixado assimétrico. Não tenho certeza se os arrays IMSM podem ser configurados com um layout diferente, mas parece improvável para mim. Se tudo isso não funcionar para você, tente layouts diferentes. Dar uma olhadana fontepara ler mais sobre os outros layouts.
Abaixo está uma visão geral de todos os níveis de RAID que o IMSM suporta. A palavra-chave dmsetup será usada no próximo capítulo.
Nível RAID | Disposição | Sintaxe dmsetup |
---|---|---|
0 | N / D | ataque0 |
1 | N / D | raid1 |
5 | esquerda assimétrica | raid5_la |
10 | padrão (sem 1E ou cópia) | raid10 |
Se você não conseguir coletar metadados de nenhuma unidade, será necessário adivinhar os valores e/ou tentar combinações diferentes. Para ajudar, estes são os diferentes modos que o IMSM suporta:
Informações | Valores possíveis |
---|---|
Níveis de RAID | 0, 1, 5, 10 |
Tamanhos de pedaços | 4 kiB, 8 kiB, 16 kiB, 32 kiB, 64 kiB, 128 kiB |
Para o setor inicial e o tamanho, é melhor assumir zero e o tamanho da menor unidade na matriz vezes o número de unidades sem paridade, se você não tiver certeza. Você pode obter o tamanho em setores de uma unidade emitindo o seguinte comando:
blockdev --getsize /dev/sdX
Se seus dados não começarem do zero, você ainda poderá obter o deslocamento correto mais tarde,procurando por um cabeçalho de partiçãoou talvez até porprocurando por sistemas de arquivos.
Montando o array usando dmsetup
Infelizmente não há como fornecer os metadados manualmente quando você está usando o mdadm
. A única exceção é para oNíveis de RAID 0 e 1 onde você pode usar--build
:
mdadm --build /dev/md0 --raid-devices=2 --level=0 --chunk=32 /dev/loop0 /dev/loop1
Como não temos sorte aqui, precisamos usar uma ferramenta diferente. Portanto, vamos usar dmsetup
em seu lugar. dmsetup
é um comando que cria discos rígidos virtuais mapeados para unidades reais ou outras fontes. Esses mapeamentos consistem em diversas seções e cada seção pode ser mapeada para uma unidade diferente. No nosso caso precisamos apenas de uma seção e estamos mapeando para um RAID cujos metadados forneceremos manualmente.
Mas primeiro precisamos falar sobre números. Como determinamos anteriormente, o tamanho do bloco no meu caso era de 32 KiB. Porém dmsetup
requer setores. Em quase todos os casos, um setor equivale a 512 bytes. Se você quiser estar seguro, pode verificar o tamanho do setor com blockdev --getss /dev/sdX
. No meu caso, isso significa 32 kiB / (512 bytes/sector) = 64 sectors
. Já sabemos o tamanho dos dados na matriz em setores (ou seja, 2441959424). Mas há um problema. Eu tenho 6 dispositivos. Com um pedaço de paridade por faixa, o número de pedaços deve ser divisível por 5. Mas o número de setores não é divisível por 5. No meu caso, é pelo menos divisível o número de setores por pedaço. Mas nem tenho certeza se isso é garantido. Parece que os dados param na metade da última faixa. Infelizmente, o dmsetup não tolerará isso. Isso significa que precisamos arredondar para o número inteiro mais próximo que seja divisível por 5 unidades e por 64 setores (ajuste esses números de acordo com sua situação). No meu caso é: 2441959680. Isso significa que fdisk
posso reclamar de um tamanho de unidade incorreto e de uma tabela de backup ausente. Mas podemos consertar isso truncando a imagem dd.
Agora crie um arquivo (por exemplo, table.txt
) que conterá uma linha para uma seção.
<start> <size> raid <raid layout> 2 <chunk size> nosync <num devices>[ - /dev/loopN|-]*num_devices
Primeiro você tem que dar o início e o tamanho dos setores. O próximo argumento diz que este é um RAID. Para o layout RAID consulte a tabela na seção anterior. O “2” no próximo argumento significa dois parâmetros especiais para o RAID. O primeiro é o tamanho do pedaço. O segundo impedirá qualquer sincronização. Depois disso, você deve descrever suas unidades, primeiro fornecendo o número de dispositivos e, em seguida, fornecendo um par de metadados e caminho de dispositivo para cada dispositivo. Como não queremos fornecer nenhum metadado, usamos um travessão para indicar isso. Se o dispositivo estiver faltando, escrevemos dois travessões indicando que nem os metadados nem o dispositivo estão disponíveis. É aconselhável deixar de fora pelo menos um dispositivo se o nível do RAID permitir. Se você já suspeita que uma unidade pode conter dados defeituosos, escolha essa.
Por exemplo, no meu caso, o arquivo fica assim. Observe que o segundo dispositivo está faltando.
0 2441959680 raid raid5_la 2 64 nosync 6 - /dev/loop2 - - - /dev/loop1 - /dev/loop3 - /dev/loop5 - /dev/loop4
Agora execute o seguinte comando para criar um novo arquivo de bloco que mapeie nosso array:
# dmsetup create sdr /path/to/table.txt
Isso pode gerar vários erros de IO. Nesse caso, o tamanho dos setores provavelmente não era divisível pelo tamanho do pedaço. Você pode remover o arquivo de bloco para refazer a última etapa com o seguinte comando:
# dmsetup remove sdr
Agora vamos dar uma olhada neste arquivo de dispositivo recém-criado. Se você correr
# fdisk -l /dev/mapper/sdr
você deverá conseguir ver sua tabela de partições. Não se preocupe com os dois erros que aparecerão se você tiver uma tabela GPT. A incompatibilidade de tamanho e a falta da tabela de backup se devem ao fato de termos escolhido um tamanho muito grande para nosso RAID.
O meu é assim:
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
Usando a coluna inicial e setores nesta tabela podemos até montar algumas dessas partições. Observe que todos os números estão em setores e precisam ser convertidos em bytes multiplicando por 512.
# mount -o ro,noload,loop,offset=348623208448,sizelimit=826658521088 /dev/mapper/sdr /mnt
O que significa que minha partição Linux agora está montada em /mnt e posso navegar por todos os meus arquivos no ro
modo (ou seja, somente leitura). O noload
é necessário paraimpedir que o ext4 execute operações de gravação.
E agora finalmente faremos um backup completo usando dd.
# dd if=/dev/mapper/sdr of=/path/to/backups/raid.img status=progress
Lembra como criamos um RAID um pouco maior do que deveria? Podemos aproveitar esta oportunidade para corrigir esse erro truncando a imagem para o tamanho correto. O número de setores precisa ser convertido em bytes: 2441959424*512 = 1250283225088
.
# truncate -s 1250283225088 /path/to/backups/raid.img
Agora fdisk -l
não reclama mais de incompatibilidade de tamanho.