From 16db72b7adc5e1a295ecd52c0a53ee5a12111878 Mon Sep 17 00:00:00 2001 From: David Lehman Date: Tue, 7 Jan 2020 17:10:24 -0500 Subject: [PATCH 1/2] Make minimal and optimal alignment getters public. Related: rhbz#1781106 --- blivet/formats/disklabel.py | 10 +++++----- tests/formats_test/disklabel_test.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/blivet/formats/disklabel.py b/blivet/formats/disklabel.py index a435bc59..a3f9d04b 100644 --- a/blivet/formats/disklabel.py +++ b/blivet/formats/disklabel.py @@ -462,7 +462,7 @@ class DiskLabel(DeviceFormat): return self._disk_label_alignment - def _get_minimal_alignment(self): + def get_minimal_alignment(self): """ Return the device's minimal alignment for new partitions. :rtype: :class:`parted.Alignment` @@ -484,7 +484,7 @@ class DiskLabel(DeviceFormat): return self._minimal_alignment - def _get_optimal_alignment(self): + def get_optimal_alignment(self): """ Return the device's optimal alignment for new partitions. :rtype: :class:`parted.Alignment` @@ -502,7 +502,7 @@ class DiskLabel(DeviceFormat): # if there is no optimal alignment, use the minimal alignment, # which has already been intersected with the disklabel # alignment - alignment = self._get_minimal_alignment() + alignment = self.get_minimal_alignment() else: try: alignment = optimal_alignment.intersect(disklabel_alignment) @@ -524,13 +524,13 @@ class DiskLabel(DeviceFormat): small to be aligned """ # default to the optimal alignment - alignment = self._get_optimal_alignment() + alignment = self.get_optimal_alignment() if size is None: return alignment # use the minimal alignment if the requested size is smaller than the # optimal io size - minimal_alignment = self._get_minimal_alignment() + minimal_alignment = self.get_minimal_alignment() optimal_grain_size = Size(alignment.grainSize * self.sector_size) minimal_grain_size = Size(minimal_alignment.grainSize * self.sector_size) if size < minimal_grain_size: diff --git a/tests/formats_test/disklabel_test.py b/tests/formats_test/disklabel_test.py index 93ce8c4a..6a1187e1 100644 --- a/tests/formats_test/disklabel_test.py +++ b/tests/formats_test/disklabel_test.py @@ -41,8 +41,8 @@ class DiskLabelTestCase(unittest.TestCase): # make sure the private methods all return the expected values self.assertEqual(dl._get_disk_label_alignment(), disklabel_alignment) - self.assertEqual(dl._get_minimal_alignment(), minimal_alignment) - self.assertEqual(dl._get_optimal_alignment(), optimal_alignment) + self.assertEqual(dl.get_minimal_alignment(), minimal_alignment) + self.assertEqual(dl.get_optimal_alignment(), optimal_alignment) # validate result when passing a start alignment to get_end_alignment self.assertEqual(dl.get_end_alignment(alignment=optimal_alignment), @@ -61,7 +61,7 @@ class DiskLabelTestCase(unittest.TestCase): minimal_end_alignment) # test the old deprecated properties' values - self.assertEqual(dl.alignment, dl._get_optimal_alignment()) + self.assertEqual(dl.alignment, dl.get_optimal_alignment()) self.assertEqual(dl.end_alignment, dl.get_end_alignment()) @patch("blivet.formats.disklabel.arch") -- 2.24.1 From f5810a412048bd445dbed02ce0d01e50a1d083ec Mon Sep 17 00:00:00 2001 From: David Lehman Date: Tue, 7 Jan 2020 17:11:43 -0500 Subject: [PATCH 2/2] Align base sizes up if smaller than min I/O size. Resolves: rhbz#1781106 --- blivet/partitioning.py | 18 +++++++++++++++--- tests/partitioning_test.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/blivet/partitioning.py b/blivet/partitioning.py index 026a3f8c..bc0fe237 100644 --- a/blivet/partitioning.py +++ b/blivet/partitioning.py @@ -408,7 +408,11 @@ def add_partition(disklabel, free, part_type, size, start=None, end=None): else: _size = size - alignment = disklabel.get_alignment(size=_size) + try: + alignment = disklabel.get_alignment(size=_size) + except AlignmentError: + alignment = disklabel.get_minimal_alignment() + end_alignment = disklabel.get_end_alignment(alignment=alignment) else: alignment = parted.Alignment(grainSize=1, offset=0) @@ -646,7 +650,12 @@ def do_partitioning(storage, boot_disk=None): def align_size_for_disklabel(size, disklabel): # Align the base size to the disk's grain size. - grain_size = Size(disklabel.alignment.grainSize) + try: + alignment = disklabel.get_alignment(size=size) + except AlignmentError: + alignment = disklabel.get_minimal_alignment() + + grain_size = Size(alignment.grainSize) grains, rem = divmod(size, grain_size) return (grains * grain_size) + (grain_size if rem else Size(0)) @@ -751,7 +760,10 @@ def allocate_partitions(storage, disks, partitions, freespace, boot_disk=None): disklabel = disklabels[_disk.path] best = None current_free = free - alignment = disklabel.get_alignment(size=_part.req_size) + try: + alignment = disklabel.get_alignment(size=_part.req_size) + except AlignmentError: + alignment = disklabel.get_minimal_alignment() # for growable requests, we don't want to pass the current free # geometry to get_best_free_region -- this allows us to try the diff --git a/tests/partitioning_test.py b/tests/partitioning_test.py index ebd05260..4fe87ebe 100644 --- a/tests/partitioning_test.py +++ b/tests/partitioning_test.py @@ -179,6 +179,8 @@ class PartitioningTestCase(unittest.TestCase): min_str = 'parted.Device.minimumAlignment' opt_al = parted.Alignment(offset=0, grainSize=8192) # 4 MiB min_al = parted.Alignment(offset=0, grainSize=2048) # 1 MiB + disk.format._minimal_alignment = None # drop cache + disk.format._optimal_alignment = None # drop cache with patch(opt_str, opt_al) as optimal, patch(min_str, min_al) as minimal: optimal_end = disk.format.get_end_alignment(alignment=optimal) minimal_end = disk.format.get_end_alignment(alignment=minimal) @@ -201,6 +203,38 @@ class PartitioningTestCase(unittest.TestCase): disk.format.remove_partition(part) self.assertEqual(len(disk.format.partitions), 0) + # + # adding a partition smaller than the minimal io size should yield + # a partition whose size is aligned up to the minimal io size + # + opt_str = 'parted.Device.optimumAlignment' + min_str = 'parted.Device.minimumAlignment' + opt_al = parted.Alignment(offset=0, grainSize=8192) # 4 MiB + min_al = parted.Alignment(offset=0, grainSize=2048) # 1 MiB + disk.format._minimal_alignment = None # drop cache + disk.format._optimal_alignment = None # drop cache + with patch(opt_str, opt_al) as optimal, patch(min_str, min_al) as minimal: + optimal_end = disk.format.get_end_alignment(alignment=optimal) + minimal_end = disk.format.get_end_alignment(alignment=minimal) + + sector_size = Size(disk.format.sector_size) + length = 1024 # 512 KiB + size = Size(sector_size * length) + part = add_partition(disk.format, free, parted.PARTITION_NORMAL, + size) + self.assertEqual(part.geometry.length, min_al.grainSize) + self.assertEqual(optimal.isAligned(free, part.geometry.start), + False) + self.assertEqual(minimal.isAligned(free, part.geometry.start), + True) + self.assertEqual(optimal_end.isAligned(free, part.geometry.end), + False) + self.assertEqual(minimal_end.isAligned(free, part.geometry.end), + True) + + disk.format.remove_partition(part) + self.assertEqual(len(disk.format.partitions), 0) + # # add a partition with an unaligned start sector # -- 2.24.1