md raid5: übersetzt md interne Sektornummern in Offsets

8

TL; DR-Zusammenfassung : Übersetzen Sie eine MD-Sektornummer in Offsets innerhalb des /dev/mdXGeräts und wie Sie sie untersuchen xfs_db. Die Sektornummer ist von sh->sectorin linux/drivers/md/raid5.c:handle_parity_checks5().

Ich kenne keine MD-Interna, daher weiß ich nicht genau, was ich mit der Ausgabe der von printkmir hinzugefügten Protokollierung tun soll .

ddInteressant wären auch Offsets in die Komponentengeräte (für oder einen Hex-Editor / Viewer).

Ich nehme an, ich sollte dies auf der Linux-Raid-Mailingliste fragen. Ist es nur für Abonnenten oder kann ich ohne Abonnement posten?


Ich habe xfs direkt auf MD RAID5 von 4 Festplatten in meinem Desktop (kein LVM). Bei einem kürzlich durchgeführten Scrub wurde ein mismatch_cntWert ungleich Null festgestellt (8 in der Tat, da md jeweils 4 KB-Seiten bearbeitet).

Dies ist ein RAID5, nicht RAID1 / RAID10, wobei mismatch_cnt! = 0 während des normalen Betriebs auftreten kann . (Die anderen Links am Ende dieser Wiki-Seite können für einige Leute nützlich sein.)

Ich könnte nur blind sein repair, aber dann hätte ich keine Ahnung, welche Datei auf mögliche Beschädigungen überprüft werden soll, abgesehen davon, dass ich keine Chance mehr habe, den Weg für die Rekonstruktion zu wählen. Die Antwort von Frostschutz auf eine ähnliche Frage ist der einzige Vorschlag, den ich gefunden habe, um einen Unterschied im Dateisystem festzustellen. Es ist umständlich und langsam, und ich würde lieber etwas Besseres verwenden, um es zuerst auf ein paar Dateien einzugrenzen.


Kernel-Patch zum Hinzufügen der Protokollierung

Seltsamerweise meldet die Überprüfungsfunktion von md nicht, wo ein Fehler gefunden wurde . Ich fügte hinzu , eine printkin md / raid5.c einzuloggen sh->sectorim ifZweig dass Schritte mddev->resync_mismatchesinhandle_parity_checks5() (kleiner Patch auf GitHub veröffentlicht , ursprünglich basierend auf 4,5-rc4 von kernel.org.) Für diese für die allgemeinen Gebrauch in Ordnung zu sein, ist es wahrscheinlich brauchen würde Vermeiden Sie es, die Protokolle bei Reparaturen mit vielen Fehlanpassungen zu überfluten (möglicherweise nur, wenn der neue Wert resync_mismatches<1000 ist?). Auch vielleicht nur anmelden checkund nicht repair.

Ich bin mir ziemlich sicher, dass ich etwas Nützliches protokolliere (obwohl ich keine MD-Interna kenne!), Da dieselbe Funktion diese Sektornummer im Fehlerbehandlungsfall desswitch druckt .

Ich habe meinen modifizierten Kernel kompiliert und gebootet und dann die Prüfung erneut ausgeführt:

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

Jetzt weiß ich nicht genau, was ich mit dieser Sektornummer anfangen soll. Ist sh->sector * 512eine lineare Adresse drin /dev/md/t-r5(aka /dev/md125)? Handelt es sich um eine Sektornummer in jedem Komponentengerät (bezieht sich also auf drei Daten und einen Paritätssektor)? Ich vermute letzteres, da eine Paritätsfehlanpassung in RAID5 bedeutet, dass N-1-Sektoren des md-Geräts in Gefahr sind und durch die Streifeneinheit gegeneinander versetzt sind. Ist Sektor 0 der Anfang des Komponentengeräts oder der Sektor nach dem Superblock oder so? Gab es weitere Informationen handle_parity_checks5(), die ich hätte berechnen / protokollieren sollen?

Wenn ich nur die nicht übereinstimmenden Blöcke erhalten wollte, ist das richtig?

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

Ich vermute nicht, weil ich 4k Nullen von allen vier Schlachtzugskomponenten bekomme, und 0^0 == 0das sollte also die richtige Parität sein, oder?

