Linux - Reparieren fehlerhafter Blöcke auf einem RAID1-Array mit GPT

20

The tl; dr: Wie gehe ich vor, um einen fehlerhaften Block auf einer Festplatte in einem RAID1-Array zu reparieren?

Aber bitte lesen Sie diese ganze Sache für das, was ich bereits ausprobiert habe und mögliche Fehler in meinen Methoden. Ich habe versucht, so detailliert wie möglich zu sein, und ich hoffe sehr auf ein Feedback

Dies ist meine Situation: Ich habe zwei 2-TB-Festplatten (dasselbe Modell) in einem RAID1-Array eingerichtet, das von verwaltet wird mdadm. Vor ungefähr 6 Monaten bemerkte ich den ersten fehlerhaften Block, als SMART ihn meldete. Heute habe ich mehr bemerkt und versuche jetzt, es zu beheben.

Diese HOWTO-Seite scheint der einzige Artikel zu sein, auf den jeder verweist , um von SMART gemeldete fehlerhafte Blöcke zu beheben. Es ist eine großartige Seite voller Informationen, die jedoch ziemlich veraltet ist und sich nicht auf mein spezielles Setup bezieht. So unterscheidet sich meine Konfiguration:

  • Anstelle einer Festplatte verwende ich zwei Festplatten in einem RAID1-Array. Eine Festplatte meldet Fehler, während die andere in Ordnung ist. Das HOWTO ist nur für eine Festplatte geschrieben, was verschiedene Fragen aufwirft, z.
  • Ich verwende GPT, das von fdisk nicht unterstützt wird. Ich habe stattdessen gdisk verwendet und hoffe, dass es mir die gleichen Informationen gibt, die ich benötige

Also, lasst uns gleich loslegen. Das habe ich getan, aber es scheint nicht zu funktionieren. Bitte überprüfen Sie meine Berechnungen und Methoden auf Fehler. Die Fehlermeldung lautet / dev / sda:

# smartctl -l selftest /dev/sda
smartctl 5.42 2011-10-20 r3458 [x86_64-linux-3.4.4-2-ARCH] (local build)
Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net

=== START OF READ SMART DATA SECTION ===
SMART Self-test log structure revision number 1
Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error
# 1  Short offline       Completed: read failure       90%     12169         3212761936

Hiermit stellen wir fest, dass der Fehler auf LBA 3212761936 liegt. Nach dem HOWTO verwende ich gdisk, um den Startsektor zu finden, der später zum Bestimmen der Blocknummer verwendet wird (da ich fdisk nicht verwenden kann, da GPT nicht unterstützt wird):

# gdisk -l /dev/sda
GPT fdisk (gdisk) version 0.8.5

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/sda: 3907029168 sectors, 1.8 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): CFB87C67-1993-4517-8301-76E16BBEA901
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 3907029134
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048      3907029134   1.8 TiB     FD00  Linux RAID

Mit tunefsfinde ich die Blockgröße zu sein 4096. Unter Verwendung dieser Informationen und der Berechnung aus dem HOWTO schließe ich, dass der fragliche Block ist ((3212761936 - 2048) * 512) / 4096 = 401594986.

Das HOWTO weist mich dann an, debugfszu prüfen , ob der Block verwendet wird. (Ich verwende das RAID-Gerät, da es ein EXT-Dateisystem benötigt. Dies war einer der Befehle, die mich verwirrten, da ich zunächst nicht wusste, ob ich / verwenden sollte.) dev / sda oder / dev / md0):

# debugfs
debugfs 1.42.4 (12-June-2012)
debugfs:  open /dev/md0
debugfs:  testb 401594986
Block 401594986 not in use

Damit der Block 401594986 leer bleibt, sollte ich ihn problemlos überschreiben können. Bevor ich jedoch darauf schreibe, versuche ich sicherzustellen, dass es tatsächlich nicht gelesen werden kann:

# dd if=/dev/sda1 of=/dev/null bs=4096 count=1 seek=401594986
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.000198887 s, 20.6 MB/s

