Signed-off-by: Hu Tao <hutao(a)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