Ein anderer Ort, an dem die Verwendung von Sektoradressen in md erwähnt wurde, ist für sync_minund sync_max(in sysfs). Neil Brown auf der Linux-Raid-Liste als Antwort auf eine Frage zu einem ausgefallenen Laufwerk mit Sektornummern von hdrecover, bei dem Neil die Vollplatten-Sektornummer als MD-Sektornummer verwendete. Das ist nicht richtig, oder? Wären md-Sektornummern nicht relativ zu den Komponentengeräten (in diesem Fall Partitionen), nicht zu dem vollständigen Gerät, zu dem die Partition gehört?


linearer Sektor zu XFS-Dateiname:

Bevor mir klar wurde, dass die md-Sektornummer wahrscheinlich für die Komponenten und nicht für das RAID-Gerät bestimmt war, habe ich versucht, sie schreibgeschützt zu verwenden xfs_db:

Dave Chinners sehr kurzer Vorschlag, wie man herausfindet, wie XFS einen bestimmten Block verwendet, schien für mich überhaupt nicht zu funktionieren. (Ich hätte für einen Sektor ein Ergebnis erwartet, da die Anzahl nicht über das Ende des Geräts hinausgehen sollte, auch wenn es sich nicht um den nicht übereinstimmenden Sektor handelt.)

# 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

huh? Was mache ich hier falsch? Ich denke, das sollte eine separate Frage sein. Ich werde dies durch einen Link ersetzen, wenn ich danach frage oder woanders eine Antwort auf diesen Teil finde.

Mein RAID5 ist im Wesentlichen inaktiv, ohne Schreibaktivität und mit minimalem noatimeLesevorgang (und daher führen Lesevorgänge nicht zu Schreibvorgängen).


Zusätzliches Zeug zu meinem Setup, hier nichts Wichtiges

Viele meiner Dateien sind Video- oder andere komprimierte Daten, mit denen effektiv festgestellt werden kann, ob die Daten korrekt sind oder nicht (entweder interne Prüfsummen im Dateiformat oder nur fehlerfreie Dekodierung). Das würde diese schreibgeschützte Loopback-Methode praktikabel machen, sobald ich weiß, welche Datei überprüft werden soll. Ich wollte jedoch nicht für jede Datei im Dateisystem einen 4-Wege-Diff ausführen, um zuerst die Nichtübereinstimmung zu finden, wenn der Kernel beim Überprüfen über die erforderlichen Informationen verfügt und diese problemlos protokollieren kann.


my /proc/mdstatfür mein Bulk-Daten-Array:

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

Es befindet sich auf Partitionen auf drei Toshiba 3-TB-Laufwerken und einem nicht partitionierten WD25EZRS-Green-Power-Laufwerk (langsam), das ich durch ein anderes Toshiba ersetze. ( mdadm --replaceIch habe es online ohne Lücken in der Redundanz gemacht. Nach einer Kopie wurde mir klar, dass ich den RAID-Zustand vorher und nachher überprüfen sollte, um Probleme zu erkennen. Dann habe ich die Nichtübereinstimmung festgestellt. Möglicherweise gibt es sie schon lange , da ich vor fast einem Jahr einige Abstürze hatte, aber keine alten Protokolle habe und mdadm standardmäßig keine E-Mails darüber sendet (Ubuntu 15.10).

Meine anderen Dateisysteme befinden sich auf RAID10f2-Geräten, die aus früheren Partitionen auf den drei größeren Festplatten (und RAID0 für / var / tmp) erstellt wurden. Das RAID5 ist nur für die Massenspeicherung gedacht, nicht /homeoder /.

Meine Laufwerke sind alle in Ordnung: Die Anzahl der SMART-Fehler beträgt 0 für alle fehlerhaften Blockzähler auf allen Laufwerken, und kurze + lange SMART-Selbsttests wurden bestanden.


Fast Duplikate dieser Frage, die keine Antworten haben:

Peter Cordes
quelle
Wenn die Zahl in Ihrem Printk ein Sektor relativ zum Array ist, müssen Sie sie durch die Streifenbreite dividieren und möglicherweise den Startversatz hinzufügen, um sie in eine Sektorzahl relativ zum Komponentengerät umzuwandeln. iirc Wenn Sie ein mdadm-Metadatenformat verwenden, das die Daten nicht immer mit dem Offset Null startet, wird der Offset, an dem sie beginnen, in der Ausgabe von aufgeführt mdadm -E /dev/xxx.
Psusi
Denken Sie auch daran, dass selbst wenn Sie den Speicherort der Daten finden und die Nichtübereinstimmung überprüfen können und die Integrität der beschädigten Datei überprüft werden können (wenn die Daten überhaupt zu einer Datei gehören, diese möglicherweise nur kostenlos sind) Leerzeichen oder fs-Metadaten), dann ist es durchaus möglich und sogar wahrscheinlich, dass die Parität ebenfalls falsch ist, und daher ist keine der möglichen Antworten, die Sie durch das Maskieren der einzelnen Datenlaufwerke erhalten, korrekt.
Psusi
@psusi: Danke, ja, ich weiß, dass es möglicherweise nicht Teil einer Datei ist. Es war schwer auszudrücken, ohne meine Sätze wirklich ungeschickt zu machen. Interessanter Punkt, dass vielleicht keine der Rekonstruktionen korrekt ist, ja das ist möglich. In jedem Fall wäre ich viel glücklicher zu wissen, in welche Datei ich umbenennen soll .damagedoder so, anstatt nur zu wissen, dass wahrscheinlich irgendwo eine kaputte Datei vorhanden ist.
Peter Cordes

