summaryrefslogtreecommitdiffstats
path: root/perl-install/fs/dmraid.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/fs/dmraid.pm')
-rw-r--r--perl-install/fs/dmraid.pm284
1 files changed, 269 insertions, 15 deletions
diff --git a/perl-install/fs/dmraid.pm b/perl-install/fs/dmraid.pm
index 7166ce12d..7a279abc7 100644
--- a/perl-install/fs/dmraid.pm
+++ b/perl-install/fs/dmraid.pm
@@ -1,4 +1,4 @@
-package fs::dmraid; # $Id$
+package fs::dmraid;
use diagnostics;
use strict;
@@ -10,20 +10,58 @@ use common;
use modules;
use devices;
use fs::type;
+use fs::wild_device;
use run_program;
-init() or log::l("dmraid::init failed");
+=head1 SYNOPSYS
+
+Manage fake RAIDs using dmraid
+
+=head1 Functions
+
+=over
+
+=item init()
+
+Load kernel modules, init device mapper then scan for fake RAIDs.
+
+=cut
sub init() {
- eval { modules::load('dm-mirror') };
+ whereis_binary('dmraid') or die "dmraid not installed";
+
+ eval { modules::load('dm-mirror', 'dm-zero') };
devices::init_device_mapper();
if ($::isInstall) {
- run_program::run('dmraid', '-ay');
+ foreach my $name (call_dmraid('-s', '-c', '-i')) {
+ chomp($name);
+ log::l("got: $name");
+ call_dmraid('-ay', '-i', '--rm_partitions', '-p', $name);
+ run_program::run('/sbin/kpartx', '-u', '-a', '/dev/mapper/' . $name);
+ }
}
1;
}
+=item call_dmraid($option, @args)
+
+Runs dmraid with $option & @args.
+It is overloaded when debugging, see the end of this file.
+
+=cut
+
+sub call_dmraid {
+ my ($option, @args) = @_;
+ run_program::get_stdout('dmraid', $option, @args);
+}
+
+=item check($in)
+
+Ensures dmraid is installed. If yes, calls init().
+
+=cut
+
sub check {
my ($in) = @_;
@@ -32,26 +70,242 @@ sub check {
1;
}
-sub pvs_and_vgs() {
+=item _raid_devices_raw()
+
+Get the real VG names, needed for ddf1, and safer than begins_with for raid10
+
+=cut
+
+sub _raid_devices_raw() {
+ log::l("_raid_devices_raw");
+ my %vgs;
+ my %pv2vg = map {
+ chomp();
+ log::l("got: $_");
+ my %l; @l{qw(name size stride level status subsets devs spares)} = split(':');
+ $vgs{$l{name}} = 1 if defined $l{spares};
+ if (/freeing device "(.*)", path "(.*)"/ && defined $vgs{$1}) {
+ log::l("$2 => $1");
+ $2 => $1;
+ }
+ } call_dmraid(qw(-d -s -c -c));
+
+ map {
+ chomp;
+ log::l("got: $_");
+ my %l; @l{qw(pv format vg level status size)} = split(':');
+ if (defined $l{size} && defined $l{vg} && defined $pv2vg{$l{pv}} && !defined $vgs{$l{vg}}) {
+ log::l("using $pv2vg{$l{pv}} instead of $l{vg}");
+ $l{vg} = $pv2vg{$l{pv}};
+ }
+ if_(defined $l{size}, \%l);
+ } call_dmraid(qw(-r -c -c));
+}
+
+sub _raid_devices() {
+ my @l = _raid_devices_raw();
+ my %vg2pv; push @{$vg2pv{$_->{vg}}}, delete $_->{pv} foreach @l;
+ my %vg2status; push @{$vg2status{$_->{vg}}}, delete $_->{status} foreach @l;
map {
- my @l = split(':');
- { pv => $l[0], format => $l[1], vg => $l[2], level => $l[3], status => $l[4] };
- } run_program::get_stdout('dmraid', '-rcc');
+ delete $_->{size}; #- now irrelevant
+ $_->{disks} = $vg2pv{$_->{vg}};
+ $_->{status} = (every { $_ eq 'ok' } @{$vg2status{$_->{vg}}}) ? 'ok' : join(' ', @{$vg2status{$_->{vg}}});
+ $_;
+ } uniq_ { $_->{vg} } @l;
}
+sub _sets_raw() {
+ map {
+ chomp;
+ log::l("got: $_");
+ my %l; @l{qw(name size stride level status subsets devs spares)} = split(':');
+ if_(defined $l{spares}, \%l);
+ } call_dmraid('-s', '-c', '-c');
+}
+
+sub _sets() {
+ my @sets = _sets_raw();
+ my @raid_devices = _raid_devices();
+ foreach (@sets) {
+ my $name = $_->{name};
+ my @l = grep { begins_with($name, $_->{vg}) } @raid_devices;
+ log::l("ERROR: multiple match for set $name: " . join(' ', map { $_->{vg} } @l)) if @l > 1;
+
+ @l = grep { begins_with($_->{vg}, $name) } @raid_devices if !@l;
+
+ if (@l) {
+ foreach my $raid (@l) {
+ push @{$_->{disks}}, @{$raid->{disks}};
+ add2hash($_, $raid);
+ $_->{status} = $raid->{status} if $_->{status} eq 'ok' && $::isInstall;
+ }
+ } else {
+ log::l("ERROR: no matching raid devices for set $name");
+ }
+ }
+ @sets;
+}
+
+=item vgs()
+
+Returns the list of VGs corresponding to dmraid
+
+=cut
+
sub vgs() {
- my @l = pvs_and_vgs();
- my %vg2pv; push @{$vg2pv{$_->{vg}}}, $_->{pv} foreach @l;
map {
- my $dev = "mapper/$_->{vg}";
- my $vg = fs::subpart_from_wild_device_name("/dev/$dev");
- add2hash($vg, { media_type => 'hd', prefix => $dev, bus => "dm_$_->{format}", disks => $vg2pv{$_->{vg}} });
+ my $dev = "mapper/$_->{name}";
+ my $vg = fs::wild_device::to_subpart("/dev/$dev");
+ add2hash($vg, { media_type => 'hd', bus => "dmraid_$_->{format}", disks => $_->{disks} });
#- device should exist, created by dmraid(8) using libdevmapper
#- if it doesn't, we suppose it's not in use
- if_(-e "/dev/$dev", $vg);
+ if (-e "/dev/$dev") {
+ $vg;
+ } else {
+ log::l("ignoring $dev as /dev/$dev doesn't exist");
+ ();
+ }
+
+ } grep {
+ if ($_->{status} eq 'ok') {
+ 1;
+ } else {
+ call_dmraid('-an', $_->{vg}) if $::isInstall; #- for things like bad_sil below, deactivating half activated dmraid
+ 0;
+ }
+ } _sets();
+}
+
+=item migrate_device_names ($vg)
+
+Handles migration from /dev/mapper/xxx1 to /dev/mapper/xxxp1, as used by initrd/nash.
+dmraid has been patched to follow xxxp1 device names.
+So until the box has rebooted on new initrd/dmraid, we must cope with /dev/mapper/xxx1 device names
+(cf mdk#44182)
+
+=cut
+
+sub migrate_device_names {
+ my ($vg) = @_;
+
+ my $dev_name = basename($vg->{device});
+ foreach (all('/dev/mapper')) {
+ my ($nb) = /^\Q$dev_name\E(\d+)$/ or next;
+ my $new = $dev_name . 'p' . $nb;
+ if (! -e "/dev/mapper/$new") {
+ log::l("migrating to $new, creating a compat symlink $_");
+ rename "/dev/mapper/$_", "/dev/mapper/$new";
+ symlink $new, "/dev/mapper/$_";
+ }
+ }
+}
+
+=back
+
+=head1 Debugging
+
+If $ENV{DRAKX_DEBUG_DMRAID} is set, debugging dmraid is done.
+The C<call_dmraid()> function is overloaded and will spit out warnings.
+=cut
+
+if ($ENV{DRAKX_DEBUG_DMRAID}) {
+ eval(<<'EOF');
+ my %debug_data = (
+
+ isw => {
+
+ # dmraid -s ####################
+ # *** Group superset isw_ffafgbdhi
+ # --> Active Subset
+ # name : isw_ffafgbdhi_toto
+ # size : 234441216
+ # stride : 256
+ # type : mirror
+ # status : ok
+ # subsets: 0
+ # devs : 2
+ # spares : 0
+
+ '-s' => "isw_ffafgbdhi_toto:234441216:256:mirror:ok:0:2:0\n",
+
+ # dmraid -r ####################
+ #/dev/sda: isw, "isw_ffafgbdhi", GROUP, ok, 488397166 sectors, data@ 0
+ #/dev/sdb: isw, "isw_ffafgbdhi", GROUP, ok, 234441646 sectors, data@ 0
+
+ '-r' => "/dev/sda:isw:isw_ffafgbdhi:GROUP:ok:488397166:0\n" .
+ "/dev/sdb:isw:isw_ffafgbdhi:GROUP:ok:234441646:0\n",
+ },
+
+ pdc => {
+ # dmraid -s ####################
+ # *** Active Set
+ # name : pdc_bcefbiigfg
+ # size : 80043200
+ # stride : 128
+ # type : mirror
+ # status : ok
+ # subsets: 0
+ # devs : 2
+ # spares : 0
+
+ '-s' => "pdc_bcefbiigfg:80043200:128:mirror:ok:0:2:0\n",
+
+ # dmraid -r ####################
+ # /dev/sda: pdc, "pdc_bcefbiigfg", mirror, ok, 80043200 sectors, data@ 0
+ # /dev/sdb: pdc, "pdc_bcefbiigfg", mirror, ok, 80043200 sectors, data@ 0
+
+ '-r' => "/dev/sda:pdc:pdc_bcefbiigfg:mirror:ok:80043200:0\n" .
+ "/dev/sdb:pdc:pdc_bcefbiigfg:mirror:ok:80043200:0\n",
+ },
+
+ bad_sil => {
+ '-s' => "sil_aeacdidecbcb:234439600:0:mirror:ok:0:1:0\n",
+ # ERROR: sil: only 3/4 metadata areas found on /dev/sdb, electing...
+
+ '-r' => "/dev/sdb:sil:sil_aeacdidecbcb:mirror:broken:234439600:0\n",
+ # ERROR: sil: only 3/4 metadata areas found on /dev/sdb, electing...
+ },
+
+ weird_nvidia => {
+ '-s' => <<'EO',
+/dev/sda: "sil" and "nvidia" formats discovered (using nvidia)!
+/dev/sdb: "sil" and "nvidia" formats discovered (using nvidia)!
+nvidia_bcjdbjfa:586114702:128:mirror:ok:0:2:0
+EO
+ '-r' => <<'EO',
+/dev/sda: "sil" and "nvidia" formats discovered (using nvidia)!
+/dev/sdb: "sil" and "nvidia" formats discovered (using nvidia)!
+/dev/sda:nvidia:nvidia_bcjdbjfa:mirror:ok:586114702:0
+/dev/sdb:nvidia:nvidia_bcjdbjfa:mirror:ok:586114702:0
+EO
+ # ERROR: multiple match for set nvidia_bcjdbjfa: nvidia_bcjdbjfa
+ },
- } grep { $_->{status} eq 'ok' } uniq_ { $_->{vg} } @l;
+ nvidia_with_subsets => {
+ '-s' => <<'EO',
+nvidia_bfcciffh:625163520:128:raid10:ok:2:4:0
+EO
+ '-r' => <<'EO',
+/dev/sda:nvidia:nvidia_bfcciffh-0:stripe:ok:312581806:0
+/dev/sdb:nvidia:nvidia_bfcciffh-0:stripe:ok:312581806:0
+/dev/sdc:nvidia:nvidia_bfcciffh-1:stripe:ok:312581806:0
+/dev/sdd:nvidia:nvidia_bfcciffh-1:stripe:ok:312581806:0
+EO
+ # ERROR: multiple match for set nvidia_bcjdbjfa: nvidia_bcjdbjfa
+ },
+ );
+
+ *call_dmraid = sub {
+ my ($option, @args) = @_;
+ if (my $s = $debug_data{$ENV{DRAKX_DEBUG_DMRAID}}{$option}) {
+ split("\n", $s);
+ } else {
+ warn "dmraid $option @args\n";
+ }
+ };
+EOF
+ $@ and die;
}
1;