md raid5: converte números de setor interno md em compensações

8

Resumo TL; DR : traduza um número de setor MD em deslocamentos dentro do /dev/mdXdispositivo e como investigá-lo xfs_db. O número do setor é de sh->sectorno linux/drivers/md/raid5.c:handle_parity_checks5().

Não conheço MD internals, portanto não sei exatamente o que fazer com a saída do printklog adicionado.

As compensações nos dispositivos componentes (para ddou um editor / visualizador hexadecimal) também seriam interessantes.

Suponho que devo perguntar isso na lista de discussão sobre ataques Linux. É apenas para assinantes ou posso postar sem assinar?


Eu tenho xfs diretamente em cima do MD RAID5 de 4 discos na minha área de trabalho (sem LVM). Uma limpeza recente detectou um valor diferente de zero mismatch_cnt(8, de fato, porque o md opera em páginas de 4kiB por vez).

Este é um RAID5, não RAID1 / RAID10, onde mismatch_cnt! = 0 pode ocorrer durante a operação normal . (Os outros links na parte inferior desta página wiki podem ser úteis para algumas pessoas.)

Eu poderia apenas cegamente repair, mas não teria idéia de qual arquivo verificar se havia uma possível corrupção, além de perder a chance de escolher qual caminho reconstruir. A resposta de Frostschutz em uma pergunta semelhante é a única sugestão que encontrei para retornar a uma diferença no sistema de arquivos. É complicado e lento, e eu prefiro usar algo melhor para reduzi-lo a alguns arquivos primeiro.


Patch do kernel para adicionar log

Estranhamente, o recurso de verificação do md não informa onde um erro foi encontrado . Eu adicionei um printkno md / raid5.c para fazer login sh->sectornoif ramo que incrementos mddev->resync_mismatchesemhandle_parity_checks5() (pequeno pedaço publicada no github , originalmente baseado no 4.5-RC4 do kernel.org.) Para que isso seja ok para uso geral, que provavelmente seria necessário evite inundar os logs nos reparos com muitas incompatibilidades (talvez apenas registre se o novo valor resync_mismatchesfor <1000?). Também talvez faça logon apenas checke não repair.

Tenho certeza de que estou registrando algo útil (mesmo que eu não conheça o MD internals!), Porque a mesma função imprime esse número de setor no caso de tratamento de erros doswitch .

Compilei meu kernel modificado e o inicializei, depois executei novamente a verificação:

[  399.957203] md: data-check of RAID array md125
...
[  399.957215] md: using 128k window, over a total of 2441757696k.
...
[21369.258985] md/raid:md125: check found mismatch at sector 4294708224    <-- custom log message
[25667.351869] md: md125: data-check done.

Agora não sei exatamente o que fazer com esse número de setor. Existe sh->sector * 512um endereço linear dentro /dev/md/t-r5(aka /dev/md125)? É um número de setor em cada dispositivo componente (portanto, refere-se a três dados e um setor de paridade)? Eu estou supondo o último, uma vez que uma incompatibilidade de paridade no RAID5 significa que os setores N-1 do dispositivo md estão em perigo, deslocados um do outro pela unidade de distribuição. O setor 0 é o início do dispositivo componente ou é o setor após o superbloco ou algo assim? Havia mais informações handle_parity_checks5()que eu deveria ter calculado / registrado?

Se eu quisesse obter apenas os blocos incompatíveis, isso está correto?

dd if=/dev/sda6 of=mmblock.0 bs=512 count=8 skip=4294708224
dd if=/dev/sdb6 of=mmblock.1 bs=512 count=8 skip=4294708224
dd if=/dev/sda6 of=mmblock.2 bs=512 count=8 skip=4294708224
dd if=/dev/sdd  of=mmblock.3 bs=512 count=8 skip=4294708224  ## not a typo: my 4th component is a smaller full-disk

# i.e.
sec_block() { for dev in {a,b,c}6 d; do dd if=/dev/sd"$dev" of="sec$1.$dev"  skip="$1"  bs=512 count=8;done; }; sec_block 123456

Acho que não, porque recebo 4k de zeros dos quatro componentes do ataque e 0^0 == 0, portanto, essa deve ser a paridade correta, certo?

