From be0f89d540a0beda69d11105eec48953f870ecd6 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 2 Feb 2023 10:18:24 +0100 Subject: [PATCH] Use mdadm to support BIOS RAID devices (#2158574) --- 0002-Fedora-dmraid-mdadm.patch | 461 +++++++++++++++++++++++++++++++++ python-blivet.spec | 7 +- 2 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 0002-Fedora-dmraid-mdadm.patch diff --git a/0002-Fedora-dmraid-mdadm.patch b/0002-Fedora-dmraid-mdadm.patch new file mode 100644 index 0000000..0118f76 --- /dev/null +++ b/0002-Fedora-dmraid-mdadm.patch @@ -0,0 +1,461 @@ +From 2645236684b12a9a029f27c758fe5db12befabd7 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Wed, 17 Aug 2022 14:24:58 +0200 +Subject: [PATCH 1/2] Do not read DDF RAID UUID from udev + +The UUID we get from udev isn't the array UUID, we need to get +that using libblockdev. +--- + blivet/populator/helpers/mdraid.py | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/blivet/populator/helpers/mdraid.py b/blivet/populator/helpers/mdraid.py +index 3479e3f7..a7602d20 100644 +--- a/blivet/populator/helpers/mdraid.py ++++ b/blivet/populator/helpers/mdraid.py +@@ -98,17 +98,21 @@ class MDFormatPopulator(FormatPopulator): + + def _get_kwargs(self): + kwargs = super(MDFormatPopulator, self)._get_kwargs() +- try: +- # ID_FS_UUID contains the array UUID +- kwargs["md_uuid"] = udev.device_get_uuid(self.data) +- except KeyError: +- log.warning("mdraid member %s has no md uuid", udev.device_get_name(self.data)) ++ kwargs["biosraid"] = udev.device_is_biosraid_member(self.data) ++ if not kwargs["biosraid"]: ++ try: ++ # ID_FS_UUID contains the array UUID ++ kwargs["md_uuid"] = udev.device_get_uuid(self.data) ++ except KeyError: ++ log.warning("mdraid member %s has no md uuid", udev.device_get_name(self.data)) ++ else: ++ # for BIOS RAIDs we can't get the UUID from udev, we'll get it from mdadm in `run` below ++ kwargs["md_uuid"] = None + + # reset the uuid to the member-specific value + # this will be None for members of v0 metadata arrays + kwargs["uuid"] = udev.device_get_md_device_uuid(self.data) + +- kwargs["biosraid"] = udev.device_is_biosraid_member(self.data) + return kwargs + + def run(self): +-- +2.39.1 + + +From 951410368163de375174b4a9da1479695b5cd77d Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Wed, 18 Jan 2023 13:23:14 +0100 +Subject: [PATCH 2/2] Remove support for DMRAID devices + +Firmware/BIOS RAID devices will be handled by the MD code. +--- + blivet/devices/__init__.py | 2 +- + blivet/devices/disk.py | 87 ------------------------ + blivet/flags.py | 2 - + blivet/formats/dmraid.py | 55 +--------------- + blivet/formats/mdraid.py | 10 +-- + blivet/populator/helpers/__init__.py | 1 - + blivet/populator/helpers/dmraid.py | 98 ---------------------------- + blivet/populator/populator.py | 4 +- + 8 files changed, 7 insertions(+), 252 deletions(-) + delete mode 100644 blivet/populator/helpers/dmraid.py + +diff --git a/blivet/devices/__init__.py b/blivet/devices/__init__.py +index 8bb0a979..d90f0d0f 100644 +--- a/blivet/devices/__init__.py ++++ b/blivet/devices/__init__.py +@@ -22,7 +22,7 @@ + from .lib import device_path_to_name, device_name_to_disk_by_path, ParentList + from .device import Device + from .storage import StorageDevice +-from .disk import DiskDevice, DiskFile, DMRaidArrayDevice, MultipathDevice, iScsiDiskDevice, FcoeDiskDevice, DASDDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice ++from .disk import DiskDevice, DiskFile, MultipathDevice, iScsiDiskDevice, FcoeDiskDevice, DASDDevice, ZFCPDiskDevice, NVDIMMNamespaceDevice + from .partition import PartitionDevice + from .dm import DMDevice, DMLinearDevice, DMCryptDevice, DMIntegrityDevice, DM_MAJORS + from .luks import LUKSDevice, IntegrityDevice +diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py +index bc4a1b5e..18c8897f 100644 +--- a/blivet/devices/disk.py ++++ b/blivet/devices/disk.py +@@ -43,7 +43,6 @@ log = logging.getLogger("blivet") + + from .lib import Tags + from .storage import StorageDevice +-from .container import ContainerDevice + from .network import NetworkStorageDevice + from .dm import DMDevice + +@@ -216,92 +215,6 @@ class DiskFile(DiskDevice): + return size + + +-class DMRaidArrayDevice(DMDevice, ContainerDevice): +- +- """ A dmraid (device-mapper RAID) device """ +- _type = "dm-raid array" +- _packages = ["dmraid"] +- _partitionable = True +- _is_disk = True +- _format_class_name = property(lambda s: "dmraidmember") +- _format_uuid_attr = property(lambda s: None) +- _external_dependencies = [availability.BLOCKDEV_DM_PLUGIN_RAID] +- +- def __init__(self, name, fmt=None, +- size=None, parents=None, sysfs_path='', wwn=None): +- """ +- :param name: the device name (generally a device node's basename) +- :type name: str +- :keyword size: the device's size +- :type size: :class:`~.size.Size` +- :keyword parents: a list of parent devices +- :type parents: list of :class:`StorageDevice` +- :keyword fmt: this device's formatting +- :type fmt: :class:`~.formats.DeviceFormat` or a subclass of it +- :keyword sysfs_path: sysfs device path +- :type sysfs_path: str +- :keyword str wwn: the device's WWN +- +- DMRaidArrayDevices always exist. Blivet cannot create or destroy +- them. +- """ +- super(DMRaidArrayDevice, self).__init__(name, fmt=fmt, size=size, +- parents=parents, exists=True, +- sysfs_path=sysfs_path) +- self.wwn = wwn or None +- self.tags.add(Tags.local) +- +- @property +- def devices(self): +- """ Return a list of this array's member device instances. """ +- return self.parents +- +- def deactivate(self): +- """ Deactivate the raid set. """ +- log_method_call(self, self.name, status=self.status) +- # This call already checks if the set is not active. +- blockdev.dm.deactivate_raid_set(self.name) +- +- def activate(self): +- """ Activate the raid set. """ +- log_method_call(self, self.name, status=self.status) +- # This call already checks if the set is active. +- blockdev.dm.activate_raid_set(self.name) +- udev.settle() +- +- 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) +- self.activate() +- +- def teardown(self, recursive=None): +- """ Close, or tear down, a device. """ +- log_method_call(self, self.name, status=self.status, +- controllable=self.controllable) +- if not self._pre_teardown(recursive=recursive): +- return +- +- log.debug("not tearing down dmraid device %s", self.name) +- +- def _add(self, member): +- raise NotImplementedError() +- +- def _remove(self, member): +- raise NotImplementedError() +- +- @property +- def description(self): +- return "BIOS RAID set (%s)" % blockdev.dm.get_raid_set_type(self.name) +- +- @property +- def model(self): +- return self.description +- +- def dracut_setup_args(self): +- return set(["rd.dm.uuid=%s" % self.name]) +- +- + class MultipathDevice(DMDevice): + + """ A multipath device """ +diff --git a/blivet/flags.py b/blivet/flags.py +index 6364164d..4929b656 100644 +--- a/blivet/flags.py ++++ b/blivet/flags.py +@@ -46,7 +46,6 @@ class Flags(object): + else: + self.selinux = selinux.is_selinux_enabled() + +- self.dmraid = True + self.ibft = True + self.noiswmd = False + +@@ -103,7 +102,6 @@ class Flags(object): + def update_from_boot_cmdline(self): + self.get_boot_cmdline() + self.multipath = "nompath" not in self.boot_cmdline +- self.dmraid = "nodmraid" not in self.boot_cmdline + self.noiswmd = "noiswmd" in self.boot_cmdline + self.gfs2 = "gfs2" in self.boot_cmdline + self.jfs = "jfs" in self.boot_cmdline +diff --git a/blivet/formats/dmraid.py b/blivet/formats/dmraid.py +index 2ba9dcfe..fe1a4f13 100644 +--- a/blivet/formats/dmraid.py ++++ b/blivet/formats/dmraid.py +@@ -21,7 +21,6 @@ + # + + from ..storage_log import log_method_call +-from ..flags import flags + from ..errors import DMRaidMemberError + from ..i18n import N_ + from . import DeviceFormat, register_device_format +@@ -35,54 +34,14 @@ class DMRaidMember(DeviceFormat): + """ A dmraid member disk. """ + _type = "dmraidmember" + _name = N_("dm-raid member device") +- # XXX This looks like trouble. +- # +- # Maybe a better approach is a RaidMember format with subclass +- # for MDRaidMember, letting all *_raid_member types fall through +- # to the generic RaidMember format, which is basically read-only. +- # +- # One problem that presents is the possibility of someone passing +- # a dmraid member to the MDRaidArrayDevice constructor. +- _udev_types = ["adaptec_raid_member", "ddf_raid_member", +- "hpt37x_raid_member", "hpt45x_raid_member", +- "isw_raid_member", ++ ++ _udev_types = ["adaptec_raid_member", "hpt37x_raid_member", "hpt45x_raid_member", + "jmicron_raid_member", "lsi_mega_raid_member", + "nvidia_raid_member", "promise_fasttrack_raid_member", + "silicon_medley_raid_member", "via_raid_member"] +- _supported = True # is supported +- _packages = ["dmraid"] # required packages ++ _supported = False # is supported + _hidden = True # hide devices with this formatting? + +- def __init__(self, **kwargs): +- """ +- :keyword device: path to the underlying device (required) +- :type device: str +- :keyword uuid: this format's UUID +- :type uuid: str +- :keyword exists: whether this is an existing format +- :type exists: bool +- +- """ +- log_method_call(self, **kwargs) +- DeviceFormat.__init__(self, **kwargs) +- +- # Initialize the attribute that will hold the block object. +- self._raidmem = None +- +- def __repr__(self): +- s = DeviceFormat.__repr__(self) +- s += (" raidmem = %(raidmem)r" % {"raidmem": self.raidmem}) +- return s +- +- def _get_raidmem(self): +- return self._raidmem +- +- def _set_raidmem(self, raidmem): +- self._raidmem = raidmem +- +- raidmem = property(lambda d: d._get_raidmem(), +- lambda d, r: d._set_raidmem(r)) +- + def create(self, **kwargs): + log_method_call(self, device=self.device, + type=self.type, status=self.status) +@@ -94,12 +53,4 @@ class DMRaidMember(DeviceFormat): + raise DMRaidMemberError("destruction of dmraid members is non-sense") + + +-if not flags.noiswmd: +- DMRaidMember._udev_types.remove("isw_raid_member") +- +-# The anaconda cmdline has not been parsed yet when we're first imported, +-# so we can not use flags.dmraid here +-if not flags.dmraid: +- DMRaidMember._udev_types = [] +- + register_device_format(DMRaidMember) +diff --git a/blivet/formats/mdraid.py b/blivet/formats/mdraid.py +index 41ddef81..af1e4505 100644 +--- a/blivet/formats/mdraid.py ++++ b/blivet/formats/mdraid.py +@@ -28,7 +28,6 @@ from gi.repository import BlockDev as blockdev + from ..storage_log import log_method_call + from parted import PARTITION_RAID + from . import DeviceFormat, register_device_format +-from ..flags import flags + from ..i18n import N_ + from ..tasks import availability + +@@ -41,7 +40,7 @@ class MDRaidMember(DeviceFormat): + """ An mdraid member disk. """ + _type = "mdmember" + _name = N_("software RAID") +- _udev_types = ["linux_raid_member"] ++ _udev_types = ["linux_raid_member", "ddf_raid_member", "isw_raid_member"] + parted_flag = PARTITION_RAID + _formattable = True # can be formatted + _supported = True # is supported +@@ -113,11 +112,4 @@ class MDRaidMember(DeviceFormat): + self.md_uuid = uuid + + +-# nodmraid -> Wether to use BIOS RAID or not +-# Note the anaconda cmdline has not been parsed yet when we're first imported, +-# so we can not use flags.dmraid here +-if not flags.noiswmd and flags.dmraid: +- MDRaidMember._udev_types.append("isw_raid_member") +- +- + register_device_format(MDRaidMember) +diff --git a/blivet/populator/helpers/__init__.py b/blivet/populator/helpers/__init__.py +index c5ac412f..57f68c73 100644 +--- a/blivet/populator/helpers/__init__.py ++++ b/blivet/populator/helpers/__init__.py +@@ -9,7 +9,6 @@ from .boot import AppleBootFormatPopulator, EFIFormatPopulator, MacEFIFormatPopu + from .disk import DiskDevicePopulator, iScsiDevicePopulator, FCoEDevicePopulator, MDBiosRaidDevicePopulator, DASDDevicePopulator, ZFCPDevicePopulator, NVDIMMNamespaceDevicePopulator + from .disklabel import DiskLabelFormatPopulator + from .dm import DMDevicePopulator +-from .dmraid import DMRaidFormatPopulator + from .loop import LoopDevicePopulator + from .luks import LUKSDevicePopulator, LUKSFormatPopulator, IntegrityDevicePopulator, IntegrityFormatPopulator + from .lvm import LVMDevicePopulator, LVMFormatPopulator +diff --git a/blivet/populator/helpers/dmraid.py b/blivet/populator/helpers/dmraid.py +deleted file mode 100644 +index b126ac46..00000000 +--- a/blivet/populator/helpers/dmraid.py ++++ /dev/null +@@ -1,98 +0,0 @@ +-# populator/helpers/dmraid.py +-# DM RAID backend code for populating a DeviceTree. +-# +-# Copyright (C) 2009-2015 Red Hat, Inc. +-# +-# This copyrighted material is made available to anyone wishing to use, +-# modify, copy, or redistribute it subject to the terms and conditions of +-# the GNU Lesser General Public License v.2, or (at your option) any later +-# version. This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY expressed or implied, including the implied +-# warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +-# the GNU Lesser General Public License for more details. You should have +-# received a copy of the GNU Lesser General Public License along with this +-# program; if not, write to the Free Software Foundation, Inc., 51 Franklin +-# Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat trademarks +-# that are incorporated in the source code or documentation are not subject +-# to the GNU Lesser General Public License and may only be used or +-# replicated with the express permission of Red Hat, Inc. +-# +-# Red Hat Author(s): David Lehman +-# +- +-import gi +-gi.require_version("BlockDev", "2.0") +- +-from gi.repository import BlockDev as blockdev +- +-from ... import udev +-from ...devices import DMRaidArrayDevice +-from ...flags import flags +-from ...storage_log import log_method_call +-from .formatpopulator import FormatPopulator +- +-import logging +-log = logging.getLogger("blivet") +- +- +-class DMRaidFormatPopulator(FormatPopulator): +- priority = 100 +- _type_specifier = "dmraidmember" +- +- def run(self): +- super(DMRaidFormatPopulator, self).run() +- +- # if dmraid usage is disabled skip any dmraid set activation +- if not flags.dmraid: +- return +- +- log_method_call(self, name=self.device.name) +- name = udev.device_get_name(self.data) +- uuid = udev.device_get_uuid(self.data) +- major = udev.device_get_major(self.data) +- minor = udev.device_get_minor(self.data) +- +- # Have we already created the DMRaidArrayDevice? +- try: +- rs_names = blockdev.dm.get_member_raid_sets(name, uuid, major, minor) +- except blockdev.DMError as e: +- log.error("Failed to get RAID sets information for '%s': %s", name, str(e)) +- return +- +- if len(rs_names) == 0: +- log.warning("dmraid member %s does not appear to belong to any " +- "array", self.device.name) +- return +- +- for rs_name in rs_names: +- dm_array = self._devicetree.get_device_by_name(rs_name, incomplete=True) +- if dm_array is not None: +- # We add the new device. +- dm_array.parents.append(self.device) +- else: +- if not blockdev.dm.map_exists(rs_name, True, True): +- # Activate the Raid set. +- try: +- blockdev.dm.activate_raid_set(rs_name) +- except blockdev.DMError: +- log.warning("Failed to activate the RAID set '%s'", rs_name) +- return +- +- dm_array = DMRaidArrayDevice(rs_name, +- parents=[self.device], +- wwn=self.device.wwn) +- +- self._devicetree._add_device(dm_array) +- +- # Wait for udev to scan the just created nodes, to avoid a race +- # with the udev.get_device() call below. +- udev.settle() +- +- # Get the DMRaidArrayDevice a DiskLabel format *now*, in case +- # its partitions get scanned before it does. +- dm_array.update_sysfs_path() +- dm_array.update_size() +- dm_array_info = udev.get_device(dm_array.sysfs_path) +- if dm_array_info: +- dm_array.wwn = udev.device_get_wwn(dm_array_info) +- self._devicetree.handle_device(dm_array_info, update_orig_fmt=True) +diff --git a/blivet/populator/populator.py b/blivet/populator/populator.py +index 3a419418..139d2c76 100644 +--- a/blivet/populator/populator.py ++++ b/blivet/populator/populator.py +@@ -32,7 +32,7 @@ gi.require_version("BlockDev", "2.0") + from gi.repository import BlockDev as blockdev + + from ..errors import DeviceError, DeviceTreeError, NoParentsError +-from ..devices import DMLinearDevice, DMRaidArrayDevice ++from ..devices import DMLinearDevice + from ..devices import FileDevice, LoopDevice + from ..devices import MDRaidArrayDevice + from ..devices import MultipathDevice +@@ -219,7 +219,7 @@ class PopulatorMixin(object): + def _update_exclusive_disks(self, device): + # If we just added a multipath or fwraid disk that is in exclusive_disks + # we have to make sure all of its members are in the list too. +- mdclasses = (DMRaidArrayDevice, MDRaidArrayDevice, MultipathDevice) ++ mdclasses = (MDRaidArrayDevice, MultipathDevice) + if device.is_disk and isinstance(device, mdclasses): + if device.name in self.exclusive_disks: + for ancestor in device.ancestors: + +-- +2.39.1 + diff --git a/python-blivet.spec b/python-blivet.spec index f4135f8..9638aae 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -23,7 +23,7 @@ Version: 3.6.1 #%%global prerelease .b2 # prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2 -Release: 2%{?prerelease}%{?dist} +Release: 3%{?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-Fedora-dmraid-mdadm.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 Feb 02 2023 Vojtech Trefny - 3.6.1-3 +- Use mdadm to support BIOS RAID devices (#2158574) + * Fri Jan 20 2023 Fedora Release Engineering - 1:3.6.1-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild