Blob Blame History Raw
From 16db72b7adc5e1a295ecd52c0a53ee5a12111878 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
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 <dlehman@redhat.com>
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