Wenn der Block nicht gelesen werden könnte, würde ich nicht erwarten, dass dies funktioniert. Das tut es jedoch. Ich wiederhole mit /dev/sda, /dev/sda1, /dev/sdb, /dev/sdb1, /dev/md0, und + -5 bis die Blocknummer zu suchen , den schlechten Block um. Es funktioniert alles. Ich zucke mit den Schultern und setze das Schreiben und Synchronisieren fort (ich verwende / dev / md0, weil ich dachte, dass das Ändern einer Festplatte und nicht der anderen Probleme verursachen könnte. Auf diese Weise überschreiben beide Festplatten den fehlerhaften Block):

# dd if=/dev/zero of=/dev/md0 bs=4096 count=1 seek=401594986
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.000142366 s, 28.8 MB/s
# sync 

Ich würde davon ausgehen, dass das Schreiben in den fehlerhaften Block dazu führen würde, dass die Datenträger den Block einem guten zuweisen, wenn jedoch ein anderer SMART-Test ausgeführt wird, sieht dies anders aus:

# 1  Short offline       Completed: read failure       90%     12170         3212761936

Zurück zu Quadrat 1. Wie kann ich also einen fehlerhaften Block auf einer Festplatte in einem RAID1-Array reparieren? Ich bin sicher, ich habe etwas nicht richtig gemacht ...

Vielen Dank für Ihre Zeit und Geduld.


EDIT 1:

Ich habe versucht, einen langen SMART-Test durchzuführen, bei dem derselbe LBA als schlecht zurückgegeben wird (der einzige Unterschied besteht darin, dass 30% übrig bleiben anstatt 90%):

SMART Self-test log structure revision number 1
Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error
# 1  Extended offline    Completed: read failure       30%     12180         3212761936
# 2  Short offline       Completed: read failure       90%     12170         3212761936

Ich habe auch Badblocks mit der folgenden Ausgabe verwendet. Die Ausgabe ist seltsam und scheint falsch formatiert zu sein, aber ich habe versucht, die als Blöcke ausgegebenen Zahlen zu testen, aber debugfs gibt einen Fehler aus

# badblocks -sv /dev/sda
Checking blocks 0 to 1953514583
Checking for bad blocks (read-only test): 1606380968ne, 3:57:08 elapsed. (0/0/0 errors)
1606380969ne, 3:57:39 elapsed. (1/0/0 errors)
1606380970ne, 3:58:11 elapsed. (2/0/0 errors)
1606380971ne, 3:58:43 elapsed. (3/0/0 errors)
done
Pass completed, 4 bad blocks found. (4/0/0 errors)
# debugfs
debugfs 1.42.4 (12-June-2012)
debugfs:  open /dev/md0
debugfs:  testb 1606380968
Illegal block number passed to ext2fs_test_block_bitmap #1606380968 for block bitmap for /dev/md0
Block 1606380968 not in use

Ich weiß nicht, wohin ich von hier aus gehen soll. badblocksIch habe definitiv etwas gefunden, bin mir aber nicht sicher, was ich mit den präsentierten Informationen anfangen soll ...


BEARBEITEN 2

Mehr Befehle und Infos.

Ich fühle mich wie ein Idiot, der vergessen hat, dies ursprünglich einzubeziehen. Dies sind SMART-Werte für /dev/sda. Ich habe 1 Current_Pending_Sector und 0 Offline_Uncorrectable.

SMART Attributes Data Structure revision number: 16
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  1 Raw_Read_Error_Rate     0x002f   100   100   051    Pre-fail  Always       -       166
  2 Throughput_Performance  0x0026   055   055   000    Old_age   Always       -       18345
  3 Spin_Up_Time            0x0023   084   068   025    Pre-fail  Always       -       5078
  4 Start_Stop_Count        0x0032   100   100   000    Old_age   Always       -       75
  5 Reallocated_Sector_Ct   0x0033   252   252   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x002e   252   252   051    Old_age   Always       -       0
  8 Seek_Time_Performance   0x0024   252   252   015    Old_age   Offline      -       0
  9 Power_On_Hours          0x0032   100   100   000    Old_age   Always       -       12224
 10 Spin_Retry_Count        0x0032   252   252   051    Old_age   Always       -       0
 11 Calibration_Retry_Count 0x0032   252   252   000    Old_age   Always       -       0
 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       75
