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