Maxim Perevedentsev
2016-Jan-19 12:02 UTC
[Libguestfs] [PATCHv2 0/3] Get/set disk GPT GUID API and support in virt-resize.
Some OSes (e.g. Windows Server 2012 R2) fail to boot after virt-resize due to changed disk guid. To fix it, we add new APIs: part_get_disk_guid part_set_disk_guid part_set_disk_guid_random We also preserve disk GUID in virt-resize. Maxim Perevedentsev (3): New API: part_get_disk_guid and part_set_disk_guid. New API: part_set_disk_guid_random. resize: preserve GPT disk GUID. daemon/parted.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 52 ++++++++++++++++++++++++++++++++++++ resize/resize.ml | 12 ++++++++- src/MAX_PROC_NR | 2 +- 4 files changed, 139 insertions(+), 2 deletions(-) -- 1.8.3.1
Maxim Perevedentsev
2016-Jan-19 12:02 UTC
[Libguestfs] [PATCHv2 1/3] New API: part_get_disk_guid and part_set_disk_guid.
Some OSes (e.g. Windows Server 2012 R2) fail to boot if the disk
GPT GUID has changed. To preserve disk guid e.g. during virt-resize,
we need a way to get/set disk GUIDs.
---
daemon/parted.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++
generator/actions.ml | 37 ++++++++++++++++++++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/daemon/parted.c b/daemon/parted.c
index b073bd8..40f9676 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -928,3 +928,63 @@ do_part_get_mbr_part_type (const char *device, int partnum)
reply_with_error ("strdup failed");
return NULL;
}
+
+char *
+do_part_get_disk_guid (const char *device)
+{
+ const char *pattern = "Disk identifier (GUID):";
+ size_t i;
+
+ CLEANUP_FREE char *err = NULL;
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, device, "-p", NULL);
+ if (r == -1) {
+ reply_with_error ("%s %s -p: %s", str_sgdisk, device, err);
+ return NULL;
+ }
+
+ CLEANUP_FREE_STRING_LIST char **lines = split_lines (err);
+ if (lines == NULL) {
+ reply_with_error ("'%s %s -p' returned no output",
+ str_sgdisk, device);
+ return NULL;
+ }
+
+ for (i = 0; lines[i] != NULL; ++i) {
+ if (STRPREFIX (lines[i], pattern)) {
+ char *value = lines[i] + strlen (pattern);
+
+ /* Skip any leading whitespace */
+ value += strspn (value, " \t");
+
+ /* Extract the actual information from the field. */
+ char *ret = extract_uuid (value);
+ if (ret == NULL) {
+ /* The extraction function already sends the error. */
+ return NULL;
+ }
+
+ return ret;
+ }
+ }
+
+ /* If we got here it means we didn't find the field */
+ reply_with_error ("sgdisk output did not contain disk GUID. "
+ "See LIBGUESTFS_DEBUG output for more details");
+ return NULL;
+}
+
+int
+do_part_set_disk_guid (const char *device, const char *guid)
+{
+ CLEANUP_FREE char *err = NULL;
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, device, "-U", guid, NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s %s -U %s: %s", str_sgdisk, device, guid,
err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 7f8e80b..62c4839 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12793,6 +12793,43 @@ 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_set_disk_guid"; added = (1, 33, 2);
+ style = RErr, [Device "device"; GUID "guid"], [];
+ proc_nr = Some 459;
+ optional = Some "gdisk";
+ tests = [
+ InitGPT, Always, TestLastFail (
+ [["part_set_disk_guid"; "/dev/sda";
"f"]]), [];
+ InitGPT, Always, TestResultString (
+ [["part_set_disk_guid"; "/dev/sda";
+ "01234567-89AB-CDEF-0123-456789ABCDEF"];
+ ["part_get_disk_guid"; "/dev/sda"]],
+ "01234567-89AB-CDEF-0123-456789ABCDEF"), [];
+ ];
+ shortdesc = "set the GUID of a GPT-partitioned disk";
+ longdesc = "\
+Set the disk identifier (GUID) of a GPT-partitioned C<device> to
C<guid>.
+Return an error if the partition table of C<device> isn't GPT,
+or if C<guid> is not a valid GUID." };
+
+ { defaults with
+ name = "part_get_disk_guid"; added = (1, 33, 2);
+ style = RString "guid", [Device "device"], [];
+ proc_nr = Some 460;
+ optional = Some "gdisk";
+ tests = [
+ InitGPT, Always, TestResultString (
+ [["part_set_disk_guid"; "/dev/sda";
+ "01234567-89AB-CDEF-0123-456789ABCDEF"];
+ ["part_get_disk_guid"; "/dev/sda"]],
+ "01234567-89AB-CDEF-0123-456789ABCDEF"), [];
+ ];
+ shortdesc = "get the GUID of a GPT-partitioned disk";
+ longdesc = "\
+Return the disk identifier (GUID) of a GPT-partitioned C<device>.
+Behaviour is undefined for other partition types." };
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c92ddb6..ccbd68f 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-458
+460
--
1.8.3.1
Maxim Perevedentsev
2016-Jan-19 12:03 UTC
[Libguestfs] [PATCHv2 2/3] New API: part_set_disk_guid_random.
Provides a way to set a new randomly-generated GUID to disk.
---
daemon/parted.c | 15 +++++++++++++++
generator/actions.ml | 15 +++++++++++++++
src/MAX_PROC_NR | 2 +-
3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/daemon/parted.c b/daemon/parted.c
index 40f9676..22cd92b 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -988,3 +988,18 @@ do_part_set_disk_guid (const char *device, const char
*guid)
return 0;
}
+
+int
+do_part_set_disk_guid_random (const char *device)
+{
+ CLEANUP_FREE char *err = NULL;
+ int r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
+ str_sgdisk, device, "-U", "R", NULL);
+
+ if (r == -1) {
+ reply_with_error ("%s %s -U R: %s", str_sgdisk, device, err);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 62c4839..d345175 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -12830,6 +12830,21 @@ or if C<guid> is not a valid GUID." };
Return the disk identifier (GUID) of a GPT-partitioned C<device>.
Behaviour is undefined for other partition types." };
+ { defaults with
+ name = "part_set_disk_guid_random"; added = (1, 33, 2);
+ style = RErr, [Device "device"], [];
+ proc_nr = Some 461;
+ optional = Some "gdisk";
+ tests = [
+ InitGPT, Always, TestRun (
+ [["part_set_disk_guid_random"; "/dev/sda"]]), [];
+ ];
+ shortdesc = "set the GUID of a GPT-partitioned disk to random
value";
+ longdesc = "\
+Set the disk identifier (GUID) of a GPT-partitioned C<device> to
+a randomly generated value.
+Return an error if the partition table of C<device> isn't GPT."
};
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index ccbd68f..408b885 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-460
+461
--
1.8.3.1
Maxim Perevedentsev
2016-Jan-19 12:03 UTC
[Libguestfs] [PATCHv2 3/3] resize: preserve GPT disk GUID.
Changed disk GUID makes some OSes fail to boot.
To enable virt-resize to support such OSes we
have to preserve disk GUID.
---
resize/resize.ml | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/resize/resize.ml b/resize/resize.ml
index d6dd9a5..8ff4793 100644
--- a/resize/resize.ml
+++ b/resize/resize.ml
@@ -407,6 +407,13 @@ read the man page virt-resize(1).
error (f_"%s: unknown partition table type\nvirt-resize only
supports MBR (DOS) and GPT partition tables.")
(fst infile) in
+ let disk_guid + match parttype with
+ | MBR -> None
+ | GPT ->
+ try Some (g#part_get_disk_guid "/dev/sda")
+ with G.Error _ -> None in
+
(* Build a data structure describing the source disk's partition layout.
*)
let get_partition_content let pvs_full = Array.to_list (g#pvs_full ())
in
@@ -977,7 +984,10 @@ read the man page virt-resize(1).
let last_error = ref "" in
let rec initialize_partition_table g attempts let ok - try
g#part_init "/dev/sdb" parttype_string; true
+ try
+ g#part_init "/dev/sdb" parttype_string;
+ may (g#part_set_disk_guid "/dev/sdb") disk_guid;
+ true
with G.Error error -> last_error := error; false in
if ok then g, true
else if attempts > 0 then (
--
1.8.3.1
Richard W.M. Jones
2016-Jan-19 16:23 UTC
Re: [Libguestfs] [PATCHv2 0/3] Get/set disk GPT GUID API and support in virt-resize.
On Tue, Jan 19, 2016 at 03:02:58PM +0300, Maxim Perevedentsev wrote:> Some OSes (e.g. Windows Server 2012 R2) fail to boot after virt-resize > due to changed disk guid. To fix it, we add new APIs: > part_get_disk_guid > part_set_disk_guid > part_set_disk_guid_random > > We also preserve disk GUID in virt-resize. > > Maxim Perevedentsev (3): > New API: part_get_disk_guid and part_set_disk_guid. > New API: part_set_disk_guid_random. > resize: preserve GPT disk GUID.This all looks fine to me. I'll push this later on once I've run some tests. Thanks, Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html
Maybe Matching Threads
- [PATCH] New API: part_get_disk_guid and part_set_disk_guid.
- resize: Preserve GPT GUID so we don't break EFI bootloaders (RHBZ#1189284)
- [PATCHv2 1/3] New API: part_get_disk_guid and part_set_disk_guid.
- OpenStack output workflow
- [PATCH] Add support for getting and setting GPT partition type GUIDs