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