summaryrefslogtreecommitdiffstats
path: root/perl-install/raid.pm
blob: 0d0a8720a0121be490c35f21396c106edb86fb95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Diffstat (limited to 'move/todo')
0 files changed, 0 insertions, 0 deletions
'n118' href='#n118'>118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
package raid; # $Id$

use diagnostics;
use strict;

#-######################################################################################
#- misc imports
#-######################################################################################
use common;
use partition_table qw(:types);
use run_program;
use devices;
use modules;
use fs;

sub nb { 
    my ($nb) = @_;
    first((ref $nb ? $nb->{device} : $nb) =~ /(\d+)/);
}

sub new {
    my ($raids, @parts) = @_;
    my $nb = @$raids; 
    $raids->[$nb] = { 'chunk-size' => "64k", type => 0x83, disks => [ @parts ], device => "md$nb", notFormatted => 1, level => 1 };
    foreach my $part (@parts) {
	$part->{raid} = $nb;
	delete $part->{mntpoint};
    }
    update($raids->[$nb]);
    $nb;
}

sub add {
    my ($raids, $part, $nb) = @_; $nb = nb($nb);
    $raids->[$nb]{isMounted} and die _("Can't add a partition to _formatted_ RAID md%d", $nb);
    $part->{raid} = $nb;
    delete $part->{mntpoint};
    push @{$raids->[$nb]{disks}}, $part;
    update($raids->[$nb]);
}

sub delete {
    my ($raids, $nb) = @_;
    $nb = nb($nb);

    delete $_->{raid} foreach @{$raids->[$nb]{disks}};
    undef $raids->[$nb];
}

sub changeNb {
    my ($raids, $oldnb, $newnb) = @_;
    if ($oldnb != $newnb) {
	($raids->[$newnb], $raids->[$oldnb]) = ($raids->[$oldnb], undef);
	$raids->[$newnb]{device} = "md$newnb";
	$_->{raid} = $newnb foreach @{$raids->[$newnb]{disks}};
    }
    $newnb;
}

sub removeDisk {
    my ($raids, $part) = @_;
    my $nb = nb($part->{raid});
    run_program::run("raidstop", devices::make($part->{device}));
    delete $part->{raid};
    my $disks = $raids->[$nb]{disks};
    @$disks = grep { $_ != $part } @$disks;
    if (@$disks) {
	update($raids->[$nb]);
    } else {
	undef $raids->[$nb];
    }
}

sub updateSize {
    my ($part) = @_;
    local $_ = $part->{level};
    my @l = map { $_->{size} } @{$part->{disks}};

    $part->{size} = do {
	if (/0|linear/) { sum @l        }
	elsif (/1/  )   { min @l        }
	elsif (/4|5/)   { min(@l) * $#l }
    };
}

sub module {
    my ($part) = @_;
    my $mod = $part->{level};

    $mod = 5 if $mod eq "4";
    $mod = "raid$mod" if $mod =~ /^\d+$/;
    $mod;
}

sub updateIsFormatted {
    my ($part) = @_;
    $part->{isFormatted}  = and_ map { $_->{isFormatted}  } @{$part->{disks}};
    $part->{notFormatted} = and_ map { $_->{notFormatted} } @{$part->{disks}};
}
sub update {
    foreach (@_) {
	updateSize($_);
	updateIsFormatted($_);
    }
}

sub write {
    my ($raids, $file) = @_;
    local *F;
    local $\ = "\n";
    open F, ">$file" or die _("Can't write file %s", $file);

    foreach (grep {$_} @$raids) {
	print F <<"EOF";
raiddev       /dev/$_->{device}
raid-level    $_->{level}
chunk-size    $_->{'chunk-size'}
persistent-superblock 1
EOF
	print F "nr-raid-disks ", int @{$_->{disks}};
	map_index {	    
	    print F "    device    ", devices::make($_->{device});
	    print F "    raid-disk $::i";
	} @{$_->{disks}};
    }
}

sub make {
    my ($raids, $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("raidstop", $dev);
    run_program::run("mkraid", "--really-force", $dev) or die
	$::isStandalone ? _("mkraid failed (maybe raidtools are missing?)") : _("mkraid failed");
}

sub format_part {
    my ($raids, $part) = @_;
    $part->{isFormatted} and return;

    make($raids, $part);
    fs::real_format_part($part);
    $_->{isFormatted} = 1 foreach @{$part->{disks}};
}

sub verify {
    my ($raids) = @_;
    $raids or return;
    foreach (grep {$_} @$raids) {
	@{$_->{disks}} >= ($_->{level} =~ /4|5/ ? 3 : 2) or die _("Not enough partitions for RAID level %d\n", $_->{level});
    }
}

sub prepare_prefixed {
    my ($raids, $prefix) = @_;
    $raids or return;

    eval { cp_af("/etc/raidtab", "$prefix/etc/raidtab") };
    foreach (grep {$_} @$raids) {
	devices::make("$prefix/dev/$_->{device}") foreach @{$_->{disks}};
    }
}

sub stopAll() { run_program::run("raidstop", devices::make("md$_")) foreach 0..7 }

1;