Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 00/13] virt-resize: add support for resizing MBR logical partitions
Hi Rich, This is v2 series to add support for resizing MBR logical partitions. I found the reason of problem in v1 that parted reports error when adding logical partitions, is that logical partitions are not aligned to 2 sectors. This problem doesn't appear in v2. This is for early review, because of: 1. I'm not sure the splitting of patches is appropriate or not, but it's much easier to review than v1. 2. The test script is not included, I'm not sure where to add the test script. But I'll send the test script I used. Thanks! changes to v1: 1. spit the patches so it's easier to review 2. fix the parted error caused by unaligned logical partitions 3. extend the content of logical partitions 4. refactor to make logical partitions a seperate list Hu Tao (13): resize: convert sectsize to int64 add function div_roundup64 resize: introduce partition type resize: introduce filter_part resize: add function find_partition resize: add function print_summmary resize: expose loop to calculate new partitions' positions resize: add function mbr_part_type resize: add function copy_partition resize: add function set_partition_bootable_and_id resize: add function expand_partition_content resize: add partition type LogicalPartition resize: add support to resize logical partitions mllib/common_utils.ml | 1 + mllib/common_utils.mli | 1 + resize/resize.ml | 217 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 161 insertions(+), 58 deletions(-) -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 01/13] resize: convert sectsize to int64
Because sectsize is used as int64 everywhere. Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 0485db0..e1634de 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -367,7 +367,7 @@ read the man page virt-resize(1). * way to do it is with g#blockdev_getsize64. *) let sectsize, insize, outsize - let sectsize = g#blockdev_getss "/dev/sdb" in + let sectsize = Int64.of_int (g#blockdev_getss "/dev/sdb") in let insize = g#blockdev_getsize64 "/dev/sda" in let outsize = g#blockdev_getsize64 "/dev/sdb" in if verbose then ( @@ -722,7 +722,7 @@ read the man page virt-resize(1). let first_part_start_sects match partitions with | { p_part = { G.part_start = start }} :: _ -> - start /^ Int64.of_int sectsize + start /^ sectsize | [] -> 0L in let max_bootloader_sects = Int64.of_int max_bootloader /^ 512L in @@ -737,7 +737,7 @@ read the man page virt-resize(1). (* Add up the total max. overhead. *) let overhead_sects start_overhead_sects +^ alignment_sects +^ gpt_end_sects in - Int64.of_int sectsize *^ overhead_sects in + sectsize *^ overhead_sects in let required = List.fold_left ( fun total p -> @@ -1019,8 +1019,6 @@ read the man page virt-resize(1). * on the target. *) let partitions - let sectsize = Int64.of_int sectsize in - let rec loop partnum start = function | p :: ps -> (match p.p_operation with -- 1.9.3
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- mllib/common_utils.ml | 1 + mllib/common_utils.mli | 1 + resize/resize.ml | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml index 5aa41c2..62d0782 100644 --- a/mllib/common_utils.ml +++ b/mllib/common_utils.ml @@ -33,6 +33,7 @@ let ( ~^ ) = Int64.lognot (* Return 'i' rounded up to the next multiple of 'a'. *) let roundup64 i a = let a = a -^ 1L in (i +^ a) &^ (~^ a) +let div_roundup64 i a = (i +^ a -^ 1L) /^ a let int_of_le32 str assert (String.length str = 4); diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli index e77fcd2..5bf4fba 100644 --- a/mllib/common_utils.mli +++ b/mllib/common_utils.mli @@ -28,6 +28,7 @@ val ( ~^ ) : int64 -> int64 (** Various int64 operators. *) val roundup64 : int64 -> int64 -> int64 +val div_roundup64 : int64 -> int64 -> int64 val int_of_le32 : string -> int64 val le32_of_int : int64 -> string diff --git a/resize/resize.ml b/resize/resize.ml index e1634de..794a574 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1026,7 +1026,7 @@ read the man page virt-resize(1). | OpIgnore | OpCopy -> (* same size *) (* Size in sectors. *) - let size = (p.p_part.G.part_size +^ sectsize -^ 1L) /^ sectsize in + let size = div_roundup64 p.p_part.G.part_size sectsize in (* Start of next partition + alignment. *) let end_ = start +^ size in let next = roundup64 end_ alignment in @@ -1040,7 +1040,7 @@ read the man page virt-resize(1). | OpResize newsize -> (* resized partition *) (* New size in sectors. *) - let size = (newsize +^ sectsize -^ 1L) /^ sectsize in + let size = div_roundup64 newsize sectsize in (* Start of next partition + alignment. *) let next = start +^ size in let next = roundup64 next alignment in -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 03/13] resize: introduce partition type
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resize/resize.ml b/resize/resize.ml index 794a574..e69e486 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -73,6 +73,9 @@ and partition_id | MBR_ID of int (* MBR ID. *) | GPT_Type of string (* GPT UUID. *) +type partition_type + | PrimaryPartition + let rec debug_partition p eprintf "%s:\n" p.p_name; eprintf "\tpartition data: %ld %Ld-%Ld (%Ld bytes)\n" -- 1.9.3
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index e69e486..660ac86 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -453,14 +453,19 @@ read the man page virt-resize(1). error (f_"the source disk has no partitions"); (* Filter out logical partitions. See note above. *) - let parts + let filter_part part_type parts match parttype with | GPT -> parts | MBR -> - List.filter (function - | { G.part_num = part_num } when part_num >= 5_l -> false - | _ -> true - ) parts in + match part_type with + | PrimaryPartition -> + List.filter (function + | { G.part_num = part_num } when part_num >= 5_l -> false + | _ -> true + ) parts + in + + let parts = filter_part PrimaryPartition parts in let partitions List.map ( -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 05/13] resize: add function find_partition
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 660ac86..8f0fbea 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -446,12 +446,9 @@ read the man page virt-resize(1). | MBR_ID _ | GPT_Type _ | No_ID -> false in - let partitions : partition list + let find_partitions part_type let parts = Array.to_list (g#part_list "/dev/sda") in - if List.length parts = 0 then - error (f_"the source disk has no partitions"); - (* Filter out logical partitions. See note above. *) let filter_part part_type parts match parttype with @@ -465,7 +462,7 @@ read the man page virt-resize(1). ) parts in - let parts = filter_part PrimaryPartition parts in + let parts = filter_part part_type parts in let partitions List.map ( @@ -495,11 +492,6 @@ read the man page virt-resize(1). p_target_start = 0L; p_target_end = 0L } ) parts in - if verbose then ( - eprintf "%d partitions found\n" (List.length partitions); - List.iter debug_partition partitions - ); - (* Check content isn't larger than partitions. If it is then * something has gone wrong and we shouldn't continue. Old * virt-resize didn't do these checks. @@ -531,6 +523,13 @@ read the man page virt-resize(1). partitions in + let partitions = find_partitions PrimaryPartition in + + if verbose then ( + eprintf "%d partitions found\n" (List.length partitions); + List.iter debug_partition partitions + ); + (* Build a data structure describing LVs on the source disk. *) let lvs let lvs = Array.to_list (g#lvs ()) in -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 06/13] resize: add function print_summmary
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 8f0fbea..37e4087 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -835,29 +835,29 @@ read the man page virt-resize(1). printf "**********\n\n"; printf "Summary of changes:\n\n"; - List.iter ( - fun ({ p_name = name; p_part = { G.part_size = oldsize }} as p) -> + let rec print_summary p let text match p.p_operation with | OpCopy -> - sprintf (f_"%s: This partition will be left alone.") name + sprintf (f_"%s: This partition will be left alone.") p.p_name | OpIgnore -> - sprintf (f_"%s: This partition will be created, but the contents will be ignored (ie. not copied to the target).") name + sprintf (f_"%s: This partition will be created, but the contents will be ignored (ie. not copied to the target).") p.p_name | OpDelete -> - sprintf (f_"%s: This partition will be deleted.") name + sprintf (f_"%s: This partition will be deleted.") p.p_name | OpResize newsize -> sprintf (f_"%s: This partition will be resized from %s to %s.") - name (human_size oldsize) (human_size newsize) ^ + p.p_name (human_size p.p_part.G.part_size) (human_size newsize) ^ if can_expand_content p.p_type then ( sprintf (f_" The %s on %s will be expanded using the '%s' method.") (string_of_partition_content_no_size p.p_type) - name + p.p_name (string_of_expand_content_method (expand_content_method p.p_type)) ) else "" in - wrap ~indent:4 (text ^ "\n\n") - ) partitions; + wrap ~indent:4 (text ^ "\n\n") in + + List.iter print_summary partitions; List.iter ( fun ({ lv_name = name } as lv) -> -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 07/13] resize: expose loop to calculate new partitions' positions
And introduce parameter create_surplus to indicate whether to create surplus partition or not. Later this parameter will be used by logical partitions. Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 37e4087..2ffd26e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1025,11 +1025,10 @@ read the man page virt-resize(1). * the final list just contains partitions that need to be created * on the target. *) - let partitions - let rec loop partnum start = function + let rec loop partnum start create_surplus = function | p :: ps -> (match p.p_operation with - | OpDelete -> loop partnum start ps (* skip p *) + | OpDelete -> loop partnum start create_surplus ps (* skip p *) | OpIgnore | OpCopy -> (* same size *) (* Size in sectors. *) @@ -1043,7 +1042,7 @@ read the man page virt-resize(1). partnum start (end_ -^ 1L); { p with p_target_start = start; p_target_end = end_ -^ 1L; - p_target_partnum = partnum } :: loop (partnum+1) next ps + p_target_partnum = partnum } :: loop (partnum+1) next create_surplus ps | OpResize newsize -> (* resized partition *) (* New size in sectors. *) @@ -1057,12 +1056,12 @@ read the man page virt-resize(1). partnum newsize start (next -^ 1L); { p with p_target_start = start; p_target_end = next -^ 1L; - p_target_partnum = partnum } :: loop (partnum+1) next ps + p_target_partnum = partnum } :: loop (partnum+1) next create_surplus ps ) | [] -> (* Create the surplus partition if there is room for it. *) - if extra_partition && surplus >= min_extra_partition then ( + if create_surplus && extra_partition && surplus >= min_extra_partition then ( [ { (* Since this partition has no source, this data is * meaningless and not used since the operation is @@ -1083,6 +1082,7 @@ read the man page virt-resize(1). else [] in + let partitions (* Choose the alignment of the first partition based on the * '--align-first' option. Old virt-resize used to always align this * to 64 sectors, but this causes boot failures unless we are able to @@ -1095,7 +1095,7 @@ read the man page virt-resize(1). (* Preserve the existing start, but convert to sectors. *) (List.hd partitions).p_part.G.part_start /^ sectsize in - loop 1 start partitions in + loop 1 start true partitions in (* Now partition the target disk. *) List.iter ( -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 08/13] resize: add function mbr_part_type
Function mbr_part_type returns one of "primary", "extended" and "logical". The type is used by parted when adding partitions. Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 2ffd26e..f57b2ff 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -50,6 +50,7 @@ type partition = { p_id : partition_id; (* Partition (MBR/GPT) ID. *) p_type : partition_content; (* Content type and content size. *) p_label : string option; (* Label/name. *) + p_part_num: int; (* partition number *) (* What we're going to do: *) mutable p_operation : partition_operation; @@ -487,7 +488,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_label = label; p_part_num = part_num; p_operation = OpCopy; p_target_partnum = 0; p_target_start = 0L; p_target_end = 0L } ) parts in @@ -1071,7 +1072,7 @@ read the man page virt-resize(1). p_part = { G.part_num = 0l; part_start = 0L; part_end = 0L; part_size = 0L }; p_bootable = false; p_id = No_ID; p_type = ContentUnknown; - p_label = None; + p_label = None; p_part_num = 0; (* Target information is meaningful. *) p_operation = OpIgnore; @@ -1097,10 +1098,15 @@ read the man page virt-resize(1). loop 1 start true partitions in + let mbr_part_type x + if x.p_part_num <= 4 && x.p_type <> ContentExtendedPartition then "primary" + else if x.p_part_num <= 4 && x.p_type = ContentExtendedPartition then "extended" + else "logical" in + (* Now partition the target disk. *) List.iter ( fun p -> - g#part_add "/dev/sdb" "primary" p.p_target_start p.p_target_end + g#part_add "/dev/sdb" (mbr_part_type p) p.p_target_start p.p_target_end ) partitions; (* Copy over the data. *) -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 09/13] resize: add function copy_partition
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index f57b2ff..3db9291 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1110,8 +1110,7 @@ read the man page virt-resize(1). ) partitions; (* Copy over the data. *) - List.iter ( - fun p -> + let copy_partition p match p.p_operation with | OpCopy | OpResize _ -> (* XXX Old code had 'when target_partnum > 0', but it appears @@ -1145,7 +1144,8 @@ read the man page virt-resize(1). g#copy_device_to_device ~srcoffset ~size:copysize "/dev/sda" target ) | OpIgnore | OpDelete -> () - ) partitions; + in + List.iter copy_partition partitions; (* Set bootable and MBR IDs. Do this *after* copying over the data, * so that we can magically change the primary partition to an extended -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 10/13] resize: add function set_partition_bootable_and_id
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 3db9291..64697f9 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1151,8 +1151,7 @@ read the man page virt-resize(1). * so that we can magically change the primary partition to an extended * partition if necessary. *) - List.iter ( - fun p -> + let set_partition_bootable_and_id p if p.p_bootable then g#part_set_bootable "/dev/sdb" p.p_target_partnum true; @@ -1168,7 +1167,8 @@ read the man page virt-resize(1). | MBR, MBR_ID mbr_id -> g#part_set_mbr_id "/dev/sdb" p.p_target_partnum mbr_id | GPT, (No_ID|MBR_ID _) | MBR, (No_ID|GPT_Type _) -> () - ) partitions; + in + List.iter set_partition_bootable_and_id partitions; (* Fix the bootloader if we aligned the first partition. *) if align_first_partition_and_fix_bootloader then ( -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 11/13] resize: add function expand_partition_content
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 64697f9..3290ba0 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1265,8 +1265,7 @@ read the man page virt-resize(1). in (* Expand partition content as required. *) - List.iter ( - function + let expand_partition_content = function | ({ p_operation = OpResize _ } as p) when can_expand_content p.p_type -> let source = p.p_name in @@ -1282,7 +1281,8 @@ read the man page virt-resize(1). do_expand_content target meth | { p_operation = (OpCopy | OpIgnore | OpDelete | OpResize _) } -> () - ) partitions; + in + List.iter expand_partition_content partitions; (* Expand logical volume content as required. *) List.iter ( -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 12/13] resize: add partition type LogicalPartition
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 3290ba0..6113095 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -76,6 +76,7 @@ and partition_id type partition_type | PrimaryPartition + | LogicalPartition let rec debug_partition p eprintf "%s:\n" p.p_name; @@ -461,6 +462,11 @@ read the man page virt-resize(1). | { G.part_num = part_num } when part_num >= 5_l -> false | _ -> true ) parts + | LogicalPartition -> + List.filter (function + | { G.part_num = part_num } when part_num >= 5_l -> true + | _ -> false + ) parts in let parts = filter_part part_type parts in @@ -525,10 +531,12 @@ read the man page virt-resize(1). partitions in let partitions = find_partitions PrimaryPartition in + let logical_partitions = find_partitions LogicalPartition in if verbose then ( - eprintf "%d partitions found\n" (List.length partitions); - List.iter debug_partition partitions + eprintf "%d partitions found\n" (List.length partitions + List.length logical_partitions); + List.iter debug_partition partitions; + List.iter debug_partition logical_partitions ); (* Build a data structure describing LVs on the source disk. *) -- 1.9.3
Hu Tao
2014-Sep-19 07:39 UTC
[Libguestfs] [PATCH v2 13/13] resize: add support to resize logical partitions
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> --- resize/resize.ml | 102 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 6113095..cb13858 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -606,6 +606,8 @@ read the man page virt-resize(1). let hash = Hashtbl.create 13 in List.iter (fun ({ p_name = name } as p) -> Hashtbl.add hash name p) partitions; + List.iter (fun ({ p_name = name } as p) -> Hashtbl.add hash name p) + logical_partitions; fun ~option name -> let name if String.length name < 5 || String.sub name 0 5 <> "/dev/" then @@ -729,8 +731,10 @@ read the man page virt-resize(1). (* We need some overhead for partitioning. *) let overhead let maxl64 = List.fold_left max 0L in + let alignment = if alignment = 1L then 2L else alignment in let nr_partitions = List.length partitions in + let nr_partitions = nr_partitions + List.length logical_partitions in let gpt_start_sects = 64L in let gpt_end_sects = gpt_start_sects in @@ -758,12 +762,24 @@ read the man page virt-resize(1). let required = List.fold_left ( fun total p -> let newsize + (* don't counting extended partition but logical partitions + * below, because we may extend and resize logical partitions. *) + if p.p_type = ContentExtendedPartition then 0L else + match p.p_operation with + | OpCopy | OpIgnore -> p.p_part.G.part_size + | OpDelete -> 0L + | OpResize newsize -> newsize in + total +^ newsize + ) 0L partitions in + let required = required +^ List.fold_left ( + fun total p -> + let newsize match p.p_operation with | OpCopy | OpIgnore -> p.p_part.G.part_size | OpDelete -> 0L | OpResize newsize -> newsize in total +^ newsize - ) 0L partitions in + ) 0L logical_partitions in let surplus = outsize -^ (required +^ overhead) in @@ -809,6 +825,28 @@ read the man page virt-resize(1). ) ); + (* handle resizing of logical partitions *) + List.iter ( + fun p -> + if p.p_type = ContentExtendedPartition then ( + let alignment = if alignment = 1L then 2L else alignment in + let size = roundup64 p.p_part.G.part_size sectsize in + let logical_sizes = List.fold_left ( + fun total p -> + match p.p_operation with + | OpDelete -> total +^ 0L + | OpCopy | OpIgnore -> total +^ (roundup64 p.p_part.G.part_size (alignment *^ sectsize)) + | OpResize newsize -> total +^ (roundup64 newsize (alignment *^ sectsize)) + ) 0L logical_partitions in + (* the first logical partition is aligned *) + let logical_sizes = logical_sizes +^ alignment *^ sectsize in + if logical_sizes > size then + p.p_operation <- OpResize logical_sizes + (* don't touch the extended partition if logical sizes less + * then the original size *) + ) + ) partitions; + (* Calculate the final surplus. * At this point, this number must be >= 0. *) @@ -867,6 +905,7 @@ read the man page virt-resize(1). wrap ~indent:4 (text ^ "\n\n") in List.iter print_summary partitions; + List.iter print_summary logical_partitions; List.iter ( fun ({ lv_name = name } as lv) -> @@ -1040,6 +1079,7 @@ read the man page virt-resize(1). | OpDelete -> loop partnum start create_surplus ps (* skip p *) | OpIgnore | OpCopy -> (* same size *) + let start = roundup64 start 2L in (* Size in sectors. *) let size = div_roundup64 p.p_part.G.part_size sectsize in (* Start of next partition + alignment. *) @@ -1054,6 +1094,7 @@ read the man page virt-resize(1). p_target_partnum = partnum } :: loop (partnum+1) next create_surplus ps | OpResize newsize -> (* resized partition *) + let start = roundup64 start 2L in (* New size in sectors. *) let size = div_roundup64 newsize sectsize in (* Start of next partition + alignment. *) @@ -1064,7 +1105,9 @@ read the man page virt-resize(1). eprintf "target partition %d: resize: newsize=%Ld start=%Ld end=%Ld\n%!" partnum newsize start (next -^ 1L); - { p with p_target_start = start; p_target_end = next -^ 1L; + (* there must be a at least 1-sector gap between logical + * partitions otherwise parted refused to add logical partition *) + { p with p_target_start = start; p_target_end = next -^ 2L; p_target_partnum = partnum } :: loop (partnum+1) next create_surplus ps ) @@ -1106,6 +1149,16 @@ read the man page virt-resize(1). loop 1 start true partitions in + let logical_partitions + let start = List.fold_left ( + fun total p -> + match p.p_type with + | ContentExtendedPartition -> total +^ p.p_target_start | _ -> 0L ) 0L partitions + in + (* align logical partitions, too *) + let start = roundup64 (start +^ 1L) alignment in + loop 5 start false logical_partitions in + let mbr_part_type x if x.p_part_num <= 4 && x.p_type <> ContentExtendedPartition then "primary" else if x.p_part_num <= 4 && x.p_type = ContentExtendedPartition then "extended" @@ -1117,9 +1170,35 @@ read the man page virt-resize(1). g#part_add "/dev/sdb" (mbr_part_type p) p.p_target_start p.p_target_end ) partitions; + List.iter ( + fun p -> + try + g#part_add "/dev/sdb" "logical" p.p_target_start p.p_target_end + with G.Error msg -> (eprintf "original error: %s\n" msg) + ) logical_partitions; + + let g + g#shutdown (); + g#close (); + + let g = new G.guestfs () in + if trace then g#set_trace true; + if verbose then g#set_verbose true; + let _, { URI.path = path; protocol = protocol; + server = server; username = username; + password = password } = infile in + g#add_drive ?format ~readonly:true ~protocol ?server ?username ?secret:password path; + (* The output disk is being created, so use cache=unsafe here. *) + g#add_drive ?format:output_format ~readonly:false ~cachemode:"unsafe" + outfile; + if not quiet then Progress.set_up_progress_bar ~machine_readable g; + g#launch (); + g in + (* Copy over the data. *) let copy_partition p match p.p_operation with + | OpCopy | OpResize _ -> (* XXX Old code had 'when target_partnum > 0', but it appears * to have served no purpose since the field could never be 0 @@ -1142,18 +1221,12 @@ read the man page virt-resize(1). | ContentUnknown | ContentPV _ | ContentFS _ -> g#copy_device_to_device ~size:copysize ~sparse source target - | ContentExtendedPartition -> - (* You can't just copy an extended partition by name, eg. - * source = "/dev/sda2", because the device name only covers - * the first 1K of the partition. Instead, copy the - * source bytes from the parent disk (/dev/sda). - *) - let srcoffset = p.p_part.G.part_start in - g#copy_device_to_device ~srcoffset ~size:copysize "/dev/sda" target + | ContentExtendedPartition -> () ) | OpIgnore | OpDelete -> () in List.iter copy_partition partitions; + List.iter copy_partition logical_partitions; (* Set bootable and MBR IDs. Do this *after* copying over the data, * so that we can magically change the primary partition to an extended @@ -1177,6 +1250,7 @@ read the man page virt-resize(1). | GPT, (No_ID|MBR_ID _) | MBR, (No_ID|GPT_Type _) -> () in List.iter set_partition_bootable_and_id partitions; + List.iter set_partition_bootable_and_id logical_partitions; (* Fix the bootloader if we aligned the first partition. *) if align_first_partition_and_fix_bootloader then ( @@ -1229,6 +1303,13 @@ read the man page virt-resize(1). can_expand_content p.p_type | { p_operation = (OpCopy | OpIgnore | OpDelete) } -> false ) partitions + || + List.exists ( + function + | ({ p_operation = OpResize _ } as p) -> + can_expand_content p.p_type + | { p_operation = (OpCopy | OpIgnore | OpDelete) } -> false + ) logical_partitions || List.exists ( function | ({ lv_operation = LVOpExpand } as lv) -> @@ -1291,6 +1372,7 @@ read the man page virt-resize(1). -> () in List.iter expand_partition_content partitions; + List.iter expand_partition_content logical_partitions; (* Expand logical volume content as required. *) List.iter ( -- 1.9.3
Hu Tao
2014-Sep-19 07:45 UTC
Re: [Libguestfs] [PATCH v2 00/13] virt-resize: add support for resizing MBR logical partitions
The test script: #!/bin/bash - set -e # test case 1: only primary partitions guestfish -N disk <<EOF part-init /dev/sda mbr part-add /dev/sda p 64 255 part-add /dev/sda p 256 -128 EOF virt-filesystems --all --long -h -a test1.img truncate -s 1G test2.img virt-resize --expand /dev/sda1 test1.img test2.img if [ ! $? -eq 0 ]; then exit 1; fi rm -rf test1.img test2.img # test case 2: only logical partitions guestfish -N disk <<EOF part-init /dev/sda mbr part-add /dev/sda extended 64 2048 part-add /dev/sda logical 512 1024 part-add /dev/sda logical 1026 2048 EOF virt-filesystems --all --long -h -a test1.img truncate -s 1G test2.img virt-resize --expand /dev/sda5 --resize /dev/sda6=+2000% test1.img test2.img if [ ! $? -eq 0 ]; then exit 1; fi rm -rf test1.img test2.img # test case 3: primary partitions and logical partitions guestfish -N disk <<EOF part-init /dev/sda mbr part-add /dev/sda p 64 255 part-add /dev/sda p 256 1024 part-add /dev/sda extended 1026 4096 part-add /dev/sda logical 1028 2048 part-add /dev/sda logical 2050 4096 EOF virt-filesystems --all --long -h -a test1.img truncate -s 1G test2.img virt-resize --expand /dev/sda5 --resize /dev/sda6=+1000% --resize /dev/sda1=+20% test1.img test2.img
Richard W.M. Jones
2014-Sep-19 12:57 UTC
Re: [Libguestfs] [PATCH v2 02/13] add function div_roundup64
Thanks - I have pushed 01 and 02. 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
2014-Sep-19 13:04 UTC
Re: [Libguestfs] [PATCH v2 06/13] resize: add function print_summmary
On Fri, Sep 19, 2014 at 03:39:08PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 18 +++++++++--------- > 1 file changed, 9 insertions(+), 9 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index 8f0fbea..37e4087 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -835,29 +835,29 @@ read the man page virt-resize(1). > printf "**********\n\n"; > printf "Summary of changes:\n\n"; > > - List.iter ( > - fun ({ p_name = name; p_part = { G.part_size = oldsize }} as p) -> > + let rec print_summary p > let text > match p.p_operation with > | OpCopy -> > - sprintf (f_"%s: This partition will be left alone.") name > + sprintf (f_"%s: This partition will be left alone.") p.p_name > | OpIgnore -> > - sprintf (f_"%s: This partition will be created, but the contents will be ignored (ie. not copied to the target).") name > + sprintf (f_"%s: This partition will be created, but the contents will be ignored (ie. not copied to the target).") p.p_name > | OpDelete -> > - sprintf (f_"%s: This partition will be deleted.") name > + sprintf (f_"%s: This partition will be deleted.") p.p_name > | OpResize newsize -> > sprintf (f_"%s: This partition will be resized from %s to %s.") > - name (human_size oldsize) (human_size newsize) ^ > + p.p_name (human_size p.p_part.G.part_size) (human_size newsize) ^ > if can_expand_content p.p_type then ( > sprintf (f_" The %s on %s will be expanded using the '%s' method.") > (string_of_partition_content_no_size p.p_type) > - name > + p.p_name > (string_of_expand_content_method > (expand_content_method p.p_type)) > ) else "" in > > - wrap ~indent:4 (text ^ "\n\n") > - ) partitions; > + wrap ~indent:4 (text ^ "\n\n") in > + > + List.iter print_summary partitions; > > List.iter ( > fun ({ lv_name = name } as lv) -> > -- > 1.9.3ACK. I have pushed this one. Thanks, 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
2014-Sep-19 13:13 UTC
Re: [Libguestfs] [PATCH v2 07/13] resize: expose loop to calculate new partitions' positions
On Fri, Sep 19, 2014 at 03:39:09PM +0800, Hu Tao wrote:> And introduce parameter create_surplus to indicate whether to > create surplus partition or not. Later this parameter will be > used by logical partitions. > > Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 14 +++++++------- > 1 file changed, 7 insertions(+), 7 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index 37e4087..2ffd26e 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -1025,11 +1025,10 @@ read the man page virt-resize(1). > * the final list just contains partitions that need to be created > * on the target. > *) > - let partitions > - let rec loop partnum start = function > + let rec loop partnum start create_surplus = functionA couple of style comments on this one. First of all, you can't really call this function 'loop', except in the case where it's immediately used. This function needs to be given a real name. Secondly it's better to use a labelled parameter for create_surplus, so that it's obvious at the calling site what that parameter (true/false) means. - let partitions - let rec loop partnum start = function + let rec calculate_target_partitions partnum start ~create_surplus = function and later when it is called: - | OpDelete -> loop partnum start ps (* skip p *) + | OpDelete -> create_target_partitions partnum start ~create_surplus ps (* skip p *) [...] - loop 1 start partitions in + create_target_partitions 1 start ~create_surplus:true partitions in Hope that's clear. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2014-Sep-19 13:21 UTC
Re: [Libguestfs] [PATCH v2 08/13] resize: add function mbr_part_type
On Fri, Sep 19, 2014 at 03:39:10PM +0800, Hu Tao wrote:> Function mbr_part_type returns one of "primary", "extended" and > "logical". The type is used by parted when adding partitions. > > Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 12 +++++++++--- > 1 file changed, 9 insertions(+), 3 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index 2ffd26e..f57b2ff 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -50,6 +50,7 @@ type partition = { > p_id : partition_id; (* Partition (MBR/GPT) ID. *) > p_type : partition_content; (* Content type and content size. *) > p_label : string option; (* Label/name. *) > + p_part_num: int; (* partition number *)I don't think it's necessary to store p_part_num in the main partitions struct. Instead you can get to the partition number using: p.p_part.G.part_num For example, mbr_part_type could be written: let mbr_part_type x if x.p_part.G.part_num <= 4 && x.p_type <> ContentExtendedPartition then "primary" [etc]> + let mbr_part_type x > + if x.p_part_num <= 4 && x.p_type <> ContentExtendedPartition then "primary" > + else if x.p_part_num <= 4 && x.p_type = ContentExtendedPartition then "extended" > + else "logical" in > + > (* Now partition the target disk. *) > List.iter ( > fun p -> > - g#part_add "/dev/sdb" "primary" p.p_target_start p.p_target_end > + g#part_add "/dev/sdb" (mbr_part_type p) p.p_target_start p.p_target_end > ) partitions;The big problem with this is I think it doesn't work properly for GPT. GPT has no idea what "extended" is -- such a concept does not exist. So if you passed a GPT guest to virt-resize with >= 5 partitions in it, then virt-resize will not work. I think you need to check the partition table type somewhere. 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
2014-Sep-19 13:22 UTC
Re: [Libguestfs] [PATCH v2 09/13] resize: add function copy_partition
On Fri, Sep 19, 2014 at 03:39:11PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index f57b2ff..3db9291 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -1110,8 +1110,7 @@ read the man page virt-resize(1). > ) partitions; > > (* Copy over the data. *) > - List.iter ( > - fun p -> > + let copy_partition p > match p.p_operation with > | OpCopy | OpResize _ -> > (* XXX Old code had 'when target_partnum > 0', but it appears > @@ -1145,7 +1144,8 @@ read the man page virt-resize(1). > g#copy_device_to_device ~srcoffset ~size:copysize "/dev/sda" target > ) > | OpIgnore | OpDelete -> () > - ) partitions; > + in > + List.iter copy_partition partitions; > > (* Set bootable and MBR IDs. Do this *after* copying over the data, > * so that we can magically change the primary partition to an extendedACKed and pushed. 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
2014-Sep-19 13:23 UTC
Re: [Libguestfs] [PATCH v2 10/13] resize: add function set_partition_bootable_and_id
On Fri, Sep 19, 2014 at 03:39:12PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index 3db9291..64697f9 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -1151,8 +1151,7 @@ read the man page virt-resize(1). > * so that we can magically change the primary partition to an extended > * partition if necessary. > *) > - List.iter ( > - fun p -> > + let set_partition_bootable_and_id p > if p.p_bootable then > g#part_set_bootable "/dev/sdb" p.p_target_partnum true; > > @@ -1168,7 +1167,8 @@ read the man page virt-resize(1). > | MBR, MBR_ID mbr_id -> > g#part_set_mbr_id "/dev/sdb" p.p_target_partnum mbr_id > | GPT, (No_ID|MBR_ID _) | MBR, (No_ID|GPT_Type _) -> () > - ) partitions; > + in > + List.iter set_partition_bootable_and_id partitions; > > (* Fix the bootloader if we aligned the first partition. *) > if align_first_partition_and_fix_bootloader then ( > -- > 1.9.3ACKed and pushed. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
Richard W.M. Jones
2014-Sep-19 13:24 UTC
Re: [Libguestfs] [PATCH v2 11/13] resize: add function expand_partition_content
On Fri, Sep 19, 2014 at 03:39:13PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index 64697f9..3290ba0 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -1265,8 +1265,7 @@ read the man page virt-resize(1). > in > > (* Expand partition content as required. *) > - List.iter ( > - function > + let expand_partition_content = function > | ({ p_operation = OpResize _ } as p) > when can_expand_content p.p_type -> > let source = p.p_name in > @@ -1282,7 +1281,8 @@ read the man page virt-resize(1). > do_expand_content target meth > | { p_operation = (OpCopy | OpIgnore | OpDelete | OpResize _) } > -> () > - ) partitions; > + in > + List.iter expand_partition_content partitions; > > (* Expand logical volume content as required. *) > List.iter ( > -- > 1.9.3ACKed and pushed. 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
Richard W.M. Jones
2014-Sep-19 13:34 UTC
Re: [Libguestfs] [PATCH v2 04/13] resize: introduce filter_part
On Fri, Sep 19, 2014 at 03:39:06PM +0800, Hu Tao wrote:> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> > --- > resize/resize.ml | 15 ++++++++++----- > 1 file changed, 10 insertions(+), 5 deletions(-) > > diff --git a/resize/resize.ml b/resize/resize.ml > index e69e486..660ac86 100644 > --- a/resize/resize.ml > +++ b/resize/resize.ml > @@ -453,14 +453,19 @@ read the man page virt-resize(1). > error (f_"the source disk has no partitions"); > > (* Filter out logical partitions. See note above. *) > - let parts > + let filter_part part_type parts > match parttype with > | GPT -> parts > | MBR -> > - List.filter (function > - | { G.part_num = part_num } when part_num >= 5_l -> false > - | _ -> true > - ) parts in > + match part_type with > + | PrimaryPartition -> > + List.filter (function > + | { G.part_num = part_num } when part_num >= 5_l -> false > + | _ -> true > + ) parts > + in > + > + let parts = filter_part PrimaryPartition parts in > > let partitions > List.map ( > -- > 1.9.3The code isn't particularly natural for OCaml. There's a built-in List.filter function which basically does this already, and it's relatively easy to use too: let parts List.filter (fun p -> parttype <> MBR || p.G.part_num <= 4_l) parts in (You can completely remove the filter_part function). To filter only logical partitions (in patch 12), you will need to do: let parts List.filter (fun p -> parttype = MBR && p.G.part_num >= 5_l) parts in (BTW I don't think that patch 12 would work correctly for GPT) Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org