[PATCH v2 00/11] virt-resize: add support for resizing MBR logical partitions
In current virt-resize, only primary partitions(including extended partition) are supported. They are collected in an array for resize operations. Logical partitions are not supported. This series add support for resizing logical partitions. v2: 1) Add 3 variables to describe relationship of logical and extended partitions: - partitions flat list of primary partitions (as now, the global 'partitions'). extended partitions is essentially primary partition - logical_partitions flat list of logical partitions - extended_partition one MBR extended partition 2) reserve enough size when resizing logical partitions Original patches by Hu Tao at: https://www.redhat.com/archives/libguestfs/2014-October/msg00238.html Chen Hanxiao (11): resize: move loop check from find_partitions resize: add logical_partitions and extended_partition resize: updated find_partition to support logical partition resize: add support for logical partitions for calculate_surplus resize: handle resize of logical partitions resize: add support for logical partitions of calculate_target_partitions resize: calculate_target_partitions for logical partitions resize: parted and copy logical partitions resize: more misc ops on logical partition resize: add support resize extended partition resize: test: add support for resizing extended and logical partitions resize/resize.ml | 189 ++++++++++++++++++++++++++++++++++----------- resize/test-virt-resize.pl | 32 ++------ 2 files changed, 149 insertions(+), 72 deletions(-) -- 2.1.0
As logical partitions laid inside extended partition, overlap check will not work. make loop as a individual function, which could do a seperate check on logical/extended partitions. Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 602a583..4c97405 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -521,20 +521,20 @@ read the man page virt-resize(1). | _ -> () ) partitions; - (* Check partitions don't overlap. *) - let rec loop end_of_prev = function - | [] -> () - | { p_name = name; p_part = { G.part_start = part_start } } :: _ - when end_of_prev > part_start -> - error (f_"%s: this partition overlaps the previous one") name - | { p_part = { G.part_end = part_end } } :: parts -> loop part_end parts - in - loop 0L partitions; - partitions in let partitions = find_partitions () in + (* Check partitions don't overlap. *) + let rec loop end_of_prev = function + | [] -> () + | { p_name = name; p_part = { G.part_start = part_start } } :: _ + when end_of_prev > part_start -> + error (f_"%s: this partition overlaps the previous one") name + | { p_part = { G.part_end = part_end } } :: parts -> loop part_end parts + in + loop 0L partitions; + if verbose () then ( printf "%d partitions found\n" (List.length partitions); List.iter (debug_partition ~sectsize) partitions -- 2.1.0
For MBR, logical partitions laid inside extended partition. Add 3 variables to describe this: - partitions flat list of primary partitions (as now, the global 'partitions'). extended partitions is essentially primary partition - logical_partitions flat list of logical partitions - extended_partition one MBR extended partition Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 4c97405..d7a8ce1 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -26,19 +26,16 @@ module G = Guestfs (* Minimum surplus before we create an extra partition. *) let min_extra_partition = 10L *^ 1024L *^ 1024L +(* mbr extended partition *) +let extended_partition_list = [] + (* Command line argument parsing. *) type align_first_t = [ `Never | `Always | `Auto ] (* Source partition type. *) type parttype = MBR | GPT -(* Data structure describing the source disk's partition layout. - * - * NOTE: For MBR, only primary/extended partitions are tracked here. - * Logical partitions are contained within an extended partition, and - * we don't track them (they are just copied within the extended - * partition). For the same reason we cannot resize logical partitions. - *) +(* Data structure describing the source disk's partition layout. *) type partition = { p_name : string; (* Device name, like /dev/sda1. *) p_part : G.partition; (* SOURCE partition data from libguestfs. *) @@ -496,12 +493,6 @@ read the man page virt-resize(1). p_target_start = 0L; p_target_end = 0L } ) parts in - (* Filter out logical partitions. See note above. *) - let partitions = - (* for GPT, all partitions are regarded as Primary Partition, - * e.g. there is no Extended Partition or Logical Partition. *) - List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition) partitions in - (* 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. @@ -533,11 +524,29 @@ read the man page virt-resize(1). error (f_"%s: this partition overlaps the previous one") name | { p_part = { G.part_end = part_end } } :: parts -> loop part_end parts in + + let extended_partition_list = List.append + extended_partition_list + (List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = ExtendedPartition) partitions) in + let extended_partition = if (List.length extended_partition_list) > 0 then + List.hd extended_partition_list else List.hd partitions in + let logical_partitions = + List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = LogicalPartition) partitions in + (* Filter out logical partitions. See note above. *) + let partitions = + (* for GPT, all partitions are regarded as Primary Partition, + * e.g. there is no Extended Partition or Logical Partition. *) + List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition) partitions in + loop 0L partitions; + loop 0L logical_partitions; if verbose () then ( printf "%d partitions found\n" (List.length partitions); - List.iter (debug_partition ~sectsize) partitions + List.iter (debug_partition ~sectsize) partitions; + List.iter (debug_partition ~sectsize) logical_partitions; + if (List.length extended_partition_list) > 0 then + printf "%s is extended partition\n" extended_partition.p_name ); (* Build a data structure describing LVs on the source disk. *) -- 2.1.0
On Wed, May 20, 2015 at 06:51:28AM -0400, Chen Hanxiao wrote:
For MBR, logical partitions laid inside extended partition. Add 3 variables to describe this: - partitions flat list of primary partitions (as now, the global 'partitions'). extended partitions is essentially primary partition
- logical_partitions flat list of logical partitions
- extended_partition one MBR extended partition
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/resize/resize.ml b/resize/resize.ml index 4c97405..d7a8ce1 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -26,19 +26,16 @@ module G = Guestfs (* Minimum surplus before we create an extra partition. *) let min_extra_partition = 10L *^ 1024L *^ 1024L
+(* mbr extended partition *) +let extended_partition_list = []
This assignment doesn't really do anything. 'let' bindings in OCaml don't create global variables. This just makes 'extended_partition_list' be a name for the empty list, ... [...]
+ let extended_partition_list = List.append + extended_partition_list
... up to here, where you create a second name, also 'extended_partition_list', completely independent from the one above, which for no reason appends to the empty list. What *doesn't* happen is 'extended_partition_list' that you created at the top is modified.
+ let extended_partition = if (List.length extended_partition_list) > 0 then + List.hd extended_partition_list else List.hd partitions in
You could write this more naturally as: let extended_partition = match extended_partition_list with | h :: _ -> h | [] -> List.hd partitions in Rewriting it like this also makes the bug in this code clearer: why is extended_partition initialized to the first partition, if there are no extended partitions? I think you probably meant to write: let extended_partition = match extended_partition_list with | h :: _ -> Some h | [] -> None in
+ let logical_partitions = + List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = LogicalPartition) partitions in + (* Filter out logical partitions. See note above. *) + let partitions = + (* for GPT, all partitions are regarded as Primary Partition, + * e.g. there is no Extended Partition or Logical Partition. *) + List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition) partitions in
Although this is code is correct, it is clearer and shorter to write the test using a separate function, so it would become: let is_logical_partition p = parttype = MBR && p.p_mbr_p_type = LogicalPartition in let logical_partitions = List.filter is_logical_partition partitions in let partitions = List.filter (fun p -> not (is_logical_partition p)) partitions in 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
In data giovedì 28 maggio 2015 12:06:18, Richard W.M. Jones ha scritto:
+ let logical_partitions = + List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = LogicalPartition) partitions in + (* Filter out logical partitions. See note above. *) + let partitions = + (* for GPT, all partitions are regarded as Primary Partition, + * e.g. there is no Extended Partition or Logical Partition. *) + List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition) partitions in
Although this is code is correct, it is clearer and shorter to write the test using a separate function, so it would become:
let is_logical_partition p = parttype = MBR && p.p_mbr_p_type = LogicalPartition in let logical_partitions = List.filter is_logical_partition partitions in let partitions = List.filter (fun p -> not (is_logical_partition p)) partitions in
Or, even better: let logical_partitions, partitions = List.partition is_logical_partition partitions in -- Pino Toscano
On Thu, May 28, 2015 at 01:13:28PM +0200, Pino Toscano wrote:
In data giovedì 28 maggio 2015 12:06:18, Richard W.M. Jones ha scritto:
+ let logical_partitions = + List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = LogicalPartition) partitions in + (* Filter out logical partitions. See note above. *) + let partitions = + (* for GPT, all partitions are regarded as Primary Partition, + * e.g. there is no Extended Partition or Logical Partition. *) + List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition) partitions in
Although this is code is correct, it is clearer and shorter to write the test using a separate function, so it would become:
let is_logical_partition p = parttype = MBR && p.p_mbr_p_type = LogicalPartition in let logical_partitions = List.filter is_logical_partition partitions in let partitions = List.filter (fun p -> not (is_logical_partition p)) partitions in
Or, even better:
let logical_partitions, partitions = List.partition is_logical_partition partitions in
Indeed, that is better :-) 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
-----Original Message----- From: libguestfs-bounces@redhat.com [mailto:libguestfs-bounces@redhat.com] On Behalf Of Richard W.M. Jones Sent: Thursday, May 28, 2015 7:18 PM To: Pino Toscano Cc: libguestfs@redhat.com Subject: Re: [Libguestfs] [PATCH v2 02/11] resize: add logical_partitions and extended_partition
In data giovedì 28 maggio 2015 12:06:18, Richard W.M. Jones ha scritto:
+ let logical_partitions = + List.filter (fun p -> parttype = MBR && p.p_mbr_p_type = LogicalPartition)
+ (* Filter out logical partitions. See note above. *) + let partitions = + (* for GPT, all partitions are regarded as Primary Partition, + * e.g. there is no Extended Partition or Logical Partition. *) + List.filter (fun p -> parttype <> MBR || p.p_mbr_p_type <> LogicalPartition)
On Thu, May 28, 2015 at 01:13:28PM +0200, Pino Toscano wrote: partitions in partitions in
Although this is code is correct, it is clearer and shorter to write the test using a separate function, so it would become:
let is_logical_partition p = parttype = MBR && p.p_mbr_p_type = LogicalPartition in let logical_partitions = List.filter is_logical_partition partitions in let partitions = List.filter (fun p -> not (is_logical_partition p)) partitions in
Or, even better:
let logical_partitions, partitions = List.partition is_logical_partition partitions in
Indeed, that is better :-)
Thanks for your comments and hints in Ocaml. That's what I want to write. Will fix in v3. Regards, - Chen
As we splited the original partitions list to partitions and logical_partitions. Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resize/resize.ml b/resize/resize.ml index d7a8ce1..92f7304 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -616,6 +616,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 -- 2.1.0
On Wed, May 20, 2015 at 06:51:29AM -0400, Chen Hanxiao wrote:
As we splited the original partitions list to partitions and logical_partitions.
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/resize/resize.ml b/resize/resize.ml index d7a8ce1..92f7304 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -616,6 +616,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
If we're going to group these patches together, this should be merged into the previous patch. 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
-----Original Message----- From: Richard W.M. Jones [mailto:rjones@redhat.com] Sent: Thursday, May 28, 2015 7:07 PM To: Chen, Hanxiao/陈 晗霄 Cc: libguestfs@redhat.com Subject: Re: [Libguestfs] [PATCH v2 03/11] resize: updated find_partition to support logical partition
On Wed, May 20, 2015 at 06:51:29AM -0400, Chen Hanxiao wrote:
As we splited the original partitions list to partitions and logical_partitions.
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/resize/resize.ml b/resize/resize.ml index d7a8ce1..92f7304 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -616,6 +616,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
If we're going to group these patches together, this should be merged into the previous patch.
Sure. Regards, - Chen
Add support for logical partitions. - count number of logical_partition (we've split partitions list) - don't count size of extended partition For it'll duplicate with logical partition, we'll count it later - we need at leat 1 gap between logical partitions. so --aligment=1 will be increased by 1 Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 92f7304..a0ed713 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -741,8 +741,10 @@ read the man page virt-resize(1). (* We need some overhead for partitioning. *) let overhead = let maxl64 = List.fold_left max 0L in + (* We need at least 1 sector gap between logical partitions *) + let alignment = if alignment = 1L then 2L else alignment in - let nr_partitions = List.length partitions in + let nr_partitions = List.length partitions + List.length logical_partitions in let gpt_start_sects = 64L in let gpt_end_sects = gpt_start_sects in @@ -770,12 +772,23 @@ read the man page virt-resize(1). let required = List.fold_left ( fun total p -> let newsize = + (* size of extended partition is calculated seperately *) + 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 -- 2.1.0
On Wed, May 20, 2015 at 06:51:30AM -0400, Chen Hanxiao wrote:
Add support for logical partitions. - count number of logical_partition (we've split partitions list) - don't count size of extended partition For it'll duplicate with logical partition, we'll count it later - we need at leat 1 gap between logical partitions. so --aligment=1 will be increased by 1
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/resize/resize.ml b/resize/resize.ml index 92f7304..a0ed713 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -741,8 +741,10 @@ read the man page virt-resize(1). (* We need some overhead for partitioning. *) let overhead = let maxl64 = List.fold_left max 0L in + (* We need at least 1 sector gap between logical partitions *) + let alignment = if alignment = 1L then 2L else alignment in
- let nr_partitions = List.length partitions in + let nr_partitions = List.length partitions + List.length logical_partitions in
I don't understand this at all. Why do logical partitions count towards the surplus? I don't think they do. Rich.
let gpt_start_sects = 64L in let gpt_end_sects = gpt_start_sects in @@ -770,12 +772,23 @@ read the man page virt-resize(1). let required = List.fold_left ( fun total p -> let newsize = + (* size of extended partition is calculated seperately *) + 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
-- 2.1.0
_______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs
-- 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
On Thu, May 28, 2015 at 12:11:17PM +0100, Richard W.M. Jones wrote:
On Wed, May 20, 2015 at 06:51:30AM -0400, Chen Hanxiao wrote:
Add support for logical partitions. - count number of logical_partition (we've split partitions list) - don't count size of extended partition For it'll duplicate with logical partition, we'll count it later - we need at leat 1 gap between logical partitions. so --aligment=1 will be increased by 1
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/resize/resize.ml b/resize/resize.ml index 92f7304..a0ed713 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -741,8 +741,10 @@ read the man page virt-resize(1). (* We need some overhead for partitioning. *) let overhead = let maxl64 = List.fold_left max 0L in + (* We need at least 1 sector gap between logical partitions *) + let alignment = if alignment = 1L then 2L else alignment in
- let nr_partitions = List.length partitions in + let nr_partitions = List.length partitions + List.length logical_partitions in
I don't understand this at all. Why do logical partitions count towards the surplus? I don't think they do.
OK I guess the answer is because logical partitions now need their own alignment (within the extended partition), and that contributes to the required surplus for the disk. Do we resize the extended partition sufficiently (eg. if the extended partition has 100 aligned logical partitions)? 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
-----Original Message----- From: Richard W.M. Jones [mailto:rjones@redhat.com] Sent: Thursday, May 28, 2015 7:16 PM To: Chen, Hanxiao/陈 晗霄 Cc: libguestfs@redhat.com Subject: Re: [Libguestfs] [PATCH v2 04/11] resize: add support for logical partitions for calculate_surplus
On Thu, May 28, 2015 at 12:11:17PM +0100, Richard W.M. Jones wrote:
On Wed, May 20, 2015 at 06:51:30AM -0400, Chen Hanxiao wrote:
Add support for logical partitions. - count number of logical_partition (we've split partitions list) - don't count size of extended partition For it'll duplicate with logical partition, we'll count it later - we need at leat 1 gap between logical partitions. so --aligment=1 will be increased by 1
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/resize/resize.ml b/resize/resize.ml index 92f7304..a0ed713 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -741,8 +741,10 @@ read the man page virt-resize(1). (* We need some overhead for partitioning. *) let overhead = let maxl64 = List.fold_left max 0L in + (* We need at least 1 sector gap between logical partitions *) + let alignment = if alignment = 1L then 2L else alignment in
- let nr_partitions = List.length partitions in + let nr_partitions = List.length partitions + List.length logical_partitions in
I don't understand this at all. Why do logical partitions count towards the surplus? I don't think they do.
OK I guess the answer is because logical partitions now need their own alignment (within the extended partition), and that contributes to the required surplus for the disk.
Do we resize the extended partition sufficiently (eg. if the extended partition has 100 aligned logical partitions)?
My fault, we don't need the surplus of logical partitions. For resizing extended partition, is in: [10/11] resize: add support resize extended partition https://www.redhat.com/archives/libguestfs/2015-May/msg00103.html For dealing with alignment of logical partitions, is in: [06/11] resize: add support for logical partitions of calculate_target_partitions https://www.redhat.com/archives/libguestfs/2015-May/msg00098.html Regards, - Chen
This will re-calculate the size of logical partitions. and take logical partitions' aligment into account. Then update extended partition's OpResize. Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/resize/resize.ml b/resize/resize.ml index a0ed713..c54ed2e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -834,6 +834,30 @@ 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 + (* the start of logical partitions is aligned *) + | 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 + * than the original size *) + ) + ) partitions; + (* Calculate the final surplus. * At this point, this number must be >= 0. *) @@ -892,6 +916,7 @@ read the man page virt-resize(1). wrap (text ^ "\n\n") in List.iter print_summary partitions; + List.iter print_summary logical_partitions; List.iter ( fun ({ lv_name = name } as lv) -> -- 2.1.0
This patch add support for logical partitions. 1) OpResize newsize: two additional parameter for resizing logical partitions: - gap_start For logical partitions, we had to reserce at least 1 gap between each other. Also, we may had an extra aligment between 1st logical partition and extended partition. We need to remove gap_start from 'OpResize newsize' - nr_logical number of logical partitions. We had to remove all size of gap between each logical partitions. each gap is in (1, alignment). So size = (nr_logical - 1) * alignment removed from size will be enough. 2) OpIgnore | OpCopy: If in logical partition, add an extra aligment of 1 sector. Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index c54ed2e..6a3d286 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1083,13 +1083,17 @@ read the man page virt-resize(1). * the final list just contains partitions that need to be created * on the target. *) - let rec calculate_target_partitions partnum start ~create_surplus = function + let rec calculate_target_partitions partnum start ~create_surplus ?(nr_logical=0) ?(gap_start=0L) = function | p :: ps -> (match p.p_operation with | OpDelete -> calculate_target_partitions partnum start ~create_surplus ps (* skip p *) | OpIgnore | OpCopy -> (* same size *) + (* add an extra gap for logical partitions *) + let alg = if p.p_mbr_p_type = LogicalPartition then 1L else 0L in + let start = roundup64 (start +^ alg) 2L in + (* Size in sectors. *) let size = div_roundup64 p.p_part.G.part_size sectsize in (* Start of next partition + alignment. *) @@ -1102,13 +1106,24 @@ read the man page virt-resize(1). { p with p_target_start = start; p_target_end = end_ -^ 1L; p_target_partnum = partnum } :: - calculate_target_partitions (partnum+1) next ~create_surplus ps + calculate_target_partitions (partnum+1) next ~create_surplus ~nr_logical ~gap_start ps | OpResize newsize -> (* resized partition *) + (* add an extra gap for logical partitions *) + let alg = if p.p_mbr_p_type = LogicalPartition then 1L else 0L in + + let start = roundup64 start 2L in (* New size in sectors. *) let size = div_roundup64 newsize sectsize in + (* remove gap_start from size *) + let size = size -^ gap_start in + (* remove max aligment between logical partitions *) + let size = size -^ ((Int64.of_int nr_logical) -^ 1L) *^ alignment in (* Start of next partition + alignment. *) let next = start +^ size in + (* We will reserve a 1-sector gap between logical partitions + * by decreasing current partition by 1 sector, see below. *) + let next = next -^ alg in let next = roundup64 next alignment in if verbose () then -- 2.1.0
Pass gap_start and nr_logical to calculate_target_partitions when calculating logical partitions. Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/resize/resize.ml b/resize/resize.ml index 6a3d286..89bcb30 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1175,9 +1175,24 @@ read the man page virt-resize(1). calculate_target_partitions 1 start ~create_surplus: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 + | _ -> total +^ 0L + ) 0L partitions in + + let gap_start = (roundup64 (start +^ 1L) alignment) -^ start in + let nr_logical = List.length logical_partitions in + (* align logical partitions, too *) + let start = roundup64 (start +^ 1L) alignment in + calculate_target_partitions 5 start ~create_surplus:false ~nr_logical ~gap_start logical_partitions in + if verbose () then ( printf "After calculate target partitions:\n"; - List.iter (debug_partition ~sectsize) partitions + List.iter (debug_partition ~sectsize) partitions; + List.iter (debug_partition ~sectsize) logical_partitions ); let mbr_part_type x = -- 2.1.0
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 89bcb30..db7e0b3 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1210,6 +1210,11 @@ 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 -> + g#part_add "/dev/sdb" "logical" p.p_target_start p.p_target_end + ) logical_partitions; + (* Copy over the data. *) let copy_partition p = match p.p_operation with @@ -1234,24 +1239,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). - * - * You can't write directly to the extended partition, - * because the size of it reported by Linux is always 1024 - * bytes. Instead, write to the offset of the extended - * partition in the destination disk (/dev/sdb). - *) - let srcoffset = p.p_part.G.part_start in - let destoffset = p.p_target_start *^ 512L in - g#copy_device_to_device ~srcoffset ~destoffset ~size:copysize "/dev/sda" "/dev/sdb" + | 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 -- 2.1.0
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/resize/resize.ml b/resize/resize.ml index db7e0b3..37b946e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -1274,6 +1274,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 ( @@ -1325,6 +1326,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) -> @@ -1386,6 +1394,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 ( -- 2.1.0
Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/resize.ml | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/resize/resize.ml b/resize/resize.ml index 37b946e..8cdc5b1 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -769,6 +769,29 @@ read the man page virt-resize(1). start_overhead_sects +^ alignment_sects +^ gpt_end_sects in sectsize *^ overhead_sects in + let required_logical = List.fold_left ( + fun total p -> + let newsize = + match p.p_operation with + | OpCopy | OpIgnore -> roundup64 p.p_part.G.part_size (alignment *^ sectsize) + | OpDelete -> 0L + | OpResize newsize -> roundup64 newsize (alignment *^ sectsize) in + total +^ newsize + ) 0L logical_partitions in + + let required_extended = List.fold_left ( + fun total p -> + let newsize = + match p.p_type with + | ContentExtendedPartition -> + (* resizing extended partition by --resize or --expand is supported *) + (match p.p_operation with + | OpResize newsize -> newsize + | _ -> p.p_part.G.part_size) + | _ -> 0L in + total +^ newsize + ) 0L partitions in + let required = List.fold_left ( fun total p -> let newsize = @@ -780,15 +803,8 @@ read the man page virt-resize(1). | 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 logical_partitions in + let required = required +^ if required_extended > required_logical + then required_extended else required_logical in let surplus = outsize -^ (required +^ overhead) in @@ -840,6 +856,8 @@ read the man page virt-resize(1). 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 + (* resizing extended partition by --resize or --expand is supported *) + let size = match p.p_operation with OpResize s -> s | _ -> size in let logical_sizes = List.fold_left ( fun total p -> match p.p_operation with -- 2.1.0
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com> Signed-off-by: Chen Hanxiao <chenhanxiao@cn.fujitsu.com> --- resize/test-virt-resize.pl | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/resize/test-virt-resize.pl b/resize/test-virt-resize.pl index be9c9b4..85ed1b2 100755 --- a/resize/test-virt-resize.pl +++ b/resize/test-virt-resize.pl @@ -75,13 +75,6 @@ if (rand () <= 0.5) { # an extended partition (#4) and zero or more logical partitions. my $nr_parts = 1 + int (rand (7)); -# XXX Temporarily restriction XXX -# Currently virt-resize is broken when dealing with any extended -# partition, so don't test this for the moment. -if ($part_type eq "mbr" && $nr_parts >= 4) { - $nr_parts = 3; -} - # expand (1) or shrink (0) my $expand = 0; if (rand () >= 0.2) { @@ -120,31 +113,16 @@ my $i; for ($i = 1; $i <= $nr_parts; ++$i) { $parts[$i] = { name => "sda".$i, resize => 0 }; - if ($part_type eq "mbr") { - if ($i < 4) { - if (rand () < 0.5) { - $parts[$i]->{resize} = 1; - } - } elsif ($i == 4) { + if ($part_type eq "mbr" && $i == 4) { $parts[$i]->{content} = "extended"; - } - } else { - if (rand () < 0.5) { - $parts[$i]->{resize} = 1; - } + } + if (rand () < 0.5) { + $parts[$i]->{resize} = 1; } } # Pick a partition at random to expand or shrink. -if ($part_type eq "mbr") { - # virt-resize cannot shrink extended or logical partitions, so we - # set $max so that these cannot be chosen: - my $max = 3; - $max = $nr_parts if $max > $nr_parts; - $i = 1 + int (rand ($max)); -} else { - $i = 1 + int (rand ($nr_parts)); -} +$i = 1 + int (rand ($nr_parts)); $parts[$i]->{resize} = 0; $parts[$i]->{expand_shrink} = 1; -- 2.1.0
-----Original Message----- From: libguestfs-bounces@redhat.com [mailto:libguestfs-bounces@redhat.com] On Behalf Of Chen Hanxiao Sent: Wednesday, May 20, 2015 6:51 PM To: libguestfs@redhat.com Subject: [Libguestfs] [PATCH v2 00/11] virt-resize: add support for resizing MBR logical partitions
In current virt-resize, only primary partitions(including extended partition) are supported. They are collected in an array for resize operations. Logical partitions are not supported.
This series add support for resizing logical partitions.
v2: 1) Add 3 variables to describe relationship of logical and extended partitions: - partitions flat list of primary partitions (as now, the global 'partitions'). extended partitions is essentially primary partition - logical_partitions flat list of logical partitions - extended_partition one MBR extended partition
2) reserve enough size when resizing logical partitions
Original patches by Hu Tao at: https://www.redhat.com/archives/libguestfs/2014-October/msg00238.html
Chen Hanxiao (11): resize: move loop check from find_partitions resize: add logical_partitions and extended_partition resize: updated find_partition to support logical partition resize: add support for logical partitions for calculate_surplus resize: handle resize of logical partitions resize: add support for logical partitions of calculate_target_partitions resize: calculate_target_partitions for logical partitions resize: parted and copy logical partitions resize: more misc ops on logical partition resize: add support resize extended partition resize: test: add support for resizing extended and logical partitions
resize/resize.ml | 189 ++++++++++++++++++++++++++++++++++----------- resize/test-virt-resize.pl | 32 ++------ 2 files changed, 149 insertions(+), 72 deletions(-)
Hi, Rich Any comments on this series? Regards, - Chen
participants (4)
-
Chen Hanxiao -
Chen, Hanxiao -
Pino Toscano -
Richard W.M. Jones