disk_layout: Align disk sizes to both 1MB and cylinder boundaries.

The VHD disk format internally includes CHS addressing and qemu-img
respectfully aligns disk images to the common 16 heads 63 sectors
geometry when possible. This is unfortunate since images uploaded to
Azure must also be aligned to 1MB we normally do.

Since qemu-img doesn't have a way to handle this well right now adjust
our existing alignment logic to create disk images aligned to both.
This commit is contained in:
Michael Marineau 2014-10-08 20:12:53 -07:00
parent e361e9170e
commit e77e4e5499
2 changed files with 10 additions and 13 deletions

View File

@ -1,7 +1,9 @@
{ {
"_comment": "See http://www.chromium.org/chromium-os/building-chromium-os/disk-layout-format", "_comment": "See http://www.chromium.org/chromium-os/building-chromium-os/disk-layout-format",
"metadata":{ "metadata":{
"alignment": 2048, "_comment": "Partitions are aligned to 1MB (2048 blocks), disks sizes should align to *both* 1MB and a CHS cylender boundry for the common 16H 63S geometry (16*63 = 1008 blocks). The least common multiple of 2048 and 1008 is 129024 blocks.",
"part_alignment": 2048,
"disk_alignment": 129024,
"block_size": 512, "block_size": 512,
"fs_block_size": 4096 "fs_block_size": 4096
}, },

View File

@ -44,10 +44,10 @@ def LoadPartitionConfig(options):
valid_keys = set(('_comment', 'metadata', 'layouts')) valid_keys = set(('_comment', 'metadata', 'layouts'))
valid_layout_keys = set(( valid_layout_keys = set((
'_comment', 'type', 'num', 'label', 'blocks', 'block_size', 'fs_blocks', '_comment', 'type', 'num', 'label', 'blocks', 'block_size', 'fs_blocks',
'fs_block_size', 'fs_type', 'features', 'uuid', 'alignment', 'mount', 'fs_block_size', 'fs_type', 'features', 'uuid', 'part_alignment', 'mount',
'binds', 'fs_subvolume')) 'binds', 'fs_subvolume'))
integer_layout_keys = set(( integer_layout_keys = set((
'blocks', 'block_size', 'fs_blocks', 'fs_block_size', 'alignment')) 'blocks', 'block_size', 'fs_blocks', 'fs_block_size', 'part_alignment'))
required_layout_keys = set(('type', 'num', 'label', 'blocks')) required_layout_keys = set(('type', 'num', 'label', 'blocks'))
filename = options.disk_layout_file filename = options.disk_layout_file
@ -63,17 +63,12 @@ def LoadPartitionConfig(options):
try: try:
metadata = config['metadata'] metadata = config['metadata']
base = config['layouts']['base'] base = config['layouts']['base']
for key in ('alignment', 'block_size', 'fs_block_size'): for key in ('part_alignment', 'disk_alignment',
'block_size', 'fs_block_size'):
metadata[key] = int(metadata[key]) metadata[key] = int(metadata[key])
except KeyError as e: except KeyError as e:
raise InvalidLayout('Metadata is missing required entries: %s' % e) raise InvalidLayout('Metadata is missing required entries: %s' % e)
# Sometimes qemu-img expects disks sizes aligned to 64k
align_bytes = metadata['alignment'] * metadata['block_size']
if align_bytes < 65536 or align_bytes % 65536 != 0:
raise InvalidLayout('Invalid alignment, 64KB or better required')
def VerifyLayout(layout_name, layout, base=None): def VerifyLayout(layout_name, layout, base=None):
for part_num, part in layout.iteritems(): for part_num, part in layout.iteritems():
part['num'] = int(part_num) part['num'] = int(part_num)
@ -136,7 +131,7 @@ def LoadPartitionConfig(options):
if part['type'] == 'blank': if part['type'] == 'blank':
continue continue
part.setdefault('alignment', metadata['alignment']) part.setdefault('part_alignment', metadata['part_alignment'])
part['bytes'] = part['blocks'] * metadata['block_size'] part['bytes'] = part['blocks'] * metadata['block_size']
part.setdefault('fs_block_size', metadata['fs_block_size']) part.setdefault('fs_block_size', metadata['fs_block_size'])
part.setdefault('fs_blocks', part['bytes'] // part['fs_block_size']) part.setdefault('fs_blocks', part['bytes'] // part['fs_block_size'])
@ -147,7 +142,7 @@ def LoadPartitionConfig(options):
'Filesystem may not be larger than partition: %s %s: %d > %d' % 'Filesystem may not be larger than partition: %s %s: %d > %d' %
(layout_name, part_num, part['fs_bytes'], part['bytes'])) (layout_name, part_num, part['fs_bytes'], part['bytes']))
disk_block_count = Align(disk_block_count, part['alignment']) disk_block_count = Align(disk_block_count, part['part_alignment'])
part['first_block'] = disk_block_count part['first_block'] = disk_block_count
part['first_byte'] = disk_block_count * metadata['block_size'] part['first_byte'] = disk_block_count * metadata['block_size']
disk_block_count += part['blocks'] disk_block_count += part['blocks']
@ -156,7 +151,7 @@ def LoadPartitionConfig(options):
# Reserved size for second GPT plus align disk image size # Reserved size for second GPT plus align disk image size
disk_block_count += GPT_RESERVED_SECTORS disk_block_count += GPT_RESERVED_SECTORS
disk_block_count = Align(disk_block_count, metadata['alignment']) disk_block_count = Align(disk_block_count, metadata['disk_alignment'])
# If this is the requested layout stash the disk size into the global # If this is the requested layout stash the disk size into the global
# metadata. Kinda odd but the best place I've got with this data structure. # metadata. Kinda odd but the best place I've got with this data structure.