use strict;
use Sys::Guestfs;
+use Sys::Guestfs::Lib qw(feature_available);
use Fcntl qw(S_ISREG SEEK_SET);
use POSIX qw(floor);
use Pod::Usage;
=head1 SYNOPSIS
- virt-resize [--resize /dev/sdaN=[+/-]<size>[%]] [--expand /dev/sdaN]
- [--shrink /dev/sdaN] [--ignore /dev/sdaN] [--delete /dev/sdaN] [...]
- indisk outdisk
+ virt-resize [--resize /dev/sdaN=[+/-]<size>[%]]
+ [--expand /dev/sdaN] [--shrink /dev/sdaN]
+ [--ignore /dev/sdaN] [--delete /dev/sdaN] [...] indisk outdisk
=head1 DESCRIPTION
L<virt-df(1)>,
we recommend you go and read those manual pages first.
-=head2 BASIC USAGE
+=head1 EXAMPLES
-This describes the common case where you want to expand an image to
-give your guest more space. Shrinking images is considerably more
-complicated (unfortunately).
+Copy C<olddisk> to C<newdisk>, extending one of the guest's partitions
+to fill the extra 5GB of space.
+
+ truncate -r olddisk newdisk; truncate -s +5G newdisk
+ virt-list-partitions -lht olddisk
+ # 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
+
+=head1 DETAILED USAGE
+
+=head2 EXPANDING A VIRTUAL MACHINE DISK
=over 4
-=item 1. Locate disk image
+=item 1. Shut down the virtual machine
+
+=item 2. Locate input disk image
-Locate the disk image that you want to resize. It could be in a local
-file or device. If the guest is managed by libvirt, you can use
-C<virsh dumpxml> like this to find the disk image name:
+Locate the input disk image (ie. the file or device on the host
+containing the guest's disk). If the guest is managed by libvirt, you
+can use C<virsh dumpxml> like this to find the disk image name:
# virsh dumpxml guestname | xpath /domain/devices/disk/source
Found 1 nodes:
-- NODE --
<source dev="/dev/vg/lv_guest" />
-=item 2. Look at current sizing
+=item 3. Look at current sizing
Use L<virt-list-partitions(1)> to display the current partitions and
sizes:
- # virt-list-partitions -lh /dev/vg/lv_guest
+ # virt-list-partitions -lht /dev/vg/lv_guest
/dev/sda1 ext3 101.9M
/dev/sda2 pv 7.9G
+ /dev/sda device 8.0G
(This example is a virtual machine with an 8 GB disk which we would
like to expand up to 10 GB).
-=item 3. Create destination disk
+=item 4. Create output disk
Virt-resize cannot do in-place disk modifications. You have to have
-space to store the resized destination disk.
+space to store the resized output disk.
To store the resized disk image in a file, create a file of a suitable
size:
# rm -f outdisk
# truncate -s 10G outdisk
-Use L<lvcreate(1)> to create a logical volume:
+Or use L<lvcreate(1)> to create a logical volume:
# lvcreate -L 10G -n lv_name vg_name
# virsh pool-list
# virsh vol-create-as poolname newvol 10G
-=item 4. Resize
+=item 5. Resize
- virt-resize indisk outdisk
+virt-resize takes two mandatory parameters, the input disk (eg. device
+or file) and the output disk. The output disk is the one created in
+the previous step.
+
+ # virt-resize indisk outdisk
This command just copies disk image C<indisk> to disk image C<outdisk>
I<without> resizing or changing any existing partitions. If
end of the disk covering the extra space. If C<outdisk> is smaller,
then it will give an error.
-To resize, you need to pass extra options (for the full list see the
+More realistically you'd want to expand existing partitions in the
+disk image by passing extra options (for the full list see the
L</OPTIONS> section below).
L</--expand> is the most useful option. It expands the named
partition within the disk to fill any extra space:
- virt-resize --expand /dev/sda2 indisk outdisk
+ # virt-resize --expand /dev/sda2 indisk outdisk
(In this case, an extra partition is I<not> created at the end of the
disk, because there will be no unused space).
-If /dev/sda2 in the image contains a filesystem or LVM PV, then
-this content is B<not> automatically resized. You can resize it
-afterwards either using L<guestfish(1)> (offline) or using commands
-inside the guest (online resizing).
-
L</--resize> is the other commonly used option. The following would
increase the size of /dev/sda1 by 200M, and expand /dev/sda2
to fill the rest of the available space:
- virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 \
- indisk outdisk
+ # virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 \
+ indisk outdisk
+
+If the expanded partition in the image contains a filesystem or LVM
+PV, then if virt-resize knows how, it will resize the contents, the
+equivalent of calling a command such as L<pvresize(8)>,
+L<resize2fs(8)> or L<ntfsresize(8)>. However virt-resize does not
+know how to resize some filesystems, so you would have to online
+resize them after booting the guest. And virt-resize also does not
+resize anything inside an LVM PV, it just resizes the PV itself and
+leaves the user to resize any LVs inside that PV as desired.
Other options are covered below.
-=item 5. Test
+=item 6. Test
Thoroughly test the new disk image I<before> discarding the old one.
# virsh start guestname
-and check that it still works.
+and check that it still works. See also the L</NOTES> section below
+for additional information.
+
+=item 7. Resize LVs etc inside the guest
+
+(This can also be done offline using L<guestfish(1)>)
-Note that to see the extra space in the guest, you may need to use
-guest commands to resize PVs, LVs and/or filesystems to fit the extra
-space available. Three common guest commands for doing this for Linux
-guests are L<pvresize(8)>, L<lvresize(8)> and L<resize2fs(8)>. It is
-also possible to do this offline (eg. for scripting changes) using
-L<guestfish(1)>.
+Once the guest has booted you should see the new space available, at
+least for filesystems that virt-resize knows how to resize, and for
+PVs. The user may need to resize LVs inside PVs, and also resize
+filesystem types that virt-resize does not know how to expand.
=back
+=head2 SHRINKING A VIRTUAL MACHINE DISK
+
+Shrinking is somewhat more complex than expanding, and only an
+overview is given here.
+
+Firstly virt-resize will not attempt to shrink any partition content
+(PVs, filesystems). The user has to shrink content before passing the
+disk image to virt-resize, and virt-resize will check that the content
+has been shrunk properly.
+
+(Shrinking can also be done offline using L<guestfish(1)>)
+
+After shrinking PVs and filesystems, shut down the guest, and proceed
+with steps 3 and 4 above to allocate a new disk image.
+
+Then run virt-resize with any of the C<--shrink> and/or C<--resize>
+options.
+
+=head2 IGNORING OR DELETING PARTITIONS
+
+virt-resize also gives a convenient way to ignore or delete partitions
+when copying from the input disk to the output disk. Ignoring a
+partition speeds up the copy where you don't care about the existing
+contents of a partition. Deleting a partition removes it completely,
+but note that it also renumbers any partitions after the one which is
+deleted, which can leave some guests unbootable.
+
=head1 OPTIONS
=over 4
--resize /dev/sda1=-10%
-You can increase the size of any partition.
+You can increase the size of any partition. Virt-resize will expand
+the direct content of the partition if it knows how (see C<--expand>
+below).
-You can I<only> B<decrease> the size of partitions that contain
+You can only I<decrease> the size of partitions that contain
filesystems or PVs which have already been shrunk. Virt-resize will
check this has been done before proceeding, or else will print an
error (see also C<--resize-force>).
Expand the named partition so it uses up all extra space (space left
over after any other resize changes that you request have been done).
-Any filesystem inside the partition is I<not> expanded. You will need
-to expand the filesystem (or PV) to fit the extra space either using
-L<guestfish(1)> (offline) or online guest tools.
+If virt-resize knows how, it will expand the direct content of the
+partition. For example, if the partition is an LVM PV, it will expand
+the PV to fit (like calling L<pvresize(8)>). Virt-resize leaves any
+other content it doesn't know about alone.
+
+Currently virt-resize can resize:
+
+=over 4
+
+=item *
+
+ext2, ext3 and ext4 filesystems when they are contained
+directly inside a partition.
+
+=item *
+
+NTFS filesystems contained directly in a partition, if libguestfs was
+compiled with support for NTFS.
+
+The filesystem must have been shut down consistently last time it was
+used. Additionally, L<ntfsresize(8)> marks the resized filesystem as
+requiring a consistency check, so at the first boot after resizing
+Windows will check the disk.
+
+=item *
+
+LVM PVs (physical volumes). However virt-resize does I<not>
+resize anything inside the PV. The user will have to resize
+LVs as desired.
+
+=back
Note that you cannot use C<--expand> and C<--shrink> together.
=cut
+my @lv_expand;
+
+=item B<--LV-expand logvol>
+
+This takes the logical volume and, as a final step, expands it to fill
+all the space available in its volume group. A typical usage,
+assuming a Linux guest with a single PV C</dev/sda2> and a root device
+called C</dev/vg_guest/lv_root> would be:
+
+ virt-resize indisk outdisk \
+ --expand /dev/sda2 --LV-expand /dev/vg_guest/lv_root
+
+This would first expand the partition (and PV), and then expand the
+root device to fill the extra space in the PV.
+
+The contents of the LV are also resized if virt-resize knows how to do
+that. You can stop virt-resize from trying to expand the content by
+using the option C<--no-expand-content>.
+
+Use L<virt-list-filesystems(1)> to list the filesystems in
+the guest.
+
+You can give this option multiple times, I<but> it doesn't
+make sense to do this unless the logical volumes you specify
+are all in different volume groups.
+
+=cut
+
my $copy_boot_loader = 1;
=item B<--no-copy-boot-loader>
=cut
+my $expand_content = 1;
+
+=item B<--no-expand-content>
+
+By default, virt-resize will try to expand the direct contents
+of partitions, if it knows how (see C<--expand> option above).
+
+If you give the C<--no-expand-content> option then virt-resize
+will not attempt this.
+
+=cut
+
my $debug;
=item B<-d> | B<--debug>
"shrink=s" => \$shrink,
"ignore=s" => \@ignore,
"delete=s" => \@delete,
+ "lv-expand=s" => \@lv_expand,
"copy-boot-loader!" => \$copy_boot_loader,
"extra-partition!" => \$extra_partition,
+ "expand-content!" => \$expand_content,
"d|debug" => \$debug,
- "n|dryrun" => \$dryrun,
+ "n|dryrun|dry-run" => \$dryrun,
"q|quiet" => \$quiet,
) or pod2usage (2);
pod2usage (1) if $help;
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;
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.
my $sectsize = $g->blockdev_getss ("/dev/sdb");
+my $to_be_expanded = 0;
+
# Get the partitions on the source disk.
my @partitions;
my %partitions;
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;
}
}
# that case user won't be allowed to shrink this partition except
# by forcing it.
$partitions{$part}->{fssize} = $fssize;
+
+ # Is it partition content that we know how to expand?
+ $partitions{$part}->{can_expand_content} = 0;
+ if ($expand_content) {
+ if ($type eq "LVM2_member") {
+ $partitions{$part}->{can_expand_content} = 1;
+ $partitions{$part}->{expand_content_method} = "pvresize";
+ } elsif ($type =~ /^ext[234]$/) {
+ $partitions{$part}->{can_expand_content} = 1;
+ $partitions{$part}->{expand_content_method} = "resize2fs";
+ } elsif ($type eq "ntfs" && feature_available ($g, "ntfsprogs")) {
+ $partitions{$part}->{can_expand_content} = 1;
+ $partitions{$part}->{expand_content_method} = "ntfsresize";
+ }
+ }
}
if ($debug) {
}
}
+# Examine the LVs (for --lv-expand option).
+my @lvs = $g->lvs ();
+my %lvs;
+examine_lv ($_) foreach @lvs;
+mark_lvs_to_expand ();
+
+sub examine_lv
+{
+ local $_ = shift;
+
+ $lvs{$_}->{name} = $_;
+
+ my $type = "unknown";
+ eval {
+ $type = $g->vfs_type ($_);
+ };
+ $lvs{$_}->{type} = $type;
+
+ if ($expand_content) {
+ if ($type =~ /^ext[234]$/) {
+ $lvs{$_}->{can_expand_content} = 1;
+ $lvs{$_}->{expand_content_method} = "resize2fs";
+ } elsif ($type eq "ntfs" && feature_available ($g, "ntfsprogs")) {
+ $lvs{$_}->{can_expand_content} = 1;
+ $lvs{$_}->{expand_content_method} = "ntfsresize";
+ }
+ }
+}
+
+sub mark_lvs_to_expand {
+ local $_;
+
+ foreach (@lv_expand) {
+ die __x("virt-resize: no logical volume called {n}\n",
+ n => $_)
+ unless exists $lvs{$_};
+
+ if ($lvs{$_}->{can_expand_content}) {
+ $lvs{$_}->{will_expand_content} = 1;
+ $to_be_expanded++;
+ }
+ }
+}
+
sub find_partition
{
local $_ = shift;
}
$partitions{$part}->{newsize} = $newsize;
+
+ if ($partitions{$part}->{can_expand_content} && $bigger) {
+ $partitions{$part}->{will_expand_content} = 1;
+ $to_be_expanded++;
+ }
}
# Handle --expand and --shrink.
# 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) {
foreach my $part (@partitions) {
if ($partitions{$part}->{ignore}) {
- print __x("{p}: partition will be ignored", p => $part);
+ print __x("{p}: partition will be ignored\n", p => $part);
} elsif ($partitions{$part}->{delete}) {
- print __x("{p}: partition will be deleted", p => $part);
+ print __x("{p}: partition will be deleted\n", p => $part);
} elsif ($partitions{$part}->{newsize}) {
- print __x("{p}: partition will be resized from {oldsize} to {newsize}",
+ print __x("{p}: partition will be resized from {oldsize} to {newsize}\n",
p => $part,
oldsize => human_size ($partitions{$part}->{part_size}),
newsize => human_size ($partitions{$part}->{newsize}));
+ if ($partitions{$part}->{will_expand_content}) {
+ print __x("{p}: content will be expanded using the '{meth}' method\n",
+ p => $part,
+ meth => $partitions{$part}->{expand_content_method});
+ }
} else {
- print __x("{p}: partition will be left alone", p => $part);
+ print __x("{p}: partition will be left alone\n", p => $part);
+ }
+ }
+
+ foreach my $lv (@lv_expand) {
+ print __x("{n}: LV will be expanded to maximum size\n",
+ n => $lv);
+ }
+
+ foreach my $lv (@lvs) {
+ if ($lvs{$lv}->{will_expand_content}) {
+ print __x("{n}: content will be expanded using the '{meth}' method\n",
+ n => $lv,
+ meth => $lvs{$lv}->{expand_content_method});
}
- print "\n"
}
if ($surplus > 0) {
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);
+ }
- # Delete any existing partitions on the destination disk.
- $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;
- my $start = 64;
+ # Align to 64.
+ $start = ($start + 63) & ~63;
+
+ print "starting to partition from $start\n" if $debug;
# Create the new partitions.
foreach my $part (@partitions) {
}
# 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;
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.
if (!$quiet && !$debug) {
local $| = 1;
- print "Copying $part ...";
+ print __x("Copying {p} ...", p => $part);
}
$g->copy_size ($part, $target,
$newsize < $oldsize ? $newsize : $oldsize);
if (!$quiet && !$debug) {
- print " done\n"
+ print " ", __"done", "\n";
+ }
+ }
+ }
+ }
+}
+
+# After copying the data over we must shut down and restart the
+# appliance in order to expand the content. The reason for this may
+# not be obvious, but it's because otherwise we'll have duplicate VGs
+# (the old VG(s) and the new VG(s)) which breaks LVM.
+#
+# The restart is only required if we're going to expand something.
+
+if ($to_be_expanded > 0) {
+ restart_appliance ();
+ expand_partitions ();
+ expand_lvs ();
+ expand_lvs_content ();
+}
+
+sub restart_appliance
+{
+ # Sync disk and exit.
+ $g->umount_all ();
+ $g->sync ();
+ undef $g;
+
+ $g = Sys::Guestfs->new ();
+ $g->set_trace (1) if $debug;
+ $g->add_drive ($outfile);
+ $g->launch ();
+
+ # Target partitions have changed from /dev/sdb to /dev/sda,
+ # so change them.
+ foreach my $part (@partitions)
+ {
+ my $target = $partitions{$part}->{target};
+ if ($target) {
+ if ($target =~ m{/dev/(.)db(.*)}) {
+ $partitions{$part}->{target} = "/dev/$1da$2";
+ } else {
+ die "internal error: unexpected partition target: $target";
+ }
+ }
+ }
+}
+
+sub expand_partitions
+{
+ foreach my $part (@partitions)
+ {
+ unless ($partitions{$part}->{ignore}) {
+ my $target = $partitions{$part}->{target};
+ if ($target) {
+ # Expand if requested.
+ if ($partitions{$part}->{will_expand_content}) {
+ if (!$quiet && !$debug) {
+ print __x("Expanding {p} using the '{meth}' method\n",
+ p => $part,
+ meth => $partitions{$part}->{expand_content_method});
+ }
+ expand_target_partition ($part)
}
}
}
}
}
+sub expand_target_partition
+{
+ local $_;
+ my $part = shift;
+
+ # Assertions.
+ die unless $part;
+ die unless $partitions{$part}->{can_expand_content};
+ die unless $partitions{$part}->{will_expand_content};
+ die unless $partitions{$part}->{expand_content_method};
+ die unless $partitions{$part}->{target};
+ die unless $expand_content;
+
+ my $target = $partitions{$part}->{target};
+ my $method = $partitions{$part}->{expand_content_method};
+ if ($method eq "pvresize") {
+ $g->pvresize ($target);
+ }
+ elsif ($method eq "resize2fs") {
+ $g->e2fsck_f ($target);
+ $g->resize2fs ($target);
+ }
+ elsif ($method eq "ntfsresize") {
+ $g->ntfsresize ($target);
+ }
+ else {
+ die "internal error: unknown method: $method";
+ }
+}
+
+sub expand_lvs
+{
+ local $_;
+
+ foreach (@lv_expand) {
+ $g->lvresize_free ($_, 100);
+ }
+}
+
+sub expand_lvs_content
+{
+ local $_;
+
+ foreach (@lvs) {
+ if ($lvs{$_}->{will_expand_content}) {
+ my $method = $lvs{$_}->{expand_content_method};
+ if (!$quiet && !$debug) {
+ print __x("Expanding {p} using the '{meth}' method\n",
+ p => $_, meth => $method);
+ }
+ if ($method eq "resize2fs") {
+ $g->e2fsck_f ($_);
+ $g->resize2fs ($_);
+ } elsif ($method eq "ntfsresize") {
+ $g->ntfsresize ($_);
+ } else {
+ die "internal error: unknown method: $method";
+ }
+ }
+ }
+}
+
+# Sync disk and exit.
+$g->umount_all ();
+$g->sync ();
+undef $g;
+
exit 0;
sub sizebytes
$_;
}
+=head1 NOTES
+
+=head2 "Partition 1 does not end on cylinder boundary."
+
+Virt-resize aligns partitions to multiples of 64 sectors. Usually
+this means the partitions will not be aligned to the ancient CHS
+geometry. However CHS geometry is meaningless for disks manufactured
+since the early 1990s, and doubly so for virtual hard drives.
+Alignment of partitions to cylinders is not required by any modern
+operating system.
+
+=head2 RESIZING WINDOWS VIRTUAL MACHINES
+
+In Windows Vista and later versions, Microsoft switched to using a
+separate boot partition. In these VMs, typically C</dev/sda1> is the
+boot partition and C</dev/sda2> is the main (C:) drive. We have not
+had any luck resizing the boot partition. Doing so seems to break the
+guest completely. However expanding the second partition (ie. C:
+drive) should work.
+
+Windows may initiate a lengthy "chkdsk" on first boot after a resize,
+if NTFS partitions have been expanded. This is just a safety check
+and (unless it find errors) is nothing to worry about.
+
+=head1 ALTERNATIVE TOOLS
+
+There are several proprietary tools for resizing partitions. We
+won't mention any here.
+
+L<parted(8)> 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<guestfish(1)> 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<virt-list-partitions(1)>,
L<pvresize(8)>,
L<lvresize(8)>,
L<resize2fs(8)>,
+L<ntfsresize(8)>,
L<virsh(1)>,
+L<parted(8)>,
L<Sys::Guestfs(3)>,
L<http://libguestfs.org/>.
=head1 AUTHOR
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+Richard W.M. Jones L<http://people.redhat.com/~rjones/>
=head1 COPYRIGHT