Antworten:

2

TL; DR sh-> Sektor ist die Anzahl der Sektoren auf den physischen Datenträgern nach dem Start des Datenabschnitts


Installieren

Hier ist ein einfacher Testaufbau zur Veranschaulichung:

  • / dev / raidme / rd [0-3], 2 GB Geräte
  • / dev / md127 wurde als raid5 über diese 5 erstellt, als xfs initiiert und mit zufälligen Daten gefüllt

Holen Sie sich jetzt einen Block ungleich Null und überschreiben Sie ihn

# 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

Stellen Sie sicher, dass der dm / md-Cache geleert ist, indem Sie das Array stoppen / neu zusammensetzen, und überprüfen Sie:

# 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

Blockieren auf Datenträgern

Okay, also lassen Sie uns zuerst überprüfen, ob 16384 mit dem übereinstimmt, was wir geschrieben haben. Meine Razzia hat einen 512k Streifen so ich , dass ich ausgerichtet schrieb etwas dafür gesorgt , einfach zu passen zu sein, wir schrieb 1024*10240also 0xa00000.

Ihr Patch enthält die Informationen. Beachten Sie 16384, dass die Daten nicht bei 0 beginnen:

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

So printf "%x\n" $(((4096+16384)*512))heißt es 0xa00000auch. Gut.


Block in md

Nun, um dahin zu gelangen, wo das am md-Ende ist, ist es tatsächlich einfacher: Es ist einfach die Position, die in Sektorzeiten angegeben wurde, number_of_stripesz. B. für mich habe ich 4 Festplatten (3 + 1), also 3 Streifen.

Hier bedeutet es 16384*3*512zB 0x1800000. Ich habe die Diskette ziemlich gut gefüllt, so dass es einfach ist, nur die Diskette zu lesen und nach 1k Nullen zu suchen:

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

Block in xfs

Cool. Mal sehen, wo das jetzt in xfs ist. 16384*3ist 49152(daddr nimmt Sektornummer):

# 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

Sicherlich sind die Nullen in dieser Datei:

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

Wenn wir diese Datei überschreiben, werden die Nullen auch in / dev / raidme / rd0 mit dem richtigen Versatz entfernt (einfach mit einer anderen Datei überschreiben). Wenn Sie erneut in / dev / raidme / rd0 schreiben (stellen Sie sicher, dass Sie das Array stoppen / erneut starten), sind die Nullen zurück. Sieht gut aus.

Es gibt jedoch noch ein weiteres Problem: Wenn Ihre Stripe-Größe hier so groß ist wie meine (512 KB), müssen wir uns nicht mit einem einzelnen Block befassen, sondern mit 1,5 MB möglicher Daten, die beschädigt sind einzelne Datei, aber Sie müssen dies überprüfen, zurück in xfs_db. Denken Sie daran, Inode früher war 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

