import python-blivet-3.1.0-20.el8

This commit is contained in:
CentOS Sources 2020-04-28 04:55:02 -04:00 committed by Andrew Lukoshko
parent 495f7f954c
commit 70f10104b7
6 changed files with 916 additions and 1 deletions

View File

@ -0,0 +1,183 @@
From 83a42f3e232c7c4a02deb3539972c82b6dca284b Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Fri, 4 Oct 2019 12:30:03 +0200
Subject: [PATCH 1/2] Add a new "sector_size" property to storage devices.
This represents the logical sector size of the device.
Related: rhbz#1754446
---
blivet/devices/disk.py | 6 +++++-
blivet/devices/md.py | 11 +++++++++++
blivet/devices/partition.py | 7 +++++++
blivet/devices/storage.py | 15 +++++++++++++++
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py
index bf2f7a4f..7dfeabf0 100644
--- a/blivet/devices/disk.py
+++ b/blivet/devices/disk.py
@@ -687,7 +687,7 @@ def __init__(self, device, **kwargs):
"""
self.mode = kwargs.pop("mode")
self.devname = kwargs.pop("devname")
- self.sector_size = kwargs.pop("sector_size")
+ self._sector_size = kwargs.pop("sector_size")
DiskDevice.__init__(self, device, **kwargs)
@@ -710,3 +710,7 @@ def description(self):
% {'devname': self.devname,
'mode': self.mode,
'path': self.path}
+
+ @property
+ def sector_size(self):
+ return self._sector_size
diff --git a/blivet/devices/md.py b/blivet/devices/md.py
index 6a837df0..0b6da980 100644
--- a/blivet/devices/md.py
+++ b/blivet/devices/md.py
@@ -19,10 +19,13 @@
# Red Hat Author(s): David Lehman <dlehman@redhat.com>
#
+import math
import os
import six
import time
+from six.moves import reduce
+
import gi
gi.require_version("BlockDev", "2.0")
@@ -195,6 +198,14 @@ def level(self, value):
self._level = level
+ @property
+ def sector_size(self):
+ if not self.exists:
+ # Least common multiple of parents' sector sizes
+ return reduce(lambda a, b: a * b // math.gcd(a, b), (int(p.sector_size) for p in self.parents))
+
+ return super(MDRaidArrayDevice, self).sector_size
+
@property
def chunk_size(self):
if self.exists and self._chunk_size == Size(0):
diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py
index 623e1c9d..73daa76f 100644
--- a/blivet/devices/partition.py
+++ b/blivet/devices/partition.py
@@ -729,6 +729,13 @@ def protected(self):
def protected(self, value):
self._protected = value
+ @property
+ def sector_size(self):
+ if self.disk:
+ return self.disk.sector_size
+
+ return super(PartitionDevice, self).sector_size
+
def _pre_resize(self):
if not self.exists:
raise errors.DeviceError("device has not been created", self.name)
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py
index e087fa64..91c5e60e 100644
--- a/blivet/devices/storage.py
+++ b/blivet/devices/storage.py
@@ -190,6 +190,21 @@ def raw_device(self):
""" The device itself, or when encrypted, the backing device. """
return self
+ @property
+ def sector_size(self):
+ """ Logical sector (block) size of this device """
+ if not self.exists:
+ if self.parents:
+ return self.parents[0].sector_size
+ else:
+ return LINUX_SECTOR_SIZE
+
+ block_size = util.get_sysfs_attr(self.sysfs_path, "queue/logical_block_size")
+ if block_size:
+ return int(block_size)
+ else:
+ return LINUX_SECTOR_SIZE
+
@property
def controllable(self):
return self._controllable and not flags.testing and not self.unavailable_type_dependencies()
From 9f81bd1ffb877862760223ba88f2086deebd2d06 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Fri, 4 Oct 2019 12:37:01 +0200
Subject: [PATCH 2/2] Do not allow creating VGs with PVs with different sector
size
New versions of LVM don't allow mixing PVs with different sector
sizes in one VG.
Resolves: rhbz#1754446
---
blivet/devices/lvm.py | 12 ++++++++++++
tests/devices_test/lvm_test.py | 13 ++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 4347f483..b9da286a 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -356,6 +356,18 @@ def _remove_log_vol(self, lv):
def _add_parent(self, parent):
super(LVMVolumeGroupDevice, self)._add_parent(parent)
+ # we are creating new VG or adding a new PV to an existing (complete) one
+ if not self.exists or (self.exists and self._complete):
+ parent_sectors = set([p.sector_size for p in self.pvs] + [parent.sector_size])
+ if len(parent_sectors) != 1:
+ if not self.exists:
+ msg = "The volume group %s cannot be created. Selected disks have " \
+ "inconsistent sector sizes (%s)." % (self.name, parent_sectors)
+ else:
+ msg = "Disk %s cannot be added to this volume group. LVM doesn't " \
+ "allow using physical volumes with inconsistent (logical) sector sizes." % parent.name
+ raise ValueError(msg)
+
if (self.exists and parent.format.exists and
len(self.parents) + 1 == self.pv_count):
self._complete = True
diff --git a/tests/devices_test/lvm_test.py b/tests/devices_test/lvm_test.py
index 8ed577f4..a32c1d83 100644
--- a/tests/devices_test/lvm_test.py
+++ b/tests/devices_test/lvm_test.py
@@ -2,7 +2,7 @@
import test_compat # pylint: disable=unused-import
import six
-from six.moves.mock import patch # pylint: disable=no-name-in-module,import-error
+from six.moves.mock import patch, PropertyMock # pylint: disable=no-name-in-module,import-error
import unittest
import blivet
@@ -352,6 +352,17 @@ def test_target_size(self):
self.assertEqual(lv.target_size, orig_size)
self.assertEqual(lv.size, orig_size)
+ def test_lvm_inconsistent_sector_size(self):
+ pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("1024 MiB"))
+ pv2 = StorageDevice("pv2", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("1024 MiB"))
+
+ with patch("blivet.devices.StorageDevice.sector_size", new_callable=PropertyMock) as mock_property:
+ mock_property.__get__ = lambda _mock, pv, _class: 512 if pv.name == "pv1" else 4096
+ with six.assertRaisesRegex(self, ValueError, "The volume group testvg cannot be created."):
+ LVMVolumeGroupDevice("testvg", parents=[pv, pv2])
+
class TypeSpecificCallsTest(unittest.TestCase):
def test_type_specific_calls(self):

View File

@ -0,0 +1,309 @@
From c85a80ca54eabb1cf2458a3e17b3472ba2eb0914 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Fri, 1 Nov 2019 12:07:43 -0400
Subject: [PATCH 1/2] Override LVM skip-activation to allow for thorough
removal.
When we have been told to remove the LV or manage the formatting we
must tell LVM to ignore the skip-activation bit. Otherwise we have
no way to properly perform the requested management.
Resolves: rhbz#1766498
---
blivet/deviceaction.py | 35 ++++++++++++++++++++++++++++++++++
blivet/devices/lvm.py | 12 ++++--------
tests/action_test.py | 16 ++++++++++++++++
tests/devices_test/lvm_test.py | 29 ++++++++++++++++++++++++++++
4 files changed, 84 insertions(+), 8 deletions(-)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py
index 14a06ff0..57115662 100644
--- a/blivet/deviceaction.py
+++ b/blivet/deviceaction.py
@@ -393,10 +393,29 @@ class ActionDestroyDevice(DeviceAction):
super(ActionDestroyDevice, self)._check_device_dependencies()
+ def apply(self):
+ """ apply changes related to the action to the device(s) """
+ if self._applied:
+ return
+
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation += 1
+
+ super(ActionDestroyDevice, self).apply()
+
def execute(self, callbacks=None):
super(ActionDestroyDevice, self).execute(callbacks=callbacks)
self.device.destroy()
+ def cancel(self):
+ if not self._applied:
+ return
+
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation -= 1
+
+ super(ActionDestroyDevice, self).cancel()
+
def requires(self, action):
""" Return True if self requires action.
@@ -715,6 +734,9 @@ class ActionDestroyFormat(DeviceAction):
return
self.device.format = None
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation += 1
+
super(ActionDestroyFormat, self).apply()
def execute(self, callbacks=None):
@@ -739,6 +761,8 @@ class ActionDestroyFormat(DeviceAction):
return
self.device.format = self.orig_format
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation -= 1
super(ActionDestroyFormat, self).cancel()
@property
@@ -834,6 +858,9 @@ class ActionResizeFormat(DeviceAction):
return
self.device.format.target_size = self._target_size
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation += 1
+
super(ActionResizeFormat, self).apply()
def execute(self, callbacks=None):
@@ -854,6 +881,9 @@ class ActionResizeFormat(DeviceAction):
return
self.device.format.target_size = self.orig_size
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation -= 1
+
super(ActionResizeFormat, self).cancel()
def requires(self, action):
@@ -1056,6 +1086,9 @@ class ActionConfigureFormat(DeviceAction):
return
setattr(self.device.format, self.attr, self.new_value)
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation += 1
+
super(ActionConfigureFormat, self).apply()
def cancel(self):
@@ -1063,6 +1096,8 @@ class ActionConfigureFormat(DeviceAction):
return
setattr(self.device.format, self.attr, self.old_value)
+ if hasattr(self.device, 'ignore_skip_activation'):
+ self.device.ignore_skip_activation -= 1
def execute(self, callbacks=None):
super(ActionConfigureFormat, self).execute(callbacks=callbacks)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 06191110..58adf5cf 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -628,6 +628,8 @@ class LVMLogicalVolumeBase(DMDevice, RaidDevice):
self.uuid = uuid
self.seg_type = seg_type or "linear"
self._raid_level = None
+ self.ignore_skip_activation = 0
+
if self.seg_type in lvm.raid_seg_types:
self._raid_level = lvm.raid_levels.raid_level(self.seg_type)
else:
@@ -1367,12 +1369,6 @@ class LVMSnapshotMixin(object):
# the old snapshot cannot be setup and torn down
pass
- def _setup(self, orig=False):
- """ Open, or set up, a device. """
- log_method_call(self, self.name, orig=orig, status=self.status,
- controllable=self.controllable)
- blockdev.lvm.lvactivate(self.vg.name, self._name, ignore_skip=True)
-
@old_snapshot_specific
def teardown(self, recursive=False):
# the old snapshot cannot be setup and torn down
@@ -1969,12 +1965,12 @@ class LVMLogicalVolumeDevice(LVMLogicalVolumeBase, LVMInternalLogicalVolumeMixin
def display_lv_name(self):
return self.lvname
- @type_specific
def _setup(self, orig=False):
""" Open, or set up, a device. """
log_method_call(self, self.name, orig=orig, status=self.status,
controllable=self.controllable)
- blockdev.lvm.lvactivate(self.vg.name, self._name)
+ ignore_skip_activation = self.is_snapshot_lv or self.ignore_skip_activation > 0
+ blockdev.lvm.lvactivate(self.vg.name, self._name, ignore_skip=ignore_skip_activation)
@type_specific
def _pre_create(self):
diff --git a/tests/action_test.py b/tests/action_test.py
index 101d5a21..24ed10b2 100644
--- a/tests/action_test.py
+++ b/tests/action_test.py
@@ -1025,12 +1025,28 @@ class DeviceActionTestCase(StorageTestCase):
# ActionDestroyFormat
original_format = lv_root.format
action = ActionDestroyFormat(lv_root)
+ orig_ignore_skip = lv_root.ignore_skip_activation
self.assertEqual(lv_root.format, original_format)
self.assertNotEqual(lv_root.format.type, None)
action.apply()
self.assertEqual(lv_root.format.type, None)
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip + 1)
action.cancel()
self.assertEqual(lv_root.format, original_format)
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip)
+
+ # ActionDestroyDevice
+ action1 = ActionDestroyFormat(lv_root)
+ orig_ignore_skip = lv_root.ignore_skip_activation
+ action1.apply()
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip + 1)
+ action2 = ActionDestroyDevice(lv_root)
+ action2.apply()
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip + 2)
+ action2.cancel()
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip + 1)
+ action1.cancel()
+ self.assertEqual(lv_root.ignore_skip_activation, orig_ignore_skip)
sdc = self.storage.devicetree.get_device_by_name("sdc")
sdc.format = None
diff --git a/tests/devices_test/lvm_test.py b/tests/devices_test/lvm_test.py
index 76a3a5db..c4c50748 100644
--- a/tests/devices_test/lvm_test.py
+++ b/tests/devices_test/lvm_test.py
@@ -360,6 +360,35 @@ class LVMDeviceTest(unittest.TestCase):
with six.assertRaisesRegex(self, ValueError, "The volume group testvg cannot be created."):
LVMVolumeGroupDevice("testvg", parents=[pv, pv2])
+ def test_skip_activate(self):
+ pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("1 GiB"), exists=True)
+ vg = LVMVolumeGroupDevice("testvg", parents=[pv], exists=True)
+ lv = LVMLogicalVolumeDevice("data_lv", parents=[vg], size=Size("500 MiB"), exists=True)
+
+ with patch("blivet.devices.lvm.blockdev.lvm") as lvm:
+ with patch.object(lv, "_pre_setup"):
+ lv.setup()
+ self.assertTrue(lvm.lvactivate.called_with(vg.name, lv.lvname, ignore_skip=False))
+
+ lv.ignore_skip_activation += 1
+ with patch("blivet.devices.lvm.blockdev.lvm") as lvm:
+ with patch.object(lv, "_pre_setup"):
+ lv.setup()
+ self.assertTrue(lvm.lvactivate.called_with(vg.name, lv.lvname, ignore_skip=True))
+
+ lv.ignore_skip_activation += 1
+ with patch("blivet.devices.lvm.blockdev.lvm") as lvm:
+ with patch.object(lv, "_pre_setup"):
+ lv.setup()
+ self.assertTrue(lvm.lvactivate.called_with(vg.name, lv.lvname, ignore_skip=True))
+
+ lv.ignore_skip_activation -= 2
+ with patch("blivet.devices.lvm.blockdev.lvm") as lvm:
+ with patch.object(lv, "_pre_setup"):
+ lv.setup()
+ self.assertTrue(lvm.lvactivate.called_with(vg.name, lv.lvname, ignore_skip=False))
+
class TypeSpecificCallsTest(unittest.TestCase):
def test_type_specific_calls(self):
--
2.24.1
From 0e19f91ff0917b7c498cdc2e6d5484847cf18cee Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Tue, 17 Dec 2019 14:43:02 -0500
Subject: [PATCH 2/2] Make sure LVs are writable before wiping.
Related: rhbz#1766498
---
blivet/deviceaction.py | 3 +++
blivet/devicelibs/lvm.py | 18 ++++++++++++++++++
blivet/devices/lvm.py | 4 ++++
3 files changed, 25 insertions(+)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py
index 57115662..ac89365b 100644
--- a/blivet/deviceaction.py
+++ b/blivet/deviceaction.py
@@ -745,6 +745,9 @@ class ActionDestroyFormat(DeviceAction):
super(ActionDestroyFormat, self).execute(callbacks=callbacks)
status = self.device.status
self.device.setup(orig=True)
+ if hasattr(self.device, 'set_rw'):
+ self.device.set_rw()
+
self.format.destroy()
udev.settle()
if isinstance(self.device, PartitionDevice) and self.device.disklabel_supported:
diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index 8eea9d19..65dc425e 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -38,7 +38,9 @@ from . import raid
from ..size import Size
from ..i18n import N_
from ..flags import flags
+from ..static_data import lvs_info
from ..tasks import availability
+from ..util import run_program
# some of lvm's defaults that we have no way to ask it for
LVM_PE_START = Size("1 MiB")
@@ -187,6 +189,22 @@ def lvmetad_socket_exists():
return os.path.exists(LVMETAD_SOCKET_PATH)
+def ensure_lv_is_writable(vg_name, lv_name):
+ lv_info = lvs_info.cache.get("%s-%s" % (vg_name, lv_name))
+ if lv_info is None:
+ return
+
+ if lv_info.attr[1] == 'w':
+ return
+
+ try:
+ rc = run_program(['lvchange', '-prw', "%s/%s" % (vg_name, lv_name)])
+ except OSError:
+ rc = -1
+
+ return rc == 0
+
+
def is_lvm_name_valid(name):
# No . or ..
if name == '.' or name == '..':
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 58adf5cf..dbecc1e5 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -951,6 +951,10 @@ class LVMLogicalVolumeBase(DMDevice, RaidDevice):
# set up the vg's pvs so lvm can remove the lv
self.vg.setup_parents(orig=True)
+ def set_rw(self):
+ """ Run lvchange as needed to ensure the lv is not read-only. """
+ lvm.ensure_lv_is_writable(self.vg.name, self.lvname)
+
@property
def lvname(self):
""" The LV's name (not including VG name). """
--
2.24.1