181 Program_Fail_Cnt_Total  0x0022   100   100   000    Old_age   Always       -       1646911
191 G-Sense_Error_Rate      0x0022   100   100   000    Old_age   Always       -       12
192 Power-Off_Retract_Count 0x0022   252   252   000    Old_age   Always       -       0
194 Temperature_Celsius     0x0002   064   059   000    Old_age   Always       -       36 (Min/Max 22/41)
195 Hardware_ECC_Recovered  0x003a   100   100   000    Old_age   Always       -       0
196 Reallocated_Event_Count 0x0032   252   252   000    Old_age   Always       -       0
197 Current_Pending_Sector  0x0032   100   100   000    Old_age   Always       -       1
198 Offline_Uncorrectable   0x0030   252   100   000    Old_age   Offline      -       0
199 UDMA_CRC_Error_Count    0x0036   200   200   000    Old_age   Always       -       0
200 Multi_Zone_Error_Rate   0x002a   100   100   000    Old_age   Always       -       30
223 Load_Retry_Count        0x0032   252   252   000    Old_age   Always       -       0
225 Load_Cycle_Count        0x0032   100   100   000    Old_age   Always       -       77

# mdadm -D /dev/md0
/dev/md0:
        Version : 1.2
  Creation Time : Thu May  5 06:30:21 2011
     Raid Level : raid1
     Array Size : 1953512383 (1863.01 GiB 2000.40 GB)
  Used Dev Size : 1953512383 (1863.01 GiB 2000.40 GB)
   Raid Devices : 2
  Total Devices : 2
    Persistence : Superblock is persistent

    Update Time : Tue Jul  3 22:15:51 2012
          State : clean
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

           Name : server:0  (local to host server)
           UUID : e7ebaefd:e05c9d6e:3b558391:9b131afb
         Events : 67889

    Number   Major   Minor   RaidDevice State
       2       8        1        0      active sync   /dev/sda1
       1       8       17        1      active sync   /dev/sdb1

Laut einer der Antworten: Es scheint, als hätte ich gewechselt seekund skipdafür dd. Ich habe seek verwendet, da dies beim HOWTO verwendet wird. Die Verwendung dieses Befehls führt ddzum Absturz von: # dd if = / dev / sda1 of = / dev / null bs = 4096 count = 1 skip = 401594986

Die Verwendung von Blöcken um diesen Block (..84, ..85, ..87, ..88) scheint einwandfrei zu funktionieren, und die Verwendung von / dev / sdb1 mit Block 401594986liest sich ebenso einwandfrei (wie erwartet, da diese Festplatte den SMART-Test bestanden hat) ). Nun ist die Frage, die ich habe: Wenn ich über diesen Bereich schreibe, um die Blöcke neu zuzuweisen, verwende ich /dev/sda1oder /dev/md0? Ich möchte keine Probleme mit dem RAID-Array verursachen, indem ich direkt auf eine Festplatte schreibe und die andere nicht aktualisiere.

EDIT 3

Das Schreiben in den Block erzeugte direkt Dateisystemfehler. Ich habe eine Antwort gewählt, die das Problem schnell gelöst hat:

# 1  Short offline       Completed without error       00%     14211         -
# 2  Extended offline    Completed: read failure       30%     12244         3212761936

Vielen Dank an alle, die mitgeholfen haben. =)