Ein Block hat hier eine Größe von 4096 Bytes (siehe xfs_info), also sind unsere 1,5 MB 384 Blöcke. Unser beschädigtes Segment ist Block 6144 bis 6528 - gut innerhalb des ersten Segments dieser Datei.

Etwas anderes zu betrachten wäre, die Blöcke von Hand zu extrahieren und zu überprüfen, wo genau die Prüfsummen nicht übereinstimmen, was Ihnen hoffentlich 3 kleinere Stücke zum Betrachten gibt.


Zu guter Letzt bin ich selbst kein md-Entwickler, aber als ehemaliger mdadm raid5-Benutzer wäre ich ziemlich interessiert gewesen. Ich würde sagen, es ist definitiv die Mühe wert, es ein bisschen voranzutreiben. Die Bereinigung, die Sie erwähnt haben, könnte nützlich sein, und ich bin sicher, dass die Entwickler einige Kommentare haben werden, sobald Sie einen Patch einreichen, aber zum Teufel muss md ausführlicher über diese Fehler sein!

Asmadeus
quelle
Huh, ich bin froh, dass Sie auf die Position auf den zugrunde liegenden Blockgeräten hingewiesen haben. In meinem Fall printf '%#x\n' $(( (259072+4294708224 )*512 ))ist 0x20000000000das offensichtlich kein Zufall. (Das sind genau 2 TB. Ich vermute einige Shenanigans von Grub-Install oder einer Art MBR-Sache). Ich hätte das nicht bemerkt, wenn ich nur Offsets im MD-Gerät betrachtet hätte, um die betroffene Datei zu finden. (Übrigens, das %#xFormat fügt das 0xPräfix für Sie hinzu.)
Peter Cordes
xfs_dbsagt nur must run blockget first, obwohl ich es gerade getan habe (genau wie ich es in der Frage gepostet habe), nachdem ich Ihrem Beispiel gefolgt bin. Auch wenn ich blockget -v -n -b 12884124672ihm einen bestimmten Block gebe. Ich habe verwendet ddund hexdumpfestgestellt, dass es in diesem Block tatsächlich eine Nichtübereinstimmung gibt. Drei sind alle Null, und der vierte hat ein einzelnes Ein-Bit, das auf 1 kB in den 512k-Streifen gesetzt ist. (Sehr praktisch, dass ich keinen Weg finden musste, um tatsächlich XOR-Blöcke zu überprüfen, um die Redundanz zu überprüfen.)
Peter Cordes
Wenn ich daddrzuerst (vor dem Blockget) verwende, erhalte ich keine Fehlermeldung, nur überhaupt keine Ausgabe von blockget -v -nund blockuse -v -n. Falls es darauf ankommt, ist mein xfsprogs 3.2.1ubuntu1 und ich verwende Linux 4.2.0-36-generic (nicht meinen gepatchten -rc-Kernel). Mein FS verwendet crc=1 isize=512, naming =version 2 bsize=4096 ascii-ci=0 ftype=1
Peter Cordes
Auf jeden Fall identifiziert diese Antwort die Position des nicht übereinstimmenden Blocks auf den Komponentengeräten und auf dem md-Gerät korrekt. Das einzige Teil, das nicht funktioniert, ist der XFS-Block-> Dateiname-Teil, der wirklich eine separate Frage ist. Ich könnte theoretisch find -exec xfs_bmap -vpl {} +nach einer Datei suchen, die den bekannten Block enthält.
Peter Cordes
1
Mir ist leider keine Möglichkeit bekannt, xfs_db dazu zu bringen, das Protokolljournal zu ignorieren (z. B. Blockget erzwingen, auch wenn es nicht 100% konsistent ist) oder den Kernel "zu leeren", den das Protokoll als umount / mount tun und xfs_db glücklich machen würde. .. Also ja, es sei denn, Sie möchten etwas kludgen, muss es möglicherweise etwas warten, bis Sie wieder einsteigen können. Halten Sie mich auf dem
Laufenden