Maxim Perevedentsev
2015-Dec-01 15:28 UTC
[Libguestfs] [PATCHv2] New API: part_expand_gpt.
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;
+ }
+
+ /* 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;
+ 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
--
1.8.3.1
Maxim Perevedentsev
2015-Dec-22 08:57 UTC
Re: [Libguestfs] [PATCHv2] New API: part_expand_gpt.
Please take a look. This feature is necessary for in-place image expanding. On 12/01/2015 06:28 PM, 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; > + } > + > + /* 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; > + 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 > -- > 1.8.3.1 > > _______________________________________________ > Libguestfs mailing list > Libguestfs@redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs-- Your sincerely, Maxim Perevedentsev
Richard W.M. Jones
2015-Dec-22 10:17 UTC
Re: [Libguestfs] [PATCHv2] New API: part_expand_gpt.
On Tue, Dec 22, 2015 at 11:57:39AM +0300, Maxim Perevedentsev wrote:> Please take a look.I am really going on holiday now, and not back until Jan 4th. I'll have a look when I get back, unless Pino, Dan or others get there before me. Also, new APIs aren't 1.32 material, since I just stabilised it, created the release notes, and nearly released it. But we'll open the gate for new APIs in 1.33, very early in Jan. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 100 libraries supported. http://fedoraproject.org/wiki/MinGW
Richard W.M. Jones
2016-Jan-19 16:26 UTC
Re: [Libguestfs] [PATCHv2] New API: part_expand_gpt.
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 0Looks 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