md raid5: traduire les numéros de secteurs internes md en décalages

8

Résumé TL; DR : Traduisez un numéro de secteur md en décalages dans l' /dev/mdXappareil, et comment enquêter avec xfs_db. Le numéro de secteur est de sh->sectoren linux/drivers/md/raid5.c:handle_parity_checks5().

Je ne connais pas les internes de MD, donc je ne sais pas exactement quoi faire avec la sortie de la printkjournalisation que j'ai ajoutée.

Les décalages dans les composants (pour ddou un éditeur / visualiseur hexadécimal) seraient également intéressants.

Je suppose que je devrais poser cette question sur la liste de diffusion Linux-raid. Est-ce réservé aux abonnés ou puis-je publier sans m'abonner?


J'ai xfs directement sur le dessus de MD RAID5 de 4 disques sur mon bureau (pas de LVM). Un nettoyage récent a détecté une valeur non nulle mismatch_cnt(8 en fait, car md fonctionne sur des pages de 4 Ko à la fois).

Il s'agit d'un RAID5, pas RAID1 / RAID10 mismatch_cnt! = 0 peut se produire pendant le fonctionnement normal . (Les autres liens au bas de cette page wiki peuvent être utiles à certaines personnes.)

Je pourrais simplement l'aveugler repair, mais alors je n'aurais aucune idée du fichier pour vérifier une éventuelle corruption, en plus de perdre toute chance de choisir la façon de reconstruire. La réponse de Frostschutz à une question similaire est la seule suggestion que j'ai trouvée pour retrouver une différence dans le système de fichiers. C'est lourd et lent, et je préfère utiliser quelque chose de mieux pour le réduire à quelques fichiers en premier.


Correctif du noyau pour ajouter la journalisation