Outro lugar que vi menção ao uso de endereços de setor no md é para sync_mine sync_max(no sysfs). Neil Brown na lista de ataques Linux , em resposta a uma pergunta sobre uma falha na unidade com números de setor dehdrecover onde Neil usou o número de setor de disco completo como um número de setor MD. Isso não está certo, está? Os números do setor md não seriam relativos aos dispositivos componentes (partições nesse caso), e não ao dispositivo completo do qual a partição faz parte?


setor linear para o nome do arquivo XFS:

Antes de perceber que o número do setor md provavelmente era para os componentes, não para o dispositivo RAID, tentei usá-lo em somente leitura xfs_db:

A breve sugestão de Dave Chinner sobre como descobrir como o XFS está usando um determinado bloco não parecia funcionar para mim. (Eu esperaria algum tipo de resultado, para algum setor, pois o número não deve estar além do final do dispositivo, mesmo que não seja o setor incompatível)

# xfs_db -r /dev/md/t-r5 
xfs_db> convert daddr 4294708224 fsblock
0x29ad5e00 (699227648)
xfs_db> blockget -nv -b 699227648
xfs_db> blockuse -n       # with or without -c 8
must run blockget first

Hã? O que eu estou fazendo errado aqui? Eu acho que isso deve ser uma pergunta separada. Vou substituí-lo por um link se / quando solicitar ou encontrar uma resposta para esta parte em outro lugar.

Meu RAID5 está essencialmente ocioso, sem atividade de gravação e leitura mínima (e noatime, portanto, as leituras não estão produzindo gravações).


Coisas extras sobre minha configuração, nada de importante aqui

Muitos dos meus arquivos são de vídeo ou outros dados compactados que fornecem uma maneira eficaz de saber se os dados estão corretos ou não (somas de verificação internas no formato de arquivo ou apenas decodificação sem erros). Isso tornaria viável esse método de loopback somente leitura , uma vez que eu saiba qual arquivo verificar. Eu não queria executar uma comparação em quatro direções de todos os arquivos no sistema de arquivos para encontrar a incompatibilidade primeiro, no entanto, quando o kernel tem as informações necessárias durante a verificação e pode registrá-las facilmente.


meu /proc/mdstatpara minha matriz de dados em massa:

md125 : active raid5 sdd[3] sda6[0] sdb6[1] sdc6[4]
      7325273088 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/4] [UUUU]
      bitmap: 0/19 pages [0KB], 65536KB chunk

Está em partições em três unidades Toshiba de 3 TB e em uma unidade de energia verde (lenta) WD25EZRS não particionada que estou substituindo por outra Toshiba. (Usandomdadm --replace para fazê-lo on-line sem falhas de redundância. Percebi, depois de uma cópia, que eu deveria verificar a integridade do RAID antes e depois, para detectar problemas. Foi quando eu detectei a incompatibilidade. É possível que já exista há muito tempo , desde que tive algumas falhas há quase um ano, mas não tenho registros antigos e o mdadm parece não enviar e-mails sobre isso por padrão (Ubuntu 15.10).

Meus outros sistemas de arquivos estão em dispositivos RAID10f2 criados a partir de partições anteriores nos três HDs maiores (e RAID0 para / var / tmp). O RAID5 é apenas para armazenamento em massa, não /homeou /.

Minhas unidades estão bem: as contagens de erros SMART são 0 em todos os contadores de blocos defeituosos em todas as unidades e os autotestes SMART curtos + longos foram aprovados.


quase duplicatas desta pergunta que não têm respostas:

Peter Cordes
fonte
Se o número no seu printk for um setor relativo à matriz, será necessário dividi-lo pela largura da faixa e, possivelmente, adicionar o deslocamento inicial para convertê-lo em um número de setor relativo ao dispositivo componente. iirc, se você estiver usando um formato de metadados mdadm que nem sempre inicia os dados no deslocamento zero, o deslocamento em que é iniciado é listado na saída de mdadm -E /dev/xxx.
Psusi
Lembre-se também de que, mesmo que você encontre o local dos dados e possa verificar a incompatibilidade e tenha uma maneira de verificar a integridade do arquivo que está danificado (se os dados pertencerem a um arquivo; talvez seja apenas gratuito) espaço ou metadados fs), é bem possível e até provável que a paridade também esteja errada e, portanto, nenhuma das respostas possíveis que você obterá ao mascarar cada uma das unidades de dados estará correta.
31416 psusi
@ psusi: obrigado, sim, eu sei que pode não fazer parte de um arquivo. Era difícil expressar isso sem tornar minhas frases realmente desajeitadas. Ponto interessante que talvez nenhuma das reconstruções esteja correta, sim, isso é possível. De qualquer forma, eu ficaria muito mais feliz em saber para qual arquivo renomear .damagedou algo assim, em vez de apenas saber que provavelmente há um arquivo quebrado em algum lugar.
Peter Cordes

