I’ve been testing the resizing of the drives located on a Dell MD3000, and i’ve seen errors when resizing after the 2TB mark. This is on the new firmware which supports > 2TB logical drives. I wrote a script to write to random locations of a block device. It can then read them back and verify that they’re still the same as what was written. Rather than writing to the entire device I use random sampling, with a few fixed points on the block device. I pretty much get consistent failures. If I put in the failed locations into the next write run they come out again in the subsequent run. Kind of makes resizing a dangerous operation, even though it is stated that resizing is non-destructive.
I realize that the array is nothing more than a rebrand of another device, but it would be great if it was tested in a lab before something this bad got out to the customers.
#! /usr/bin/perl -w
use strict;
use Getopt::Long;
use Digest::MD5 qw(md5_hex);
use File::Basename;
my $fs;
my $readfile;
my $writefile;
my $numpatterns = 2048;
my $seed = undef;
my $size;
my $real_size;
my $help;
my %vars;
my @def_offsets = (0);
sub usage($) {
print <<EOM;
Usage: $0 –fs=<filesystem> –read=<file>|–write=<file>
[–num=<number of blocks>] [–offset=<offset to test>]
[–seed=<random number seed>]
EOM
exit ($_[0]);
}
my $result = GetOptions( ‘fs=s‘ => \$fs,
‘num=i‘ => \$numpatterns,
‘seed=i‘ => \$seed,
‘read=s‘ => \$readfile,
‘offset=i‘ => \@def_offsets,
‘write=s‘ => \$writefile,
‘h|help‘ => \$help);
usage(0) if defined($help);
warn "Need file system to use" if (!defined($fs));
warn "Need either a read or write file" if (!(defined($readfile) || defined($writefile)));
usage (1) if (!defined($fs) || !(defined($readfile) || defined($writefile)));
my $base = basename($fs);
open (IN, "</proc/partitions") || die "Could not load partition tables";
while (<IN>) {
chomp();
my ($major, $minor, $blocks, $name) = m/(\w*)\s+(\w*)\s+(\w*)\s+(\w*)$/;
next if (!defined($major));
if ($name eq $base) {
$real_size = $blocks;
last;
}
}
close(IN);
die "Could not get size" if (!defined($real_size));
# Write to the offset in blocks
sub write_to_offset($$) {
my ($offset, $buffer) = @_;
sysseek(INFS, $offset * 1024, 0);
my $write = syswrite(INFS, $buffer, 1024);
if (!defined($write) || $write != 1024) {
warn "Failed to write: $offset $!\n";
} else {
$vars{$offset} = md5_hex($buffer);
}
}
sub read_from_offset($) {
my ($offset) = @_;
my $buffer;
sysseek(INFS, $offset * 1024, 0);
my $read = sysread(INFS, $buffer, 1024);
if (!defined($read) || $read != 1024) {
warn "Could not read 1024 bytes at $offset $!";
return (1);
}
if (md5_hex($buffer) ne $vars{$offset}) {
warn "Data at offset $offset was not the same as expected";
return (1);
}
return (0);
}
sub get_buffer {
my $i = 0;
my $buffer = "";
while ($i++ < 256) {
my $randval = int(rand(255 * 255 * 255 * 255));
$buffer .= chr($randval >> 24) . chr(($randval >> 16) & 255) .
chr(($randval >> 8) & 255) . chr($randval & 255);
}
(length($buffer) == 1024) || die "Buffer was " . length($buffer);
return $buffer;
}
if (defined($readfile)) {
# reading from previous file
open (INPUT, "<$readfile") || die "Could not open previous run log";
while(<INPUT>) {
chomp();
my ($key, $value) = m/(.*)=(.*)/;
if ($key eq "patterncount") {
$numpatterns = $value;
next;
}
if ($key eq "size") {
$size = $value;
next;
}
if ($key eq "seed") {
$seed = $value;
next;
}
$vars{$key} = $value;
}
close(INPUT);
} else {
$seed = time ^ $$ ^ unpack "%L*", `ls -l /proc/ | gzip -f` if (!defined($seed));
$size = $real_size if (!defined($size));
open (OUTPUT, ">$writefile") || die "Could not open new run log";
print OUTPUT "patterncount=$numpatterns\n" .
"size=$size\n" .
"seed=$seed\n";
}
print "Size: $real_size [$size] Seed: $seed\n";
srand($seed);
my $mode = "<";
$mode = "+<" if ($writefile);
open(INFS, "$mode$fs") || die "Could not open raw device";
if ($writefile) {
map { write_to_offset($_, get_buffer()) } @def_offsets;
write_to_offset($size – 1, get_buffer());
while($numpatterns > 0) {
my $offset = int(rand($size));
print "Writing pattern: $numpatterns \r";
next if defined($vars{$offset});
write_to_offset($offset, get_buffer());
$numpatterns–;
}
map { print OUTPUT "$_=" . $vars{$_} . "\n" } keys(%vars);
close(OUTPUT);
} else {
my $failcount = 0;
my $tocount = scalar(keys(%vars));
map { $failcount += read_from_offset($_); printf("To Count: %0.7d\r", $tocount–); } sort(keys(%vars));
print "Count difference: $failcount\n";
}
consistency.pl.txt