diff --git a/0014-LVM-devices-file-support.patch b/0014-LVM-devices-file-support.patch
new file mode 100644
index 0000000..5baca1a
--- /dev/null
+++ b/0014-LVM-devices-file-support.patch
@@ -0,0 +1,774 @@
+From 43c5a6ef094e5f333a6dd47c467a1516488e2097 Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Mon, 24 May 2021 13:35:39 +0200
+Subject: [PATCH 1/7] Remove action device from LVM reject list
+
+Because the device doesn't depend on itself the existing code
+won't remove the device we are trying to modify from the list.
+
+Resolves: rhbz#1955942
+---
+ blivet/actionlist.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/blivet/actionlist.py b/blivet/actionlist.py
+index d03e32b9..2de3fed3 100644
+--- a/blivet/actionlist.py
++++ b/blivet/actionlist.py
+@@ -260,6 +260,7 @@ class ActionList(object):
+             log.debug("action: %s", action)
+ 
+             # Remove lvm filters for devices we are operating on
++            lvm.lvm_cc_removeFilterRejectRegexp(action.device.name)
+             for device in (d for d in devices if d.depends_on(action.device)):
+                 lvm.lvm_cc_removeFilterRejectRegexp(device.name)
+ 
+-- 
+2.31.1
+
+
+From 2db8aa0aa6ea03c182f7e8e08cd1371ded13b71c Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Mon, 24 May 2021 14:49:12 +0200
+Subject: [PATCH 2/7] Convert LVM filter lists to sets
+
+To prevent devices being added multiple times and removed only
+once.
+
+Related: rhbz#1955942
+---
+ blivet/devicelibs/lvm.py | 12 ++++++------
+ tests/devicetree_test.py |  6 +++---
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
+index 121797ce..9e396cca 100644
+--- a/blivet/devicelibs/lvm.py
++++ b/blivet/devicelibs/lvm.py
+@@ -72,8 +72,8 @@ safe_name_characters = "0-9a-zA-Z._-"
+ # Theoretically we can handle all that can be handled with the LVM --config
+ # argument.  For every time we call an lvm_cc (lvm compose config) funciton
+ # we regenerate the config_args with all global info.
+-config_args_data = {"filterRejects": [],    # regular expressions to reject.
+-                    "filterAccepts": []}   # regexp to accept
++config_args_data = {"filterRejects": set(),    # regular expressions to reject.
++                    "filterAccepts": set()}    # regexp to accept
+ 
+ 
+ def _set_global_config():
+@@ -125,7 +125,7 @@ def needs_config_refresh(fn):
+ def lvm_cc_addFilterRejectRegexp(regexp):
+     """ Add a regular expression to the --config string."""
+     log.debug("lvm filter: adding %s to the reject list", regexp)
+-    config_args_data["filterRejects"].append(regexp)
++    config_args_data["filterRejects"].add(regexp)
+ 
+ 
+ @needs_config_refresh
+@@ -134,15 +134,15 @@ def lvm_cc_removeFilterRejectRegexp(regexp):
+     log.debug("lvm filter: removing %s from the reject list", regexp)
+     try:
+         config_args_data["filterRejects"].remove(regexp)
+-    except ValueError:
++    except KeyError:
+         log.debug("%s wasn't in the reject list", regexp)
+         return
+ 
+ 
+ @needs_config_refresh
+ def lvm_cc_resetFilter():
+-    config_args_data["filterRejects"] = []
+-    config_args_data["filterAccepts"] = []
++    config_args_data["filterRejects"] = set()
++    config_args_data["filterAccepts"] = set()
+ 
+ 
+ def determine_parent_lv(internal_lv, lvs, lv_info):
+diff --git a/tests/devicetree_test.py b/tests/devicetree_test.py
+index d1f4d8f3..ef163c0a 100644
+--- a/tests/devicetree_test.py
++++ b/tests/devicetree_test.py
+@@ -125,7 +125,7 @@ class DeviceTreeTestCase(unittest.TestCase):
+         dt.actions._actions.append(Mock(name="fake action"))
+ 
+         lvm.lvm_cc_addFilterRejectRegexp("xxx")
+-        lvm.config_args_data["filterAccepts"].append("yyy")
++        lvm.config_args_data["filterAccepts"].add("yyy")
+ 
+         dt.ignored_disks.append(names[0])
+         dt.exclusive_disks.append(names[1])
+@@ -144,8 +144,8 @@ class DeviceTreeTestCase(unittest.TestCase):
+ 
+         self.assertEqual(dt._hidden, empty_list)
+ 
+-        self.assertEqual(lvm.config_args_data["filterAccepts"], empty_list)
+-        self.assertEqual(lvm.config_args_data["filterRejects"], empty_list)
++        self.assertEqual(lvm.config_args_data["filterAccepts"], set())
++        self.assertEqual(lvm.config_args_data["filterRejects"], set())
+ 
+         self.assertEqual(dt.exclusive_disks, empty_list)
+         self.assertEqual(dt.ignored_disks, empty_list)
+-- 
+2.31.1
+
+
+From e2540422945586ca45848a663e391a91b2fdd714 Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Tue, 27 Jul 2021 14:07:05 +0200
+Subject: [PATCH 3/7] Switch LVM devices filter from "reject" to "accept" by
+ default
+
+We currently use the LVM reject filter to filter out hidden and
+ignored devices, this commit changes the behaviour to reject all
+devices by default and accept only physical volumes that are not
+hidden or ignored. This is preparation for the switch from the
+existing lvm.conf based filtering to the new devices file based
+filtering introduced in LVM 2.03.12 which allows only listing
+"accepted" devices. This allows us to support both the "old" and
+"new" style filtering using the same code.
+---
+ blivet/actionlist.py                  |  5 +--
+ blivet/devicelibs/lvm.py              | 62 +++++++++++----------------
+ blivet/devices/lvm.py                 |  4 +-
+ blivet/devicetree.py                  |  8 ++--
+ blivet/formats/lvmpv.py               |  2 +
+ blivet/populator/helpers/lvm.py       |  6 +++
+ blivet/populator/helpers/partition.py |  8 ----
+ blivet/populator/populator.py         |  4 +-
+ tests/devicetree_test.py              | 37 ++++++++++++++--
+ tests/populator_test.py               |  6 ++-
+ 10 files changed, 81 insertions(+), 61 deletions(-)
+
+diff --git a/blivet/actionlist.py b/blivet/actionlist.py
+index 2de3fed3..f3977401 100644
+--- a/blivet/actionlist.py
++++ b/blivet/actionlist.py
+@@ -259,10 +259,9 @@ class ActionList(object):
+         for action in self._actions:
+             log.debug("action: %s", action)
+ 
+-            # Remove lvm filters for devices we are operating on
+-            lvm.lvm_cc_removeFilterRejectRegexp(action.device.name)
+             for device in (d for d in devices if d.depends_on(action.device)):
+-                lvm.lvm_cc_removeFilterRejectRegexp(device.name)
++                if device.format.type == "lvmpv":
++                    lvm.lvm_devices_add(device.path)
+ 
+     def _post_process(self, devices=None):
+         """ Clean up relics from action queue execution. """
+diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
+index 9e396cca..96d037b8 100644
+--- a/blivet/devicelibs/lvm.py
++++ b/blivet/devicelibs/lvm.py
+@@ -67,40 +67,29 @@ LVMETAD_SOCKET_PATH = "/run/lvm/lvmetad.socket"
+ 
+ safe_name_characters = "0-9a-zA-Z._-"
+ 
+-# Start config_args handling code
+-#
+-# Theoretically we can handle all that can be handled with the LVM --config
+-# argument.  For every time we call an lvm_cc (lvm compose config) funciton
+-# we regenerate the config_args with all global info.
+-config_args_data = {"filterRejects": set(),    # regular expressions to reject.
+-                    "filterAccepts": set()}    # regexp to accept
++# list of devices that LVM is allowed to use
++# with LVM >= 2.0.13 we'll use this for the --devices option and when creating
++# the /etc/lvm/devices/system.devices file
++# with older versions of LVM we will use this for the --config based filtering
++_lvm_devices = set()
+ 
+ 
+ def _set_global_config():
+     """lvm command accepts lvm.conf type arguments preceded by --config. """
+ 
+-    filter_string = ""
+-    rejects = config_args_data["filterRejects"]
+-    for reject in rejects:
+-        filter_string += ("\"r|/%s$|\"," % reject)
++    device_string = ""
++
++    # now explicitly "accept" all LVM devices
++    for device in _lvm_devices:
++        device_string += "\"a|%s$|\"," % device
+ 
+-    if filter_string:
+-        filter_string = "filter=[%s]" % filter_string.strip(",")
++    # now add all devices to the "reject" filter
++    device_string += "\"r|.*|\""
+ 
+-    # XXX consider making /tmp/blivet.lvm.XXXXX, writing an lvm.conf there, and
+-    #     setting LVM_SYSTEM_DIR
+-    devices_string = 'preferred_names=["^/dev/mapper/", "^/dev/md/", "^/dev/sd"]'
+-    if filter_string:
+-        devices_string += " %s" % filter_string
++    filter_string = "filter=[%s]" % device_string
+ 
+-    # for now ignore the LVM devices file and rely on our filters
+-    if availability.LVMDEVICES.available:
+-        devices_string += " use_devicesfile=0"
++    config_string = " devices { %s } " % filter_string
+ 
+-    # devices_string can have (inside the brackets) "dir", "scan",
+-    # "preferred_names", "filter", "cache_dir", "write_cache_state",
+-    # "types", "sysfs_scan", "md_component_detection".  see man lvm.conf.
+-    config_string = " devices { %s } " % (devices_string)  # strings can be added
+     if not flags.lvm_metadata_backup:
+         config_string += "backup {backup=0 archive=0} "
+     if flags.debug:
+@@ -122,27 +111,26 @@ def needs_config_refresh(fn):
+ 
+ 
+ @needs_config_refresh
+-def lvm_cc_addFilterRejectRegexp(regexp):
+-    """ Add a regular expression to the --config string."""
+-    log.debug("lvm filter: adding %s to the reject list", regexp)
+-    config_args_data["filterRejects"].add(regexp)
++def lvm_devices_add(path):
++    """ Add a device (PV) to the list of devices LVM is allowed to use """
++    log.debug("lvm filter: device %s added to the list of allowed devices")
++    _lvm_devices.add(path)
+ 
+ 
+ @needs_config_refresh
+-def lvm_cc_removeFilterRejectRegexp(regexp):
+-    """ Remove a regular expression from the --config string."""
+-    log.debug("lvm filter: removing %s from the reject list", regexp)
++def lvm_devices_remove(path):
++    """ Remove a device (PV) to the list of devices LVM is allowed to use """
++    log.debug("lvm filter: device %s removed from the list of allowed devices")
+     try:
+-        config_args_data["filterRejects"].remove(regexp)
++        _lvm_devices.remove(path)
+     except KeyError:
+-        log.debug("%s wasn't in the reject list", regexp)
++        log.debug("%s wasn't in the devices list", path)
+         return
+ 
+ 
+ @needs_config_refresh
+-def lvm_cc_resetFilter():
+-    config_args_data["filterRejects"] = set()
+-    config_args_data["filterAccepts"] = set()
++def lvm_devices_reset():
++    _lvm_devices.clear()
+ 
+ 
+ def determine_parent_lv(internal_lv, lvs, lv_info):
+diff --git a/blivet/devices/lvm.py b/blivet/devices/lvm.py
+index c61eeb4b..9c230f1b 100644
+--- a/blivet/devices/lvm.py
++++ b/blivet/devices/lvm.py
+@@ -273,8 +273,8 @@ class LVMVolumeGroupDevice(ContainerDevice):
+         log_method_call(self, self.name, status=self.status)
+         if not self.complete:
+             for pv in self.pvs:
+-                # Remove the PVs from the ignore filter so we can wipe them.
+-                lvm.lvm_cc_removeFilterRejectRegexp(pv.name)
++                # add PVS to the list of LVM devices so we can wipe them.
++                lvm.lvm_devices_add(pv.path)
+ 
+             # Don't run vgremove or vgreduce since there may be another VG with
+             # the same name that we want to keep/use.
+diff --git a/blivet/devicetree.py b/blivet/devicetree.py
+index f4ae1968..c6c1b440 100644
+--- a/blivet/devicetree.py
++++ b/blivet/devicetree.py
+@@ -96,7 +96,7 @@ class DeviceTreeBase(object):
+ 
+         self._hidden = []
+ 
+-        lvm.lvm_cc_resetFilter()
++        lvm.lvm_devices_reset()
+ 
+         self.exclusive_disks = exclusive_disks or []
+         self.ignored_disks = ignored_disks or []
+@@ -879,7 +879,8 @@ class DeviceTreeBase(object):
+         self._remove_device(device, force=True, modparent=False)
+ 
+         self._hidden.append(device)
+-        lvm.lvm_cc_addFilterRejectRegexp(device.name)
++        if device.format.type == "lvmpv":
++            lvm.lvm_devices_remove(device.path)
+ 
+     def unhide(self, device):
+         """ Restore a device's visibility.
+@@ -905,7 +906,8 @@ class DeviceTreeBase(object):
+                 self._hidden.remove(hidden)
+                 self._devices.append(hidden)
+                 hidden.add_hook(new=False)
+-                lvm.lvm_cc_removeFilterRejectRegexp(hidden.name)
++                if hidden.format.type == "lvmpv":
++                    lvm.lvm_devices_add(hidden.path)
+ 
+     def expand_taglist(self, taglist):
+         """ Expands tags in input list into devices.
+diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
+index ea84e9e4..3b00951f 100644
+--- a/blivet/formats/lvmpv.py
++++ b/blivet/formats/lvmpv.py
+@@ -124,6 +124,7 @@ class LVMPhysicalVolume(DeviceFormat):
+     def _create(self, **kwargs):
+         log_method_call(self, device=self.device,
+                         type=self.type, status=self.status)
++        lvm.lvm_devices_add(self.device)
+ 
+         lvm._set_global_config()
+ 
+@@ -138,6 +139,7 @@ class LVMPhysicalVolume(DeviceFormat):
+         except blockdev.LVMError:
+             DeviceFormat._destroy(self, **kwargs)
+         finally:
++            lvm.lvm_devices_remove(self.device)
+             udev.settle()
+ 
+     @property
+diff --git a/blivet/populator/helpers/lvm.py b/blivet/populator/helpers/lvm.py
+index c7adfa4e..9e7e4630 100644
+--- a/blivet/populator/helpers/lvm.py
++++ b/blivet/populator/helpers/lvm.py
+@@ -87,6 +87,12 @@ class LVMFormatPopulator(FormatPopulator):
+     def _get_kwargs(self):
+         kwargs = super(LVMFormatPopulator, self)._get_kwargs()
+ 
++        # new PV, add it to the LVM devices list and re-run pvs/lvs/vgs
++        lvm.lvm_devices_add(self.device.path)
++        pvs_info.drop_cache()
++        vgs_info.drop_cache()
++        lvs_info.drop_cache()
++
+         pv_info = pvs_info.cache.get(self.device.path, None)
+ 
+         name = udev.device_get_name(self.data)
+diff --git a/blivet/populator/helpers/partition.py b/blivet/populator/helpers/partition.py
+index f00323d1..8659bd48 100644
+--- a/blivet/populator/helpers/partition.py
++++ b/blivet/populator/helpers/partition.py
+@@ -24,7 +24,6 @@ import copy
+ import six
+ 
+ from ... import udev
+-from ...devicelibs import lvm
+ from ...devices import PartitionDevice
+ from ...errors import DeviceError
+ from ...formats import get_format
+@@ -66,7 +65,6 @@ class PartitionDevicePopulator(DevicePopulator):
+         if disk is None:
+             # if the disk is still not in the tree something has gone wrong
+             log.error("failure finding disk for %s", name)
+-            lvm.lvm_cc_addFilterRejectRegexp(name)
+             return
+ 
+         if not disk.partitioned or not disk.format.supported:
+@@ -78,12 +76,6 @@ class PartitionDevicePopulator(DevicePopulator):
+             # and instantiate a PartitionDevice so our view of the layout is
+             # complete.
+             if not disk.partitionable or disk.format.type == "iso9660" or disk.format.hidden:
+-                # there's no need to filter partitions on members of multipaths or
+-                # fwraid members from lvm since multipath and dmraid are already
+-                # active and lvm should therefore know to ignore them
+-                if not disk.format.hidden:
+-                    lvm.lvm_cc_addFilterRejectRegexp(name)
+-
+                 log.debug("ignoring partition %s on %s", name, disk.format.type)
+                 return
+ 
+diff --git a/blivet/populator/populator.py b/blivet/populator/populator.py
+index 75bb1741..958593ec 100644
+--- a/blivet/populator/populator.py
++++ b/blivet/populator/populator.py
+@@ -317,10 +317,10 @@ class PopulatorMixin(object):
+                 continue
+ 
+             # Make sure lvm doesn't get confused by PVs that belong to
+-            # incomplete VGs. We will remove the PVs from the reject list when/if
++            # incomplete VGs. We will add the PVs to the accept list when/if
+             # the time comes to remove the incomplete VG and its PVs.
+             for pv in vg.pvs:
+-                lvm.lvm_cc_addFilterRejectRegexp(pv.name)
++                lvm.lvm_devices_remove(pv.path)
+ 
+     def set_disk_images(self, images):
+         """ Set the disk images and reflect them in exclusive_disks.
+diff --git a/tests/devicetree_test.py b/tests/devicetree_test.py
+index ef163c0a..3be4d572 100644
+--- a/tests/devicetree_test.py
++++ b/tests/devicetree_test.py
+@@ -124,8 +124,7 @@ class DeviceTreeTestCase(unittest.TestCase):
+ 
+         dt.actions._actions.append(Mock(name="fake action"))
+ 
+-        lvm.lvm_cc_addFilterRejectRegexp("xxx")
+-        lvm.config_args_data["filterAccepts"].add("yyy")
++        lvm.lvm_devices_add("xxx")
+ 
+         dt.ignored_disks.append(names[0])
+         dt.exclusive_disks.append(names[1])
+@@ -144,8 +143,7 @@ class DeviceTreeTestCase(unittest.TestCase):
+ 
+         self.assertEqual(dt._hidden, empty_list)
+ 
+-        self.assertEqual(lvm.config_args_data["filterAccepts"], set())
+-        self.assertEqual(lvm.config_args_data["filterRejects"], set())
++        self.assertEqual(lvm._lvm_devices, set())
+ 
+         self.assertEqual(dt.exclusive_disks, empty_list)
+         self.assertEqual(dt.ignored_disks, empty_list)
+@@ -438,6 +436,37 @@ class DeviceTreeTestCase(unittest.TestCase):
+         self.assertEqual(tree.get_related_disks(sda), set([sda, sdb]))
+         self.assertEqual(tree.get_related_disks(sdb), set([sda, sdb]))
+ 
++    def test_lvm_filter_hide_unhide(self):
++        tree = DeviceTree()
++
++        sda = DiskDevice("sda", size=Size("30 GiB"))
++        sdb = DiskDevice("sdb", size=Size("30 GiB"))
++
++        tree._add_device(sda)
++        tree._add_device(sdb)
++
++        self.assertTrue(sda in tree.devices)
++        self.assertTrue(sdb in tree.devices)
++
++        sda.format = get_format("lvmpv", device=sda.path)
++        sdb.format = get_format("lvmpv", device=sdb.path)
++
++        # LVMPhysicalVolume._create would do this
++        lvm.lvm_devices_add(sda.path)
++        lvm.lvm_devices_add(sdb.path)
++
++        self.assertSetEqual(lvm._lvm_devices, {sda.path, sdb.path})
++
++        tree.hide(sda)
++        self.assertSetEqual(lvm._lvm_devices, {sdb.path})
++        tree.hide(sdb)
++        self.assertSetEqual(lvm._lvm_devices, set())
++
++        tree.unhide(sda)
++        self.assertSetEqual(lvm._lvm_devices, {sda.path})
++        tree.unhide(sdb)
++        self.assertSetEqual(lvm._lvm_devices, {sda.path, sdb.path})
++
+ 
+ class DeviceTreeIgnoredExclusiveMultipathTestCase(unittest.TestCase):
+ 
+diff --git a/tests/populator_test.py b/tests/populator_test.py
+index 2a8532f0..dd36c16a 100644
+--- a/tests/populator_test.py
++++ b/tests/populator_test.py
+@@ -13,6 +13,7 @@ from gi.repository import BlockDev as blockdev
+ from blivet.devices import DiskDevice, DMDevice, FileDevice, LoopDevice
+ from blivet.devices import MDRaidArrayDevice, MultipathDevice, OpticalDevice
+ from blivet.devices import PartitionDevice, StorageDevice, NVDIMMNamespaceDevice
++from blivet.devicelibs import lvm
+ from blivet.devicetree import DeviceTree
+ from blivet.formats import get_device_format_class, get_format, DeviceFormat
+ from blivet.formats.disklabel import DiskLabel
+@@ -393,8 +394,7 @@ class PartitionDevicePopulatorTestCase(PopulatorHelperTestCase):
+     @patch.object(DiskLabel, "parted_disk")
+     @patch.object(DiskLabel, "parted_device")
+     @patch.object(PartitionDevice, "probe")
+-    # TODO: fix the naming of the lvm filter functions
+-    @patch("blivet.devicelibs.lvm.lvm_cc_addFilterRejectRegexp")
++    @patch("blivet.devicelibs.lvm.lvm_devices_add")
+     @patch("blivet.udev.device_get_major", return_value=88)
+     @patch("blivet.udev.device_get_minor", return_value=19)
+     @patch.object(DeviceTree, "get_device_by_name")
+@@ -973,6 +973,8 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
+                     self.assertTrue(vg_device is not None)
+                     devicetree._remove_device(vg_device)
+ 
++                    self.assertIn(device.path, lvm._lvm_devices)
++
+         get_device_by_uuid.reset_mock()
+ 
+         # pv belongs to a valid vg not in the tree with two lvs
+-- 
+2.31.1
+
+
+From 15a63b01bd2b6e7fe197fade849f28b83407c166 Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Fri, 30 Jul 2021 14:01:04 +0200
+Subject: [PATCH 4/7] Use LVM devices for filtering LVM devices with LVM >=
+ 2.02.13
+
+---
+ blivet/devicelibs/lvm.py | 38 +++++++++++++++++++++++++++++---------
+ tests/populator_test.py  |  9 ++++-----
+ 2 files changed, 33 insertions(+), 14 deletions(-)
+
+diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
+index 96d037b8..3ab1540b 100644
+--- a/blivet/devicelibs/lvm.py
++++ b/blivet/devicelibs/lvm.py
+@@ -67,6 +67,16 @@ LVMETAD_SOCKET_PATH = "/run/lvm/lvmetad.socket"
+ 
+ safe_name_characters = "0-9a-zA-Z._-"
+ 
++if hasattr(blockdev.LVMTech, "DEVICES"):
++    try:
++        blockdev.lvm.is_tech_avail(blockdev.LVMTech.DEVICES, 0)  # pylint: disable=no-member
++    except blockdev.LVMError:
++        HAVE_LVMDEVICES = False
++    else:
++        HAVE_LVMDEVICES = True
++else:
++    HAVE_LVMDEVICES = False
++
+ # list of devices that LVM is allowed to use
+ # with LVM >= 2.0.13 we'll use this for the --devices option and when creating
+ # the /etc/lvm/devices/system.devices file
+@@ -79,25 +89,34 @@ def _set_global_config():
+ 
+     device_string = ""
+ 
+-    # now explicitly "accept" all LVM devices
+-    for device in _lvm_devices:
+-        device_string += "\"a|%s$|\"," % device
++    if not HAVE_LVMDEVICES:
++        # now explicitly "accept" all LVM devices
++        for device in _lvm_devices:
++            device_string += "\"a|%s$|\"," % device
+ 
+-    # now add all devices to the "reject" filter
+-    device_string += "\"r|.*|\""
++        # now add all devices to the "reject" filter
++        device_string += "\"r|.*|\""
+ 
+-    filter_string = "filter=[%s]" % device_string
++        filter_string = "filter=[%s]" % device_string
+ 
+-    config_string = " devices { %s } " % filter_string
++        config_string = " devices { %s } " % filter_string
++    else:
++        config_string = " "
+ 
+     if not flags.lvm_metadata_backup:
+         config_string += "backup {backup=0 archive=0} "
+-    if flags.debug:
+-        config_string += "log {level=7 file=/tmp/lvm.log syslog=0}"
++    config_string += "log {level=7 file=/tmp/lvm.log syslog=0}"
+ 
+     blockdev.lvm.set_global_config(config_string)
+ 
+ 
++def _set_lvm_devices():
++    if not HAVE_LVMDEVICES:
++        return
++
++    blockdev.lvm.set_devices_filter(list(_lvm_devices))
++
++
+ def needs_config_refresh(fn):
+     if not availability.BLOCKDEV_LVM_PLUGIN.available:
+         return lambda *args, **kwargs: None
+@@ -105,6 +124,7 @@ def needs_config_refresh(fn):
+     def fn_with_refresh(*args, **kwargs):
+         ret = fn(*args, **kwargs)
+         _set_global_config()
++        _set_lvm_devices()
+         return ret
+ 
+     return fn_with_refresh
+diff --git a/tests/populator_test.py b/tests/populator_test.py
+index dd36c16a..a9584319 100644
+--- a/tests/populator_test.py
++++ b/tests/populator_test.py
+@@ -897,6 +897,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
+         device = Mock()
+         device.parents = []
+         device.size = Size("10g")
++        device.path = "/dev/sda1"
+         devicetree._add_device(device)
+ 
+         # pylint: disable=attribute-defined-outside-init
+@@ -924,15 +925,13 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
+         pv_info.pe_start = 0
+         pv_info.pv_free = 0
+ 
+-        device.path = sentinel.pv_path
+-
+         vg_device = Mock()
+         vg_device.parents = []
+         vg_device.lvs = []
+         get_device_by_uuid.return_value = vg_device
+ 
+         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
+-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
++            mock_pvs_cache.return_value = {device.path: pv_info}
+             with patch("blivet.udev.device_get_format", return_value=self.udev_type):
+                 helper = self.helper_class(devicetree, data, device)
+                 self.assertFalse(device in vg_device.parents)
+@@ -957,7 +956,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
+         pv_info.vg_pv_count = 1
+ 
+         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
+-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
++            mock_pvs_cache.return_value = {device.path: pv_info}
+             with patch("blivet.static_data.lvm_info.VGsInfo.cache", new_callable=PropertyMock) as mock_vgs_cache:
+                 mock_vgs_cache.return_value = {pv_info.vg_uuid: Mock()}
+                 with patch("blivet.udev.device_get_format", return_value=self.udev_type):
+@@ -1007,7 +1006,7 @@ class LVMFormatPopulatorTestCase(FormatPopulatorTestCase):
+         get_device_by_uuid.side_effect = gdbu
+ 
+         with patch("blivet.static_data.lvm_info.PVsInfo.cache", new_callable=PropertyMock) as mock_pvs_cache:
+-            mock_pvs_cache.return_value = {sentinel.pv_path: pv_info}
++            mock_pvs_cache.return_value = {device.path: pv_info}
+             with patch("blivet.static_data.lvm_info.VGsInfo.cache", new_callable=PropertyMock) as mock_vgs_cache:
+                 mock_vgs_cache.return_value = {pv_info.vg_uuid: Mock()}
+                 with patch("blivet.static_data.lvm_info.LVsInfo.cache", new_callable=PropertyMock) as mock_lvs_cache:
+-- 
+2.31.1
+
+
+From d4e1395de3691f30196b6b0e3b2c82e83b27afaf Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Fri, 30 Jul 2021 14:01:43 +0200
+Subject: [PATCH 5/7] Make sure PVs are added/deleted to/from the LVM device
+ file
+
+We are using the --devices option when running LVM commands which
+mean the newly created PV won't be added to the device list by
+pvcreate so we need to do that manually.
+---
+ blivet/formats/lvmpv.py | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
+index 3b00951f..71ec699f 100644
+--- a/blivet/formats/lvmpv.py
++++ b/blivet/formats/lvmpv.py
+@@ -131,6 +131,9 @@ class LVMPhysicalVolume(DeviceFormat):
+         ea_yes = blockdev.ExtraArg.new("-y", "")
+         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
+ 
++        if lvm.HAVE_LVMDEVICES:
++            blockdev.lvm.devices_add(self.device)
++
+     def _destroy(self, **kwargs):
+         log_method_call(self, device=self.device,
+                         type=self.type, status=self.status)
+@@ -141,6 +144,8 @@ class LVMPhysicalVolume(DeviceFormat):
+         finally:
+             lvm.lvm_devices_remove(self.device)
+             udev.settle()
++            if lvm.HAVE_LVMDEVICES:
++                blockdev.lvm.devices_delete(self.device)
+ 
+     @property
+     def destroyable(self):
+-- 
+2.31.1
+
+
+From c221d313bde21fb2cba701b93fe0c57336cba8ec Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Thu, 14 Oct 2021 15:32:24 +0200
+Subject: [PATCH 6/7] Ignore errors for LVM devices file actions
+
+The LVM devices file feature might be disabled either locally or
+globally by LVM config.
+---
+ blivet/formats/lvmpv.py | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
+index 71ec699f..b27213cc 100644
+--- a/blivet/formats/lvmpv.py
++++ b/blivet/formats/lvmpv.py
+@@ -132,7 +132,10 @@ class LVMPhysicalVolume(DeviceFormat):
+         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
+ 
+         if lvm.HAVE_LVMDEVICES:
+-            blockdev.lvm.devices_add(self.device)
++            try:
++                blockdev.lvm.devices_add(self.device)
++            except blockdev.LVMError as e:
++                log.debug("Failed to add newly created PV %s to the LVM devices file: %s", self.device, str(e))
+ 
+     def _destroy(self, **kwargs):
+         log_method_call(self, device=self.device,
+@@ -145,7 +148,10 @@ class LVMPhysicalVolume(DeviceFormat):
+             lvm.lvm_devices_remove(self.device)
+             udev.settle()
+             if lvm.HAVE_LVMDEVICES:
+-                blockdev.lvm.devices_delete(self.device)
++                try:
++                    blockdev.lvm.devices_delete(self.device)
++                except blockdev.LVMError as e:
++                    log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
+ 
+     @property
+     def destroyable(self):
+-- 
+2.31.1
+
+
+From 6b96d4ead6890fffd95840b8935f71ecd9e310ef Mon Sep 17 00:00:00 2001
+From: Vojtech Trefny <vtrefny@redhat.com>
+Date: Tue, 19 Oct 2021 14:27:05 +0200
+Subject: [PATCH 7/7] Add public functions to add/remove PV to/from the LVM
+ system.devices
+
+Anaconda needs to be able to add preexisting PVs to the file
+during installation.
+---
+ blivet/formats/lvmpv.py | 28 ++++++++++++++++++++--------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
+index b27213cc..3fef667e 100644
+--- a/blivet/formats/lvmpv.py
++++ b/blivet/formats/lvmpv.py
+@@ -121,6 +121,24 @@ class LVMPhysicalVolume(DeviceFormat):
+     def supported(self):
+         return super(LVMPhysicalVolume, self).supported and self._plugin.available
+ 
++    def lvmdevices_add(self):
++        if not lvm.HAVE_LVMDEVICES:
++            raise PhysicalVolumeError("LVM devices file feature is not supported")
++
++        try:
++            blockdev.lvm.devices_add(self.device)
++        except blockdev.LVMError as e:
++            log.debug("Failed to add PV %s to the LVM devices file: %s", self.device, str(e))
++
++    def lvmdevices_remove(self):
++        if not lvm.HAVE_LVMDEVICES:
++            raise PhysicalVolumeError("LVM devices file feature is not supported")
++
++        try:
++            blockdev.lvm.devices_delete(self.device)
++        except blockdev.LVMError as e:
++            log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
++
+     def _create(self, **kwargs):
+         log_method_call(self, device=self.device,
+                         type=self.type, status=self.status)
+@@ -132,10 +150,7 @@ class LVMPhysicalVolume(DeviceFormat):
+         blockdev.lvm.pvcreate(self.device, data_alignment=self.data_alignment, extra=[ea_yes])
+ 
+         if lvm.HAVE_LVMDEVICES:
+-            try:
+-                blockdev.lvm.devices_add(self.device)
+-            except blockdev.LVMError as e:
+-                log.debug("Failed to add newly created PV %s to the LVM devices file: %s", self.device, str(e))
++            self.lvmdevices_add()
+ 
+     def _destroy(self, **kwargs):
+         log_method_call(self, device=self.device,
+@@ -148,10 +163,7 @@ class LVMPhysicalVolume(DeviceFormat):
+             lvm.lvm_devices_remove(self.device)
+             udev.settle()
+             if lvm.HAVE_LVMDEVICES:
+-                try:
+-                    blockdev.lvm.devices_delete(self.device)
+-                except blockdev.LVMError as e:
+-                    log.debug("Failed to remove PV %s from the LVM devices file: %s", self.device, str(e))
++                self.lvmdevices_remove()
+ 
+     @property
+     def destroyable(self):
+-- 
+2.31.1
+
diff --git a/python-blivet.spec b/python-blivet.spec
index 3a36bc0..8728358 100644
--- a/python-blivet.spec
+++ b/python-blivet.spec
@@ -23,7 +23,7 @@ Version: 3.4.0
 
 #%%global prerelease .b2
 # prerelease, if defined, should be something like .a1, .b1, .b2.dev1, or .c2
-Release: 9%{?prerelease}%{?dist}
+Release: 10%{?prerelease}%{?dist}
 Epoch: 1
 License: LGPLv2+
 %global realname blivet
@@ -42,6 +42,7 @@ Patch8: 0010-Fix-running-tests-in-gating.patch
 Patch9: 0011-Tell-LVM-to-ignore-the-new-devices-file-for-now.patch
 Patch10: 0012-Improve-error-message-printed-for-missing-dependecie.patch
 Patch11: 0013-Use-bigger-chunk-size-for-thinpools-bigger-than-15.8.patch
+Patch12: 0014-LVM-devices-file-support.patch
 
 # Versions of required components (done so we make sure the buildrequires
 # match the requires versions of things).
@@ -204,6 +205,10 @@ configuration.
 %endif
 
 %changelog
+* Thu Dec 09 2021 Vojtech Trefny <vtrefny@redhat.com> - 3.4.0-10
+- Use LVM devices file instead of filter regex
+  Resolves: rhbz#1967212
+
 * Tue Nov 30 2021 Vojtech Trefny <vtrefny@redhat.com> - 3.4.0-9
 - Rebuild with higher release number to fix errata
   Related: rhbz#2012121