[Libguestfs] [PATCH v2 13/13] resize: add support to resize logical partitions

Hu Tao hutao at cn.fujitsu.com
Fri Sep 19 07:39:15 UTC 2014


Signed-off-by: Hu Tao <hutao at 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




More information about the Libguestfs mailing list