[Fai-commit] r4832 - in people/michael/features/setup_harddisks_2/implementation: . lib
mt at alioth.debian.org
mt at alioth.debian.org
Sun Dec 23 15:20:44 UTC 2007
Author: mt
Date: 2007-12-23 15:20:43 +0000 (Sun, 23 Dec 2007)
New Revision: 4832
Modified:
people/michael/features/setup_harddisks_2/implementation/lib/commands.pm
people/michael/features/setup_harddisks_2/implementation/lib/exec.pm
people/michael/features/setup_harddisks_2/implementation/lib/parser.pm
people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm
people/michael/features/setup_harddisks_2/implementation/lib/volumes.pm
people/michael/features/setup_harddisks_2/implementation/setup-storage
Log:
code cleanup done, remaining TODOs are in the Wiki, but testing is probably the
most important thing.
Modified: people/michael/features/setup_harddisks_2/implementation/lib/commands.pm
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/lib/commands.pm 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/lib/commands.pm 2007-12-23 15:20:43 UTC (rev 4832)
@@ -111,8 +111,7 @@
################################################################################
sub build_raid_commands {
- # loop through all configs
- foreach my $config (keys %FAI::configs) {
+ foreach my $config (keys %FAI::configs) { # loop through all configs
# no LVM or physical devices here
next if ($config =~ /^VG_./ || $config =~ /^PHY_./);
($config eq "RAID") or &FAI::internal_error("Invalid config $config");
Modified: people/michael/features/setup_harddisks_2/implementation/lib/exec.pm
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/lib/exec.pm 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/lib/exec.pm 2007-12-23 15:20:43 UTC (rev 4832)
@@ -53,8 +53,7 @@
{
error => "parted_1",
message => "Parted failed to remove the partition\n",
- stderr_regex =>
- ".*Error: Could not stat device rm - No such file or directory.*",
+ stderr_regex => "Error: Could not stat device rm - No such file or directory",
stdout_regex => "",
program => "parted",
response => "die",
@@ -62,7 +61,7 @@
{
error => "parted_2",
message => "Parted could not read a disk label\n",
- stderr_regex => ".*Error: Unable to open .* - unrecognised disk label.*",
+ stderr_regex => "Error: Unable to open .* - unrecognised disk label",
stdout_regex => "",
program => "parted",
response => "warn",
@@ -70,8 +69,7 @@
{
error => "parted_3",
message => "Parted failed to open the device\n",
- stderr_regex =>
- ".*Error: Could not stat device .* - No such file or directory.*",
+ stderr_regex => "Error: Could not stat device .* - No such file or directory",
stdout_regex => "",
program => "parted",
response => "die"
@@ -79,8 +77,7 @@
{
error => "parted_4",
message => "parted not found\n",
- stderr_regex =>
- ".*(parted: command not found|/sbin/parted: No such file or directory)",
+ stderr_regex => "(parted: command not found|/sbin/parted: No such file or directory)",
stdout_regex => "",
program => "parted",
response => "die"
@@ -95,14 +92,20 @@
},
{
error => "mkfs.xfs_1",
- message =>
-"mkfs.xfs refused to create a filesystem. Probably you should add -f to the mkfs options in your disk_config file.\n",
- stderr_regex =>
- "mkfs.xfs: /dev/.* appears to contain an existing filesystem",
+ message => "mkfs.xfs refused to create a filesystem. Probably you should add -f to the mkfs options in your disk_config file.\n",
+ stderr_regex => "mkfs.xfs: /dev/.* appears to contain an existing filesystem",
stdout_regex => "",
program => "mkfs.xfs",
response => "die",
},
+ {
+ error => "parted_6",
+ message => "Parted was unable to read the partition table\n",
+ stderr_regex => "No Implementation: Partition 1 isn't aligned to cylinder boundaries",
+ stdout_regex => "",
+ program => "parted",
+ response => "die",
+ },
];
################################################################################
Modified: people/michael/features/setup_harddisks_2/implementation/lib/parser.pm
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/lib/parser.pm 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/lib/parser.pm 2007-12-23 15:20:43 UTC (rev 4832)
@@ -273,6 +273,7 @@
my ($val) = @_;
($val =~ /^(\d+)([kMGTP%]?)(B)?\s*$/) or
&FAI::internal_error("convert_unit $val");
+ $val = $1 * (1 / 1024) * (1 / 1024) if ($2 eq "" && defined ($3) && $3 eq "B");
$val = $1 * (1 / 1024) if ($2 eq "k");
$val = $1 if ($2 eq "M");
$val = $1 * 1024 if ($2 eq "G");
Modified: people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm 2007-12-23 15:20:43 UTC (rev 4832)
@@ -33,8 +33,6 @@
#
################################################################################
-use POSIX qw(ceil floor);
-
package FAI;
################################################################################
@@ -42,17 +40,43 @@
# @brief Build an array $start,$end from ($start-$end)
#
# @param $rstr Range string
+# @param $size Size and unit
#
-# @return ($start,$end)
+# @return ($start,$end) in bytes
#
################################################################################
sub make_range {
- my ($rstr) = @_;
+ use POSIX qw(ceil floor);
+
+ my ($rstr, $size) = @_;
+ # convert size to Bytes
+ my $size_b = &FAI::convert_unit($size);
+ # check the format of the string
($rstr =~ /^(\d+%?)-(\d+%?)$/) or &FAI::internal_error("Invalid range");
- my @range = ();
- push @range, ($1, $2);
- return @range;
+ my ($start, $end) = ($1, $2);
+ # start may be given in percents of the size
+ if ($start =~ /^(\d+)%$/) {
+ # rewrite it to bytes
+ $start = POSIX::floor($size_b * $1 / 100);
+ } else {
+ # it is given in megabytes, make it bytes
+ $start = $start * 1024.0 * 1024.0;
+ }
+
+ # end may be given in percents of the size
+ if ( $end =~ /^(\d+)%$/ ) {
+ # rewrite it to bytes
+ $end = POSIX::ceil($size_b * $1 / 100);
+ } else {
+ # it is given in megabytes, make it bytes
+ $end = $end * 1024.0 * 1024.0;
+ }
+
+ # make sure that $end >= $start
+ ($end >= $start) or &FAI::internal_error("end < start");
+
+ return ($start, $end);
}
################################################################################
@@ -188,23 +212,12 @@
foreach my $lv (keys %{ $FAI::configs{$config}{volumes} }) {
# reference to the size of the current logical volume
my $lv_size = (\%FAI::configs)->{$config}->{volumes}->{$lv}->{size};
+ # get the effective sizes (in Bytes) from the range
+ my ($start, $end) = &FAI::make_range($lv_size->{range}, "${vg_size}MB");
+ # make them MB
+ $start *= 1024.0 * 1024.0;
+ $end *= 1024.0 * 1024.0;
- # make sure the size specification is a range (even though it might be
- # something like x-x) and store the dimensions
- ($lv_size->{range} =~ /^(\d+%?)-(\d+%?)$/)
- or &FAI::internal_error("Invalid range");
- my $start = $1;
- my $end = $2;
-
- # start may be given in percents of the size, rewrite it to megabytes
- $start = POSIX::floor($vg_size * $1 / 100) if ($start =~ /^(\d+)%$/);
-
- # end may be given in percents of the size, rewrite it to megabytes
- $end = POSIX::ceil($vg_size * $1 / 100) if ($end =~ /^(\d+)%$/);
-
- # make sure that $end >= $start
- ($end >= $start) or &FAI::internal_error("end < start");
-
# increase the used space
$min_space += $start;
$max_space += $end;
@@ -236,7 +249,11 @@
foreach my $lv (@redist_list) {
# get the range again
- my ($start, $end) = &FAI::make_range($FAI::configs{$config}{volumes}{$lv}{size}{range});
+ my ($start, $end) =
+ &FAI::make_range($FAI::configs{$config}{volumes}{$lv}{size}{range}, "${vg_size}MB");
+ # make them MB
+ $start *= 1024.0 * 1024.0;
+ $end *= 1024.0 * 1024.0;
# write the final size
$FAI::configs{$config}{volumes}{$lv}{size}{eff_size} =
@@ -244,423 +261,415 @@
}
}
}
-
+
################################################################################
#
-# @brief Compute the desired sizes of the partitions and test feasibility
-# thereof.
+# @brief Handle preserved partitions while computing the size of partitions
#
+# @param $part_id Partition id within $config
+# @param $config Disk config
+# @param $current_disk Current config of this disk
+# @param $next_start Start of the next partition
+# @param $min_req_total_space Minimum space required on disk
+#
+# @return Updated values of ($next_start, $min_req_total_space)
+#
################################################################################
-sub compute_partition_sizes
-{
+sub do_partition_preserve {
- # loop through all device configurations
- foreach my $config ( keys %FAI::configs ) {
+ my ($part_id, $config, $current_disk, $next_start, $min_req_total_space) = @_;
+
+ # reference to the current partition
+ my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
- # for RAID, there is nothing to be done here
- next if ( $config eq "RAID" );
+ # a partition that should be preserved must exist already
+ defined($current_disk->{partitions}->{$part_id})
+ or die "$part_id can't be preserved, it does not exist.\n";
- # don't configure the sizes of logical volumes here
- next if ( $config =~ /^VG_(.+)$/ );
+ my $curr_part = $current_disk->{partitions}->{$part_id};
- # device is an effective disk
- ( $config =~ /^PHY_(.+)$/ )
- or &FAI::internal_error("invalid config entry $config");
+ ($next_start > $curr_part->{begin_byte})
+ and die "Previous partitions overflow begin of preserved partition $part_id\n";
- # nothing to be done, if this is a configuration for a virtual disk
- next if ( $FAI::configs{$config}{virtual} == 1 );
+ # set the effective size to the value known already
+ $part->{size}->{eff_size} = $curr_part->{count_byte};
- # the device name of the disk
- my $disk = $1;
- # reference to the current disk config
- my $current_disk = $FAI::current_config{$disk};
+ # copy the start_byte and end_byte information
+ $part->{start_byte} = $curr_part->{begin_byte};
+ $part->{end_byte} = $curr_part->{end_byte};
- # at various points the following code highly depends on the desired disk label!
- # initialise variables
- # the id of the extended partition to be created, if required
- my $extended = -1;
+ # and add it to the total disk space required by this config
+ $min_req_total_space += $part->{size}->{eff_size};
- # the id of the current extended partition, if any; this setup only caters
- # for a single existing extended partition!
- my $current_extended = -1;
+ # set the next start
+ $next_start = $part->{end_byte} + 1;
- # find the first existing extended partition
- foreach my $part_id ( sort keys %{ $current_disk->{partitions} } ) {
- if ( 1 == $current_disk->{partitions}->{$part_id}->{is_extended} ) {
- $current_extended = $part_id;
- last;
- }
- }
+ # several msdos specific parts
+ if ($FAI::configs{$config}{disklabel} eq "msdos") {
- # the space required on the disk
- my $min_req_total_space = 0;
+ # make sure the partition ends at a cylinder boundary
+ (0 == ($curr_part->{end_byte} + 1)
+ % ($current_disk->{sector_size} *
+ $current_disk->{bios_sectors_per_track} *
+ $current_disk->{bios_heads})) or
+ die "Preserved partition $part_id does not end at a cylinder boundary\n";
- # the start byte for the next partition
- my $next_start = 0;
+ # add one head of disk usage if this is a logical partition
+ $min_req_total_space += $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size} if ($part_id > 4);
- # on msdos disk labels, the first partitions starts at head #1
- if ( $FAI::configs{$config}{disklabel} eq "msdos" ) {
- $next_start = $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
+ # extended partitions consume no space
+ if ($part->{size}->{extended}) {
- # the MBR requires space, too
- $min_req_total_space += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
- }
+ # revert the addition of the size
+ $min_req_total_space -= $part->{size}->{eff_size};
- # on GPT disk labels the first 34 and last 34 sectors must be left alone
- if ( $FAI::configs{$config}{disklabel} eq "gpt" ) {
- $next_start = 34 * $current_disk->{sector_size};
-
- # modify the disk to claim the space for the second partition table
- $current_disk->{end_byte} -= 34 * $current_disk->{sector_size};
-
- # the space required by the GPTs
- $min_req_total_space += 2 * 34 * $current_disk->{sector_size};
+ # set the next start to the start of the extended partition
+ $next_start = $part->{start_byte};
}
+ }
- # the list of partitions that we need to find start and end bytes for
- my @worklist = ( sort keys %{ $FAI::configs{$config}{partitions} } );
+ # on gpt, ensure that the partition ends at a sector boundary
+ if ($FAI::configs{$config}{disklabel} eq "gpt") {
+ (0 == ($current_disk->{partitions}{$part_id}{end_byte} + 1)
+ % $current_disk->{sector_size})
+ or die "Preserved partition $part_id does not end at a sector boundary\n";
+ }
- while ( scalar(@worklist) > 0 )
- {
+ return ($next_start, $min_req_total_space);
+}
- # work on the first entry of the list
- my $part_id = $worklist[0];
- # reference to the current partition
- my $part = ( \%FAI::configs )->{$config}->{partitions}->{$part_id};
+################################################################################
+#
+# @brief Handle extended partitions while computing the size of partitions
+#
+# @param $part_id Partition id within $config
+# @param $config Disk config
+# @param $current_disk Current config of this disk
+#
+################################################################################
+sub do_partition_extended {
- # the partition $part_id must be preserved
- if ( $part->{size}->{preserve} == 1 ) {
+ my ($part_id, $config, $current_disk) = @_;
+
+ # reference to the current partition
+ my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
- # a partition that should be preserved must exist already
- defined( $current_disk->{partitions}->{$part_id} )
- or die "$part_id can't be preserved, it does not exist.\n";
+ ($FAI::configs{$config}{disklabel} eq "msdos")
+ or die "found an extended partition on a non-msdos disklabel\n";
- ( $next_start > $current_disk->{partitions}->{$part_id}->{begin_byte} )
- and die "Previous partitions overflow begin of preserved partition $part_id\n";
+ # ensure that it is a primary partition
+ ($part_id <= 4) or
+ &FAI::internal_error("Extended partition wouldn't be a primary one");
- # set the effective size to the value known already
- $part->{size}->{eff_size} = $current_disk->{partitions}->{$part_id}->{count_byte};
+ my $epbr_size = $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
- # copy the start_byte and end_byte information
- $part->{start_byte} = $current_disk->{partitions}->{$part_id}->{begin_byte};
- $part->{end_byte} = $current_disk->{partitions}->{$part_id}->{end_byte};
+ # initialise the size and the start byte
+ $part->{size}->{eff_size} = 0;
+ $part->{start_byte} = -1;
- # and add it to the total disk space required by this config
- $min_req_total_space += $part->{size}->{eff_size};
+ foreach my $p (sort keys %{ $FAI::configs{$config}{partitions} }) {
+ next if ($p < 5);
- # set the next start
- $next_start = $part->{end_byte} + 1;
+ $part->{start_byte} = $FAI::configs{$config}{partitions}{$p}{start_byte} -
+ $epbr_size if (-1 == $part->{start_byte});
- # several msdos specific parts
- if ( $FAI::configs{$config}{disklabel} eq "msdos" ) {
+ $part->{size}->{eff_size} += $FAI::configs{$config}{partitions}{$p}{size}{eff_size} +
+ $epbr_size;
- # make sure the partition ends at a cylinder boundary
- ( 0 == ( $current_disk->{partitions}->{$part_id}->{end_byte} + 1
- ) % ( $current_disk->{sector_size} *
- $current_disk->{bios_sectors_per_track} *
- $current_disk->{bios_heads}
- )
- ) or die "Preserved partition $part_id does not end at a cylinder boundary\n";
+ $part->{end_byte} = $FAI::configs{$config}{partitions}{$p}{end_byte};
+ }
- # add one head of disk usage if this is a logical partition
- $min_req_total_space += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size} if ( $part_id > 4 );
+ ($part->{size}->{eff_size} > 0)
+ or die "Extended partition has a size of 0\n";
+}
- # extended partitions consume no space
- if ( $part->{size}->{extended} == 1 ) {
+################################################################################
+#
+# @brief Handle all other partitions while computing the size of partitions
+#
+# @param $part_id Partition id within $config
+# @param $config Disk config
+# @param $current_disk Current config of this disk
+# @param $next_start Start of the next partition
+# @param $min_req_total_space Minimum space required on disk
+# @param $worklist Reference to the remaining partitions
+#
+# @return Updated values of ($next_start, $min_req_total_space)
+#
+################################################################################
+sub do_partition_real {
- # revert the addition of the size
- $min_req_total_space -= $part->{size}->{eff_size};
+ my ($part_id, $config, $current_disk, $next_start, $min_req_total_space,
+ $worklist) = @_;
+
+ # reference to the current partition
+ my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
+
+ my ($start, $end) = &FAI::make_range($part->{size}->{range}, $current_disk->{size});
- # set the next start to the start of the extended partition
- $next_start = $part->{start_byte};
- }
+ # check, whether the size is fixed
+ if ($end != $start) {
- }
+ # the end of the current range (may be the end of the disk or some
+ # preserved partition
+ my $end_of_range = -1;
- # on gpt, ensure that the partition ends at a sector boundary
- if ( $FAI::configs{$config}{disklabel} eq "gpt" ) {
- ( 0 == ( $current_disk->{partitions}{$part_id}{end_byte} + 1
- ) % $current_disk->{sector_size})
- or die "Preserved partition $part_id does not end at a sector boundary\n";
- }
+ # minimum space required by all partitions, i.e., the lower ends of the
+ # ranges
+ # $min_req_space counts up to the next preserved partition or the
+ # end of the disk
+ my $min_req_space = 0;
- # partition done
- shift @worklist;
- }
+ # maximum useful space
+ my $max_space = 0;
- # msdos specific: deal with extended partitions
- elsif ( $part->{size}->{extended} == 1 ) {
- ( $FAI::configs{$config}{disklabel} eq "msdos" )
- or die "found an extended partition on a non-msdos disklabel\n";
+ # inspect all remaining entries in the worklist
+ foreach my $p (@{$worklist}) {
- # make sure that there is only one extended partition
- ( $extended == -1 || 1 == scalar(@worklist) )
- or &FAI::internal_error("More than 1 extended partition");
+ # we have found the delimiter
+ if ($FAI::configs{$config}{partitions}{$p}{size}{preserve}) {
+ $end_of_range = $current_disk->{partitions}->{$p}->{begin_byte};
- # ensure that it is a primary partition
- ( $part_id <= 4 ) or
- &FAI::internal_error("Extended partition wouldn't be a primary one");
-
- # set the local variable to this id
- $extended = $part_id;
-
- # the size cannot be determined now, push it to the end of the
- # worklist; the check against $extended being == -1 ensures that
- # there is no indefinite loop
- if ( scalar(@worklist) > 1 ) {
- push @worklist, shift @worklist;
+ # logical partitions require the space for the EPBR to be left
+ # out
+ if (($FAI::configs{$config}{disklabel} eq "msdos")
+ && ($p > 4)) {
+ $end_of_range -= $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
}
+ last;
+ } elsif ($FAI::configs{$config}{partitions}{$p}{size}{extended}) {
+ next;
+ } else {
+ my ($min_size, $max_size) = &FAI::make_range(
+ $FAI::configs{$config}{partitions}{$p}{size}{range}, $current_disk->{size});
- # determine the size of the extended partition
- else {
- my $epbr_size =
- $current_disk->{bios_sectors_per_track} *
+ # logical partitions require the space for the EPBR to be left
+ # out
+ if (($FAI::configs{$config}{disklabel} eq "msdos")
+ && ($p > 4)) {
+ $min_size += $current_disk->{bios_sectors_per_track} *
$current_disk->{sector_size};
+ $max_size += $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
+ }
- # initialise the size and the start byte
- $part->{size}->{eff_size} = 0;
- $part->{start_byte} = -1;
+ $min_req_space += $min_size;
+ $max_space += $max_size;
+ }
+ }
- foreach my $p ( sort keys %{ $FAI::configs{$config}{partitions} } )
- {
- next if ( $p < 5 );
+ # set the end if we have reached the end of the disk
+ $end_of_range = $current_disk->{end_byte} if (-1 == $end_of_range);
- if ( -1 == $part->{start_byte} )
- {
- $part->{start_byte} =
- $FAI::configs{$config}{partitions}{$p}{start_byte} -
- $epbr_size;
- }
+ my $available_space = $end_of_range - $next_start + 1;
- $part->{size}->{eff_size} +=
- $FAI::configs{$config}{partitions}{$p}{size}{eff_size} +
- $epbr_size;
+ # the next boundary is closer than the minimal space that we need
+ ($available_space < $min_req_space)
+ and die "Insufficient space available for partition $part_id\n";
- $part->{end_byte} = $FAI::configs{$config}{partitions}{$p}{end_byte};
- }
+ # the new size
+ my $scaled_size = $end;
+ $scaled_size = POSIX::floor(($end - $start) *
+ (($available_space - $min_req_space) /
+ ($max_space - $min_req_space))) + $start
+ if ($max_space > $available_space);
- ( $part->{size}->{eff_size} > 0 )
- or die "Extended partition has a size of 0\n";
+ ($scaled_size >= $start)
+ or &FAI::internal_error("scaled size is smaller than the desired minimum");
- # partition done
- shift @worklist;
- }
- } else {
+ $start = $scaled_size;
+ $end = $start;
+ }
- # make sure the size specification is a range (even though it might be
- # something like x-x) and store the dimensions
- ( $part->{size}->{range} =~
- /^(\d+%?)-(\d+%?)$/ ) or &FAI::internal_error("Invalid range");
- my $start = $1;
- my $end = $2;
+ # now we compute the effective locations on the disk
+ # msdos specific offset for logical partitions
+ if (($FAI::configs{$config}{disklabel} eq "msdos")
+ && ($part_id > 4)) {
- # start may be given in percents of the size
- if ( $start =~ /^(\d+)%$/ ) {
+ # add one head of disk usage if this is a logical partition
+ $min_req_total_space += $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
- # rewrite it to bytes
- $start = POSIX::floor( $current_disk->{size} * $1 / 100 );
- } else {
+ # move the start byte as well
+ $next_start += $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
+ }
- # it is given in megabytes, make it bytes
- $start = $start * 1024.0 * 1024.0;
- }
+ # partition starts at where we currently are
+ $FAI::configs{$config}{partitions}{$part_id}{start_byte} =
+ $next_start;
- # end may be given in percents of the size
- if ( $end =~ /^(\d+)%$/ ) {
+ # the end may need some alignment, depending on the disk label
+ my $end_byte = $next_start + $start - 1;
- # rewrite it to bytes
- $end = POSIX::ceil( $current_disk->{size} * $1 / 100 );
- } else {
+ # on msdos, ensure that the partition ends at a cylinder boundary
+ if ($FAI::configs{$config}{disklabel} eq "msdos") {
+ $end_byte -=
+ ($end_byte + 1) % ($current_disk->{sector_size} *
+ $current_disk->{bios_sectors_per_track} *
+ $current_disk->{bios_heads});
+ }
- # it is given in megabytes, make it bytes
- $end = $end * 1024.0 * 1024.0;
- }
+ # on gpt, ensure that the partition ends at a sector boundary
+ if ($FAI::configs{$config}{disklabel} eq "gpt") {
+ $end_byte -=
+ ($end_byte + 1) % $current_disk->{sector_size};
+ }
- # make sure that $end >= $start
- ( $end >= $start ) or &FAI::internal_error("end < start");
+ # set $start and $end to the effective values
+ $start = $end_byte - $next_start + 1;
+ $end = $start;
- # check, whether the size is fixed
- if ( $end != $start ) {
+ # write back the size spec in bytes
+ $part->{size}->{range} = $start . "-" . $end;
- # the end of the current range (may be the end of the disk or some
- # preserved partition
- my $end_of_range = -1;
+ # then set eff_size to a proper value
+ $part->{size}->{eff_size} = $start;
- # minimum space required by all partitions, i.e., the lower ends of the
- # ranges
- # $min_req_space counts up to the next preserved partition or the
- # end of the disk
- my $min_req_space = 0;
+ # write the end byte to the configuration
+ $part->{end_byte} = $end_byte;
- # maximum useful space
- my $max_space = 0;
+ # and add it to the total disk space required by this config
+ $min_req_total_space += $part->{size}->{eff_size};
- # inspect all remaining entries in the worklist
- foreach my $p (@worklist) {
+ # set the next start
+ $next_start = $part->{end_byte} + 1;
- # we have found the delimiter
- if ( $FAI::configs{$config}{partitions}{$p}{size}{preserve} == 1 ) {
- $end_of_range = $current_disk->{partitions}->{$p}->{begin_byte};
+ return ($next_start, $min_req_total_space);
+}
- # logical partitions require the space for the EPBR to be left
- # out
- if ( ( $FAI::configs{$config}{disklabel} eq "msdos" )
- && ( $p > 4 ) ) {
- $end_of_range -= $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
- }
- last;
- } elsif ( $FAI::configs{$config}{partitions}{$p}{size}{extended} == 1 ) {
- next;
- } else {
+################################################################################
+#
+# @brief Compute the desired sizes of the partitions and test feasibility
+# thereof.
+#
+################################################################################
+sub compute_partition_sizes
+{
- # below is a slight duplication of the code
- # make sure the size specification is a range (even though it might be
- # something like x-x) and store the dimensions
- ( $FAI::configs{$config}{partitions}{$p}{size}{range} =~
- /^(\d+%?)-(\d+%?)$/ )
- or &FAI::internal_error("Invalid range");
- my $min_size = $1;
- my $max_size = $2;
+ # loop through all device configurations
+ foreach my $config (keys %FAI::configs) {
- # start may be given in percents of the size
- if ( $min_size =~ /^(\d+)%$/ ) {
+ # for RAID or LVM, there is nothing to be done here
+ next if ($config eq "RAID" || $config =~ /^VG_./);
+ ($config =~ /^PHY_(.+)$/) or &FAI::internal_error("invalid config entry $config");
+ # nothing to be done, if this is a configuration for a virtual disk
+ next if $FAI::configs{$config}{virtual};
+ my $disk = $1; # the device name of the disk
+ # reference to the current disk config
+ my $current_disk = $FAI::current_config{$disk};
- # rewrite it to bytes
- $min_size = POSIX::floor( $current_disk->{size} * $1 / 100 );
- } else {
+ # at various points the following code highly depends on the desired disk label!
+ # initialise variables
+ # the id of the extended partition to be created, if required
+ my $extended = -1;
- # it is given in megabytes, make it bytes
- $min_size *= 1024.0 * 1024.0;
- }
+ # the id of the current extended partition, if any; this setup only caters
+ # for a single existing extended partition!
+ my $current_extended = -1;
- # end may be given in percents of the size
- if ( $max_size =~ /^(\d+)%$/ ) {
+ # find the first existing extended partition
+ foreach my $part_id (sort keys %{ $current_disk->{partitions} }) {
+ if ($current_disk->{partitions}->{$part_id}->{is_extended}) {
+ $current_extended = $part_id;
+ last;
+ }
+ }
- # rewrite it to bytes
- $max_size =
- POSIX::ceil( $current_disk->{size} * $1 / 100 );
- } else {
+ # the space required on the disk
+ my $min_req_total_space = 0;
- # it is given in megabytes, make it bytes
- $max_size *= 1024.0 * 1024.0;
- }
+ # the start byte for the next partition
+ my $next_start = 0;
- # logical partitions require the space for the EPBR to be left
- # out
- if ( ( $FAI::configs{$config}{disklabel} eq "msdos" )
- && ( $p > 4 ) ) {
- $min_size += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
- $max_size += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
- }
+ # on msdos disk labels, the first partitions starts at head #1
+ if ($FAI::configs{$config}{disklabel} eq "msdos") {
+ $next_start = $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
- $min_req_space += $min_size;
- $max_space += $max_size;
- }
- }
+ # the MBR requires space, too
+ $min_req_total_space += $current_disk->{bios_sectors_per_track} *
+ $current_disk->{sector_size};
+ }
- # set the end if we have reached the end of the disk
- $end_of_range = $current_disk->{end_byte} if ( -1 == $end_of_range );
+ # on GPT disk labels the first 34 and last 34 sectors must be left alone
+ if ($FAI::configs{$config}{disklabel} eq "gpt") {
+ $next_start = 34 * $current_disk->{sector_size};
- my $available_space = $end_of_range - $next_start + 1;
+ # modify the disk to claim the space for the second partition table
+ $current_disk->{end_byte} -= 34 * $current_disk->{sector_size};
- # the next boundary is closer than the minimal space that we need
- ( $available_space < $min_req_space )
- and die "Insufficient space available for partition $part_id\n";
+ # the space required by the GPTs
+ $min_req_total_space += 2 * 34 * $current_disk->{sector_size};
+ }
- # the new size
- my $scaled_size = $end;
- $scaled_size = POSIX::floor( ( $end - $start ) * (
- ( $available_space - $min_req_space ) /
- ( $max_space - $min_req_space ) )) + $start
- if ( $max_space > $available_space );
+ # the list of partitions that we need to find start and end bytes for
+ my @worklist = (sort keys %{ $FAI::configs{$config}{partitions} });
- ( $scaled_size >= $start )
- or &FAI::internal_error("scaled size is smaller than the desired minimum");
+ while (scalar (@worklist))
+ {
- $start = $scaled_size;
- $end = $start;
- }
+ # work on the first entry of the list
+ my $part_id = $worklist[0];
+ # reference to the current partition
+ my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
- # now we compute the effective locations on the disk
- # msdos specific offset for logical partitions
- if ( ( $FAI::configs{$config}{disklabel} eq "msdos" )
- && ( $part_id > 4 ) ) {
+ # the partition $part_id must be preserved
+ if ($part->{size}->{preserve}) {
+ ($next_start, $min_req_total_space) = &FAI::do_partition_preserve($part_id,
+ $config, $current_disk, $next_start, $min_req_total_space);
- # add one head of disk usage if this is a logical partition
- $min_req_total_space += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
+ # partition done
+ shift @worklist;
+ }
- # move the start byte as well
- $next_start += $current_disk->{bios_sectors_per_track} *
- $current_disk->{sector_size};
- }
+ # msdos specific: deal with extended partitions
+ elsif ($part->{size}->{extended}) {
+ # make sure that there is only one extended partition
+ ($extended == -1 || 1 == scalar (@worklist))
+ or &FAI::internal_error("More than 1 extended partition");
- # partition starts at where we currently are
- $FAI::configs{$config}{partitions}{$part_id}{start_byte} =
- $next_start;
+ # set the local variable to this id
+ $extended = $part_id;
- # the end may need some alignment, depending on the disk label
- my $end_byte = $next_start + $start - 1;
-
- # on msdos, ensure that the partition ends at a cylinder boundary
- if ( $FAI::configs{$config}{disklabel} eq "msdos" ) {
- $end_byte -=
- ( $end_byte + 1 ) % ( $current_disk->{sector_size} *
- $current_disk->{bios_sectors_per_track} *
- $current_disk->{bios_heads} );
+ # the size cannot be determined now, push it to the end of the
+ # worklist; the check against $extended being == -1 ensures that
+ # there is no indefinite loop
+ if (scalar (@worklist) > 1) {
+ push @worklist, shift @worklist;
+ next;
}
- # on gpt, ensure that the partition ends at a sector boundary
- if ( $FAI::configs{$config}{disklabel} eq "gpt" ) {
- $end_byte -=
- ( $end_byte + 1 ) % $current_disk->{sector_size};
- }
+ # determine the size of the extended partition
+ &FAI::do_partition_extended($part_id, $config, $current_disk);
- # set $start and $end to the effective values
- $start = $end_byte - $next_start + 1;
- $end = $start;
+ # partition done
+ shift @worklist;
+ } else {
+ ($next_start, $min_req_total_space) = &FAI::do_partition_real($part_id,
+ $config, $current_disk, $next_start, $min_req_total_space, \@worklist);
- # write back the size spec in bytes
- $part->{size}->{range} = $start . "-" . $end;
-
- # then set eff_size to a proper value
- $part->{size}->{eff_size} = $start;
-
- # write the end byte to the configuration
- $part->{end_byte} = $end_byte;
-
- # and add it to the total disk space required by this config
- $min_req_total_space += $part->{size}->{eff_size};
-
- # set the next start
- $next_start = $part->{end_byte} + 1;
-
# partition done
shift @worklist;
}
}
# check, whether there is sufficient space on the disk
- ( $min_req_total_space > $current_disk->{size} )
+ ($min_req_total_space > $current_disk->{size})
and die "Disk $disk is too small - at least $min_req_total_space bytes are required\n";
# make sure, extended partitions are only created on msdos disklabels
- ( $FAI::configs{$config}{disklabel} ne "msdos" && $extended > -1 )
+ ($FAI::configs{$config}{disklabel} ne "msdos" && $extended > -1)
and &FAI::internal_error("extended partitions are not supported by this disklabel");
# ensure that we have done our work
- foreach my $part_id ( sort keys %{ $FAI::configs{$config}{partitions} } ) {
- ( defined( $FAI::configs{$config}{partitions}{$part_id}{start_byte} )
- && defined( $FAI::configs{$config}{partitions}{$part_id}{end_byte} ) )
- or &FAI::internal_error("start or end of partition $part_id not set");
- }
-
+ (defined ($FAI::configs{$config}{partitions}{$_}{start_byte})
+ && defined ($FAI::configs{$config}{partitions}{$_}{end_byte}))
+ or &FAI::internal_error("start or end of partition $_ not set")
+ foreach (sort keys %{ $FAI::configs{$config}{partitions} });
}
}
Modified: people/michael/features/setup_harddisks_2/implementation/lib/volumes.pm
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/lib/volumes.pm 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/lib/volumes.pm 2007-12-23 15:20:43 UTC (rev 4832)
@@ -47,10 +47,10 @@
foreach my $disk (@FAI::disks) {
# create full paths
- ( $disk =~ m{^/} ) or $disk = "/dev/$disk";
+ ($disk =~ m{^/}) or $disk = "/dev/$disk";
# make sure, $disk is a proper block device
- ( -b $disk ) or die "$disk is not a block special device!\n";
+ (-b $disk) or die "$disk is not a block special device!\n";
# initialise the hash
$FAI::current_config{$disk}{partitions} = {};
@@ -61,37 +61,30 @@
# try to obtain the partition table for $disk
# it might fail with parted_2 in case the disk has no partition table
my $error =
- &FAI::execute_ro_command( "parted -s $disk unit TiB print", \@parted_print, 0 );
+ &FAI::execute_ro_command("parted -s $disk unit TiB print", \@parted_print, 0);
# parted_2 happens when the disk has no disk label, because parted then
# provides no information about the disk
- if ( $error eq "parted_2" ) {
+ if ($error eq "parted_2") {
$FAI::no_dry_run or die
"Can't run on test-only mode on this system because there is no disklabel on $disk\n";
# if there is no disk configuration, write an msdos disklabel
- if ( !defined( $FAI::configs{"PHY_$disk"}{disklabel} ) ) {
+ if (!defined ($FAI::configs{"PHY_$disk"}{disklabel})) {
# write the disk label as configured
$error = &FAI::execute_command("parted -s $disk mklabel msdos");
} else {
# write the disk label as configured
- $error = &FAI::execute_command(
- "parted -s $disk mklabel " . $FAI::configs{"PHY_$disk"}{disklabel} );
+ $error = &FAI::execute_command("parted -s $disk mklabel "
+ . $FAI::configs{"PHY_$disk"}{disklabel});
}
# retry partition-table print
$error =
- &FAI::execute_ro_command( "parted -s $disk unit TiB print", \@parted_print, 0 );
+ &FAI::execute_ro_command("parted -s $disk unit TiB print", \@parted_print, 0);
}
- # check, whether there is still an error
- if ( $error ne "" ) {
- my $response = &FAI::get_error( $error, "response" );
- ( $response eq "die" ) and die &FAI::get_error( $error, "message" );
- ( $response eq "warn" ) and warn &FAI::get_error( $error, "message" );
- }
-
# the following code parses the output of parted print, using various units
# (TiB, B, chs)
# the parser is capable of reading the output of parted version 1.7.1, which
@@ -141,34 +134,33 @@
foreach my $line (@parted_print) {
# now we test line by line - some of them may be ignored
- next if ( $line =~ /^Disk /
- || $line =~ /^\s*$/
- || $line =~ /^WARNING: You are not superuser/ );
+ next if ($line =~ /^Disk / || $line =~ /^\s*$/
+ || $line =~ /^WARNING: You are not superuser/);
# determine the logical sector size
- if ( $line =~ /^Sector size \(logical\/physical\): (\d+)B\/(\d+)B$/ ) {
+ if ($line =~ /^Sector size \(logical\/physical\): (\d+)B\/\d+B$/) {
$FAI::current_config{$disk}{sector_size} = $1;
}
# read and store the current disk label
- elsif ( $line =~ /^Partition Table: (.+)$/ ) {
+ elsif ($line =~ /^Partition Table: (.+)$/) {
$FAI::current_config{$disk}{disklabel} = $1;
}
# the line containing the table headers
- elsif ( $line =~ /^(Number\s+)(\S+\s+)+/ ) {
+ elsif ($line =~ /^(Number\s+)(\S+\s+)+/) {
my $col_start = 0;
# check the length of each heading; note that they might contain spaces
- while ( $line =~ /^(\S+( [a-z]\S+)?\s*)([A-Z].*)?$/ ) {
+ while ($line =~ /^(\S+( [a-z]\S+)?\s*)([A-Z].*)?$/) {
my $heading = $1;
# set the line to the remainder
$line = "";
- $line = $3 if defined($3);
+ $line = $3 if defined ($3);
# the width of the column includes any whitespace
- my $col_width = length($heading);
+ my $col_width = length ($heading);
$heading =~ s/(\S+)\s*$/$1/;
# build the hash entry
@@ -179,14 +171,11 @@
};
$col_start += $col_width;
}
- }
+ } else { # one of the partitions
- # one of the partitions
- else {
-
# we must have seen the header, otherwise probably the format has
# changed
- defined( $cols{"File system"}{"start"} )
+ defined ($cols{"File system"}{"start"})
or &FAI::internal_error("Table header not seen yet");
# the info for the partition number
@@ -204,7 +193,7 @@
# if there is no partition number, then it must be free space, so no
# file system either
- next if ( $id eq "" );
+ next if ($id eq "");
# extract the set of characters
$line =~ /^.{$fs_cols_before}(.{$fs_col_width})/;
@@ -223,15 +212,15 @@
# obtain the partition table using bytes as units
$error =
- &FAI::execute_ro_command( "parted -s $disk unit B print free", \@parted_print, 0 );
+ &FAI::execute_ro_command("parted -s $disk unit B print free", \@parted_print, 0);
# Parse the output of the byte-wise partition table
foreach my $line (@parted_print) {
# the disk size line (Disk /dev/hda: 82348277759B)
- if ( $line =~ /Disk \Q$disk\E: (\d+)B$/ ) {
+ if ($line =~ /Disk \Q$disk\E: (\d+)B$/) {
$FAI::current_config{$disk}{begin_byte} = 0;
- $FAI::current_config{$disk}{end_byte} = ( $1 - 1 );
+ $FAI::current_config{$disk}{end_byte} = $1 - 1;
$FAI::current_config{$disk}{size} = $1;
# nothing else to be done
@@ -239,10 +228,8 @@
}
# One of the partition lines, see above example
- next
- unless ( $line =~
- /^\s*(\d+)\s+(\d+)B\s+(\d+)B\s+(\d+)B(\s+(primary|logical|extended))?/i
- );
+ next unless ($line =~
+ /^\s*(\d+)\s+(\d+)B\s+(\d+)B\s+(\d+)B(\s+(primary|logical|extended))?/i);
# mark the bounds of existing partitions
$FAI::current_config{$disk}{partitions}{$1}{begin_byte} = $2;
@@ -264,16 +251,15 @@
# obtain the partition table using bytes as units
$error =
&FAI::execute_ro_command(
- "parted -s $disk unit chs print free", \@parted_print, 0 );
+ "parted -s $disk unit chs print free", \@parted_print, 0);
# Parse the output of the CHS partition table
foreach my $line (@parted_print) {
# find the BIOS geometry that looks like this:
# BIOS cylinder,head,sector geometry: 10011,255,63. Each cylinder is 8225kB.
- if ( $line =~
- /^BIOS cylinder,head,sector geometry:\s*(\d+),(\d+),(\d+)\.\s*Each cylinder is \d+kB\.$/
- ) {
+ if ($line =~
+ /^BIOS cylinder,head,sector geometry:\s*(\d+),(\d+),(\d+)\.\s*Each cylinder is \d+kB\.$/) {
$FAI::current_config{$disk}{bios_cylinders} = $1;
$FAI::current_config{$disk}{bios_heads} = $2;
$FAI::current_config{$disk}{bios_sectors_per_track} = $3;
@@ -281,27 +267,27 @@
}
# make sure we have determined all the necessary information
- ( $FAI::current_config{$disk}{begin_byte} == 0 )
+ ($FAI::current_config{$disk}{begin_byte} == 0)
or die "Invalid start byte\n";
- ( $FAI::current_config{$disk}{end_byte} > 0 ) or die "Invalid end byte\n";
- defined( $FAI::current_config{$disk}{size} )
+ ($FAI::current_config{$disk}{end_byte} > 0) or die "Invalid end byte\n";
+ defined ($FAI::current_config{$disk}{size})
or die "Failed to determine disk size\n";
- defined( $FAI::current_config{$disk}{sector_size} )
+ defined ($FAI::current_config{$disk}{sector_size})
or die "Failed to determine sector size\n";
- defined( $FAI::current_config{$disk}{bios_sectors_per_track} )
+ defined ($FAI::current_config{$disk}{bios_sectors_per_track})
or die "Failed to determine the number of sectors per track\n";
}
}
-use Linux::LVM;
-
################################################################################
#
# @brief Collect the current LVM configuration
#
################################################################################
sub get_current_lvm {
+
+ use Linux::LVM;
# get the existing volume groups
foreach my $vg (get_volume_group_list()) {
@@ -320,8 +306,8 @@
my $short_name = $lv_name;
$short_name =~ "s{/dev/\Q$vg\E/}{}";
$FAI::current_lvm_config{$vg}{volumes}{$short_name}{size} =
- &FAI::convert_unit( $lv_info{$lv_name}->{lv_size} .
- $lv_info{$lv_name}->{lv_size_unit} );
+ &FAI::convert_unit($lv_info{$lv_name}->{lv_size} .
+ $lv_info{$lv_name}->{lv_size_unit});
}
# store the physical volumes
@@ -345,8 +331,8 @@
# try to obtain the list of existing RAID arrays
my $error =
- &FAI::execute_ro_command( "mdadm --detail --scan --verbose -c partitions",
- \@mdadm_print, 0 );
+ &FAI::execute_ro_command("mdadm --detail --scan --verbose -c partitions",
+ \@mdadm_print, 0);
# the expected output is as follows
# $ mdadm --detail --scan --verbose -c partitions
@@ -360,11 +346,11 @@
# parse the output line by line
foreach my $line (@mdadm_print) {
- if ( $line =~ /^ARRAY \/dev\/md(\d+) level=(\S+) num-devices=\d+ UUID=/ ) {
+ if ($line =~ /^ARRAY \/dev\/md(\d+) level=(\S+) num-devices=\d+ UUID=/) {
$id = $1;
$FAI::current_raid_config{$id}{mode} = $2;
- } elsif ( $line =~ /^\s*devices=(\S+)$/ ) {
- @{ $FAI::current_raid_config{$id}{devices} } = split( ",", $1 );
+ } elsif ($line =~ /^\s*devices=(\S+)$/) {
+ @{ $FAI::current_raid_config{$id}{devices} } = split (",", $1);
}
}
}
Modified: people/michael/features/setup_harddisks_2/implementation/setup-storage
===================================================================
--- people/michael/features/setup_harddisks_2/implementation/setup-storage 2007-12-22 23:05:14 UTC (rev 4831)
+++ people/michael/features/setup_harddisks_2/implementation/setup-storage 2007-12-23 15:20:43 UTC (rev 4832)
@@ -54,11 +54,7 @@
# command line parameter handling
use Getopt::Std;
-
-# the variables for getopt
-our ($opt_X, $opt_f);
-
-# parse the command line
+our ($opt_X, $opt_f); # the variables for getopt
&getopts('Xf:') || die <<EOF;
USAGE: [-X] no test, your harddisks will be formated
default: only test, no real formating
@@ -89,10 +85,8 @@
# the config source file
my $config_file = undef;
-
# use the config file, if given
open($config_file, $opt_f) or die "Failed to open config file $opt_f\n" if ($opt_f);
-
unless ($opt_f) {
# see which class file to use
foreach my $classfile (reverse split(/\s+/, $ENV{classes})) {
@@ -149,11 +143,9 @@
&FAI::compute_partition_sizes;
&FAI::compute_lv_sizes;
-# debugging only: print the current contents of $FAI::configs
-if ($FAI::debug) {
- print "Desired disk layout\n";
- print Dumper \%FAI::configs;
-}
+# print the current contents of $FAI::configs
+$FAI::debug and print "Desired disk layout\n";
+$FAI::debug and print Dumper \%FAI::configs;
# generate the command script
&FAI::build_disk_commands;
@@ -170,7 +162,7 @@
# generate the proposed fstab contents
my @fstab = &FAI::generate_fstab(\%FAI::configs);
-# debugging only; print fstab
+# print fstab
$FAI::debug and print "$_\n" foreach (@fstab);
# write the proposed contents of fstab to $LOGDIR/fstab
More information about the Fai-commit
mailing list