Cédric Bosdonnat
2018-Jan-10 12:07 UTC
[Libguestfs] [PATCH 0/3] Handle GPT attribute flags
Hi all, Here is the series fixing the bug I mentioned on IRC regarding the GPT attribute flags to copy to the new disk in a virt-resize. Cédric Bosdonnat (3): daemon: make sgdisk_info_extract_uuid_field more generic New APIs: part_set_gpt_attributes and part_get_gpt_attributes resize: copy GPT partition flags daemon/parted.ml | 34 +++++++++++++++++++++++++++------- daemon/parted.mli | 3 +++ generator/actions_core.ml | 40 ++++++++++++++++++++++++++++++++++++++++ generator/proc_nr.ml | 2 ++ lib/MAX_PROC_NR | 2 +- resize/resize.ml | 15 ++++++++++++--- 6 files changed, 85 insertions(+), 11 deletions(-) -- 2.15.1
Cédric Bosdonnat
2018-Jan-10 12:07 UTC
[Libguestfs] [PATCH 1/3] daemon: make sgdisk_info_extract_uuid_field more generic
Rename the sgdisk_info_extract_uuid_field to sgdisk_info_extract_field in order to reuse it for other field types. To avoid possible confusion, the list of valid characters used to extract the value is added to the function parameters. --- daemon/parted.ml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/daemon/parted.ml b/daemon/parted.ml index d6638867a..cf1a54a08 100644 --- a/daemon/parted.ml +++ b/daemon/parted.ml @@ -124,12 +124,16 @@ let part_get_parttype device | _ -> failwithf "%s: cannot parse the output of parted" device +let hex_chars = "0123456789ABCDEF" + let rec part_get_gpt_type device partnum - sgdisk_info_extract_uuid_field device partnum "Partition GUID code" + sgdisk_info_extract_field device partnum "Partition GUID code" + ("-" ^ hex_chars) and part_get_gpt_guid device partnum - sgdisk_info_extract_uuid_field device partnum "Partition unique GUID" + sgdisk_info_extract_field device partnum "Partition unique GUID" + ("-" ^ hex_chars) -and sgdisk_info_extract_uuid_field device partnum field +and sgdisk_info_extract_field device partnum field chars if partnum <= 0 then failwith "partition number must be >= 1"; udev_settle (); @@ -167,13 +171,13 @@ and sgdisk_info_extract_uuid_field device partnum field (* Skip any whitespace after the colon. *) let value = String.triml value in - (* Extract the UUID. *) - extract_uuid value + (* Extract the value. *) + extract_string chars value | _ :: lines -> loop lines in loop lines -and extract_uuid value +and extract_string chars value (* The value contains only valid GUID characters. *) - String.sub value 0 (String.span value "-0123456789ABCDEF") + String.sub value 0 (String.span value chars) -- 2.15.1
Cédric Bosdonnat
2018-Jan-10 12:07 UTC
[Libguestfs] [PATCH 2/3] New APIs: part_set_gpt_attributes and part_get_gpt_attributes
Allow reading and setting the GPT partition attribute flags. --- daemon/parted.ml | 18 +++++++++++++++++- daemon/parted.mli | 3 +++ generator/actions_core.ml | 40 ++++++++++++++++++++++++++++++++++++++++ generator/proc_nr.ml | 2 ++ lib/MAX_PROC_NR | 2 +- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/daemon/parted.ml b/daemon/parted.ml index cf1a54a08..5f553c2da 100644 --- a/daemon/parted.ml +++ b/daemon/parted.ml @@ -124,7 +124,19 @@ let part_get_parttype device | _ -> failwithf "%s: cannot parse the output of parted" device -let hex_chars = "0123456789ABCDEF" +let part_set_gpt_attributes device partnum attributes + if partnum <= 0 then failwith "partition number must be >= 1"; + + udev_settle (); + + let arg = string_of_int partnum ^ ":=:" ^ attributes in + let r, _, err + commandr ~fold_stdout_on_stderr:true + "sgdisk" [ device; "-A"; arg ] in + if r <> 0 then + failwithf "sgdisk: %s" err; + + udev_settle () let rec part_get_gpt_type device partnum sgdisk_info_extract_field device partnum "Partition GUID code" @@ -132,6 +144,8 @@ let rec part_get_gpt_type device partnum and part_get_gpt_guid device partnum sgdisk_info_extract_field device partnum "Partition unique GUID" ("-" ^ hex_chars) +and part_get_gpt_attributes device partnum + sgdisk_info_extract_field device partnum "Attribute flags" hex_chars and sgdisk_info_extract_field device partnum field chars if partnum <= 0 then failwith "partition number must be >= 1"; @@ -178,6 +192,8 @@ and sgdisk_info_extract_field device partnum field chars in loop lines +and hex_chars = "0123456789ABCDEF" + and extract_string chars value (* The value contains only valid GUID characters. *) String.sub value 0 (String.span value chars) diff --git a/daemon/parted.mli b/daemon/parted.mli index cbcb7b503..300adfa75 100644 --- a/daemon/parted.mli +++ b/daemon/parted.mli @@ -30,3 +30,6 @@ val part_get_parttype : string -> string val part_get_gpt_type : string -> int -> string val part_get_gpt_guid : string -> int -> string +val part_get_gpt_attributes : string -> int -> string + +val part_set_gpt_attributes : string -> int -> string -> unit diff --git a/generator/actions_core.ml b/generator/actions_core.ml index 02759a6b7..786953d0c 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -8265,6 +8265,46 @@ Return the type GUID of numbered GPT partition C<partnum>. For MBR partitions, return an appropriate GUID corresponding to the MBR type. Behaviour is undefined for other partition types." }; + { defaults with + name = "part_set_gpt_attributes"; added = (1, 21, 1); + style = RErr, [String (Device, "device"); Int "partnum"; String (PlainString, "attributes")], []; + impl = OCaml "Parted.part_set_gpt_attributes"; + optional = Some "gdisk"; + tests = [ + InitGPT, Always, TestLastFail ( + [["part_set_gpt_attributes"; "/dev/sda"; "1"; "foo"]]), []; + InitGPT, Always, TestResultString ( + [["part_set_gpt_attributes"; "/dev/sda"; "1"; + "0000000000000004"]; + ["part_get_gpt_attributes"; "/dev/sda"; "1"]], + "0000000000000004"), []; + ]; + shortdesc = "set the attribute flags of a GPT partition"; + longdesc = "\ +Set the attribute flags of numbered GPT partition C<partnum> to C<guid>. Return an +error if the partition table of C<device> isn't GPT, or if C<attributes> is not a +valid hexadecimal value. + +See L<https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries> +for a useful list of partition attributes." }; + + { defaults with + name = "part_get_gpt_attributes"; added = (1, 21, 1); + style = RString (RPlainString, "attributes"), [String (Device, "device"); Int "partnum"], []; + impl = OCaml "Parted.part_get_gpt_attributes"; + optional = Some "gdisk"; + tests = [ + InitGPT, Always, TestResultString ( + [["part_set_gpt_attributes"; "/dev/sda"; "1"; + "0000000000000000"]; + ["part_get_gpt_attributes"; "/dev/sda"; "1"]], + "0000000000000004"), []; + ]; + shortdesc = "get the attribute flags of a GPT partition"; + longdesc = "\ +Return the attribute flags of numbered GPT partition C<partnum> as a hexadecimal bit mask. +For MBR partitions, return all flags set to 0." }; + { defaults with name = "rename"; added = (1, 21, 5); style = RErr, [String (Pathname, "oldpath"); String (Pathname, "newpath")], []; diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml index 3e393da73..9e16ab14a 100644 --- a/generator/proc_nr.ml +++ b/generator/proc_nr.ml @@ -510,6 +510,8 @@ let proc_nr = [ 500, "inspect_get_mountpoints"; 501, "inspect_get_filesystems"; 502, "inspect_get_drive_mappings"; +503, "part_set_gpt_attributes"; +504, "part_get_gpt_attributes"; ] (* End of list. If adding a new entry, add it at the end of the list diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR index cc5027eed..3091e8eea 100644 --- a/lib/MAX_PROC_NR +++ b/lib/MAX_PROC_NR @@ -1 +1 @@ -502 +504 -- 2.15.1
Cédric Bosdonnat
2018-Jan-10 12:07 UTC
[Libguestfs] [PATCH 3/3] resize: copy GPT partition flags
In some cases, the first stage bootloader needs the 'Legacy BIOS bootable' flag to be set on the partition. This change copies all flags (including this one) for each partition of the old disk to the new one to avoid ending up with non-bootable disks. --- resize/resize.ml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 880fa98cb..4328d162e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -50,6 +50,7 @@ type partition = { p_type : partition_content; (* Content type and content size. *) p_label : string option; (* Label/name. *) p_guid : string option; (* Partition GUID (GPT only). *) + p_attributes : string option; (* Partition attributes hex bit mask (GPT only). *) (* What we're going to do: *) mutable p_operation : partition_operation; @@ -493,6 +494,12 @@ read the man page virt-resize(1). let label try Some (g#part_get_name "/dev/sda" part_num) with G.Error _ -> None in + let attributes + match parttype with + | MBR -> None + | GPT -> + try Some (g#part_get_gpt_attributes "/dev/sda" part_num) + with G.Error _ -> None in let guid match parttype with | MBR -> None @@ -502,7 +509,7 @@ read the man page virt-resize(1). { p_name = name; p_part = part; p_bootable = bootable; p_id = id; p_type = typ; - p_label = label; p_guid = guid; + p_label = label; p_guid = guid; p_attributes = attributes; p_operation = OpCopy; p_target_partnum = 0; p_target_start = 0L; p_target_end = 0L } ) parts in @@ -1150,6 +1157,7 @@ read the man page virt-resize(1). part_size = 0L }; p_bootable = false; p_id = No_ID; p_type = ContentUnknown; p_label = None; p_guid = None; + p_attributes = None; (* Target information is meaningful. *) p_operation = OpIgnore; @@ -1191,12 +1199,13 @@ read the man page virt-resize(1). * is changed from primary to extended. Thus we need to set the * MBR ID before doing the copy so sfdisk doesn't corrupt things. *) - let set_partition_bootable_and_id p + let set_partition_bootable_attributes_and_id p if p.p_bootable then g#part_set_bootable "/dev/sdb" p.p_target_partnum true; Option.may (g#part_set_name "/dev/sdb" p.p_target_partnum) p.p_label; Option.may (g#part_set_gpt_guid "/dev/sdb" p.p_target_partnum) p.p_guid; + Option.may (g#part_set_gpt_attributes "/dev/sdb" p.p_target_partnum) p.p_attributes; match parttype, p.p_id with | GPT, GPT_Type gpt_type -> @@ -1205,7 +1214,7 @@ read the man page virt-resize(1). g#part_set_mbr_id "/dev/sdb" p.p_target_partnum mbr_id | GPT, (No_ID|MBR_ID _) | MBR, (No_ID|GPT_Type _) -> () in - List.iter set_partition_bootable_and_id partitions; + List.iter set_partition_bootable_attributes_and_id partitions; (* Copy over the data. *) let copy_partition p -- 2.15.1
Pino Toscano
2018-Jan-12 15:28 UTC
Re: [Libguestfs] [PATCH 1/3] daemon: make sgdisk_info_extract_uuid_field more generic
On Wednesday, 10 January 2018 13:07:49 CET Cédric Bosdonnat wrote:> let rec part_get_gpt_type device partnum > - sgdisk_info_extract_uuid_field device partnum "Partition GUID code" > + sgdisk_info_extract_field device partnum "Partition GUID code" > + ("-" ^ hex_chars) > and part_get_gpt_guid device partnum > - sgdisk_info_extract_uuid_field device partnum "Partition unique GUID" > + sgdisk_info_extract_field device partnum "Partition unique GUID" > + ("-" ^ hex_chars)IMHO a better option here would be to pass as parameter, instead of the allowed characters (which is an implementation of the extract_uuid function), the function itself. This would bring this code much like as it was the old C version of it, and even help for patch #2 of this series. The sgdisk_info_extract_uuid_field -> sgdisk_info_extract_field renaming is OK. -- Pino Toscano
Pino Toscano
2018-Jan-12 15:36 UTC
Re: [Libguestfs] [PATCH 2/3] New APIs: part_set_gpt_attributes and part_get_gpt_attributes
On Wednesday, 10 January 2018 13:07:50 CET Cédric Bosdonnat wrote:> + { defaults with > + name = "part_set_gpt_attributes"; added = (1, 21, 1); > + style = RErr, [String (Device, "device"); Int "partnum"; String (PlainString, "attributes")], []; > + impl = OCaml "Parted.part_set_gpt_attributes"; > + optional = Some "gdisk"; > + tests = [ > + InitGPT, Always, TestLastFail ( > + [["part_set_gpt_attributes"; "/dev/sda"; "1"; "foo"]]), []; > + InitGPT, Always, TestResultString ( > + [["part_set_gpt_attributes"; "/dev/sda"; "1"; > + "0000000000000004"]; > + ["part_get_gpt_attributes"; "/dev/sda"; "1"]], > + "0000000000000004"), []; > + ];Considering that the attribute flags look like a 64bit value, and they seem to behave like proper flags, I would expose them as Int64/RInt64 in these new get/set APIs. Handling strings with number is not very convenient for the users of the APIs, anyway. -- Pino Toscano
Pino Toscano
2018-Jan-12 15:38 UTC
Re: [Libguestfs] [PATCH 3/3] resize: copy GPT partition flags
On Wednesday, 10 January 2018 13:07:51 CET Cédric Bosdonnat wrote:> In some cases, the first stage bootloader needs the 'Legacy BIOS > bootable' flag to be set on the partition. This change copies all > flags (including this one) for each partition of the old disk to the > new one to avoid ending up with non-bootable disks. > ---This of course needs changes according to my notes in patch #2 (basically regarding the type for the part_(get|set)_gpt_attributes APIs).> @@ -1191,12 +1199,13 @@ read the man page virt-resize(1). > * is changed from primary to extended. Thus we need to set the > * MBR ID before doing the copy so sfdisk doesn't corrupt things. > *) > - let set_partition_bootable_and_id p > + let set_partition_bootable_attributes_and_id pConsidering the function already does more than what the name says, I would simply rename it to set_partition_attributes, and be done with it. -- Pino Toscano
Possibly Parallel Threads
- [PATCH v2 0/3] copying gpt attributes
- [PATCH v3 0/3] copy GPT attributes
- resize: Preserve GPT GUID so we don't break EFI bootloaders (RHBZ#1189284)
- [PATCH 0/3] virt-resize: preserve GPT partitions label
- [PATCH 2/3] New APIs: part_set_gpt_attributes and part_get_gpt_attributes