Add support for specifying stripe size for RAID LVs

This commit is contained in:
Vojtech Trefny 2023-05-04 09:58:43 +02:00
parent b01a7c7308
commit 4c2a70e0da
2 changed files with 176 additions and 1 deletions

View File

@ -0,0 +1,170 @@
From ce21086cfce21faacdb29adb8e28ede24c2bfa50 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Thu, 9 Mar 2023 13:18:42 +0100
Subject: [PATCH] Add support for specifying stripe size for RAID LVs
---
blivet/devices/lvm.py | 28 +++++++++++++++++---
tests/storage_tests/devices_test/lvm_test.py | 12 +++++++--
tests/unit_tests/devices_test/lvm_test.py | 27 +++++++++++++++++++
3 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
index 434c359f6..e97b61916 100644
--- a/blivet/devices/lvm.py
+++ b/blivet/devices/lvm.py
@@ -659,7 +659,8 @@ class LVMLogicalVolumeBase(DMDevice, RaidDevice):
def __init__(self, name, parents=None, size=None, uuid=None, seg_type=None,
fmt=None, exists=False, sysfs_path='', grow=None, maxsize=None,
- percent=None, cache_request=None, pvs=None, from_lvs=None):
+ percent=None, cache_request=None, pvs=None, from_lvs=None,
+ stripe_size=0):
if not exists:
if seg_type not in [None, "linear", "thin", "thin-pool", "cache", "vdo-pool", "vdo", "cache-pool"] + lvm.raid_seg_types:
@@ -756,6 +757,15 @@ def __init__(self, name, parents=None, size=None, uuid=None, seg_type=None,
if self._pv_specs:
self._assign_pv_space()
+ self._stripe_size = stripe_size
+ if not self.exists and self._stripe_size:
+ if self.seg_type not in lvm.raid_seg_types:
+ raise errors.DeviceError("Stripe size can be specified only for RAID volumes")
+ if self.seg_type in ("raid1", "RAID1", "1", 1, "mirror"):
+ raise errors.DeviceError("Specifying stripe size is not allowed for RAID1 or mirror")
+ if self.cache:
+ raise errors.DeviceError("Creating cached LVs with custom stripe size is not supported")
+
def _assign_pv_space(self):
if not self.is_raid_lv:
# nothing to do for non-RAID (and thus non-striped) LVs here
@@ -2295,7 +2305,7 @@ def __init__(self, name, parents=None, size=None, uuid=None, seg_type=None,
parent_lv=None, int_type=None, origin=None, vorigin=False,
metadata_size=None, chunk_size=None, profile=None, from_lvs=None,
compression=False, deduplication=False, index_memory=0,
- write_policy=None, cache_mode=None, attach_to=None):
+ write_policy=None, cache_mode=None, attach_to=None, stripe_size=0):
"""
:param name: the device name (generally a device node's basename)
:type name: str
@@ -2375,6 +2385,11 @@ def __init__(self, name, parents=None, size=None, uuid=None, seg_type=None,
be attached to when created
:type attach_to: :class:`LVMLogicalVolumeDevice`
+ For RAID LVs only:
+
+ :keyword stripe_size: size of the RAID stripe
+ :type stripe_size: :class:`~.size.Size`
+
"""
if isinstance(parents, (list, ParentList)):
@@ -2395,7 +2410,8 @@ def __init__(self, name, parents=None, size=None, uuid=None, seg_type=None,
LVMCachePoolMixin.__init__(self, metadata_size, cache_mode, attach_to)
LVMLogicalVolumeBase.__init__(self, name, parents, size, uuid, seg_type,
fmt, exists, sysfs_path, grow, maxsize,
- percent, cache_request, pvs, from_lvs)
+ percent, cache_request, pvs, from_lvs,
+ stripe_size)
LVMVDOPoolMixin.__init__(self, compression, deduplication, index_memory,
write_policy)
LVMVDOLogicalVolumeMixin.__init__(self)
@@ -2661,8 +2677,12 @@ def _create(self):
pvs = [spec.pv.path for spec in self._pv_specs]
pvs = pvs or None
+ extra = dict()
+ if self._stripe_size:
+ extra["stripesize"] = str(int(self._stripe_size.convert_to("KiB")))
+
blockdev.lvm.lvcreate(self.vg.name, self._name, self.size,
- type=self.seg_type, pv_list=pvs)
+ type=self.seg_type, pv_list=pvs, **extra)
else:
fast_pvs = [pv.path for pv in self.cache.fast_pvs]
diff --git a/tests/storage_tests/devices_test/lvm_test.py b/tests/storage_tests/devices_test/lvm_test.py
index 2cb05f547..e2bc82cd9 100644
--- a/tests/storage_tests/devices_test/lvm_test.py
+++ b/tests/storage_tests/devices_test/lvm_test.py
@@ -1,5 +1,6 @@
import os
import shutil
+import subprocess
from ..storagetestcase import StorageTestCase
@@ -138,7 +139,7 @@ def test_lvm_thin(self):
self.assertTrue(snap.is_snapshot_lv)
self.assertEqual(snap.origin, thinlv)
- def _test_lvm_raid(self, seg_type, raid_level):
+ def _test_lvm_raid(self, seg_type, raid_level, stripe_size=0):
disk1 = self.storage.devicetree.get_device_by_path(self.vdevs[0])
self.assertIsNotNone(disk1)
self.storage.initialize_disk(disk1)
@@ -162,7 +163,7 @@ def _test_lvm_raid(self, seg_type, raid_level):
raidlv = self.storage.new_lv(fmt_type="ext4", size=blivet.size.Size("50 MiB"),
parents=[vg], name="blivetTestRAIDLV",
- seg_type=seg_type, pvs=[pv1, pv2])
+ seg_type=seg_type, pvs=[pv1, pv2], stripe_size=stripe_size)
self.storage.create_device(raidlv)
self.storage.do_it()
@@ -174,9 +175,16 @@ def _test_lvm_raid(self, seg_type, raid_level):
self.assertEqual(raidlv.raid_level, raid_level)
self.assertEqual(raidlv.seg_type, seg_type)
+ if stripe_size:
+ out = subprocess.check_output(["lvs", "-o", "stripe_size", "--noheadings", "--nosuffix", "--units=b", raidlv.vg.name + "/" + raidlv.lvname])
+ self.assertEqual(out.decode().strip(), str(int(stripe_size.convert_to())))
+
def test_lvm_raid_raid0(self):
self._test_lvm_raid("raid0", blivet.devicelibs.raid.RAID0)
+ def test_lvm_raid_raid0_stripe_size(self):
+ self._test_lvm_raid("raid0", blivet.devicelibs.raid.RAID0, stripe_size=blivet.size.Size("1 MiB"))
+
def test_lvm_raid_striped(self):
self._test_lvm_raid("striped", blivet.devicelibs.raid.Striped)
diff --git a/tests/unit_tests/devices_test/lvm_test.py b/tests/unit_tests/devices_test/lvm_test.py
index 636336c66..83f003c0e 100644
--- a/tests/unit_tests/devices_test/lvm_test.py
+++ b/tests/unit_tests/devices_test/lvm_test.py
@@ -363,6 +363,33 @@ def test_lvm_logical_volume_pv_free_cached(self):
self.assertEqual(pv.format.free, Size("264 MiB"))
self.assertEqual(pv2.format.free, Size("256 MiB"))
+ def test_lvm_logical_volume_raid_stripe_size(self):
+ pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("1025 MiB"))
+ pv2 = StorageDevice("pv2", fmt=blivet.formats.get_format("lvmpv"),
+ size=Size("513 MiB"))
+ vg = LVMVolumeGroupDevice("testvg", parents=[pv, pv2])
+
+ with self.assertRaises(blivet.errors.DeviceError):
+ # non-raid LV
+ lv = LVMLogicalVolumeDevice("testlv", parents=[vg], size=Size("1 GiB"),
+ fmt=blivet.formats.get_format("xfs"),
+ exists=False, stripe_size=Size("1 MiB"))
+
+ with self.assertRaises(blivet.errors.DeviceError):
+ # raid1 LV
+ lv = LVMLogicalVolumeDevice("testlv", parents=[vg], size=Size("1 GiB"),
+ fmt=blivet.formats.get_format("xfs"),
+ exists=False, seg_type="raid1", pvs=[pv, pv2],
+ stripe_size=Size("1 MiB"))
+
+ lv = LVMLogicalVolumeDevice("testlv", parents=[vg], size=Size("1 GiB"),
+ fmt=blivet.formats.get_format("xfs"),
+ exists=False, seg_type="raid0", pvs=[pv, pv2],
+ stripe_size=Size("1 MiB"))
+
+ self.assertEqual(lv._stripe_size, Size("1 MiB"))
+
@patch("blivet.formats.fs.Ext4FS.resizable", return_value=True)
def test_target_size(self, *args): # pylint: disable=unused-argument
pv = StorageDevice("pv1", fmt=blivet.formats.get_format("lvmpv"),

View File

@ -23,7 +23,7 @@ Version: 3.7.1
#%%global prerelease .b2
# prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2
Release: 1%{?prerelease}%{?dist}
Release: 2%{?prerelease}%{?dist}
Epoch: 1
License: LGPL-2.1-or-later
%global realname blivet
@ -35,6 +35,8 @@ Source1: http://github.com/storaged-project/blivet/archive/%{realname}-%{realver
Patch0: 0001-remove-btrfs-plugin.patch
%endif
Patch1: 0002-Add-support-for-specifying-stripe-size-for-RAID-LVs.patch
# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).
%global partedver 1.8.1
@ -196,6 +198,9 @@ configuration.
%endif
%changelog
* Thu May 04 2023 Vojtech Trefny <vtrefny@redhat.com> - 3.7.1-2
- Add support for specifying stripe size for RAID LVs
* Thu Mar 16 2023 Vojtech Trefny <vtrefny@redhat.com> - 3.7.1-1
- Fix the get_mount_device function (vponcova)
- Prefer using UUID for the kickstart --onpart argument (vtrefny)