diff options
Diffstat (limited to 'perl-install/raid.pm')
-rw-r--r-- | perl-install/raid.pm | 131 |
1 files changed, 120 insertions, 11 deletions
diff --git a/perl-install/raid.pm b/perl-install/raid.pm index 11284a90a..480868547 100644 --- a/perl-install/raid.pm +++ b/perl-install/raid.pm @@ -1,4 +1,4 @@ -package raid; # $Id$ +package raid; use diagnostics; use strict; @@ -13,10 +13,21 @@ use run_program; use devices; use modules; -sub max_nb() { 31 } +=head1 SYNOPSYS + +Manage regular soft RAID (MD=Multiple Drive). + +=head1 Functions + +=over + +=cut + +sub max_nb() { 131 } sub check_prog { - my ($in) = @_; + # perl_checker: require interactive + my ($in) = @_; # perl_checker: $in = interactive->new $::prefix ? whereis_binary('mdadm') : $in->do_pkgs->ensure_binary_is_installed('mdadm', 'mdadm'); } @@ -37,9 +48,15 @@ sub new { $md_part; } +=item add() + +Add a partition to a RAID array + +=cut + sub add { my ($md_part, $part) = @_; - $md_part->{isMounted} and die N("Can not add a partition to _formatted_ RAID %s", $md_part->{device}); + $md_part->{isMounted} and die N("Cannot add a partition to _formatted_ RAID %s", $md_part->{device}); inactivate_and_dirty($md_part); set_isFormatted($part, 0); $part->{raid} = $md_part->{device}; @@ -48,6 +65,12 @@ sub add { update($md_part); } +=item delete() + +Remove a partition from a RAID array + +=cut + sub delete { my ($raids, $md_part) = @_; inactivate_and_dirty($md_part); @@ -91,13 +114,26 @@ sub updateSize { elsif (/1/) { min @l } elsif (/4|5/) { min(@l) * (@l - 1) } elsif (/6/) { min(@l) * (@l - 2) } + elsif (/10/) { min(@l) * (@l / 2) } }; } +=item allmodules() + +Return list of the RAID modules we support + +=cut + sub allmodules { - [ 'raid0', 'raid1', 'raid10', 'raid456' ]; + ('raid0', 'raid1', 'raid10', 'raid456'); } +=item module($part) + +Return list of modules need by a md device (according to its RAID level) + +=cut + sub module { my ($part) = @_; my $level = $part->{level}; @@ -105,6 +141,8 @@ sub module { if (member($level, 4, 5, 6)) { 'raid456'; + } elsif (member($level, 10)) { + 'raid10'; } elsif ($level =~ /^\d+$/) { "raid$level"; } else { @@ -134,9 +172,11 @@ sub make { run_program::run_or_die('mdadm', '--create', '--run', $dev, if_($nb == 1, '--force'), + if_($nb == 2 && $part->{level} == 10, '--layout=f2'), '--chunk=' . $part->{'chunk-size'}, "--level=$part->{level}", "--raid-devices=$nb", + if_($part->{metadata}, "--metadata=$part->{metadata}"), map { devices::make($_->{device}) } @{$part->{disks}}); if (my $raw_part = get_md_info($dev)) { @@ -157,7 +197,7 @@ sub format_part { sub verify { my ($raids) = @_; foreach (@$raids) { - my $nb = $_->{level} =~ /6/ ? 4 : $_->{level} =~ /4|5/ ? 3 : 2; + my $nb = $_->{level} =~ /4|5|6/ ? 3 : 2; @{$_->{disks}} >= $nb or die N("Not enough partitions for RAID level %d\n", $_->{level}); } } @@ -168,32 +208,77 @@ sub inactivate_and_dirty { set_isFormatted($part, 0); } +=item active_mds() + +Return list of active MDs + +=cut + sub active_mds() { map { if_(/^(md\S+)\s*:\s*active/, $1) } cat_("/proc/mdstat"); } + +=item inactive_mds() + +Return list of inactive MDs + +=cut + sub inactive_mds() { map { if_(/^(md\S+)\s*:\s*inactive/, $1) } cat_("/proc/mdstat"); } +=item free_mds() + +Return list of unused MD device nodes + +=cut + sub free_mds { my ($raids) = @_; difference2([ map { "md$_" } 0 .. max_nb() ], [ map { $_->{device} } @$raids ]); } +=item detect_durting_install() + +Load RAID modules. +Stop RAIDS that might have been started too early by udev. +Scan & starts RAID arrays, then stop any inactive md. + +=cut + sub detect_during_install { my (@parts) = @_; - foreach (@{allmodules()}) { - eval { modules::load($_) }; - } + eval { modules::load($_) } foreach allmodules(); + + # udev may have started raids but failed due to not yet loaded modules and + # they remains inactive ("md: personality for level 1 is not loaded!") + stop_inactive_mds(); + detect_during_install_once(@parts); detect_during_install_once(@parts) if active_mds(); #- try again to detect RAID 10 + stop_inactive_mds(); +} + +=item stop_inactive_mds() + +Stop any inactive md. +=cut + +sub stop_inactive_mds() { foreach (inactive_mds()) { log::l("$_ is an inactive md, we stop it to ensure it doesn't busy devices"); run_program::run('mdadm', '--stop', devices::make($_)); } } +=item detect_during_install_once(@parts) + +Scan & starts RAID arrays, then stop any inactive md. + +=cut + sub detect_during_install_once { my (@parts) = @_; devices::make("md$_") foreach 0 .. max_nb(); @@ -210,7 +295,7 @@ sub get_existing { foreach my $md (active_mds()) { my $raw_part = get_md_info(devices::make($md)) or next; - $raw_part->{level} =~ s/raid//; #- { linear | raid0 | raid1 | raid5 | raid6 } -> { linear | 0 | 1 | 5 | 6 } + $raw_part->{level} =~ s/raid//; #- { linear | raid0 | raid1 | raid5 | raid6 | raid10 } -> { linear | 0 | 1 | 5 | 6 | 10 } my @mdparts = map { @@ -222,7 +307,14 @@ sub get_existing { } } split(',', $raw_part->{devices}); - my $md_part = new($raids, device => $md, UUID => $raw_part->{UUID}, level => $raw_part->{level}, disks => \@mdparts); + my ($info) = $md =~ m!([^/]*)$!; + my $md_part = new($raids, + device => $md, + UUID => $raw_part->{UUID}, + level => $raw_part->{level}, + metadata => $raw_part->{metadata}, + info => $info . " (RAID$raw_part->{level})", + disks => \@mdparts); my $type = fs::type::type_subpart_from_magic($md_part); if ($type) { @@ -238,11 +330,23 @@ sub get_existing { $raids; } +=item is_active($dev) + +Is it an?active md + +=cut + sub is_active { my ($dev) = @_; member($dev, active_mds()); } +=item write_conf() + +Write /etc/mdadm.conf + +=cut + sub write_conf { my ($raids) = @_; @@ -250,6 +354,7 @@ sub write_conf { my @devices = uniq(map { devices::make($_->{device}) } map { @{$_->{disks}} } @$raids); + # $::isInstall test for draklive-install: output($::isInstall ? "$::prefix/etc/mdadm.conf" : "/etc/mdadm.conf", join(' ', 'DEVICE', @devices) . "\n", map { "ARRAY " . devices::make($_->{device}) . " UUID=$_->{UUID} auto=yes\n" } @$raids); @@ -282,4 +387,8 @@ sub parse_mdadm_conf { \%conf; } +=back + +=cut + 1; |