Merge pull request #1445 from ogayot/LP1991413-LP1991929
Multiple fixes for size: -1 partitions
This commit is contained in:
commit
d41c3b9ec0
|
@ -26,6 +26,7 @@ python3-dev
|
|||
python3-distutils-extra
|
||||
python3-flake8
|
||||
python3-jsonschema
|
||||
python3-more-itertools
|
||||
python3-nose
|
||||
python3-parameterized
|
||||
python3-pip
|
||||
|
|
|
@ -26,6 +26,8 @@ import pathlib
|
|||
import platform
|
||||
import tempfile
|
||||
|
||||
import more_itertools
|
||||
|
||||
from curtin import storage_config
|
||||
from curtin.block import partition_kname
|
||||
from curtin.util import human2bytes
|
||||
|
@ -552,7 +554,7 @@ class _Device(_Formattable, ABC):
|
|||
|
||||
@property
|
||||
def available_for_partitions(self):
|
||||
return align_down(self.size, 1 << 20) - GPT_OVERHEAD
|
||||
raise NotImplementedError
|
||||
|
||||
def available(self):
|
||||
# A _Device is available if:
|
||||
|
@ -605,6 +607,12 @@ class Disk(_Device):
|
|||
|
||||
_info = attr.ib(default=None)
|
||||
|
||||
@property
|
||||
def available_for_partitions(self):
|
||||
margin_before = self.alignment_data().min_start_offset
|
||||
margin_after = self.alignment_data().min_end_offset
|
||||
return align_down(self.size, 1 << 20) - margin_before - margin_after
|
||||
|
||||
def alignment_data(self):
|
||||
ptable = self.ptable_for_new_partition()
|
||||
return self._m._partition_alignment_data[ptable]
|
||||
|
@ -1167,6 +1175,48 @@ class FilesystemModel(object):
|
|||
return candidates[0]
|
||||
return None
|
||||
|
||||
def assign_omitted_offsets(self):
|
||||
""" Assign offsets to partitions that do not already have one.
|
||||
This method does nothing for storage version 1. """
|
||||
if self.storage_version != 2:
|
||||
return
|
||||
|
||||
for disk in self._all(type="disk"):
|
||||
info = disk.alignment_data()
|
||||
|
||||
def au(v): # au == "align up"
|
||||
r = v % info.part_align
|
||||
if r:
|
||||
return v + info.part_align - r
|
||||
else:
|
||||
return v
|
||||
|
||||
def ad(v): # ad == "align down"
|
||||
return v - v % info.part_align
|
||||
|
||||
# Extended is considered a primary partition too.
|
||||
primary_parts, logical_parts = map(list, more_itertools.partition(
|
||||
is_logical_partition,
|
||||
disk.partitions()))
|
||||
|
||||
prev_end = info.min_start_offset
|
||||
for part in primary_parts:
|
||||
if part.offset is None:
|
||||
part.offset = au(prev_end)
|
||||
prev_end = part.offset + part.size
|
||||
|
||||
if not logical_parts:
|
||||
return
|
||||
|
||||
extended_part = next(
|
||||
filter(lambda x: x.flag == "extended", disk.partitions()))
|
||||
|
||||
prev_end = extended_part.offset
|
||||
for part in logical_parts:
|
||||
if part.offset is None:
|
||||
part.offset = au(prev_end + info.ebr_space)
|
||||
prev_end = part.offset + part.size
|
||||
|
||||
def apply_autoinstall_config(self, ai_config):
|
||||
disks = self.all_disks()
|
||||
for action in ai_config:
|
||||
|
@ -1192,6 +1242,9 @@ class FilesystemModel(object):
|
|||
action['serial'] = disk.serial
|
||||
self._actions = self._actions_from_config(
|
||||
ai_config, self._probe_data['blockdev'], is_probe_data=False)
|
||||
|
||||
self.assign_omitted_offsets()
|
||||
|
||||
for p in self._all(type="partition") + self._all(type="lvm_partition"):
|
||||
# NOTE For logical partitions (DOS), the parent is set to the disk,
|
||||
# not the extended partition.
|
||||
|
@ -1213,6 +1266,10 @@ class FilesystemModel(object):
|
|||
"{} has negative size but is not final partition "
|
||||
"of {}".format(p, parent))
|
||||
|
||||
# Exclude the current partition itself so that its
|
||||
# incomplete size is not used as is.
|
||||
filtered_parent._partitions.remove(p)
|
||||
|
||||
from subiquity.common.filesystem.gaps import (
|
||||
largest_gap_size,
|
||||
)
|
||||
|
|
|
@ -600,23 +600,20 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
|
||||
def test_extended_partition_remaining_size(self):
|
||||
model = make_model(bootloader=Bootloader.BIOS, storage_version=2)
|
||||
disk = make_disk(model, serial='aaaa', size=dehumanize_size("100M"),
|
||||
ptable='msdos')
|
||||
ebr_space = disk.alignment_data().ebr_space
|
||||
start_offset = disk.alignment_data().min_start_offset
|
||||
make_disk(model, serial='aaaa', size=dehumanize_size("100M"))
|
||||
|
||||
fake_up_blockdata(model)
|
||||
model.apply_autoinstall_config([
|
||||
{
|
||||
'type': 'disk',
|
||||
'id': 'disk0',
|
||||
'ptable': 'msdos',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'id': 'part0',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('40M'),
|
||||
'offset': start_offset,
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -624,8 +621,6 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'extended',
|
||||
# p0 offset + p0 size
|
||||
'offset': start_offset + dehumanize_size('40M'),
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -634,27 +629,32 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': dehumanize_size('10M'),
|
||||
'flag': 'logical',
|
||||
# p1 (extended) offset + ebr_space
|
||||
'offset': start_offset + dehumanize_size('40M') + ebr_space,
|
||||
},
|
||||
])
|
||||
extended = model._one(type="partition", id="part1")
|
||||
self.assertEqual(
|
||||
extended.size,
|
||||
disk.available_for_partitions - dehumanize_size('40M'))
|
||||
# Disk test.img: 100 MiB, 104857600 bytes, 204800 sectors
|
||||
# Units: sectors of 1 * 512 = 512 bytes
|
||||
# Sector size (logical/physical): 512 bytes / 512 bytes
|
||||
# I/O size (minimum/optimal): 512 bytes / 512 bytes
|
||||
# Disklabel type: dos
|
||||
# Disk identifier: 0x2cbec179
|
||||
#
|
||||
# Device Boot Start End Sectors Size Id Type
|
||||
# test.img1 2048 83967 81920 40M 83 Linux
|
||||
# test.img2 83968 204799 120832 59M 5 Extended
|
||||
# test.img5 86016 106495 20480 10M 83 Linux
|
||||
self.assertEqual(extended.size, 120832 * 512)
|
||||
|
||||
def test_logical_partition_remaining_size(self):
|
||||
model = make_model(bootloader=Bootloader.BIOS, storage_version=2)
|
||||
disk = make_disk(model, serial='aaaa', size=dehumanize_size("100M"),
|
||||
ptable='msdos')
|
||||
ebr_space = disk.alignment_data().ebr_space
|
||||
start_offset = disk.alignment_data().min_start_offset
|
||||
make_disk(model, serial='aaaa', size=dehumanize_size("100M"))
|
||||
|
||||
fake_up_blockdata(model)
|
||||
model.apply_autoinstall_config([
|
||||
{
|
||||
'type': 'disk',
|
||||
'id': 'disk0',
|
||||
'ptable': 'msdos',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -662,7 +662,6 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': dehumanize_size('40M'),
|
||||
'flag': 'extended',
|
||||
'offset': start_offset,
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -671,35 +670,47 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'logical',
|
||||
# p0 (extended) offset + ebr_space
|
||||
'offset': start_offset + ebr_space,
|
||||
},
|
||||
])
|
||||
disk = model._one(type="disk")
|
||||
extended = model._one(type="partition", id="part0")
|
||||
logical = model._one(type="partition", id="part5")
|
||||
|
||||
ebr_space = disk.alignment_data().ebr_space
|
||||
# Disk test.img: 100 MiB, 104857600 bytes, 204800 sectors
|
||||
# Units: sectors of 1 * 512 = 512 bytes
|
||||
# Sector size (logical/physical): 512 bytes / 512 bytes
|
||||
# I/O size (minimum/optimal): 512 bytes / 512 bytes
|
||||
# Disklabel type: dos
|
||||
# Disk identifier: 0x16011ba9
|
||||
#
|
||||
# Device Boot Start End Sectors Size Id Type
|
||||
# test.img1 2048 83967 81920 40M 5 Extended
|
||||
# test.img5 4096 83967 79872 39M 83 Linux
|
||||
|
||||
# At this point, there should be one large gap outside the extended
|
||||
# partition and one smaller one inside the extended partition.
|
||||
# partition and a smaller one inside the extended partition.
|
||||
# Make sure our logical partition picks up the smaller one.
|
||||
|
||||
self.assertEqual(extended.offset, 2048 * 512)
|
||||
self.assertEqual(logical.offset, 4096 * 512)
|
||||
self.assertEqual(logical.size, extended.size - ebr_space)
|
||||
|
||||
def test_partition_remaining_size_in_extended_and_logical(self):
|
||||
model = make_model(bootloader=Bootloader.BIOS, storage_version=2)
|
||||
disk = make_disk(model, serial='aaaa', size=dehumanize_size("100M"),
|
||||
ptable='msdos')
|
||||
ebr_space = disk.alignment_data().ebr_space
|
||||
start_offset = disk.alignment_data().min_start_offset
|
||||
make_disk(model, serial='aaaa', size=dehumanize_size("100M"))
|
||||
fake_up_blockdata(model)
|
||||
model.apply_autoinstall_config([
|
||||
{
|
||||
'type': 'disk',
|
||||
'id': 'disk0',
|
||||
'ptable': 'msdos',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'id': 'part0',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('40M'),
|
||||
'offset': start_offset,
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -707,8 +718,6 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'extended',
|
||||
# p0 offset + size of p0
|
||||
'offset': start_offset + dehumanize_size('40M'),
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -717,8 +726,6 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': dehumanize_size('10M'),
|
||||
'flag': 'logical',
|
||||
# p1 offset + ebr_space
|
||||
'offset': start_offset + dehumanize_size('40M') + ebr_space,
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
|
@ -727,20 +734,125 @@ class TestAutoInstallConfig(unittest.TestCase):
|
|||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'logical',
|
||||
# p5 offset + p5 size + ebr_space
|
||||
'offset': start_offset + dehumanize_size('40M') + ebr_space \
|
||||
+ dehumanize_size('10M') + ebr_space
|
||||
},
|
||||
])
|
||||
extended = model._one(type="partition", id="part1")
|
||||
p5 = model._one(type="partition", id="part5")
|
||||
p6 = model._one(type="partition", id="part6")
|
||||
self.assertEqual(
|
||||
extended.size,
|
||||
disk.available_for_partitions - dehumanize_size('40M'))
|
||||
self.assertEqual(
|
||||
p6.size,
|
||||
extended.size - p5.size - 2 * ebr_space)
|
||||
# Disk test.img: 100 MiB, 104857600 bytes, 204800 sectors
|
||||
# Units: sectors of 1 * 512 = 512 bytes
|
||||
# Sector size (logical/physical): 512 bytes / 512 bytes
|
||||
# I/O size (minimum/optimal): 512 bytes / 512 bytes
|
||||
# Disklabel type: dos
|
||||
# Disk identifier: 0x0b01e1ca
|
||||
#
|
||||
# Device Boot Start End Sectors Size Id Type
|
||||
# test.img1 2048 83967 81920 40M 83 Linux
|
||||
# test.img2 83968 204799 120832 59M 5 Extended
|
||||
# test.img5 86016 106495 20480 10M 83 Linux
|
||||
# test.img6 108544 204799 96256 47M 83 Linux
|
||||
|
||||
self.assertEqual(extended.offset, 83968 * 512)
|
||||
self.assertEqual(extended.size, 120832 * 512)
|
||||
self.assertEqual(p5.offset, 86016 * 512)
|
||||
self.assertEqual(p6.offset, 108544 * 512)
|
||||
self.assertEqual(p6.size, 96256 * 512)
|
||||
|
||||
def test_partition_remaining_size_in_extended_and_logical_multiple(self):
|
||||
model = make_model(bootloader=Bootloader.BIOS, storage_version=2)
|
||||
make_disk(model, serial='aaaa', size=dehumanize_size("20G"))
|
||||
fake_up_blockdata(model)
|
||||
model.apply_autoinstall_config([
|
||||
{
|
||||
'type': 'disk',
|
||||
'id': 'disk0',
|
||||
'ptable': 'msdos',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'flag': 'boot',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('1G'),
|
||||
'id': 'partition-boot',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('6G'),
|
||||
'id': 'partition-root',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('100M'),
|
||||
'id': 'partition-swap',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'extended',
|
||||
'id': 'partition-extended',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('1G'),
|
||||
'flag': 'logical',
|
||||
'id': 'partition-tmp',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': dehumanize_size('2G'),
|
||||
'flag': 'logical',
|
||||
'id': 'partition-var',
|
||||
},
|
||||
{
|
||||
'type': 'partition',
|
||||
'device': 'disk0',
|
||||
'size': -1,
|
||||
'flag': 'logical',
|
||||
'id': 'partition-home',
|
||||
}
|
||||
])
|
||||
p_boot = model._one(type="partition", id="partition-boot")
|
||||
p_root = model._one(type="partition", id="partition-root")
|
||||
p_swap = model._one(type="partition", id="partition-swap")
|
||||
p_extended = model._one(type="partition", id="partition-extended")
|
||||
p_tmp = model._one(type="partition", id="partition-tmp")
|
||||
p_var = model._one(type="partition", id="partition-var")
|
||||
p_home = model._one(type="partition", id="partition-home")
|
||||
|
||||
# Disk test.img: 20 GiB, 21474836480 bytes, 41943040 sectors
|
||||
# Units: sectors of 1 * 512 = 512 bytes
|
||||
# Sector size (logical/physical): 512 bytes / 512 bytes
|
||||
# I/O size (minimum/optimal): 512 bytes / 512 bytes
|
||||
# Disklabel type: dos
|
||||
# Disk identifier: 0xfbc457e5
|
||||
#
|
||||
# Device Boot Start End Sectors Size Id Type
|
||||
# test.img1 2048 2099199 2097152 1G 83 Linux
|
||||
# test.img2 2099200 14682111 12582912 6G 83 Linux
|
||||
# test.img3 14682112 14886911 204800 100M 82 Linux swap ...
|
||||
# test.img4 14886912 41943039 27056128 12,9G 5 Extended
|
||||
# test.img5 14888960 16986111 2097152 1G 83 Linux
|
||||
# test.img6 16988160 21182463 4194304 2G 83 Linux
|
||||
# test.img7 21184512 41943039 20758528 9,9G 83 Linux
|
||||
self.assertEqual(p_boot.offset, 2048 * 512)
|
||||
self.assertEqual(p_boot.size, 2097152 * 512)
|
||||
self.assertEqual(p_root.offset, 2099200 * 512)
|
||||
self.assertEqual(p_root.size, 12582912 * 512)
|
||||
self.assertEqual(p_swap.offset, 14682112 * 512)
|
||||
self.assertEqual(p_swap.size, 204800 * 512)
|
||||
self.assertEqual(p_extended.offset, 14886912 * 512)
|
||||
self.assertEqual(p_extended.size, 27056128 * 512)
|
||||
self.assertEqual(p_tmp.offset, 14888960 * 512)
|
||||
self.assertEqual(p_tmp.size, 2097152 * 512)
|
||||
self.assertEqual(p_var.offset, 16988160 * 512)
|
||||
self.assertEqual(p_var.size, 4194304 * 512)
|
||||
self.assertEqual(p_home.offset, 21184512 * 512)
|
||||
self.assertEqual(p_home.size, 20758528 * 512)
|
||||
|
||||
def test_lv_percent(self):
|
||||
model = make_model()
|
||||
|
|
Loading…
Reference in New Issue