From 3c6fbfb082361277877a5dd82f7014eff0afaa92 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Sun, 8 Aug 2004 07:10:15 +0000 Subject: - switch to mdadm (instead of raidtools) - create mdadm.conf instead of raidtab - internal {raids} is no more indexed by X for mdX, and so don't have holes anymore - internal {chunk-size} is now a number in KiB - internal {raid} is the raid device name, not the number - various cleanup for raid detection --- perl-install/raid.pm | 204 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 76 deletions(-) (limited to 'perl-install/raid.pm') diff --git a/perl-install/raid.pm b/perl-install/raid.pm index d91f3984b..a91466a6b 100644 --- a/perl-install/raid.pm +++ b/perl-install/raid.pm @@ -15,65 +15,60 @@ use fs; sub max_nb() { 31 } -sub nb { - my ($nb) = @_; - first((ref($nb) ? $nb->{device} : $nb) =~ /(\d+)/); -} - sub new { - my ($raids, @parts) = @_; - my $nb = @$raids; - $raids->[$nb] = { 'chunk-size' => "64k", fs_type => 'ext3', disks => [ @parts ], device => "md$nb", notFormatted => 1, level => 1 }; - foreach my $part (@parts) { - $part->{raid} = $nb; - delete $part->{mntpoint}; + my ($raids, %opts) = @_; + my $md_part = { %opts }; + add2hash_($md_part, { 'chunk-size' => '64', disks => [], + device => 'md' . int(@$raids), + notFormatted => 1, level => 1 }); + push @$raids, $md_part; + foreach (@{$md_part->{disks}}) { + $_->{raid} = $md_part->{device}; + fs::type::set_pt_type($_, 0xfd); + delete $_->{mntpoint}; } - update($raids->[$nb]); - $nb; + update($md_part); + $md_part; } sub add { - my ($raids, $part, $nb) = @_; $nb = nb($nb); - $raids->[$nb]{isMounted} and die N("Can't add a partition to _formatted_ RAID md%d", $nb); - inactivate_and_dirty($raids->[$nb]); + my ($md_part, $part) = @_; + $md_part->{isMounted} and die N("Can't add a partition to _formatted_ RAID %s", $md_part->{device}); + inactivate_and_dirty($md_part); set_isFormatted($part, 0); - $part->{raid} = $nb; + $part->{raid} = $md_part->{device}; delete $part->{mntpoint}; - push @{$raids->[$nb]{disks}}, $part; - update($raids->[$nb]); + push @{$md_part->{disks}}, $part; + update($md_part); } sub delete { - my ($raids, $nb) = @_; - $nb = nb($nb); - inactivate_and_dirty($raids->[$nb]); - delete $_->{raid} foreach @{$raids->[$nb]{disks}}; - undef $raids->[$nb]; + my ($raids, $md_part) = @_; + inactivate_and_dirty($md_part); + delete $_->{raid} foreach @{$md_part->{disks}}; + @$raids = grep { $_ != $md_part } @$raids; } -sub changeNb { - my ($raids, $oldnb, $newnb) = @_; - if ($oldnb != $newnb) { - inactivate_and_dirty($raids->[$_]) foreach $oldnb, $newnb; - - ($raids->[$newnb], $raids->[$oldnb]) = ($raids->[$oldnb], undef); - $raids->[$newnb]{device} = "md$newnb"; - $_->{raid} = $newnb foreach @{$raids->[$newnb]{disks}}; +sub change_device { + my ($md_part, $prev_device) = @_; + if ($prev_device ne $md_part->{device}) { + inactivate_and_dirty({ device => $prev_device }); + $_->{raid} = $md_part->{device} foreach @{$md_part->{disks}}; } - $newnb; } sub removeDisk { my ($raids, $part) = @_; - my $nb = nb($part->{raid}); - inactivate_and_dirty($raids->[$nb]); + my $md_part = fs::get::device2part($part->{raid}, $raids); + inactivate_and_dirty($md_part); + fs::type::set_isFormatted($part, 0); delete $part->{raid}; - my $disks = $raids->[$nb]{disks}; + my $disks = $md_part->{disks}; @$disks = grep { $_ != $part } @$disks; if (@$disks) { - update($raids->[$nb]); + update($md_part); } else { - undef $raids->[$nb]; + @$raids = grep { $_ != $md_part } @$raids; } } @@ -103,27 +98,6 @@ sub update { updateSize($_) foreach @_; } -sub write { - my ($raids, $file) = @_; - return if $::testing; - - output($file, - map { - my $s = sprintf(<{device}), $_->{level}, $_->{'chunk-size'}, int @{$_->{disks}}); -raiddev %s -raid-level %s -chunk-size %s -persistent-superblock 1 -nr-raid-disks %d -EOF - my @devs = map_index { - " device " . devices::make($_->{device}) . "\n raid-disk $::i\n"; - } @{$_->{disks}}; - - $s, @devs - } grep { $_ } @$raids); -} - sub make { my ($raids, $part) = @_; @@ -132,11 +106,15 @@ sub make { inactivate_and_dirty($part); isRAID($_) and make($raids, $_) foreach @{$part->{disks}}; - my $dev = devices::make($part->{device}); eval { modules::load(module($part)) }; - &write($raids, "/etc/raidtab"); - run_program::run("mkraid", "--really-force", $dev) or die - $::isStandalone ? N("mkraid failed (maybe raidtools are missing?)") : N("mkraid failed"); + + whereis_binary('mdadm') or die 'mdadm not installed'; + + run_program::run_or_die('mdadm', '--create', '--run', devices::make($part->{device}), + '--chunk=' . $part->{'chunk-size'}, + "--level=$part->{level}", + '--raid-devices=' . int(@{$part->{disks}}), + map { devices::make($_->{device}) } @{$part->{disks}}); } sub format_part { @@ -150,27 +128,18 @@ sub format_part { sub verify { my ($raids) = @_; - $raids or return; - foreach (grep { $_ } @$raids) { + foreach (@$raids) { @{$_->{disks}} >= ($_->{level} =~ /4|5/ ? 3 : 2) or die N("Not enough partitions for RAID level %d\n", $_->{level}); } } sub prepare_prefixed { - my ($raids, $prefix) = @_; - $raids or return; - - &write($raids, "/etc/raidtab") if ! -e "/etc/raidtab"; - - eval { cp_af("/etc/raidtab", "$prefix/etc/raidtab") }; - foreach (grep { $_ } @$raids) { - devices::make("$prefix/dev/$_->{device}") foreach @{$_->{disks}}; - } + my ($_raids) = @_; } sub inactivate_and_dirty { my ($part) = @_; - run_program::run("raidstop", devices::make($part->{device})); + run_program::run('mdadm', '--stop', devices::make($part->{device})); set_isFormatted($part, 0); } @@ -178,11 +147,94 @@ sub active_mds() { map { if_(/^(md\d+) /, $1) } cat_("/proc/mdstat"); } +sub detect_during_install { + my (@parts) = @_; + detect_during_install_once(@parts); + detect_during_install_once(@parts) if active_mds(); #- try again to detect RAID 10 +} + +sub detect_during_install_once { + my (@parts) = @_; + devices::make("md$_") foreach 0 .. max_nb(); + output('/etc/mdadm.conf', join(' ', 'DEVICE', + (map { "/dev/$_" } active_mds()), + map { devices::make($_->{device}) } @parts), "\n"); + run_program::run('mdadm', '>>', '/etc/mdadm.conf', '--examine', '--scan'); + + foreach (@{parse_mdadm_conf(scalar cat_('/etc/mdadm.conf'))->{ARRAY}}) { + eval { modules::load($_->{level}) }; + } + run_program::run('mdadm', '--assemble', '--scan'); +} + +sub get_existing { + my @parts = @_; + my $raids = []; + foreach my $md (active_mds()) { + my $conf = parse_mdadm_conf(scalar run_program::get_stdout('mdadm', '--detail', '--brief', devices::make($md))); + + @{$conf->{ARRAY}} == 1 or internal_error("too many answers"); + my $raw_part = $conf->{ARRAY}[0]; + + $raw_part->{level} =~ s/raid//; #- { linear | raid0 | raid1 | raid5 } -> { linear | 0 | 1 | 5 } + + my @mdparts = + map { + if (my $part = fs::get::device2part($_, [ @parts, @$raids ])) { + $part; + } else { + log::l("ERROR: unknown raw raid device $_"); + (); + } + } split(',', $raw_part->{devices}); + + my $md_part = new($raids, device => $md, level => $raw_part->{level}, disks => \@mdparts); + + my $fs_type = fs::type::fs_type_from_magic($md_part); + fs::type::set_fs_type($md_part, $fs_type || 'ext3'); + fs::type::set_isFormatted($md_part, to_bool($fs_type)); + + log::l("RAID: found $md (raid $md_part->{level}) type $fs_type with parts $raw_part->{devices}"); + } + $raids; +} + sub is_active { my ($dev) = @_; member($dev, active_mds()); } -sub inactivate_all() { run_program::run("raidstop", devices::make($_)) foreach active_mds() } +sub inactivate_all() { + run_program::run('mdadm', '--stop', devices::make($_)) foreach active_mds(); +} + +sub prepare_prefixed { + my ($raids) = @_; + my %raids = map { + devices::make($_->{device}) => + [ map { devices::make($_->{device}) } @{$_->{disks}} ] + } @$raids; + + output("$::prefix/etc/mdadm.conf", + join(' ', 'DEVICE', uniq(map { @$_ } values %raids)) . "\n", + map_each { "ARRAY $::a devices=" . join(',', @$::b) . "\n" } %raids); +} + +sub parse_mdadm_conf { + my ($s) = @_; + my %conf = (DEVICE => [], ARRAY => []); + $s =~ s!^\s*#.*!!gm; #- remove comments + $s =~ s!\n(\s)!$1!g; #- join lines starting with a space + foreach (split("\n", $s)) { + if (/^DEVICE\s+(.*)/) { + push @{$conf{DEVICE}}, split(' ', $1); + } elsif (my ($md, $md_conf) = /^ARRAY\s+(\S+)\s*(.*)/) { + my %md_conf = map { if_(/(.*)=(.*)/, $1 => $2) } split(' ', $md_conf); + $md_conf{device} = $md; + push @{$conf{ARRAY}}, \%md_conf; + } + } + \%conf +} 1; -- cgit v1.2.1