Blitzmann
quelle
Sie konnten den Block lesen, damit er nicht beschädigt wird. Daher keine neu zugewiesenen Sektoren. Ich habe Ihre fs-Blockberechnung überprüft und es scheint legitim zu sein. Bei Neuzuweisungen von fehlerhaften Blöcken stellte sich heraus, dass der fehlerhafte Block manchmal von einem intelligenten Kurztest nicht korrekt gemeldet wurde. In der Zwischenzeit können Sie den langen Offline-Test ausführen smartctl -t long /dev/sdaund feststellen, ob sich die LBA des ersten Fehlers ändert.
Jari Laamanen
1
Versuchen Sie /sbin/badblocks -sv /dev/sda, die Festplatte zu überprüfen.
jippie
Ich habe beide Vorschläge gemacht und den Beitrag entsprechend aktualisiert. Immer noch stecken. = /
Blitzmann
Meldet smartctl eine Zählung ungleich Null Current_Pending_Sector? Ist Offline_Uncorrectable ungleich Null?
mgorven
Bitte fügen Sie den Array-Status der Frage hinzu:sudo mdadm -D /dev/md0
psusi

Antworten:

20

Alle diese "Poke the Sektor" -Antworten sind ehrlich gesagt verrückt. Sie riskieren eine (möglicherweise versteckte) Beschädigung des Dateisystems. Wenn die Daten bereits weg wären, weil auf dieser Festplatte die einzige Kopie gespeichert ist, wäre dies vernünftig. Auf dem Spiegel befindet sich jedoch ein perfektes Exemplar.

Sie müssen nur Angst haben, den Spiegel zu schrubben. Der fehlerhafte Sektor wird erkannt und automatisch neu geschrieben.

# echo 'check' > /sys/block/mdX/md/sync_action    # use 'repair' instead for older kernels

Sie müssen das richtige Gerät dort einsetzen (z. B. md0 anstelle von mdX). Dies dauert eine Weile, da dies standardmäßig für das gesamte Array gilt. Auf einem ausreichend neuen Kernel können Sie zuerst Sektornummern in sync_min / sync_max schreiben, um sie auf einen Teil des Arrays zu beschränken.

Dies ist eine sichere Operation. Sie können dies auf allen Ihren mdraid-Geräten tun. In der Tat, Sie sollten es auf alle Ihre mdraid Geräte tun, regelmäßig. Ihre Distribution wird wahrscheinlich mit einem Cronjob ausgeliefert, um dies zu handhaben. Vielleicht müssen Sie etwas tun, um dies zu ermöglichen?


Skript für alle RAID-Geräte im System

Vor einiger Zeit habe ich dieses Skript geschrieben, um alle RAID-Geräte auf dem System zu "reparieren". Dies wurde für ältere Kernelversionen geschrieben, bei denen nur durch 'Reparieren' der fehlerhafte Sektor behoben werden konnte. Jetzt reicht es aus, nur die Überprüfung durchzuführen (die Reparatur funktioniert auf neueren Kerneln noch einwandfrei, aber es wird auch die Parität neu kopiert / wiederhergestellt, was nicht immer das ist, was Sie wollen, insbesondere auf Flash-Laufwerken).

#!/bin/bash

save="$(tput sc)";
clear="$(tput rc)$(tput el)";
for sync in /sys/block/md*/md/sync_action; do
    md="$(echo "$sync" | cut -d/ -f4)"
    cmpl="/sys/block/$md/md/sync_completed"

    # check current state and get it repairing.
    read current < "$sync"
    case "$current" in
        idle)
            echo 'repair' > "$sync"
            true
            ;;
        repair)
            echo "WARNING: $md already repairing"
            ;;
        check)
            echo "WARNING: $md checking, aborting check and starting repair"
            echo 'idle' > "$sync"
            echo 'repair' > "$sync"
            ;;
        *)
            echo "ERROR: $md in unknown state $current. ABORT."
            exit 1
            ;;
    esac

    echo -n "Repair $md...$save" >&2
    read current < "$sync"
    while [ "$current" != "idle" ]; do
        read stat < "$cmpl"
        echo -n "$clear $stat" >&2
        sleep 1
        read current < "$sync"
    done
    echo "$clear done." >&2;
