Off Topic: Recovering a RAID

This posting is a bit off topic for us, but we still thought you’d find it interesting.  In another posting I had explained how I was dealing with a failing drive controller in a RAID.  Just in case someone else confronts this problem too, I thought I’d give out the Perl source code that I used to patch everything back together.

Essentially, what we need to do is to interleave the blocks between two drives.  The script is pretty self explanatory, but if you run into problems or questions, please let me know!

#!/usr/bin/perl

$spread=32;
$Drive1 = $ARGV[0];
$Drive2 = $ARGV[1];
$Blocksize = $ARGV[2];
$Skip = $ARGV[3];
$Output = $ARGV[4];

print "Reading from $Drive1 + $Drive2 with a stripe/block size of $Blocksize after skipping $Skip blocks, writing to $Output.\n";
open(D1, "$Drive1") or die "$Drive1 not available or does not exist!";
open(D2, "$Drive2") or die "$Drive2 not available or does not exist!";
open(Out, ">$Output") or die "$Output could not be opened for writing!";
$doubleblocks = 0;
while(1)
{
	$read = sysread(D1, $d1, $Blocksize);
		# On some RAIDs, the first stripe contains the RAID configuration information.
		# If your RAID does then set $Skip to 1 in the command line arguments, otherwise set it to 0
	if($doubleblocks > (-1 + $Skip)) { syswrite(Out, $d1, $Blocksize); }
	sysread(D2, $d2, $Blocksize);
	syswrite(Out, $d2, $Blocksize);
	$doubleblocks ++;
	if($read == 0)
	{
		print "Finished!\n";
		close(Out);
		close(D1);
		close(D2);
		exit;
	}
		# I'm ADD when it comes to knowing if things are working.  This will print a periodic
		# status with the ending and beginning of the last stripes to be stitched together
		# Very useful for spot checking whether or not you've got the stripe size right.
		# Don't panic if not every stripe lines up.  You might be looking at file fragmentation
		# across multiple blocks.  If nothing lines up, that's a really bad sign.
	if($doubleblocks % 512 == 0)
	{
		print ($doubleblocks * 2) * $Blocksize; print "\n";
		@b1 = split(//, $d1);
		@b2 = split(//, $d2);
		for($i=($spread * -1); $i != 0; $i++)
		{
			$c = $b1[$i];
			$c =~ s/[^[:print:]]/./;
			print "$c";
		}
		print "|";
		for ($i = 0; $i != $spread; $i ++)
		{
			$c = $b2[$i];
			$c =~ s/[^[:print:]]/./;
			print "$c";
		}
		print "\n";
	}
}

Comments are closed.