On Tue, Dec 01, 2015 at 06:28:44PM +0300, Maxim Perevedentsev wrote:
This action moves second(backup) GPT header to the end of the disk. It is usable in in-place image expanding, since free space after second GPT header is unusable. To use additional space, we have to move second header. This is what sgdisk -e does.
However, sgdisk -e may perform additional actions if the partition table has unexpected params (e.g. if we call sgdisk -e /dev/sda1, it may fix partition table thus destroying the filesystem). To prevent such cases, we do a dry-run at first and fail if additional actions are scheduled. --- daemon/parted.c | 33 ++++++++++++++++++++ generator/actions.ml | 14 +++++++++ src/MAX_PROC_NR | 2 +- tests/daemon/Makefile.am | 3 +- tests/daemon/test-expand-gpt.pl | 69 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100755 tests/daemon/test-expand-gpt.pl
diff --git a/daemon/parted.c b/daemon/parted.c index df6b7e7..033c136 100644 --- a/daemon/parted.c +++ b/daemon/parted.c @@ -928,3 +928,36 @@ do_part_get_mbr_part_type (const char *device, int partnum) reply_with_error ("strdup failed"); return NULL; } + +int +do_part_expand_gpt(const char *device) +{ + CLEANUP_FREE char *err = NULL; + + /* If something is broken, sgdisk may try to correct it. + * (e.g. recreate partition table and so on). + * We do not want such behavior, so dry-run at first.*/ + int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, + str_sgdisk, "--pretend", "-e", device, NULL); + + if (r == -1) { + reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err); + return -1; + } + if (err && strlen(err) != 0) { + /* Unexpected actions. */ + reply_with_error ("%s --pretend -e %s: %s", str_sgdisk, device, err); + return -1; + }
Need to call `free (err);' right here. The CLEANUP_FREE macro only frees the string at the end of the enclosing {} block.
+ /* Now we can do a real run. */ + r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, + str_sgdisk, "-e", device, NULL); + + if (r == -1) { + reply_with_error ("%s -e %s: %s", str_sgdisk, device, err); + return -1; + } + + return 0; +} diff --git a/generator/actions.ml b/generator/actions.ml index 7ab8ee4..3a14683 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12787,6 +12787,20 @@ See also L<ntfsresize(8)>, L<resize2fs(8)>, L<btrfs(8)>, L<xfs_info(8)>." }; longdesc = "\ This is the internal call which implements C<guestfs_feature_available>." };
+ { defaults with + name = "part_expand_gpt"; added = (1, 31, 29); + style = RErr, [Device "device"], []; + proc_nr = Some 459;
Needs to be rebased on top of the current code. This proc number will change.
+ optional = Some "gdisk"; + shortdesc = "move backup GPT header to the end of the disk"; + longdesc = "\ +Move backup GPT data structures to the end of the disk. +This is useful in case of in-place image expand +since disk space after backup GPT header is not usable. +This is equivalent to C<sgdisk -e>. + +See also L<sgdisk(8)>." }; + ]
(* Non-API meta-commands available only in guestfish. diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index c92ddb6..658bd78 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -458 +459
diff --git a/tests/daemon/Makefile.am b/tests/daemon/Makefile.am index bb380c5..329b00c 100644 --- a/tests/daemon/Makefile.am +++ b/tests/daemon/Makefile.am @@ -25,7 +25,8 @@ check_DATA = captive-daemon.pm
TESTS = \ test-daemon-start.pl \ - test-btrfs.pl + test-btrfs.pl \ + test-expand-gpt.pl
TESTS_ENVIRONMENT = $(top_builddir)/run --test $(VG)
diff --git a/tests/daemon/test-expand-gpt.pl b/tests/daemon/test-expand-gpt.pl new file mode 100755 index 0000000..637b90e --- /dev/null +++ b/tests/daemon/test-expand-gpt.pl @@ -0,0 +1,69 @@ +#!/usr/bin/env perl +# Copyright (C) 2015 Maxim Perevedentsev mperevedentsev@virtuozzo.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use Sys::Guestfs; + +sub tests { + my $g = Sys::Guestfs->new (); + + foreach ("gpt", "mbr") { + $g->disk_create ("disk_$_.img", "qcow2", 50 * 1024 * 1024); + $g->add_drive ("disk_$_.img"); + } + + $g->launch (); + + $g->part_disk ("/dev/sda", "gpt"); + $g->part_disk ("/dev/sdb", "mbr"); + + $g->close (); + + die if system ("qemu-img resize disk_gpt.img 100M &>/dev/null"); + + $g = Sys::Guestfs->new (); + + foreach ("gpt", "mbr") { + $g->add_drive ("disk_$_.img"); + } + + $g->launch (); + die if $g->part_expand_gpt ("/dev/sda"); + + my $output = $g->debug ("sh", ["sgdisk", "-p", "/dev/sda"]); + die if $output eq ""; + $output =~ s/\n/ /g; + $output =~ s/.*last usable sector is (\d+).*/$1/g; + + my $end_sectors = 100 * 1024 * 2 - $output; + die unless $end_sectors <= 34; + + # Negative tests. + eval { $g->part_expand_gpt ("/dev/sdb") }; + die unless $@; + eval { $g->part_expand_gpt ("/dev/sda1") }; + die unless $@; +} + +eval { tests() }; +system ("rm -f disk_*.img"); +if ($@) { + die; +} +exit 0
Looks fine to me apart from those two things. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v