done

for dev in /dev/sd?; do
    echo "Starting offline data collection for $dev."
    smartctl -t offline "$dev"
done

Wenn Sie dies checkstattdessen tun möchten repair, sollte dieser (nicht getestete) erste Block funktionieren:

    case "$current" in
        idle)
            echo 'check' > "$sync"
            true
            ;;
        repair|check)
            echo "NOTE: $md $current already in progress."
            ;;
        *)
            echo "ERROR: $md in unknown state $current. ABORT."
            exit 1
            ;;
    esac
derobert
quelle
Danke dafür. Ich bin kürzlich zu diesem Problem zurückgekehrt, in der Hoffnung, es endlich zu lösen. Ich habe in den / dev / md0-Block geschrieben und hatte Dateisystemprobleme, aber zum Glück war nach ein paar Stunden Terror und dem Booten von Recovery-Shells alles Reparaturen ohne Datenverlust. Ich werde zuerst Ihre Methode ausprobieren und mich hoffentlich vom anstehenden Sektor befreien. =)
Blitzmann
Wie können Sie feststellen, wann das Peeling abgeschlossen ist? Wird cat /sys/block/mdX/md/sync_action"Leerlauf" lesen, wenn Sie fertig sind?
Jon Cram
@ JonCram ja, und Sie können den Status von beobachten cat /proc/mdstatoder wenn Sie es /sys/…/sync_completed
skripten
5

Ich hatte gerade so ziemlich das gleiche Problem mit einem RAID1-Array. Der fehlerhafte Sektor befand sich direkt am Anfang einer der Partitionen - Sektor 16 von / dev / sdb2. Ich habe die obigen Anweisungen befolgt: Nachdem ich überprüft habe, dass der logische Block 2 nicht vom Dateisystem verwendet wird, und darauf geachtet habe, dass dd search und skip the right way around ausgeführt werden, und 1 Dateisystemblock auf Null gesetzt habe:

# dd if=/dev/zero of=/dev/md0 bs=4096 count=1 seek=2

Was hat das getan? Es hat den schlechten Sektor nicht repariert. Dies liegt, wie ich jetzt weiß, daran, dass / dev / md0 nicht direkt auf / dev / sdb2 abgebildet wird. Sie müssen den RAID-DATA-OFFSET berücksichtigen! Mehr dazu weiter unten. Was es tat, war ein kleiner, aber möglicherweise verheerender Fehler in meinem Dateisystem. Es stellte sich heraus, dass der logische Block 2 von / dev / md0 nützliche Metadaten des Dateisystems enthielt und auf beiden Datenträgern in Ordnung war, bis ich beide Kopien durch Schreiben in / dev / md0 zum Erliegen brachte. Glücklicherweise hat e2fsck -y / dev / md0 das Problem behoben (nachdem eine alarmierende Menge an Ausgaben ausgegeben wurde), ohne dass ein offensichtlicher Datenverlust auftrat. Lektion gelernt: Wenn debugfs icheck "Block nicht gefunden" sagt, bedeutet dies nicht unbedingt, dass die entsprechenden Sektoren nicht verwendet werden.

Zurück zum Datenoffset: Verwenden Sie mdadm, um den Offset wie folgt zu ermitteln:

# mdadm --examine /dev/sdb2
/dev/sdb2:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x0
     Array UUID : ef7934b9:24696df9:b89ff03e:b4e5a05b
           Name : XXXXXXXX
  Creation Time : Sat Sep  1 01:20:22 2012
     Raid Level : raid1
   Raid Devices : 2

 Avail Dev Size : 1953241856 (931.38 GiB 1000.06 GB)
     Array Size : 976620736 (931.38 GiB 1000.06 GB)
  Used Dev Size : 1953241472 (931.38 GiB 1000.06 GB)
    Data Offset : 262144 sectors
   Super Offset : 8 sectors
          State : clean
    Device UUID : f3b5d515:446d4225:c2191fa0:9a9847b8

    Update Time : Thu Sep  6 12:11:24 2012
       Checksum : abb47d8b - correct
         Events : 54


    Device Role : Active device 0
    Array State : AA ('A' == active, '.' == missing)

