Merge lp:~paelzer/curtin/fix-bug-1513085-partition-alignment-v3 into lp:~curtin-dev/curtin/trunk

Proposed by Christian Ehrhardt 
Status: Merged
Merged at revision: 295
Proposed branch: lp:~paelzer/curtin/fix-bug-1513085-partition-alignment-v3
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 99 lines (+52/-8)
2 files modified
curtin/commands/block_meta.py (+51/-7)
examples/tests/lvm.yaml (+1/-1)
To merge this branch: bzr merge lp:~paelzer/curtin/fix-bug-1513085-partition-alignment-v3
Reviewer Review Type Date Requested Status
curtin developers Pending
Review via email: mp+277117@code.launchpad.net

Commit message

Partition alignment and sizing fixes:
- end sector calculation so that partition size matches what was requested
- proper size of extended partition size calculation to be able to hold as much
  as it was specified in the yaml
- proper logical partition start calculation and realignment
- prepare curtin for the appearance of 4K logical sector size disk.
- by that implicitly fixing our alignment issues as long as sizes are aligned
  which they usually are as e.g. MAAS exposes only 1MB units
- extends one of the existing tests to cover 2G+3G logical in 5G extended

Description of the change

First partitions start at 2048 by default (which is parted default as well)
As I pointed out we have to understand that when currently creating a 1024
byte partition (small size makes no sense but good for the example) we do
2048 - 2048 + (1024/512)
2048 - 2050
That means we span 2048, 2049 2050 => that is 1536 byte

Also logical/extended partitions did wrong sector calculations by adding the
size of the extended (2 sectors) to the start - that only accidentially worked
most of the time.
Extended and Logical can't share the start sector and subsequent logical
partitions can't go head-to-head with former logical partitions.
While all that goes on a human would assume all that just works.
Also one will assume that e.g. a 5G extended partition can hold a 3G and a 2G
logical which so far it couldn't for all these reasons.

All that also broke alignment.

This patch now fixes:
- end sector calculation so that partition size matches what was requested
- proper size of extended partition size calculation to be able to hold as much
  as it was specified in the yaml
- proper logical partition start calculation and realignment
- prepare curtin for the appearance of 4K logical sector size disk.
- by that implicitly fixing our alignment issues as long as sizes are aligned
  which they usually are as e.g. MAAS exposes only 1MB units
- extends one of the existing tests to cover 2G+3G logical in 5G extended

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

This looks good. Thank you Christian.
We really should start to write some doc to say things like "1MB gap" and such.
and also document what we leave at the end.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'curtin/commands/block_meta.py'
--- curtin/commands/block_meta.py 2015-10-30 13:00:28 +0000
+++ curtin/commands/block_meta.py 2015-11-10 12:47:04 +0000
@@ -480,6 +480,14 @@
480 make_dname(info.get('id'), storage_config)480 make_dname(info.get('id'), storage_config)
481481
482482
483def getnumberoflogicaldisks(device, storage_config):
484 logicaldisks = 0
485 for key, item in storage_config.items():
486 if item.get('device') == device and item.get('flag') == "logical":
487 logicaldisks = logicaldisks + 1
488 return logicaldisks
489
490
483def partition_handler(info, storage_config):491def partition_handler(info, storage_config):
484 device = info.get('device')492 device = info.get('device')
485 size = info.get('size')493 size = info.get('size')
@@ -494,11 +502,18 @@
494 disk = get_path_to_storage_volume(device, storage_config)502 disk = get_path_to_storage_volume(device, storage_config)
495 partnumber = determine_partition_number(info.get('id'), storage_config)503 partnumber = determine_partition_number(info.get('id'), storage_config)
496504
497 # Offset is either 1 sector after last partition, or near the beginning if505 disk_kname = os.path.split(
498 # this is the first partition506 get_path_to_storage_volume(device, storage_config))[-1]
507 # consider the disks logical sector size when calculating sectors
508 try:
509 prefix = "/sys/block/%s/queue/" % disk_kname
510 with open(prefix + "logical_block_size", "r") as f:
511 l = f.readline()
512 logical_block_size_bytes = int(l)
513 except:
514 logical_block_size_bytes = 512
515
499 if partnumber > 1:516 if partnumber > 1:
500 disk_kname = os.path.split(
501 get_path_to_storage_volume(device, storage_config))[-1]
502 if partnumber == 5 and disk_ptable == "msdos":517 if partnumber == 5 and disk_ptable == "msdos":
503 for key, item in storage_config.items():518 for key, item in storage_config.items():
504 if item.get('type') == "partition" and \519 if item.get('type') == "partition" and \
@@ -515,12 +530,41 @@
515 with open(os.path.join(previous_partition, "size"), "r") as fp:530 with open(os.path.join(previous_partition, "size"), "r") as fp:
516 previous_size = int(fp.read())531 previous_size = int(fp.read())
517 with open(os.path.join(previous_partition, "start"), "r") as fp:532 with open(os.path.join(previous_partition, "start"), "r") as fp:
518 offset_sectors = previous_size + int(fp.read()) + 1533 previous_start = int(fp.read())
534
535 # Align to 1M at the beginning of the disk and at logical partitions
536 alignment_offset = (1 << 20) / logical_block_size_bytes
537 if partnumber == 1:
538 # start of disk
539 offset_sectors = alignment_offset
519 else:540 else:
520 offset_sectors = 2048541 # further partitions
542 if disk_ptable == "gpt" or flag != "logical":
543 # msdos primary and any gpt part start after former partition end
544 offset_sectors = previous_start + previous_size
545 else:
546 # msdos extended/logical partitions
547 if flag == "logical":
548 if partnumber == 5:
549 # First logical partition
550 # start at extended partition start + alignment_offset
551 offset_sectors = previous_start + alignment_offset
552 else:
553 # Further logical partitions
554 # start at former logical partition end + alignment_offset
555 offset_sectors = (previous_start + previous_size
556 + alignment_offset)
521557
522 length_bytes = util.human2bytes(size)558 length_bytes = util.human2bytes(size)
523 length_sectors = int(length_bytes / 512)559 # start sector is part of the sectors that define the partitions size
560 # so length has to be "size in sectors - 1"
561 length_sectors = int(length_bytes / logical_block_size_bytes) - 1
562 # logical partitions can't share their start sector with the extended
563 # partition and logical partitions can't go head-to-head, so we have to
564 # realign and for that increase size as required
565 if info.get('flag') == "extended":
566 logdisks = getnumberoflogicaldisks(device, storage_config)
567 length_sectors = length_sectors + (logdisks * alignment_offset)
524568
525 # Handle preserve flag569 # Handle preserve flag
526 if info.get('preserve'):570 if info.get('preserve'):
527571
=== modified file 'examples/tests/lvm.yaml'
--- examples/tests/lvm.yaml 2015-08-12 17:42:11 +0000
+++ examples/tests/lvm.yaml 2015-11-10 12:47:04 +0000
@@ -24,7 +24,7 @@
24 device: sda24 device: sda
25 - id: sda325 - id: sda3
26 type: partition26 type: partition
27 size: 2G27 size: 3G
28 flag: logical28 flag: logical
29 device: sda29 device: sda
30 - id: volgroup130 - id: volgroup1

Subscribers

People subscribed via source and target branches