Respostas:

2

TL; DR sh-> sector é o número de setores nos discos físicos após o início da seção de dados


Configuração

Aqui está uma configuração de teste simples para ilustrar:

  • / dev / raidme / rd [0-3], dispositivos de 2 GB
  • / dev / md127 criado como um raid5 sobre esses 5, iniciado como xfs e preenchido com dados aleatórios

Agora, para começar, obtenha um bloco diferente de zero e substitua-o

# dd if=/dev/raidme/rd0 bs=1k count=1 skip=10240 | hexdump -C | head
...
# dd if=/dev/zero of=/dev/raidme/rd0 bs=1k count=1 seek=10240
...
# dd if=/dev/raidme/rd2 bs=1k count=1 skip=10240 | hexdump  -C | head
1024 bytes (1.0 kB, 1.0 KiB) copied, 8.6021e-05 s, 11.9 MB/s
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400

Verifique se o cache do dm / md está nivelado, parando / remontando a matriz e verifique:

# mdadm --stop /dev/md127
# mdadm --assemble /dev/md127 /dev/raidme/rd*
# echo check > /sys/class/block/md127/md/sync_action
# dmesg | tail
...
[ 1188.057900] md/raid:md127: check found mismatch at sector 16384

Bloquear em discos

Ok, primeiro vamos verificar 16384 corresponde ao que escrevemos. Meu ataque tem uma faixa de 512k, então eu escrevi algo alinhado para facilitar a correspondência, escrevemos em 1024*10240ie 0xa00000.

Seu patch fornece as informações 16384, uma coisa a ter em atenção é que os dados não começam em 0:

# mdadm -E /dev/raidme/rd0 | grep "Data Offset"
    Data Offset : 4096 sectors

É o printf "%x\n" $(((4096+16384)*512))que diz isso 0xa00000também. Boa.


Bloquear em md

Agora, para chegar a esse ponto final, é realmente mais fácil: é simplesmente a posição dada nos horários do setor, number_of_stripespor exemplo, para mim, tenho 4 discos (3 + 1) e 3 faixas.

Aqui, isso significa, 16384*3*512por exemplo 0x1800000. Enchi o disco muito bem, então é fácil verificar apenas lendo o disco e procurando 1k de zeros:

# dd if=/dev/md127 bs=1M | hexdump -C | grep -C 3 '00 00 00 00 00 00'
... some false positives...
01800000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
01800400  6b a8 9e e0 ad 88 a8 de  dd 2e 68 00 d8 7a a3 52  |k.........h..z.R|

Bloquear em xfs

Legal. Vamos ver onde está o xfs agora. 16384*3is 49152(daddr leva o número do setor):

# xfs_db -r /dev/md127
xfs_db> blockget -n
xfs_db> daddr 49152
xfs_db> blockuse -n
block 6144 (0/6144) type data inode 2052 d.1/f.1

Certamente, os zeros estão nesse arquivo:

# dd if=/mnt/d.1/f.1 bs=1M | hexdump -C | grep -C 3 '00 00 00 00 00'
...
03680000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
03680400  6b a8 9e e0 ad 88 a8 de  dd 2e 68 00 d8 7a a3 52  |k.........h..z.R|