In diesem Fall beträgt der Datenversatz 262144 Sektoren mit 512 Bytes. Wenn Sie von / dev / md0 dd und vergleichen Sie es mit Daten aus der rohen Partition mit einem Offset von 131072K, werden Sie feststellen, dass sie übereinstimmen. In meinem Fall befindet sich der logische Block 2 (Sektoren 16-23) von / dev / sdb2 nicht einmal im Dateisystem. Sie befinden sich im RAID-Superblock, den Sie hier nachlesen können: https://raid.wiki.kernel.org/index.php/RAID_superblock_formats - für Version 1.2 besteht er aus 256 Byte + 2 Byte pro Gerät im Array In meinem Fall wurde der fehlerhafte Sektor nicht verwendet. Die entsprechenden Sektoren von / dev / sdc2 (die andere Hälfte des RAID1-Arrays) sind Null.

# dd if=/dev/zero of=/dev/sdb2 bs=4096 count=1 seek=2

Es funktionierte!

Samer
quelle
OP hier. Danke für diese Information. Als dieses Problem für mich auftrat, habe ich den Sprung gemacht und den Block auf der Ebene / dev / md0 auf Null gesetzt. Schlechte Idee, da ich auch mein Dateisystem kaputt gemacht habe. Zum Glück schien nach einer gottlosen Reparaturzeit alles ohne Datenverlust in Ordnung zu sein. Aber mit der anfänglichen Panik habe ich diesen Beitrag komplett vergessen. Ich habe kürzlich meinen Server in meiner neuen Wohnung eingerichtet, und dies ist wieder eines der Dinge auf meiner ToDo-Liste, und ich danke Ihnen für Ihren Einblick in das Problem. Ich werde das OP aktualisieren, wenn ich etwas mehr darüber nachdenke. =)
Blitzmann
2

Wenn Sie Debian ausführen, haben Sie höchstwahrscheinlich einen Job in /etc/cron.d/mdadm. Dies findet /usr/share/mdadm/checkarray --cron --all --idle --quiet jeden ersten Sonntag im Monat statt. Führen Sie dies manuell aus, wenn Sie nicht korrigierbare Hardwarefehler erhalten, um das Neuschreiben zu beschleunigen.

Håkon Alstadheim
quelle
Wenn Sie es manuell ausführen, möchten Sie wahrscheinlich aufhören --cron.
Derobert
1

Sie haben Ihre ddArgumente durcheinander gebracht . seekBewirkt, dass der angegebene Offset in der Ausgabe gesucht wird . Sie wollten skipden Eingang sperren .

Psusi
quelle
Vielen Dank! Ich habe den ursprünglichen Beitrag aktualisiert, um Daten daraus aufzunehmen. Wenn Sie mir sagen könnten, wie Sie den Block von hier aus reparieren können, werde ich Ihnen eine Antwort geben. (Ich bin mir nicht sicher, ob ich direkt schreiben /dev/sda1/oder verwenden soll /dev/md0, um den Block zu überschreiben) =)
Blitzmann
@ Ryan, Schreiben auf md0 sollte der richtige Weg sein, obwohl sda1 auch funktionieren sollte.
Psusi
0

Wenn Sie einen sw-raid1 haben und Daten direkt an eines der Mitglieder schreiben, haben Sie sofort einen beschädigten Überfall. Schreiben Sie KEINE Daten auf eine SDAX oder SDBX, wenn diese Teil einer MDX sind. Wenn Sie auf mdX schreiben, werden die Daten auf beide Laufwerke kopiert. Wenn Sie von mdX lesen, werden die Daten von einem der Laufwerke gelesen.

Jose Tavares
quelle