View File

@ -0,0 +1,195 @@
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

View File

@ -0,0 +1,130 @@
From 4e23e410bb5fcab5db931ad42a9b46af6be4fb3d Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Thu, 16 Jan 2020 13:14:29 -0500
Subject: [PATCH 1/2] Add recognition of Dell FW RAID to udev.device_is_disk.
Resolves: rhbz#1758102
---
blivet/udev.py | 16 +++++++++++++++-
tests/udev_test.py | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/blivet/udev.py b/blivet/udev.py
index 53e7b7ca..df2b4e64 100644
--- a/blivet/udev.py
+++ b/blivet/udev.py
@@ -353,7 +353,7 @@ def device_is_disk(info):
device_is_dm_lvm(info) or
device_is_dm_crypt(info) or
(device_is_md(info) and
- not device_get_md_container(info))))
+ (not device_get_md_container(info) and not all(device_is_disk(d) for d in device_get_slaves(info))))))
def device_is_partition(info):
@@ -432,6 +432,20 @@ def device_get_devname(info):
return info.get('DEVNAME')
+def device_get_slaves(info):
+ """ Return a list of udev device objects representing this device's slaves. """
+ slaves_dir = device_get_sysfs_path(info) + "/slaves/"
+ names = list()
+ if os.path.isdir(slaves_dir):
+ names = os.listdir(slaves_dir)
+
+ slaves = list()
+ for name in names:
+ slaves.append(get_device(device_node="/dev/" + name))
+
+ return slaves
+
+
def device_get_md_level(info):
""" Returns the RAID level of the array of which this device is a member.
diff --git a/tests/udev_test.py b/tests/udev_test.py
index 5cc81a05..beb8109c 100644
--- a/tests/udev_test.py
+++ b/tests/udev_test.py
@@ -35,3 +35,45 @@ class UdevTest(unittest.TestCase):
import blivet.udev
blivet.udev.trigger()
self.assertTrue(blivet.udev.util.run_program.called)
+
+ @mock.patch('blivet.udev.device_is_cdrom', return_value=False)
+ @mock.patch('blivet.udev.device_is_partition', return_value=False)
+ @mock.patch('blivet.udev.device_is_dm_partition', return_value=False)
+ @mock.patch('blivet.udev.device_is_dm_lvm', return_value=False)
+ @mock.patch('blivet.udev.device_is_dm_crypt', return_value=False)
+ @mock.patch('blivet.udev.device_is_md')
+ @mock.patch('blivet.udev.device_get_md_container')
+ @mock.patch('blivet.udev.device_get_slaves')
+ def test_udev_device_is_disk_md(self, *args):
+ import blivet.udev
+ info = dict(DEVTYPE='disk', SYS_PATH=mock.sentinel.md_path)
+ (device_get_slaves, device_get_md_container, device_is_md) = args[:3] # pylint: disable=unbalanced-tuple-unpacking
+
+ disk_parents = [dict(DEVTYPE="disk", SYS_PATH='/fake/path/2'),
+ dict(DEVTYPE="disk", SYS_PATH='/fake/path/3')]
+ partition_parents = [dict(DEVTYPE="partition", SYS_PATH='/fake/path/2'),
+ dict(DEVTYPE="partition", SYS_PATH='/fake/path/3')]
+ mixed_parents = [dict(DEVTYPE="partition", SYS_PATH='/fake/path/2'),
+ dict(DEVTYPE="partition", SYS_PATH='/fake/path/3')]
+
+ blivet.udev.os.path.exists.return_value = False # has_range checked in device_is_disk
+ device_is_md.return_value = True
+
+ # Intel FW RAID (MD RAID w/ container layer)
+ # device_get_container will return some mock value which will evaluate to True
+ device_get_md_container.return_value = mock.sentinel.md_container
+ device_get_slaves.side_effect = lambda info: list()
+ self.assertTrue(blivet.udev.device_is_disk(info))
+
+ # Normal MD RAID
+ device_get_slaves.side_effect = lambda info: partition_parents if info['SYS_PATH'] == mock.sentinel.md_path else list()
+ device_get_md_container.return_value = None
+ self.assertFalse(blivet.udev.device_is_disk(info))
+
+ # Dell FW RAID (MD RAID whose members are all whole disks)
+ device_get_slaves.side_effect = lambda info: disk_parents if info['SYS_PATH'] == mock.sentinel.md_path else list()
+ self.assertTrue(blivet.udev.device_is_disk(info))
+
+ # Normal MD RAID (w/ at least one non-disk member)
+ device_get_slaves.side_effect = lambda info: mixed_parents if info['SYS_PATH'] == mock.sentinel.md_path else list()
+ self.assertFalse(blivet.udev.device_is_disk(info))
--
2.24.1
From 1d75298702f55830a3d69858c3b0b7defa7bf6f2 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Tue, 21 Jan 2020 15:28:27 -0500
Subject: [PATCH 2/2] Fix udev test names so they actually get run.
---
tests/udev_test.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/udev_test.py b/tests/udev_test.py
index beb8109c..653eeb6d 100644
--- a/tests/udev_test.py
+++ b/tests/udev_test.py
@@ -26,12 +26,12 @@ class UdevTest(unittest.TestCase):
for device in devices:
self.assertNotEqual(blivet.udev.get_device(device.sys_path), None)
- def udev_settle_test(self):
+ def test_udev_settle(self):
import blivet.udev
blivet.udev.settle()
self.assertTrue(blivet.udev.util.run_program.called)
- def udev_trigger_test(self):
+ def test_udev_trigger(self):
import blivet.udev
blivet.udev.trigger()
self.assertTrue(blivet.udev.util.run_program.called)
--
2.24.1

View File

@ -0,0 +1,71 @@
From a873679b9440105740e7e34f5a3fc9ce0f2c2ace Mon Sep 17 00:00:00 2001
From: Hongxu Jia <hongxu.jia@windriver.com>
Date: Tue, 28 Aug 2018 09:41:38 +0800
Subject: [PATCH 1/2] add `-y' to lvm.pvcreate
While reinstall a crypt fs, it occasionally failed
[snip]
|gi.overrides.BlockDev.LVMError: Process reported exit code 5:
WARNING: atari signature detected on /dev/mapper/luks-0e5f891c
-7701-48bc-a41e-8d626b6ef953 at offset 466. Wipe it? [y/n]:
[snip]
Add `-y' to lvm.pvcreate
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
blivet/formats/lvmpv.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
index 260cc0bd..96d25394 100644
--- a/blivet/formats/lvmpv.py
+++ b/blivet/formats/lvmpv.py
@@ -120,9 +120,8 @@ class LVMPhysicalVolume(DeviceFormat):
log_method_call(self, device=self.device,
type=self.type, status=self.status)
- # Consider use of -Z|--zero
- # -f|--force or -y|--yes may be required
- blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment)
+ ea_yes = blockdev.ExtraArg.new("-y", "")
+ blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
def _destroy(self, **kwargs):
log_method_call(self, device=self.device,
--
2.24.1
From d3d86ec2383bbd8e2797ebaaed551a3fbe8ee437 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Wed, 29 Aug 2018 10:05:29 +0200
Subject: [PATCH 2/2] Adjust LVMPhysicalVolumeMethodsTestCase to new pvcreate
option
Adjust tests to changes in f8a7ee3dbd6617eb9a0add96b2c4d124d78a1b98
---
tests/formats_test/methods_test.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/formats_test/methods_test.py b/tests/formats_test/methods_test.py
index 741c4f15..710fa1c5 100644
--- a/tests/formats_test/methods_test.py
+++ b/tests/formats_test/methods_test.py
@@ -389,10 +389,12 @@ class LVMPhysicalVolumeMethodsTestCase(FormatMethodsTestCase):
self.patches["blockdev"].lvm.pvremove.assert_called_with(self.format.device)
def _test_create_backend(self):
+ self.patches["blockdev"].ExtraArg.new.return_value = sentinel.extra_arg
self.format.exists = False
self.format.create()
self.patches["blockdev"].lvm.pvcreate.assert_called_with(self.format.device,
- data_alignment=self.format.data_alignment) # pylint: disable=no-member
+ data_alignment=self.format.data_alignment, # pylint: disable=no-member
+ extra=[sentinel.extra_arg])
class MDRaidMemberMethodsTestCase(FormatMethodsTestCase):
--
2.24.1

View File

@ -23,7 +23,7 @@ Version: 3.1.0
#%%global prerelease .b2
# prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2
Release: 17%{?prerelease}%{?dist}
Release: 20%{?prerelease}%{?dist}
Epoch: 1
License: LGPLv2+
Group: System Environment/Libraries
@ -56,6 +56,11 @@ Patch21: 0021-Correctly-handle-non-unicode-iSCSI-initiator-names.patch
Patch22: 0022-Do-not-crash-if-dm_get_member_raid_sets-fails.patch
Patch23: 0023-Minor-cleanups-to-reduce-log-noise.patch
Patch24: 0024-Fix-util.detect_virt-function.patch
Patch25: 0025-Check-for-PV-sector-size-when-creating-new-VG.patch
Patch26: 0026-Tell-lvm-to-ignore-skip-activation-flag-on-lvs-we-are-removing-or-otherwise-modifying.patch
Patch27: 0027-Align-base-partition-sizes-in-PartitionFactory.patch
Patch28: 0028-Add-recognition-of-Dell-FW-RAID-to-udev-device_is_disk.patch
Patch29: 0029-add-y-to-lvm.pvcreate.patch
# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).
@ -218,6 +223,28 @@ configuration.
%endif
%changelog
* Mon Mar 02 2020 Vojtech Trefny <vtrefny@redhat.com> - 3.1.0-20
- add `-y' to lvm.pvcreate
Resolves: rhbz#1768494
* Wed Jan 29 2020 Vojtech Trefny <vtrefny@redhat.com> - 3.1.0-19
- Override LVM skip-activation to allow for thorough removal
Resolves: rhbz#1766498
- Make sure LVs are writable before wiping
Related: rhbz#1766498
- Fix udev test names so they actually get run.
Related: rhbz#1758102
- Add recognition of Dell FW RAID to udev.device_is_disk.
Resolves: rhbz#1758102
- Align base sizes up if smaller than min I/O size.
Resolves: rhbz#1781106
- Make minimal and optimal alignment getters public.
Related: rhbz#1781106
* Tue Nov 19 2019 Vojtech Trefny <vtrefny@redhat.com> - 3.1.0-18
- Check for PV sector size when creating new VG
Resolves: rhbz#1754446
* Wed Oct 02 2019 David Lehman <dlehman@redhat.com> - 3.1.0-17
- Fix util.detect_virt function
Resolves: rhbz#1676935