Bizarrement, la fonction de vérification de md ne signale pas où une erreur a été trouvée . J'ai ajouté un printkfichier dans md / raid5.c pour se connecter sh->sectorà la ifbranche qui s'incrémente mddev->resync_mismatchesdanshandle_parity_checks5() (minuscule patch publié sur github , basé à l'origine sur 4.5-rc4 de kernel.org.) Pour que cela soit correct pour une utilisation générale, il faudrait probablement évitez d'inonder les journaux dans les réparations avec beaucoup de discordances (peut-être uniquement si la nouvelle valeur de resync_mismatchesest <1000?). Peut-être aussi ne vous connectez que pour checket non repair.

Je suis à peu près sûr que j'enregistre quelque chose d'utile (même si je ne connais pas les internes MD!), Car la même fonction imprime ce numéro de secteur dans le cas de gestion des erreurs duswitch .

J'ai compilé mon noyau modifié et l'ai démarré, puis j'ai relancé la vérification:

[  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.

Maintenant, je ne sais pas exactement quoi faire avec ce numéro de secteur. Est sh->sector * 512une adresse linéaire à l'intérieur /dev/md/t-r5(aka /dev/md125)? S'agit-il d'un numéro de secteur dans chaque appareil composant (il fait donc référence à trois données et à un secteur de parité)? J'imagine ce dernier, car une disparité de parité dans RAID5 signifie que les secteurs N-1 du périphérique md sont en danger, décalés les uns des autres par l'unité de bande. Le secteur 0 est-il le tout début du périphérique composant, ou est-ce le secteur après le superbloc ou quelque chose? Y avait-il plus d'informations en ce handle_parity_checks5()que j'aurais dû calculer / enregistrer?

Si je voulais obtenir uniquement les blocs incompatibles, est-ce correct?

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

Je suppose que non, parce que j'obtiens 4k de zéros des quatre composants de raid, et 0^0 == 0donc ça devrait être la parité correcte, non?

Un autre endroit que j'ai vu mentionner l'utilisation des adresses de secteur dans md est pour sync_minet sync_max(dans sysfs). Neil Brown sur la liste Linux-raid , en réponse à une question sur un disque défectueux avec des numéros de secteur hdrecover, où Neil a utilisé le numéro de secteur du disque complet comme numéro de secteur MD. Ce n'est pas vrai, n'est-ce pas? Les numéros de secteur md ne seraient-ils pas relatifs aux périphériques composants (partitions dans ce cas), pas au périphérique complet dont la partition fait partie?


secteur linéaire en nom de fichier XFS:

Avant de réaliser que le numéro de secteur md était probablement pour les composants, pas pour le périphérique RAID, j'ai essayé de l'utiliser en lecture seule xfs_db:

La très brève suggestion de Dave Chinner sur la façon de trouver comment XFS utilise un bloc donné ne semble pas du tout fonctionner pour moi. (Je m'attendais à une sorte de résultat, pour certains secteurs, car le nombre ne devrait pas dépasser la fin de l'appareil même si ce n'est pas le secteur qui ne correspond pas)

# 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

hein? Qu'est-ce que je fais mal ici? Je suppose que cela devrait être une question distincte. Je vais remplacer cela par un lien si / quand je le demande ou trouver une réponse à cette partie ailleurs.

Mon RAID5 est essentiellement inactif, sans activité d'écriture et lecture minimale (et noatimedonc les lectures ne produisent pas d'écritures).


Des trucs supplémentaires sur ma configuration, rien d'important ici

Beaucoup de mes fichiers sont des vidéos ou d'autres données compressées qui donnent un moyen efficace de dire si les données sont correctes ou non (soit des sommes de contrôle internes au format de fichier, soit juste si elles décodent sans erreur). Cela rendrait cette méthode de bouclage en lecture seule viable, une fois que je connais le fichier à vérifier. Je ne voulais pas exécuter une différence à 4 voies de chaque fichier dans le système de fichiers pour trouver d'abord la non-concordance, lorsque le noyau a les informations nécessaires lors de la vérification et pourrait facilement les enregistrer.


mon /proc/mdstatpour mon tableau de données en vrac:

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

Il se trouve sur des partitions sur trois disques Toshiba de 3 To et sur un disque WD25EZRS non partitionné à énergie verte (lent) que je remplace par un autre Toshiba. (Utilisation mdadm --replacepour le faire en ligne sans lacunes de redondance. J'ai réalisé après une copie que je devais vérifier la santé du RAID avant et après, pour détecter les problèmes. C'est à ce moment-là que j'ai détecté le décalage. Il est possible que cela existe depuis longtemps , car j'ai eu quelques plantages il y a presque un an, mais je n'ai pas d'anciens journaux et mdadm ne semble pas envoyer de courrier à ce sujet par défaut (Ubuntu 15.10).

Mes autres systèmes de fichiers se trouvent sur des périphériques RAID10f2 fabriqués à partir de partitions antérieures sur les trois plus grands disques durs (et RAID0 pour / var / tmp). Le RAID5 est juste pour le stockage en vrac, pas /homeou /.

Mes lecteurs sont tous très bien: le nombre d'erreurs SMART est de 0 tous les compteurs de bloc défectueux sur tous les lecteurs, et les autotests SMART courts + longs ont réussi.


quasi-doublons de cette question qui n'ont pas de réponses:

Peter Cordes
la source
Si le numéro dans votre printk est un secteur par rapport au tableau, vous devez le diviser par la largeur de bande et éventuellement ajouter le décalage de départ pour le convertir en un numéro de secteur par rapport au périphérique composant. iirc, si vous utilisez un format de métadonnées mdadm qui ne démarre pas toujours les données à l'offset zéro, l'offset où il démarre est répertorié dans la sortie de mdadm -E /dev/xxx.
psusi
Gardez également à l'esprit que même si vous trouvez l'emplacement des données et que vous pouvez vérifier la non-concordance, et que vous avez un moyen de vérifier l'intégrité du fichier endommagé (si les données appartiennent même à un fichier; elles peuvent simplement être libres espace ou métadonnées fs), alors il est tout à fait possible et même probable que la parité soit également erronée et donc aucune des réponses possibles que vous obtiendrez en masquant chacun des lecteurs de données à son tour ne sera correcte.
psusi
@psusi: merci, oui je sais que cela pourrait ne pas faire partie d'un fichier. Il était difficile d'exprimer cela sans rendre mes phrases vraiment maladroites. Point intéressant: peut-être qu'aucune des reconstructions n'est correcte, oui c'est possible. Quoi qu'il en soit, je serais beaucoup plus heureux de savoir dans quel fichier renommer .damagedou quelque chose, au lieu de simplement savoir qu'il y a probablement un fichier cassé quelque part.
Peter Cordes

Réponses:

2

TL; DR sh-> sector est le nombre de secteurs dans les disques physiques après le début de la section de données


Installer

Voici une configuration de test simple pour illustrer:

  • / dev / raidme / rd [0-3], périphériques de 2 Go
  • / dev / md127 créé comme un raid5 sur ces 5, initié en xfs et rempli de données aléatoires

Maintenant, pour commencer, obtenez un bloc non nul et écrasez-le

# 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

Assurez-vous que le cache dm / md est vidé en arrêtant / réassemblant le tableau et vérifiez:

# 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

Bloquer sur les disques

D'accord, vérifions d'abord que 16384 correspond à ce que nous avons écrit. Mon raid a une bande de 512k, donc je me suis assuré que j'écrivais quelque chose aligné pour être facile à assortir, nous avons écrit sur 1024*10240ie 0xa00000.

Votre patch donne les informations 16384, une chose à savoir est que les données ne commencent pas à 0:

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

C'est printf "%x\n" $(((4096+16384)*512))ce que dit 0xa00000aussi. Bien.


Bloquer en md

Maintenant, pour arriver là où c'est sur la fin md, c'est en fait plus facile: c'est tout simplement la position donnée en temps de secteur number_of_stripespar exemple pour moi j'ai 4 disques (3 + 1) donc 3 bandes.

Ici, cela signifie 16384*3*512par exemple 0x1800000. J'ai assez bien rempli le disque, il est donc facile de vérifier simplement en lisant le disque et en recherchant 1k de zéros:

# 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|

Bloquer dans xfs

Cool. Voyons maintenant où cela se trouve dans xfs. 16384*3est 49152(daddr prend le numéro de secteur):

# 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

Assurément, les zéros sont dans ce fichier:

# 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|

Si nous remplaçons ce fichier, les zéros disparaissent également dans / dev / raidme / rd0 avec le décalage correct (il suffit de le redéfinir avec un autre fichier). Si vous écrivez à nouveau dans / dev / raidme / rd0 (assurez-vous d'arrêter / redémarrer le tableau), les zéros sont de retour. Cela semble bon.

Il y a un autre problème cependant, si votre taille de bande est aussi grande que la mienne ici (512 Ko), nous n'avons pas un seul bloc à gérer, mais 1,5 Mo de données possibles corrompues ... Souvent, cela suffira dans un fichier unique, mais vous devez vérifier cela, de retour dans xfs_db. Rappelez-vous que l'inode précédente était 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

Un bloc a une taille de 4096 octets ici (voir xfs_info), donc nos 1,5 Mo sont 384 blocs. Notre segment corrompu est le bloc 6144 à 6528 - bien dans le premier segment de ce fichier.

Une autre chose à regarder serait d'extraire les blocs à la main et de vérifier où les sommes de contrôle ne correspondent pas exactement, ce qui vous donnera, espérons-le, 3 morceaux plus petits à regarder.


Enfin à propos de votre patch, je ne suis pas moi-même un développeur md mais en tant qu'ancien utilisateur de raid5 mdadm, j'aurais été très intéressé. Je dirais que ça vaut vraiment la peine de pousser un peu. Le nettoyage que vous avez mentionné pourrait être utile et je suis sûr que les développeurs auront des commentaires une fois que vous aurez soumis un correctif, mais diable md doit être plus bavard sur ces erreurs!

Asmadeus
la source
Huh, je suis content que vous ayez signalé la position sur les périphériques sous-jacents. Dans mon cas, printf '%#x\n' $(( (259072+4294708224 )*512 ))c'est 0x20000000000, ce qui n'est évidemment pas un hasard. (C'est 2TiB précisément. Je soupçonne des manigances de grub-install ou une sorte de truc MBR). Je ne l'aurais pas remarqué si je regardais simplement les décalages dans le périphérique MD pour trouver le fichier affecté. (BTW, le %#xformat ajoute le 0xpréfixe pour vous.)
Peter Cordes
xfs_dbdit simplement must run blockget first, même si je viens de le faire (exactement comme je l'ai posté dans la question), après avoir suivi votre exemple. Même si j'utilise blockget -v -n -b 12884124672pour lui donner un bloc spécifique. J'ai utilisé ddet hexdumppour trouver qu'il y a en fait un décalage dans ce bloc, cependant. Trois sont tous nuls et le quatrième a un seul bit défini à 1 Ko dans la bande de 512 Ko. (Très pratique, je n'ai pas eu à trouver de moyen de bloquer XOR pour vérifier la redondance.)
Peter Cordes
Si j'utilise d' daddrabord (avant blockget), je ne reçois pas de message d'erreur, juste aucune sortie du blockget -v -net blockuse -v -n. Dans le cas où cela compte, mon xfsprogs est 3.2.1ubuntu1, et j'utilise Linux 4.2.0-36-generic (pas mon noyau patch -rc). Mon FS utilise crc=1 isize=512, naming =version 2 bsize=4096 ascii-ci=0 ftype=1
Peter Cordes
Quoi qu'il en soit, cette réponse identifie correctement l'emplacement du bloc non compatible sur les périphériques composants et sur le périphérique md. La seule pièce qui ne fonctionne pas est la partie XFS block-> filename, qui est vraiment une question distincte. Je pourrais en théorie utiliser find -exec xfs_bmap -vpl {} +pour rechercher un fichier contenant le bloc connu.
Peter Cordes
1
Je ne suis malheureusement pas au courant d'aucune façon de faire en sorte que xfs_db ignore le journal de journal (par exemple, forcer le blocage de bloc même s'il n'est pas cohérent à 100%), ou de faire en sorte que le noyau "vide" ce journal comme un umount / mount le ferait et rendrait xfs_db heureux. .. Alors oui, à moins que vous ne vouliez faire quelque chose, il faudra peut-être attendre un peu pour pouvoir remonter. Tenez-moi au courant et n'oubliez pas d'essayer de
remonter