Se sobrescrevermos esse arquivo, os zeros desaparecerão em / dev / raidme / rd0 no deslocamento correto também (apenas coloque-o em outro arquivo). Se você escrever em / dev / raidme / rd0 novamente (certifique-se de parar / iniciar o array novamente), os zeros estão de volta. Parece bom.

Porém, há mais um problema: se o tamanho da faixa for tão grande quanto o meu aqui (512k), não teremos um único bloco para lidar, mas 1,5 MB de dados possíveis corrompidos ... Muitas vezes, único arquivo, mas você precisa verificar isso em xfs_db. Lembre-se de inode anteriormente era 2052.

xfs_db> inode 2052
xfs_db> bmap
data offset 0 startblock 256 (0/256) count 17536 flag 0
data offset 17536 startblock 122880 (0/122880) count 4992 flag 0
data offset 22528 startblock 91136 (0/91136) count 3072 flag 0

Um bloco tem o tamanho de 4096 bytes aqui (consulte xfs_info), então nossos 1,5 MB são 384 blocos. Nosso segmento corrompido é o bloco 6144 a 6528 - bem dentro do primeiro segmento deste arquivo.

Outra coisa a considerar seria extrair os blocos manualmente e verificar onde exatamente as somas de verificação não coincidem, o que, com sorte, fornecerá três pedaços menores para serem examinados.


Por fim, sobre o seu patch, eu não sou um desenvolvedor md, mas como um ex-usuário do mdadm raid5, eu ficaria muito interessado. Eu diria que definitivamente vale a pena o esforço para avançar um pouco. A limpeza que você mencionou pode ser útil e tenho certeza que os desenvolvedores terão alguns comentários depois que você enviar um patch, mas o md precisa ser mais detalhado sobre esses erros!

Asmadeus
fonte
Estou feliz que você apontou a posição nos dispositivos de bloco subjacentes. No meu caso, printf '%#x\n' $(( (259072+4294708224 )*512 ))é 0x20000000000, o que obviamente não é uma coincidência. (Isso é 2TiB precisamente. Eu suspeito que algumas travessuras do grub-install ou algum tipo de coisa do MBR). Eu não teria notado isso se estivesse apenas olhando as compensações dentro do dispositivo MD para encontrar o arquivo afetado. (BTW, o %#xformato adiciona o 0xprefixo para você.)
Peter Cordes
xfs_dbapenas diz must run blockget first, mesmo que acabei de fazer (exatamente como postei na pergunta), depois de seguir o seu exemplo. Mesmo se eu usar blockget -v -n -b 12884124672para atribuir um bloco específico. Eu usei dde hexdumpdescobri que, na verdade, existe uma incompatibilidade nesse bloco. Três são zero e o quarto tem um único bit definido em 1kiB na faixa de 512k. (Muito conveniente que eu não tenho que encontrar uma maneira de realmente XOR blocos para verificar a redundância.)
Peter Cordes
Se eu usar daddrprimeiro (antes do blockget), não recebo uma mensagem de erro, apenas nenhuma saída de blockget -v -ne blockuse -v -n. Caso isso importe, meu xfsprogs é o 3.2.1ubuntu1 e estou usando o Linux 4.2.0-36-generic (não o meu kernel -rc corrigido). Meu FS está usando crc=1 isize=512, naming =version 2 bsize=4096 ascii-ci=0 ftype=1
Peter Cordes
De qualquer forma, esta resposta identifica corretamente a localização do bloco incompatível nos dispositivos componentes e no dispositivo md. A única parte que não funciona é a parte XFS block-> filename, que é realmente uma pergunta separada. Em teoria, eu poderia usar find -exec xfs_bmap -vpl {} +para procurar um arquivo contendo o bloco conhecido.
22616 Peter Cordes
1
Infelizmente, eu não estou ciente de nenhuma maneira de fazer o xfs_db ignorar o diário de registros (por exemplo, forçar o blockget, mesmo que não seja 100% consistente), ou fazer o kernel "liberar" esse log como umount / mount faria e faria o xfs_db feliz. .. Então sim, a menos que você queira julgar algo, pode ser necessário esperar um pouco até que você possa remontar. Mantenha-me atualizado e não se esqueça de tentar a montante que remendo :)
Asmadeus