Login
Immer anmelden
SSL Login

 
Newsletter
Werbung
Shopping
International Shopping
 
 


Yatego Shopping bei über 10000 Händlern und über
3 Mio. Artikel.


Linux

:

Linux-Bücher

Handy
Shop

  und Computer.

Viele Services

:

Apple iPad Reader,


Ratgeber,

 

Techniktops,

 

Yatego Clicks

  & über 3000

Gutscheine.

 
So, 27. August 2006, 00:00

Fehlerhafte Festplattensektoren neu zuweisen

Festplatten mit SMART lassen sich mit den smartmontools während des Betriebes überwachen und testen. Defekte Sektoren können diese Platten auch neu zuweisen. Das Ermitteln der Blöcke und der Dateien, die diese Blöcke verwenden, ist jedoch etwas umständlich. Mit Unterstützung eines Skriptes geht es zumindest für ext2 und ext3 recht flott.

Betroffene Datei ermitteln

Mit mount kontrolliere ich, dass die ermittelte Partition wirklich vom Typ ext2 bzw. ext3 ist. Dann ermittle ich den zugehörigen Dateisystemblock. Um diesen zu berechnen, muss ich mit tune2fs ermitteln, wie groß die Blockgröße des Dateisystems auf dieser Partition ist.

open(MOUNT,"mount|")
 or die "Could not mount: $!";
while (<MOUNT>) {
 if (m{ ^$part
 \s+on\s+
 (\S+)
 \s+type\s+
 (\S+)
 \s+
 }x) {
 $mpoint = $1;
 $ptype = $2;
 last;
 }
}
die "Don't handle $ptype"
 unless ($ptype =~ /^ext&#91;23&#93;$/);
$tune2fs_cmd = "tune2fs -l $part";
open(TUNE2FS,"$tune2fs_cmd|")
 or die "Could not tune2fs $!";
while (<TUNE2FS>) {
 if (m{ ^Block\ size:\s+
 (\d+)
 \s*$
 }x) {
 $bsize = $1;
 last;
 }
}
$fsb = int($poffset*512/$bsize);

Ich habe jetzt die Blockgröße des Dateisystems in $bsize und die Nummer des Blocks in $fsb. Als nächstes versuche ich mit debugfs rauszukriegen, welche Datei den Inode an Positon $poffset in Partition $part (bzw. den Block $fsb im Dateisystem) belegt. Das ist etwas kniffelig, da debugfs eigentlich interaktiv bedient wird. Hier kommt mir expect zu Hilfe, genauer Expect.pm.

Vorher noch ein kleiner Ausflug zu debugfs. Wenn ich das Programm aufrufe, habe ich eine Shell, in der ich mit Dateisystemen interessante Sachen machen kann. Mit open /dev/hda1 sage ich debugfs z.B., dass ich mit der ersten Partition der ersten IDE-Platte arbeiten möchte. Mit icheck 33 teile ich ihm mit, dass ich wissen möchte, welcher Inode den Dateisystemblock 33 benutzt. Die Aussage lautet dann z.B. 33 11, was bedeutet, dass der Inode 11 den Block 33 benutzt. Oder ich bekomme zurück 33 &lt;block not found&gt;, was bedeutet, dass der Dateisystemblock im Moment nicht verwendet wird. In diesem Fall kann ich abbrechen. Habe ich eine Inode-Nummer bekommen, kann ich z.B. mit ncheck 11 herausbekommen, welche Datei sich hinter Inode 11 dieses Dateisystems verbirgt. Das ist genau, was ich wissen will:

use Expect;
$robot = Expect->spawn('debugfs');
@pattern = $robot->expect(10
 ,'-re'
 ,'debugfs:\s+');
$robot->send_slow(0, "open $part\n");
@pattern = $robot->expect(10
 ,'-re'
 ,'debugfs:\s+');
$robot->send_slow(0, "icheck $fsb\n");
@pattern = $robot->expect(100
 ,'-re'
 ,'debugfs:\s+');
if ($pattern&#91;3&#93; =~ /^$fsb\s+(\d+)\s*$/m) {
 my $inode = $1;
 $robot->send_slow(0, "ncheck $inode\n");
 @pattern = $robot->expect(100
 ,'-re'
 ,'debugfs:\s+');
 if ($pattern&#91;3&#93;
 =~ m{ \s*$inode\s+
 (\S+)
 \s*
 }msx) {
 $fname = $1;
 }
 else {
 $fname = "<got $pattern&#91;3&#93;>";
 }
}
elsif ($pattern&#91;3&#93;
 =~ m{ \s*$fsb\s+
 <block\ not\ found>\s*
 }msx) {
 $fname = "<no inode at $fsb>";
}
else {
 $fname = "<got $pattern&#91;3&#93;>";
}
$robot->send("quit\n");
$robot->soft_close();
$robot->hard_close();

Damit habe ich die letzte benötigte Information, den Dateinamen (oder &lt;no inode uses block ...&gt;) in $fname. Falls debugfs unerwartet anders reagiert, als ich es in meiner Einfalt erwartet habe, wird mir auch das mitgeteilt.

Block neu zuweisen

Der Rest ist einfach, ich ziehe es jedoch vor, den Block explizit selbst reallozieren zu lassen, und lasse mir nur eine Empfehlung ausgeben:

if ($fname =~ /^<.+>$/s) {
 print "\n$fname\n";
} else {
 print "\nBlock $fsb belongs"
 . " to $mpoint$fname\n";
}
print <<"EOT";
To reallocate bad block do (as root):
dd if=/dev/zero of=$part bs=$bsize count=1 seek=$fsb
sync
smartctl -t long $disk
and then start over.
EOT

Das war's dann auch schon. Das Skript ermittelt mir in wenigen Sekunden, ob und wenn ja welche Dateien von dem schlechten Block betroffen sind und teilt mir außerdem mit, wie ich den Block durch die Platte ersetzen lassen kann. Dabei schreibt 'dd' auf den Dateisystemblock der Festplatte, der den defekten Plattenblock enthält und sync sorgt dafür, dass der Plattenplatz auch wirklich auf die Festplatte geschrieben wird.

Das komplette Skript finden Sie hier: reallocate_badblocks. Es muss noch mit chmod a+x reallocate_badblocks ausführbar gemacht werden.

Hinweis

Dieser Artikel ist ursprünglich in der Uptimes erschienen, der Mitgliederzeitschrift der German Unix User Group.

Dank

Lars Langhans erinnerte mich daran, dass mittlerweile etliche Programme an verschiedene Sprachen angepasst sind und dann andere Ausgaben bringen. Um dem zu begegnen, wird am Anfang des Skripts $ENV{LC_ALL} = 'C'; gesetzt.

Dieter Stüken machte mich darauf aufmerksam, dass neuere Versionen von dd die Option oflag=direct unterstützen. Damit ist es möglich, am Ende die Platte nur mit 512 Bytes (der Größe eines Festplattensektors) statt mit 1024, 2048 oder 4096 Bytes (der Größe eines Filesystemblocks) zu beschreiben. Von ihm kam auch der Code, der testet, ob das vorhandene dd diese Optionen kennt, und die Empfehlung, am Ende einen Filesystem-Check laufen zu lassen und vor dem Schreiben mit dd durch einen Lesezugriff zu prüfen, ob das Skript die richtige Stelle ermittelt hat.

Kommentare (Insgesamt: 0 || Kommentieren )
Pro-Linux
Newsletter
Neue Nachrichten