diff options
Diffstat (limited to 'perl-install/raid.pm')
| -rw-r--r-- | perl-install/raid.pm | 181 |
1 files changed, 153 insertions, 28 deletions
diff --git a/perl-install/raid.pm b/perl-install/raid.pm index 4c0b6ca2c..f20a511eb 100644 --- a/perl-install/raid.pm +++ b/perl-install/raid.pm @@ -1,4 +1,4 @@ -package raid; # $Id$ +package raid; use diagnostics; use strict; @@ -8,22 +8,34 @@ use strict; #-###################################################################################### use common; use fs::type; +use fs::get; 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) = @_; - $::isInstall || $in->do_pkgs->ensure_binary_is_installed('mdadm', 'mdadm'); + # perl_checker: require interactive + my ($in) = @_; # perl_checker: $in = interactive->new + $::prefix ? whereis_binary('mdadm') : $in->do_pkgs->ensure_binary_is_installed('mdadm', 'mdadm'); } sub new { my ($raids, %opts) = @_; my $md_part = { %opts }; add2hash_($md_part, { 'chunk-size' => '64', disks => [], - fs_type => 'ext3', + fs_type => defaultFS(), device => first(free_mds($raids)), notFormatted => 1, level => 1 }); push @$raids, $md_part; @@ -36,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}; @@ -47,11 +65,18 @@ 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); delete $_->{raid} foreach @{$md_part->{disks}}; @$raids = grep { $_ != $md_part } @$raids; + write_conf($raids) if $::isStandalone; } sub change_device { @@ -76,6 +101,7 @@ sub removeDisk { } else { @$raids = grep { $_ != $md_part } @$raids; } + write_conf($raids) if $::isStandalone; } sub updateSize { @@ -84,19 +110,44 @@ sub updateSize { my @l = map { $_->{size} } @{$part->{disks}}; $part->{size} = do { - if (/0|linear/) { sum @l } - elsif (/1/) { min @l } - elsif (/4|5/) { min(@l) * $#l } + if (/0|linear/) { sum @l } + 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'); +} + +=item module($part) + +Return list of modules need by a md device (according to its RAID level) + +=cut + sub module { my ($part) = @_; - my $mod = $part->{level}; - - $mod = 5 if $mod eq "4"; - $mod = "raid$mod" if $mod =~ /^\d+$/; - $mod; + my $level = $part->{level}; + log::l("level $level"); + + if (member($level, 4, 5, 6)) { + 'raid456'; + } elsif (member($level, 10)) { + 'raid10'; + } elsif ($level =~ /^\d+$/) { + "raid$level"; + } else { + $level; + } } @@ -117,11 +168,15 @@ sub make { whereis_binary('mdadm') or die 'mdadm not installed'; my $dev = devices::make($part->{device}); + my $nb = @{$part->{disks}}; run_program::run_or_die('mdadm', '--create', '--run', $dev, - '--chunk=' . $part->{'chunk-size'}, + if_($nb == 1, '--force'), + if_($nb == 2 && $part->{level} == 10, '--layout=f2'), + if_($part->{level} != 1, '--chunk=' . $part->{'chunk-size'}), "--level=$part->{level}", - '--raid-devices=' . int(@{$part->{disks}}), + "--raid-devices=$nb", + if_($part->{metadata}, "--metadata=$part->{metadata}"), map { devices::make($_->{device}) } @{$part->{disks}}); if (my $raw_part = get_md_info($dev)) { @@ -142,7 +197,8 @@ sub format_part { sub verify { my ($raids) = @_; foreach (@$raids) { - @{$_->{disks}} >= ($_->{level} =~ /4|5/ ? 3 : 2) or die N("Not enough partitions for RAID level %d\n", $_->{level}); + my $nb = $_->{level} =~ /4|5|6/ ? 3 : 2; + @{$_->{disks}} >= $nb or die N("Not enough partitions for RAID level %d\n", $_->{level}); } } @@ -152,29 +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\d+)\s*:\s*active/, $1) } cat_("/proc/mdstat"); + 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\d+)\s*:\s*inactive/, $1) } cat_("/proc/mdstat"); + 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) = @_; + 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(); @@ -182,10 +286,6 @@ sub detect_during_install_once { (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'); } @@ -195,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 } -> { linear | 0 | 1 | 5 } + $raw_part->{level} =~ s/raid//; #- { linear | raid0 | raid1 | raid5 | raid6 | raid10 } -> { linear | 0 | 1 | 5 | 6 | 10 } my @mdparts = map { @@ -207,13 +307,20 @@ 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) { put_in_hash($md_part, $type); } else { - fs::type::set_fs_type($md_part, 'ext3'); + fs::type::set_fs_type($md_part, defaultFS()); } my $fs_type = $type && $type->{fs_type}; fs::type::set_isFormatted($md_part, to_bool($fs_type)); @@ -223,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) = @_; @@ -235,14 +354,15 @@ sub write_conf { my @devices = uniq(map { devices::make($_->{device}) } map { @{$_->{disks}} } @$raids); - output("$::prefix/etc/mdadm.conf", + # $::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); } sub get_md_info { my ($dev) = @_; - my $conf = parse_mdadm_conf(scalar run_program::get_stdout('mdadm', '--detail', '--brief', $dev)); + my $conf = parse_mdadm_conf(scalar run_program::get_stdout('mdadm', '--detail', '--brief', '-v', $dev)); @{$conf->{ARRAY}} or return; @{$conf->{ARRAY}} == 1 or internal_error("too many answers"); @@ -259,6 +379,7 @@ sub parse_mdadm_conf { 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{level} =~ s/^raid//; $md_conf{device} = $md; push @{$conf{ARRAY}}, \%md_conf; } @@ -266,4 +387,8 @@ sub parse_mdadm_conf { \%conf; } +=back + +=cut + 1; |
