X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=tools%2Fvirt-resize;h=e89564f60feca61255bffa63b6a0355fc9bfad07;hb=51c6cc6081e2ca760e0fb4cf7cc11872f27fae3a;hp=1c4006ae50e8b442b2a925d8683eabedd4088074;hpb=2e47daea514fe577bf8b1661ceb070103e20ded1;p=libguestfs.git diff --git a/tools/virt-resize b/tools/virt-resize index 1c4006a..e89564f 100755 --- a/tools/virt-resize +++ b/tools/virt-resize @@ -60,7 +60,23 @@ L and L, we recommend you go and read those manual pages first. -=head2 BASIC USAGE +=head2 EXAMPLES + +Copy C to C, extending one of the guest's partitions +to fill the extra 5GB of space. + + virt-list-partitions -lh olddisk + # Make a new blank disk which is larger than the old disk file. + dd if=/dev/zero of=newdisk bs=1024k count=15000 + # Note "/dev/sda2" is a partition inside the "olddisk" file. + virt-resize --expand /dev/sda2 olddisk newdisk + +As above, but make the /boot partition 200MB bigger, while giving the +remaining space to /dev/sda2: + + virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 olddisk newdisk + +=head2 DETAILED USAGE This describes the common case where you want to expand an image to give your guest more space. Shrinking images is considerably more @@ -411,12 +427,23 @@ if ($debug) { print "$outfile size $outsize bytes\n"; } +# In reality the number of sectors containing boot loader data will be +# less than this (although Windows 7 defaults to putting the first +# partition on sector 2048, and has quite a large boot loader). +# +# However make this large enough to be sure that we have copied over +# the boot loader. We could also do this by looking for the sector +# offset of the first partition. +# +# It doesn't matter if we copy too much. +my $boot_sectors = 4096; + die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n", file => $infile, sz => $insize) - if $insize < 64 * 512; + if $insize < $boot_sectors * 512; die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n", file => $outfile, sz => $outsize) - if $outsize < 64 * 512; + if $outsize < $boot_sectors * 512; # Copy the boot loader across. do_copy_boot_loader () if $copy_boot_loader; @@ -426,12 +453,12 @@ sub do_copy_boot_loader print "copying boot loader ...\n" if $debug; open IFILE, $infile or die "$infile: $!"; my $s; - my $r = sysread (IFILE, $s, 64 * 512) or die "$infile: $!"; - die "$infile: short read" if $r < 64 * 512; + my $r = sysread (IFILE, $s, $boot_sectors * 512) or die "$infile: $!"; + die "$infile: short read" if $r < $boot_sectors * 512; open OFILE, "+<$outfile" or die "$outfile: $!"; sysseek OFILE, 0, SEEK_SET or die "$outfile: seek: $!"; - $r = syswrite (OFILE, $s, 64 * 512) or die "$outfile: $!"; - die "$outfile: short write" if $r < 64 * 512; + $r = syswrite (OFILE, $s, $boot_sectors * 512) or die "$outfile: $!"; + die "$outfile: short write" if $r < $boot_sectors * 512; } # Add them to the handle and launch the appliance. @@ -466,6 +493,8 @@ sub check_source_disk my %h = %$_; $h{name} = $name; + $h{bootable} = $g->part_get_bootable ("/dev/sda", $h{part_num}); + eval { $h{mbr_id} = $g->part_get_mbr_id ("/dev/sda", $h{part_num}); }; $partitions{$name} = \%h; } } @@ -676,7 +705,11 @@ sub calculate_surplus # We need some overhead for partitioning. Worst case would be for # EFI partitioning + massive per-partition alignment. - my $overhead = $sectsize * (2 * 64 + (64 * (@partitions + 1)) + 128); + my $overhead = $sectsize * ( + 2 * 64 + # GPT start and end + (64 * (@partitions + 1)) + # Maximum alignment + ($boot_sectors - 64) # Boot loader + ); my $required = 0; foreach (@partitions) { @@ -777,17 +810,36 @@ sub repartition if ($copy_boot_loader) { $parttype = $g->part_get_parttype ("/dev/sdb"); - print "partition table type: $parttype\n" if $debug; } else { - # Didn't copy over the initial boot loader, so we need - # to make a new partition type here. $parttype = "efi"; } + print "partition table type: $parttype\n" if $debug; + + # Delete any existing partitions on the destination disk, + # but leave the bootloader that we copied over intact. + if ($copy_boot_loader) { + # Delete in reverse as an easy way to deal with extended + # partitions. + foreach (sort { $b cmp $a } $g->list_partitions ()) { + if (m{^/dev/.db(\d+)$}) { + $g->part_del ("/dev/sdb", $1); + } + } + } else { + # Didn't copy over the initial boot loader, so we need + # to make a new partition table here. + $g->part_init ("/dev/sdb", $parttype); + } + + # Work out where to start the first partition. + die __"virt-resize: source disk does not have a first partition\n" + unless exists ($partitions{"/dev/sda1"}); + my $start = $partitions{"/dev/sda1"}->{part_start} / $sectsize; - # Delete any existing partitions on the destination disk. - $g->part_init ("/dev/sdb", $parttype); + # Align to 64. + $start = ($start + 63) & ~63; - my $start = 64; + print "starting to partition from $start\n" if $debug; # Create the new partitions. foreach my $part (@partitions) { @@ -803,9 +855,18 @@ sub repartition } # Create it. - my ($target, $end) = add_partition ($start, $size); + my ($target, $end, $part_num) = add_partition ($start, $size); $partitions{$part}->{target} = $target; + if ($partitions{$part}->{bootable}) { + $g->part_set_bootable ("/dev/sdb", $part_num, 1); + } + + if ($partitions{$part}->{mbr_id}) { + $g->part_set_mbr_id ("/dev/sdb", $part_num, + $partitions{$part}->{mbr_id}); + } + # Start of next partition + alignment. $start = $end + 1; $start = ($start + 63) & ~63; @@ -825,26 +886,26 @@ sub add_partition my $start = shift; my $size = shift; - my ($target, $end); + my ($target, $end, $part_num); if ($nextpart <= 3 || $parttype ne "msdos") { $target = "/dev/sdb$nextpart"; $end = $start + $size - 1; $g->part_add ("/dev/sdb", "primary", $start, $end); - $nextpart++; + $part_num = $nextpart++; } else { if ($nextpart == 4) { $g->part_add ("/dev/sdb", "extended", $start, -1); - $nextpart++; + $part_num = $nextpart++; $start += 64; } $target = "/dev/sdb$nextpart"; $end = $start + $size - 1; $g->part_add ("/dev/sdb", "logical", $start, $end); - $nextpart++; + $part_num = $nextpart++; } - return ($target, $end); + return ($target, $end, $part_num); } # Copy over the data. @@ -881,6 +942,11 @@ sub copy_data } } +# Sync disk and exit. +$g->umount_all (); +$g->sync (); +undef $g; + exit 0; sub sizebytes @@ -945,6 +1011,22 @@ sub canonicalize $_; } +=head1 ALTERNATIVE TOOLS + +There are several proprietary tools for resizing partitions. We +won't mention any here. + +L and its graphical shell gparted can do some types of +resizing operations on disk images. They can resize and move +partitions, but I don't think they can do anything with the contents, +and they certainly don't understand LVM. + +L can do everything that virt-resize can do and a lot +more, but at a much lower level. You will probably end up +hand-calculating sector offsets, which is something that virt-resize +was designed to avoid. If you want to see the guestfish-equivalent +commands that virt-resize runs, use the C<--debug> flag. + =head1 SEE ALSO L, @@ -957,12 +1039,13 @@ L, L, L, L, +L, L, L. =head1 AUTHOR -Richard W.M. Jones L +Richard W.M. Jones L =head1 COPYRIGHT