/[fai]/people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm
ViewVC logotype

Contents of /people/michael/features/setup_harddisks_2/implementation/lib/sizes.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4866 - (hide annotations) (download)
Wed Apr 9 12:45:38 2008 UTC (5 years, 1 month ago) by mt
File size: 24199 byte(s)
parentheses and me, we're not gonna become friends...
1 michael-guest 3583 #!/usr/bin/perl -w
2    
3 michael-guest 3668 #*********************************************************************
4     # This program is free software; you can redistribute it and/or modify
5     # it under the terms of the GNU General Public License as published by
6     # the Free Software Foundation; either version 2 of the License, or
7     # (at your option) any later version.
8     #
9     # This program is distributed in the hope that it will be useful, but
10     # WITHOUT ANY WARRANTY; without even the implied warranty of
11     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12     # General Public License for more details.
13 michael-guest 3669 #
14 michael-guest 3668 # A copy of the GNU General Public License is available as
15     # `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
16     # or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html. You
17     # can also obtain it by writing to the Free Software Foundation, Inc.,
18 michael-guest 4708 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 michael-guest 3668 #*********************************************************************
20    
21 michael-guest 3583 use strict;
22    
23 michael-guest 3666 ################################################################################
24     #
25 michael-guest 4715 # @file sizes.pm
26 michael-guest 3666 #
27 michael-guest 4293 # @brief Compute the size of the partitions and volumes to be created
28 michael-guest 3666 #
29     # $Id$
30     #
31     # @author Christian Kern, Michael Tautschnig
32     # @date Sun Jul 23 16:09:36 CEST 2006
33     #
34     ################################################################################
35    
36 michael-guest 3583 package FAI;
37    
38 michael-guest 3671 ################################################################################
39     #
40 mt 4831 # @brief Build an array $start,$end from ($start-$end)
41     #
42     # @param $rstr Range string
43 mt 4832 # @param $size Size and unit
44 mt 4831 #
45 mt 4832 # @return ($start,$end) in bytes
46 mt 4831 #
47     ################################################################################
48     sub make_range {
49    
50 mt 4832 use POSIX qw(ceil floor);
51    
52     my ($rstr, $size) = @_;
53     # convert size to Bytes
54 mt 4840 my $size_b = &FAI::convert_unit($size) * 1024.0 * 1024.0;
55 mt 4832 # check the format of the string
56 mt 4841 ($rstr =~ /^(\d+(\.\d+)?%?)-(\d+(\.\d+)?%?)$/) or &FAI::internal_error("Invalid range");
57     my ($start, $end) = ($1, $3);
58 mt 4832 # start may be given in percents of the size
59 mt 4841 if ($start =~ /^(\d+(\.\d+)?)%$/) {
60 mt 4832 # rewrite it to bytes
61     $start = POSIX::floor($size_b * $1 / 100);
62     } else {
63     # it is given in megabytes, make it bytes
64     $start = $start * 1024.0 * 1024.0;
65     }
66    
67     # end may be given in percents of the size
68 mt 4841 if ( $end =~ /^(\d+(\.\d+)?)%$/ ) {
69 mt 4832 # rewrite it to bytes
70     $end = POSIX::ceil($size_b * $1 / 100);
71     } else {
72     # it is given in megabytes, make it bytes
73     $end = $end * 1024.0 * 1024.0;
74     }
75    
76     # make sure that $end >= $start
77     ($end >= $start) or &FAI::internal_error("end < start");
78    
79     return ($start, $end);
80 mt 4831 }
81    
82     ################################################################################
83     #
84 michael-guest 4293 # @brief Estimate the size of the device $dev
85 michael-guest 3671 #
86 michael-guest 4293 # @param $dev Device the size of which should be determined. This may be a
87     # a partition, a RAID device or an entire disk.
88     #
89     # @return the size of the device in megabytes
90     #
91 michael-guest 3671 ################################################################################
92 michael-guest 4715 sub estimate_size {
93 andreas 4614 my ($dev) = @_;
94 michael-guest 3672
95 michael-guest 4293 # try the entire disk first; we then use the data from the current
96     # configuration; this matches in fact for than the allowable strings, but
97     # this should be caught later on
98 mt 4862 if ($dev =~ m{^/dev/(i2o/hd[a-t]|cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|ataraid/d\d|sd[a-t]|hd[a-t])$}) {
99 mt 4831 defined ($FAI::current_config{$dev}{end_byte})
100 andreas 4614 or die "$dev is not a valid block device\n";
101 michael-guest 3977
102 michael-guest 4293 # the size is known, return it
103 mt 4831 return ($FAI::current_config{$dev}{end_byte} -
104     $FAI::current_config{$dev}{begin_byte}) / (1024 * 1024);
105 michael-guest 4293 }
106 andreas 4614
107 michael-guest 4293 # try a partition
108 mt 4866 elsif ($dev =~ m{^(/dev/(i2o/hd[a-t]|cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|ataraid/d\d|sd[a-t]|hd[a-t]))p?(\d+)$}) {
109 andreas 4614
110 michael-guest 4293 # the size is configured, return it
111 mt 4866 defined ($FAI::configs{"PHY_$1"}{partitions}{$3}{size}{eff_size})
112     and return $FAI::configs{"PHY_$1"}{partitions}{$3}{size}{eff_size} /
113 mt 4831 (1024 * 1024);
114 andreas 4614
115 michael-guest 4293 # the size is known from the current configuration on disk, return it
116 mt 4866 defined ($FAI::current_config{$1}{partitions}{$3}{count_byte})
117     and return $FAI::current_config{$1}{partitions}{$3}{count_byte} /
118 mt 4831 (1024 * 1024);
119 andreas 4614
120 michael-guest 4293 # the size is not known (yet?)
121     die "Cannot determine size of $dev\n";
122     }
123 andreas 4614
124 michael-guest 4293 # try RAID; estimations here are very limited and possible imprecise
125 mt 4831 elsif ($dev =~ /^\/dev\/md(\d+)$/) {
126 andreas 4614
127 michael-guest 4293 # the list of underlying devices
128     my @devs = ();
129 andreas 4614
130 michael-guest 4293 # the raid level, like raid0, raid5, linear, etc.
131     my $level = "";
132 michael-guest 3672
133 michael-guest 4293 # let's see, whether there is a configuration of this volume
134 mt 4831 if (defined ($FAI::configs{RAID}{volumes}{$1}{devices})) {
135 michael-guest 4722 @devs = keys %{ $FAI::configs{RAID}{volumes}{$1}{devices} };
136     $level = $FAI::configs{RAID}{volumes}{$1}{mode};
137 mt 4831 } elsif (defined ($FAI::current_raid_config{$1}{devices})) {
138 michael-guest 4722 @devs = $FAI::current_raid_config{$1}{devices};
139     $level = $FAI::current_raid_config{$1}{mode};
140 michael-guest 4715 } else {
141 michael-guest 4293 die "$dev is not a known RAID device\n";
142     }
143 andreas 4614
144 michael-guest 4293 # prepend "raid", if the mode is numeric-only
145 mt 4831 $level = "raid$level" if ($level =~ /^\d+$/);
146 andreas 4614
147 michael-guest 4293 # the number of devices in the volume
148 mt 4831 my $dev_count = scalar (@devs);
149 michael-guest 3672
150 michael-guest 4293 # now do the mode-specific size estimations
151 mt 4831 if ($level =~ /^raid[015]$/) {
152     my $min_size = &estimate_size(shift @devs);
153 michael-guest 4715 foreach (@devs) {
154 mt 4831 my $s = &FAI::estimate_size($_);
155     $min_size = $s if ($s < $min_size);
156 michael-guest 4293 }
157 michael-guest 3672
158 mt 4831 return $min_size * POSIX::floor($dev_count / 2)
159     if ($level eq "raid1");
160     return $min_size * $dev_count if ($level eq "raid0");
161     return $min_size * ($dev_count - 1) if ($level eq "raid5");
162 michael-guest 4715 } else {
163 andreas 4614
164 michael-guest 4293 # probably some more should be implemented
165     die "Don't know how to estimate the size of a $level device\n";
166 michael-guest 3672 }
167 michael-guest 4293 }
168 andreas 4614
169 michael-guest 4293 # otherwise we are clueless
170 michael-guest 4715 else {
171 mt 4861 die "Cannot determine size of $dev - scheme unknown\n";
172 michael-guest 4293 }
173     }
174 michael-guest 3634
175 michael-guest 4293 ################################################################################
176 michael-guest 3672 #
177 michael-guest 4293 # @brief Compute the desired sizes of logical volumes
178 michael-guest 3672 #
179 michael-guest 4293 ################################################################################
180 michael-guest 4715 sub compute_lv_sizes {
181 andreas 4614
182 michael-guest 4293 # loop through all device configurations
183 mt 4831 foreach my $config (keys %FAI::configs) {
184 andreas 4614
185 mt 4831 # for RAID or physical disks there is nothing to be done here
186     next if ($config eq "RAID" || $config =~ /^PHY_./);
187     ($config =~ /^VG_(.+)$/) or &FAI::internal_error("invalid config entry $config");
188     my $vg = $1; # the volume group name
189 andreas 4614
190 michael-guest 4293 # compute the size of the volume group; this is not exact, but should at
191     # least give a rough estimation, we assume 1 % of overhead; the value is
192     # stored in megabytes
193     my $vg_size = 0;
194 mt 4831 foreach my $dev (keys %{ $FAI::configs{$config}{devices} }) {
195 andreas 4614
196 michael-guest 4293 # $dev may be a partition, an entire disk or a RAID device; otherwise we
197     # cannot deal with it
198 mt 4831 $vg_size += &FAI::estimate_size($dev);
199 michael-guest 4293 }
200 andreas 4614
201 michael-guest 4293 # now subtract 1% of overhead
202     $vg_size *= 0.99;
203 michael-guest 3634
204 michael-guest 4293 # the volumes that require redistribution of free space
205     my @redist_list = ();
206 michael-guest 3634
207 mt 4831 # the minimum and maximum space required in this volume group
208 michael-guest 4293 my $min_space = 0;
209     my $max_space = 0;
210 andreas 4614
211 michael-guest 4293 # set effective sizes where available
212 mt 4831 foreach my $lv (keys %{ $FAI::configs{$config}{volumes} }) {
213 michael-guest 4715 # reference to the size of the current logical volume
214 mt 4831 my $lv_size = (\%FAI::configs)->{$config}->{volumes}->{$lv}->{size};
215 mt 4832 # get the effective sizes (in Bytes) from the range
216     my ($start, $end) = &FAI::make_range($lv_size->{range}, "${vg_size}MB");
217     # make them MB
218 mt 4836 $start /= 1024.0 * 1024.0;
219     $end /= 1024.0 * 1024.0;
220 andreas 4614
221 michael-guest 4293 # increase the used space
222     $min_space += $start;
223     $max_space += $end;
224 andreas 4614
225 michael-guest 4293 # write back the range in MB
226 michael-guest 4769 $lv_size->{range} = "$start-$end";
227 andreas 4614
228 michael-guest 4293 # the size is fixed
229 mt 4831 if ($start == $end) {
230 michael-guest 4293 # write the size back to the configuration
231 michael-guest 4769 $lv_size->{eff_size} = $start;
232 michael-guest 4715 } else {
233 andreas 4614
234 michael-guest 4293 # add this volume to the redistribution list
235     push @redist_list, $lv;
236 michael-guest 3627 }
237 michael-guest 3586 }
238    
239 michael-guest 4293 # test, whether the configuration fits on the volume group at all
240 mt 4831 ($min_space < $vg_size)
241 mt 4835 or die "Volume group $vg requires $min_space MB, but available space was estimated to be $vg_size\n";
242 michael-guest 3977
243 michael-guest 4293 # the extension factor
244     my $redist_factor = 0;
245 mt 4831 $redist_factor = ($vg_size - $min_space) / ($max_space - $min_space)
246     if ($max_space > $min_space);
247 michael-guest 3977
248 michael-guest 4293 # update all sizes that are still ranges
249 michael-guest 4715 foreach my $lv (@redist_list) {
250 andreas 4614
251 michael-guest 4293 # get the range again
252 mt 4832 my ($start, $end) =
253     &FAI::make_range($FAI::configs{$config}{volumes}{$lv}{size}{range}, "${vg_size}MB");
254     # make them MB
255 mt 4836 $start /= 1024.0 * 1024.0;
256     $end /= 1024.0 * 1024.0;
257 michael-guest 3977
258 michael-guest 4293 # write the final size
259 michael-guest 4722 $FAI::configs{$config}{volumes}{$lv}{size}{eff_size} =
260 mt 4831 $start + (($end - $start) * $redist_factor);
261 michael-guest 3588 }
262 michael-guest 3618 }
263 michael-guest 3588 }
264 mt 4832
265 michael-guest 3671 ################################################################################
266     #
267 mt 4832 # @brief Handle preserved partitions while computing the size of partitions
268 michael-guest 3671 #
269 mt 4832 # @param $part_id Partition id within $config
270     # @param $config Disk config
271     # @param $current_disk Current config of this disk
272     # @param $next_start Start of the next partition
273     # @param $min_req_total_space Minimum space required on disk
274     #
275     # @return Updated values of ($next_start, $min_req_total_space)
276     #
277 michael-guest 3671 ################################################################################
278 mt 4832 sub do_partition_preserve {
279 michael-guest 4048
280 mt 4832 my ($part_id, $config, $current_disk, $next_start, $min_req_total_space) = @_;
281    
282     # reference to the current partition
283     my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
284 andreas 4614
285 mt 4832 # a partition that should be preserved must exist already
286     defined($current_disk->{partitions}->{$part_id})
287     or die "$part_id can't be preserved, it does not exist.\n";
288 andreas 4614
289 mt 4832 my $curr_part = $current_disk->{partitions}->{$part_id};
290 michael-guest 3617
291 mt 4832 ($next_start > $curr_part->{begin_byte})
292     and die "Previous partitions overflow begin of preserved partition $part_id\n";
293 andreas 4614
294 mt 4832 # set the effective size to the value known already
295     $part->{size}->{eff_size} = $curr_part->{count_byte};
296 michael-guest 4048
297 mt 4832 # copy the start_byte and end_byte information
298     $part->{start_byte} = $curr_part->{begin_byte};
299     $part->{end_byte} = $curr_part->{end_byte};
300 andreas 4614
301 mt 4832 # and add it to the total disk space required by this config
302     $min_req_total_space += $part->{size}->{eff_size};
303 michael-guest 4293
304 mt 4832 # set the next start
305     $next_start = $part->{end_byte} + 1;
306 andreas 4614
307 mt 4832 # several msdos specific parts
308     if ($FAI::configs{$config}{disklabel} eq "msdos") {
309 michael-guest 4048
310 mt 4832 # make sure the partition ends at a cylinder boundary
311     (0 == ($curr_part->{end_byte} + 1)
312     % ($current_disk->{sector_size} *
313     $current_disk->{bios_sectors_per_track} *
314     $current_disk->{bios_heads})) or
315     die "Preserved partition $part_id does not end at a cylinder boundary\n";
316 michael-guest 4048
317 mt 4832 # add one head of disk usage if this is a logical partition
318     $min_req_total_space += $current_disk->{bios_sectors_per_track} *
319     $current_disk->{sector_size} if ($part_id > 4);
320 andreas 4614
321 mt 4832 # extended partitions consume no space
322     if ($part->{size}->{extended}) {
323 michael-guest 4048
324 mt 4832 # revert the addition of the size
325     $min_req_total_space -= $part->{size}->{eff_size};
326 michael-guest 4048
327 mt 4832 # set the next start to the start of the extended partition
328     $next_start = $part->{start_byte};
329 michael-guest 4293 }
330 mt 4832 }
331 michael-guest 4048
332 mt 4832 # on gpt, ensure that the partition ends at a sector boundary
333     if ($FAI::configs{$config}{disklabel} eq "gpt") {
334     (0 == ($current_disk->{partitions}{$part_id}{end_byte} + 1)
335     % $current_disk->{sector_size})
336     or die "Preserved partition $part_id does not end at a sector boundary\n";
337     }
338 michael-guest 4048
339 mt 4832 return ($next_start, $min_req_total_space);
340     }
341 andreas 4614
342 mt 4832 ################################################################################
343     #
344     # @brief Handle extended partitions while computing the size of partitions
345     #
346     # @param $part_id Partition id within $config
347     # @param $config Disk config
348     # @param $current_disk Current config of this disk
349     #
350     ################################################################################
351     sub do_partition_extended {
352 michael-guest 4048
353 mt 4832 my ($part_id, $config, $current_disk) = @_;
354    
355     # reference to the current partition
356     my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
357 michael-guest 4048
358 mt 4832 ($FAI::configs{$config}{disklabel} eq "msdos")
359     or die "found an extended partition on a non-msdos disklabel\n";
360 michael-guest 4048
361 mt 4832 # ensure that it is a primary partition
362     ($part_id <= 4) or
363     &FAI::internal_error("Extended partition wouldn't be a primary one");
364 michael-guest 4048
365 mt 4832 my $epbr_size = $current_disk->{bios_sectors_per_track} *
366     $current_disk->{sector_size};
367 michael-guest 4048
368 mt 4832 # initialise the size and the start byte
369     $part->{size}->{eff_size} = 0;
370     $part->{start_byte} = -1;
371 michael-guest 4048
372 mt 4859 foreach my $p (sort { $a <=> $b } keys %{ $FAI::configs{$config}{partitions} }) {
373 mt 4832 next if ($p < 5);
374 michael-guest 4048
375 mt 4832 $part->{start_byte} = $FAI::configs{$config}{partitions}{$p}{start_byte} -
376     $epbr_size if (-1 == $part->{start_byte});
377 andreas 4614
378 mt 4832 $part->{size}->{eff_size} += $FAI::configs{$config}{partitions}{$p}{size}{eff_size} +
379     $epbr_size;
380 michael-guest 4048
381 mt 4832 $part->{end_byte} = $FAI::configs{$config}{partitions}{$p}{end_byte};
382     }
383 michael-guest 4048
384 mt 4832 ($part->{size}->{eff_size} > 0)
385     or die "Extended partition has a size of 0\n";
386     }
387 michael-guest 4048
388 mt 4832 ################################################################################
389     #
390     # @brief Handle all other partitions while computing the size of partitions
391     #
392     # @param $part_id Partition id within $config
393     # @param $config Disk config
394     # @param $current_disk Current config of this disk
395     # @param $next_start Start of the next partition
396     # @param $min_req_total_space Minimum space required on disk
397     # @param $worklist Reference to the remaining partitions
398     #
399     # @return Updated values of ($next_start, $min_req_total_space)
400     #
401     ################################################################################
402     sub do_partition_real {
403 andreas 4614
404 mt 4832 my ($part_id, $config, $current_disk, $next_start, $min_req_total_space,
405     $worklist) = @_;
406    
407     # reference to the current partition
408     my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
409    
410 mt 4841 my ($start, $end) = &FAI::make_range($part->{size}->{range},
411     $current_disk->{size} . "B");
412 michael-guest 4048
413 mt 4832 # check, whether the size is fixed
414     if ($end != $start) {
415 michael-guest 4048
416 mt 4832 # the end of the current range (may be the end of the disk or some
417 mt 4863 # preserved partition or an ntfs volume to be resized)
418 mt 4832 my $end_of_range = -1;
419 andreas 4614
420 mt 4832 # minimum space required by all partitions, i.e., the lower ends of the
421     # ranges
422     # $min_req_space counts up to the next preserved partition or the
423     # end of the disk
424     my $min_req_space = 0;
425 michael-guest 4048
426 mt 4832 # maximum useful space
427     my $max_space = 0;
428 andreas 4614
429 mt 4832 # inspect all remaining entries in the worklist
430     foreach my $p (@{$worklist}) {
431 michael-guest 4048
432 mt 4832 # we have found the delimiter
433 mt 4863 if ($FAI::configs{$config}{partitions}{$p}{size}{preserve} ||
434     ($FAI::configs{$config}{partitions}{$p}{size}{resize} &&
435     ($current_disk->{partitions}->{$p}->{filesystem} eq "ntfs"))) {
436 mt 4832 $end_of_range = $current_disk->{partitions}->{$p}->{begin_byte};
437 michael-guest 4048
438 mt 4832 # logical partitions require the space for the EPBR to be left
439     # out
440     if (($FAI::configs{$config}{disklabel} eq "msdos")
441     && ($p > 4)) {
442     $end_of_range -= $current_disk->{bios_sectors_per_track} *
443     $current_disk->{sector_size};
444 michael-guest 4293 }
445 mt 4832 last;
446     } elsif ($FAI::configs{$config}{partitions}{$p}{size}{extended}) {
447     next;
448     } else {
449     my ($min_size, $max_size) = &FAI::make_range(
450 mt 4841 $FAI::configs{$config}{partitions}{$p}{size}{range},
451     $current_disk->{size} . "B");
452 andreas 4614
453 mt 4832 # logical partitions require the space for the EPBR to be left
454     # out
455     if (($FAI::configs{$config}{disklabel} eq "msdos")
456     && ($p > 4)) {
457     $min_size += $current_disk->{bios_sectors_per_track} *
458 michael-guest 4722 $current_disk->{sector_size};
459 mt 4832 $max_size += $current_disk->{bios_sectors_per_track} *
460     $current_disk->{sector_size};
461     }
462 andreas 4614
463 mt 4832 $min_req_space += $min_size;
464     $max_space += $max_size;
465     }
466     }
467 michael-guest 4293
468 mt 4832 # set the end if we have reached the end of the disk
469     $end_of_range = $current_disk->{end_byte} if (-1 == $end_of_range);
470 michael-guest 4048
471 mt 4832 my $available_space = $end_of_range - $next_start + 1;
472 andreas 4614
473 mt 4832 # the next boundary is closer than the minimal space that we need
474     ($available_space < $min_req_space)
475     and die "Insufficient space available for partition $part_id\n";
476 andreas 4614
477 mt 4832 # the new size
478     my $scaled_size = $end;
479     $scaled_size = POSIX::floor(($end - $start) *
480     (($available_space - $min_req_space) /
481     ($max_space - $min_req_space))) + $start
482     if ($max_space > $available_space);
483 andreas 4614
484 mt 4832 ($scaled_size >= $start)
485     or &FAI::internal_error("scaled size is smaller than the desired minimum");
486 andreas 4614
487 mt 4832 $start = $scaled_size;
488     $end = $start;
489     }
490 andreas 4614
491 mt 4832 # now we compute the effective locations on the disk
492     # msdos specific offset for logical partitions
493     if (($FAI::configs{$config}{disklabel} eq "msdos")
494     && ($part_id > 4)) {
495 michael-guest 4048
496 mt 4832 # add one head of disk usage if this is a logical partition
497     $min_req_total_space += $current_disk->{bios_sectors_per_track} *
498     $current_disk->{sector_size};
499 michael-guest 4048
500 mt 4832 # move the start byte as well
501     $next_start += $current_disk->{bios_sectors_per_track} *
502     $current_disk->{sector_size};
503     }
504 michael-guest 4048
505 mt 4863 # partition starts at where we currently are, or remains fixed in case of
506     # resized ntfs
507     if ($FAI::configs{$config}{partitions}{$part_id}{size}{resize} &&
508     ($current_disk->{partitions}->{$part_id}->{filesystem} eq "ntfs")) {
509     ($next_start <= $current_disk->{partitions}->{$part_id}->{begin_byte})
510     or die "Cannot preserve start byte of ntfs volume on partition $part_id, space before it is too small\n";
511     $next_start = $current_disk->{partitions}->{$part_id}->{begin_byte};
512     }
513 mt 4832 $FAI::configs{$config}{partitions}{$part_id}{start_byte} =
514     $next_start;
515 michael-guest 4048
516 mt 4832 # the end may need some alignment, depending on the disk label
517     my $end_byte = $next_start + $start - 1;
518 michael-guest 4048
519 mt 4832 # on msdos, ensure that the partition ends at a cylinder boundary
520     if ($FAI::configs{$config}{disklabel} eq "msdos") {
521     $end_byte -=
522     ($end_byte + 1) % ($current_disk->{sector_size} *
523     $current_disk->{bios_sectors_per_track} *
524     $current_disk->{bios_heads});
525     }
526 michael-guest 4048
527 mt 4832 # on gpt, ensure that the partition ends at a sector boundary
528     if ($FAI::configs{$config}{disklabel} eq "gpt") {
529     $end_byte -=
530     ($end_byte + 1) % $current_disk->{sector_size};
531     }
532 andreas 4614
533 mt 4832 # set $start and $end to the effective values
534     $start = $end_byte - $next_start + 1;
535     $end = $start;
536 michael-guest 4048
537 mt 4832 # write back the size spec in bytes
538     $part->{size}->{range} = $start . "-" . $end;
539 andreas 4614
540 mt 4832 # then set eff_size to a proper value
541     $part->{size}->{eff_size} = $start;
542 michael-guest 4048
543 mt 4832 # write the end byte to the configuration
544     $part->{end_byte} = $end_byte;
545 michael-guest 4048
546 mt 4832 # and add it to the total disk space required by this config
547     $min_req_total_space += $part->{size}->{eff_size};
548 michael-guest 4048
549 mt 4832 # set the next start
550     $next_start = $part->{end_byte} + 1;
551 andreas 4614
552 mt 4832 return ($next_start, $min_req_total_space);
553     }
554 andreas 4614
555 mt 4832 ################################################################################
556     #
557     # @brief Compute the desired sizes of the partitions and test feasibility
558     # thereof.
559     #
560     ################################################################################
561     sub compute_partition_sizes
562     {
563 andreas 4614
564 mt 4832 # loop through all device configurations
565     foreach my $config (keys %FAI::configs) {
566 michael-guest 4048
567 mt 4832 # for RAID or LVM, there is nothing to be done here
568     next if ($config eq "RAID" || $config =~ /^VG_./);
569     ($config =~ /^PHY_(.+)$/) or &FAI::internal_error("invalid config entry $config");
570     # nothing to be done, if this is a configuration for a virtual disk
571     next if $FAI::configs{$config}{virtual};
572     my $disk = $1; # the device name of the disk
573 mt 4850 # test, whether $disk is a block special device
574     (-b $disk) or die "$disk is not a valid device name\n";
575 mt 4832 # reference to the current disk config
576     my $current_disk = $FAI::current_config{$disk};
577 michael-guest 4048
578 mt 4832 # at various points the following code highly depends on the desired disk label!
579     # initialise variables
580     # the id of the extended partition to be created, if required
581     my $extended = -1;
582 michael-guest 3638
583 mt 4832 # the id of the current extended partition, if any; this setup only caters
584     # for a single existing extended partition!
585     my $current_extended = -1;
586 andreas 4614
587 mt 4832 # find the first existing extended partition
588 mt 4859 foreach my $part_id (sort { $a <=> $b } keys %{ $current_disk->{partitions} }) {
589 mt 4832 if ($current_disk->{partitions}->{$part_id}->{is_extended}) {
590     $current_extended = $part_id;
591     last;
592     }
593     }
594 michael-guest 4048
595 mt 4832 # the space required on the disk
596     my $min_req_total_space = 0;
597 michael-guest 4048
598 mt 4832 # the start byte for the next partition
599     my $next_start = 0;
600 michael-guest 4048
601 mt 4832 # on msdos disk labels, the first partitions starts at head #1
602     if ($FAI::configs{$config}{disklabel} eq "msdos") {
603     $next_start = $current_disk->{bios_sectors_per_track} *
604     $current_disk->{sector_size};
605 michael-guest 4048
606 mt 4832 # the MBR requires space, too
607     $min_req_total_space += $current_disk->{bios_sectors_per_track} *
608     $current_disk->{sector_size};
609     }
610 michael-guest 3638
611 mt 4832 # on GPT disk labels the first 34 and last 34 sectors must be left alone
612     if ($FAI::configs{$config}{disklabel} eq "gpt") {
613     $next_start = 34 * $current_disk->{sector_size};
614 michael-guest 4048
615 mt 4832 # modify the disk to claim the space for the second partition table
616     $current_disk->{end_byte} -= 34 * $current_disk->{sector_size};
617 michael-guest 4048
618 mt 4832 # the space required by the GPTs
619     $min_req_total_space += 2 * 34 * $current_disk->{sector_size};
620     }
621 andreas 4614
622 mt 4832 # the list of partitions that we need to find start and end bytes for
623 mt 4859 my @worklist = (sort { $a <=> $b } keys %{ $FAI::configs{$config}{partitions} });
624 michael-guest 3638
625 mt 4832 while (scalar (@worklist))
626     {
627 michael-guest 4293
628 mt 4832 # work on the first entry of the list
629     my $part_id = $worklist[0];
630     # reference to the current partition
631     my $part = (\%FAI::configs)->{$config}->{partitions}->{$part_id};
632 andreas 4614
633 mt 4832 # the partition $part_id must be preserved
634     if ($part->{size}->{preserve}) {
635     ($next_start, $min_req_total_space) = &FAI::do_partition_preserve($part_id,
636     $config, $current_disk, $next_start, $min_req_total_space);
637 andreas 4614
638 mt 4832 # partition done
639     shift @worklist;
640     }
641 andreas 4614
642 mt 4832 # msdos specific: deal with extended partitions
643     elsif ($part->{size}->{extended}) {
644     # make sure that there is only one extended partition
645     ($extended == -1 || 1 == scalar (@worklist))
646     or &FAI::internal_error("More than 1 extended partition");
647 michael-guest 3627
648 mt 4832 # set the local variable to this id
649     $extended = $part_id;
650 michael-guest 4048
651 mt 4832 # the size cannot be determined now, push it to the end of the
652     # worklist; the check against $extended being == -1 ensures that
653     # there is no indefinite loop
654     if (scalar (@worklist) > 1) {
655     push @worklist, shift @worklist;
656     next;
657 michael-guest 4293 }
658 michael-guest 3627
659 mt 4832 # determine the size of the extended partition
660     &FAI::do_partition_extended($part_id, $config, $current_disk);
661 michael-guest 4048
662 mt 4832 # partition done
663     shift @worklist;
664     } else {
665     ($next_start, $min_req_total_space) = &FAI::do_partition_real($part_id,
666     $config, $current_disk, $next_start, $min_req_total_space, \@worklist);
667 andreas 4614
668 michael-guest 4293 # partition done
669     shift @worklist;
670 michael-guest 3618 }
671 michael-guest 4293 }
672 michael-guest 3627
673 michael-guest 4293 # check, whether there is sufficient space on the disk
674 mt 4832 ($min_req_total_space > $current_disk->{size})
675 michael-guest 4715 and die "Disk $disk is too small - at least $min_req_total_space bytes are required\n";
676 michael-guest 3616
677 michael-guest 4293 # make sure, extended partitions are only created on msdos disklabels
678 mt 4832 ($FAI::configs{$config}{disklabel} ne "msdos" && $extended > -1)
679 mt 4831 and &FAI::internal_error("extended partitions are not supported by this disklabel");
680 michael-guest 4047
681 michael-guest 4293 # ensure that we have done our work
682 mt 4832 (defined ($FAI::configs{$config}{partitions}{$_}{start_byte})
683     && defined ($FAI::configs{$config}{partitions}{$_}{end_byte}))
684     or &FAI::internal_error("start or end of partition $_ not set")
685 mt 4859 foreach (sort { $a <=> $b } keys %{ $FAI::configs{$config}{partitions} });
686 michael-guest 3618 }
687 michael-guest 3583 }
688    
689     1;
690    

Properties

Name Value
svn:executable *
svn:keywords Id

  ViewVC Help
Powered by ViewVC 1.1.5