neil / rpms / libblockdev

Forked from rpms/libblockdev a year ago
Clone

Blame SOURCES/0007-lvm-devices-file-support.patch

3b3b27
From e364883416785d51ff8eb132b63bd802ab0ccfe9 Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Tue, 13 Jul 2021 13:22:05 +0200
3b3b27
Subject: [PATCH 1/8] lvm: Allow configuring global "device filter" for LVM
3b3b27
 commands
3b3b27
3b3b27
Starting with 2.03.12 LVM introduces a new system for telling LVM
3b3b27
which devices it should use. The old device filters in config are
3b3b27
no longer working and we need to use either the system.devices
3b3b27
config file in /etc/lvm/devices (default behaviour) or specify
3b3b27
all allowed devices using the new --devices option. Because this
3b3b27
option must be specified for every call which might be incovenient
3b3b27
for our users, this commit introduces a new function to configure
3b3b27
this globally, which we already do for the --config option.
3b3b27
---
3b3b27
 src/lib/plugin_apis/lvm.api |  23 +++
3b3b27
 src/plugins/lvm-dbus.c      |  74 ++++++++-
3b3b27
 src/plugins/lvm.c           |  97 ++++++++++--
3b3b27
 src/plugins/lvm.h           |   4 +
3b3b27
 tests/library_test.py       | 304 ++++++++++++++++++++----------------
3b3b27
 tests/lvm_dbus_tests.py     |  47 +++++-
3b3b27
 tests/lvm_test.py           |  50 ++++++
3b3b27
 tests/overrides_test.py     |  23 ++-
3b3b27
 8 files changed, 469 insertions(+), 153 deletions(-)
3b3b27
3b3b27
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
3b3b27
index 563c104..62f602f 100644
3b3b27
--- a/src/lib/plugin_apis/lvm.api
3b3b27
+++ b/src/lib/plugin_apis/lvm.api
3b3b27
@@ -601,6 +601,7 @@ typedef enum {
3b3b27
     BD_LVM_TECH_CACHE_CALCS,
3b3b27
     BD_LVM_TECH_GLOB_CONF,
3b3b27
     BD_LVM_TECH_VDO,
3b3b27
+    BD_LVM_TECH_DEVICES,
3b3b27
 } BDLVMTech;
3b3b27
 
3b3b27
 typedef enum {
3b3b27
@@ -1214,6 +1215,28 @@ gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error);
3b3b27
  */
3b3b27
 gchar* bd_lvm_get_global_config (GError **error);
3b3b27
 
3b3b27
+/**
3b3b27
+ * bd_lvm_set_devices_filter:
3b3b27
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the devices filter was successfully set or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error);
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_get_devices_filter:
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
3b3b27
+ *                                                     the currently set LVM devices filter
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gchar** bd_lvm_get_devices_filter (GError **error);
3b3b27
+
3b3b27
 /**
3b3b27
  * bd_lvm_cache_get_default_md_size:
3b3b27
  * @cache_size: size of the cache to determine MD size for
3b3b27
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
3b3b27
index 144551f..d1726ed 100644
3b3b27
--- a/src/plugins/lvm-dbus.c
3b3b27
+++ b/src/plugins/lvm-dbus.c
3b3b27
@@ -35,6 +35,8 @@
3b3b27
 static GMutex global_config_lock;
3b3b27
 static gchar *global_config_str = NULL;
3b3b27
 
3b3b27
+static gchar *global_devices_str = NULL;
3b3b27
+
3b3b27
 #define LVM_BUS_NAME "com.redhat.lvmdbus1"
3b3b27
 #define LVM_OBJ_PREFIX "/com/redhat/lvmdbus1"
3b3b27
 #define MANAGER_OBJ "/com/redhat/lvmdbus1/Manager"
3b3b27
@@ -247,6 +249,14 @@ static volatile guint avail_features = 0;
3b3b27
 static volatile guint avail_module_deps = 0;
3b3b27
 static GMutex deps_check_lock;
3b3b27
 
3b3b27
+#define DEPS_LVMDEVICES 0
3b3b27
+#define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
3b3b27
+#define DEPS_LAST 1
3b3b27
+
3b3b27
+static const UtilDep deps[DEPS_LAST] = {
3b3b27
+    {"lvmdevices", NULL, NULL, NULL},
3b3b27
+};
3b3b27
+
3b3b27
 #define DBUS_DEPS_LVMDBUSD 0
3b3b27
 #define DBUS_DEPS_LVMDBUSD_MASK (1 << DBUS_DEPS_LVMDBUSD)
3b3b27
 #define DBUS_DEPS_LAST 1
3b3b27
@@ -385,6 +395,8 @@ gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
3b3b27
             return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error) &&
3b3b27
                    check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
3b3b27
                    check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error);
3b3b27
+    case BD_LVM_TECH_DEVICES:
3b3b27
+        return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
3b3b27
     default:
3b3b27
         /* everything is supported by this implementation of the plugin */
3b3b27
         return check_dbus_deps (&avail_dbus_deps, DBUS_DEPS_LVMDBUSD_MASK, dbus_deps, DBUS_DEPS_LAST, &deps_check_lock, error);
3b3b27
@@ -522,6 +534,7 @@ static gboolean unbox_params_and_add (GVariant *params, GVariantBuilder *builder
3b3b27
 
3b3b27
 static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gchar *method, GVariant *params, GVariant *extra_params, const BDExtraArg **extra_args, guint64 *task_id, guint64 *progress_id, gboolean lock_config, GError **error) {
3b3b27
     GVariant *config = NULL;
3b3b27
+    GVariant *devices = NULL;
3b3b27
     GVariant *param = NULL;
3b3b27
     GVariantIter iter;
3b3b27
     GVariantBuilder builder;
3b3b27
@@ -543,8 +556,8 @@ static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gch
3b3b27
     if (lock_config)
3b3b27
         g_mutex_lock (&global_config_lock);
3b3b27
 
3b3b27
-    if (global_config_str || extra_params || extra_args) {
3b3b27
-        if (global_config_str || extra_args) {
3b3b27
+    if (global_config_str || global_devices_str || extra_params || extra_args) {
3b3b27
+        if (global_config_str || global_devices_str || extra_args) {
3b3b27
             /* add the global config to the extra_params */
3b3b27
             g_variant_builder_init (&extra_builder, G_VARIANT_TYPE_DICTIONARY);
3b3b27
 
3b3b27
@@ -565,6 +578,11 @@ static GVariant* call_lvm_method (const gchar *obj, const gchar *intf, const gch
3b3b27
                 g_variant_builder_add (&extra_builder, "{sv}", "--config", config);
3b3b27
                 added_extra = TRUE;
3b3b27
             }
3b3b27
+            if (global_devices_str) {
3b3b27
+                devices = g_variant_new ("s", global_devices_str);
3b3b27
+                g_variant_builder_add (&extra_builder, "{sv}", "--devices", devices);
3b3b27
+                added_extra = TRUE;
3b3b27
+            }
3b3b27
 
3b3b27
             if (added_extra)
3b3b27
                 config_extra_params = g_variant_builder_end (&extra_builder);
3b3b27
@@ -2651,6 +2669,58 @@ gchar* bd_lvm_get_global_config (GError **error UNUSED) {
3b3b27
     return ret;
3b3b27
 }
3b3b27
 
3b3b27
+/**
3b3b27
+ * bd_lvm_set_devices_filter:
3b3b27
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the devices filter was successfully set or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error) {
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    g_mutex_lock (&global_config_lock);
3b3b27
+
3b3b27
+    /* first free the old value */
3b3b27
+    g_free (global_devices_str);
3b3b27
+
3b3b27
+    /* now store the new one */
3b3b27
+    if (!devices || !(*devices))
3b3b27
+        global_devices_str = NULL;
3b3b27
+    else
3b3b27
+        global_devices_str = g_strjoinv (",", (gchar **) devices);
3b3b27
+
3b3b27
+    g_mutex_unlock (&global_config_lock);
3b3b27
+    return TRUE;
3b3b27
+}
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_get_devices_filter:
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
3b3b27
+ *                                                     the currently set LVM devices filter
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gchar** bd_lvm_get_devices_filter (GError **error UNUSED) {
3b3b27
+    gchar **ret = NULL;
3b3b27
+
3b3b27
+    g_mutex_lock (&global_config_lock);
3b3b27
+
3b3b27
+    if (global_devices_str)
3b3b27
+        ret = g_strsplit (global_devices_str, ",", -1);
3b3b27
+    else
3b3b27
+        ret = NULL;
3b3b27
+
3b3b27
+    g_mutex_unlock (&global_config_lock);
3b3b27
+
3b3b27
+    return ret;
3b3b27
+}
3b3b27
+
3b3b27
 /**
3b3b27
  * bd_lvm_cache_get_default_md_size:
3b3b27
  * @cache_size: size of the cache to determine MD size for
3b3b27
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
3b3b27
index 2be1dbd..c0d8198 100644
3b3b27
--- a/src/plugins/lvm.c
3b3b27
+++ b/src/plugins/lvm.c
3b3b27
@@ -34,6 +34,8 @@
3b3b27
 static GMutex global_config_lock;
3b3b27
 static gchar *global_config_str = NULL;
3b3b27
 
3b3b27
+static gchar *global_devices_str = NULL;
3b3b27
+
3b3b27
 /**
3b3b27
  * SECTION: lvm
3b3b27
  * @short_description: plugin for operations with LVM
3b3b27
@@ -212,10 +214,13 @@ static GMutex deps_check_lock;
3b3b27
 
3b3b27
 #define DEPS_LVM 0
3b3b27
 #define DEPS_LVM_MASK (1 << DEPS_LVM)
3b3b27
-#define DEPS_LAST 1
3b3b27
+#define DEPS_LVMDEVICES 1
3b3b27
+#define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES)
3b3b27
+#define DEPS_LAST 2
3b3b27
 
3b3b27
 static const UtilDep deps[DEPS_LAST] = {
3b3b27
     {"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"},
3b3b27
+    {"lvmdevices", NULL, NULL, NULL},
3b3b27
 };
3b3b27
 
3b3b27
 #define FEATURES_VDO 0
3b3b27
@@ -327,6 +332,8 @@ gboolean bd_lvm_is_tech_avail (BDLVMTech tech, guint64 mode, GError **error) {
3b3b27
     case BD_LVM_TECH_VDO:
3b3b27
             return check_features (&avail_features, FEATURES_VDO_MASK, features, FEATURES_LAST, &deps_check_lock, error) &&
3b3b27
                    check_module_deps (&avail_module_deps, MODULE_DEPS_VDO_MASK, module_deps, MODULE_DEPS_LAST, &deps_check_lock, error);
3b3b27
+    case BD_LVM_TECH_DEVICES:
3b3b27
+            return check_deps (&avail_deps, DEPS_LVMDEVICES_MASK, deps, DEPS_LAST, &deps_check_lock, error);
3b3b27
     default:
3b3b27
         /* everything is supported by this implementation of the plugin */
3b3b27
         return check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error);
3b3b27
@@ -337,6 +344,8 @@ static gboolean call_lvm_and_report_error (const gchar **args, const BDExtraArg
3b3b27
     gboolean success = FALSE;
3b3b27
     guint i = 0;
3b3b27
     guint args_length = g_strv_length ((gchar **) args);
3b3b27
+    g_autofree gchar *config_arg = NULL;
3b3b27
+    g_autofree gchar *devices_arg = NULL;
3b3b27
 
3b3b27
     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
3b3b27
         return FALSE;
3b3b27
@@ -345,20 +354,26 @@ static gboolean call_lvm_and_report_error (const gchar **args, const BDExtraArg
3b3b27
     if (lock_config)
3b3b27
         g_mutex_lock (&global_config_lock);
3b3b27
 
3b3b27
-    /* allocate enough space for the args plus "lvm", "--config" and NULL */
3b3b27
-    const gchar **argv = g_new0 (const gchar*, args_length + 3);
3b3b27
+    /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
3b3b27
+    const gchar **argv = g_new0 (const gchar*, args_length + 4);
3b3b27
 
3b3b27
     /* construct argv from args with "lvm" prepended */
3b3b27
     argv[0] = "lvm";
3b3b27
     for (i=0; i < args_length; i++)
3b3b27
         argv[i+1] = args[i];
3b3b27
-    argv[args_length + 1] = global_config_str ? g_strdup_printf("--config=%s", global_config_str) : NULL;
3b3b27
-    argv[args_length + 2] = NULL;
3b3b27
+    if (global_config_str) {
3b3b27
+        config_arg = g_strdup_printf("--config=%s", global_config_str);
3b3b27
+        argv[++args_length] = config_arg;
3b3b27
+    }
3b3b27
+    if (global_devices_str) {
3b3b27
+        devices_arg = g_strdup_printf("--devices=%s", global_devices_str);
3b3b27
+        argv[++args_length] = devices_arg;
3b3b27
+    }
3b3b27
+    argv[++args_length] = NULL;
3b3b27
 
3b3b27
     success = bd_utils_exec_and_report_error (argv, extra, error);
3b3b27
     if (lock_config)
3b3b27
         g_mutex_unlock (&global_config_lock);
3b3b27
-    g_free ((gchar *) argv[args_length + 1]);
3b3b27
     g_free (argv);
3b3b27
 
3b3b27
     return success;
3b3b27
@@ -368,6 +383,8 @@ static gboolean call_lvm_and_capture_output (const gchar **args, const BDExtraAr
3b3b27
     gboolean success = FALSE;
3b3b27
     guint i = 0;
3b3b27
     guint args_length = g_strv_length ((gchar **) args);
3b3b27
+    g_autofree gchar *config_arg = NULL;
3b3b27
+    g_autofree gchar *devices_arg = NULL;
3b3b27
 
3b3b27
     if (!check_deps (&avail_deps, DEPS_LVM_MASK, deps, DEPS_LAST, &deps_check_lock, error))
3b3b27
         return FALSE;
3b3b27
@@ -375,19 +392,25 @@ static gboolean call_lvm_and_capture_output (const gchar **args, const BDExtraAr
3b3b27
     /* don't allow global config string changes during the run */
3b3b27
     g_mutex_lock (&global_config_lock);
3b3b27
 
3b3b27
-    /* allocate enough space for the args plus "lvm", "--config" and NULL */
3b3b27
-    const gchar **argv = g_new0 (const gchar*, args_length + 3);
3b3b27
+    /* allocate enough space for the args plus "lvm", "--config", "--devices" and NULL */
3b3b27
+    const gchar **argv = g_new0 (const gchar*, args_length + 4);
3b3b27
 
3b3b27
     /* construct argv from args with "lvm" prepended */
3b3b27
     argv[0] = "lvm";
3b3b27
     for (i=0; i < args_length; i++)
3b3b27
         argv[i+1] = args[i];
3b3b27
-    argv[args_length + 1] = global_config_str ? g_strdup_printf("--config=%s", global_config_str) : NULL;
3b3b27
-    argv[args_length + 2] = NULL;
3b3b27
+    if (global_config_str) {
3b3b27
+        config_arg = g_strdup_printf("--config=%s", global_config_str);
3b3b27
+        argv[++args_length] = config_arg;
3b3b27
+    }
3b3b27
+    if (global_devices_str) {
3b3b27
+        devices_arg = g_strdup_printf("--devices=%s", global_devices_str);
3b3b27
+        argv[++args_length] = devices_arg;
3b3b27
+    }
3b3b27
+    argv[++args_length] = NULL;
3b3b27
 
3b3b27
     success = bd_utils_exec_and_capture_output (argv, extra, output, error);
3b3b27
     g_mutex_unlock (&global_config_lock);
3b3b27
-    g_free ((gchar *) argv[args_length + 1]);
3b3b27
     g_free (argv);
3b3b27
 
3b3b27
     return success;
3b3b27
@@ -2018,6 +2041,58 @@ gchar* bd_lvm_get_global_config (GError **error UNUSED) {
3b3b27
     return ret;
3b3b27
 }
3b3b27
 
3b3b27
+/**
3b3b27
+ * bd_lvm_set_devices_filter:
3b3b27
+ * @devices: (allow-none) (array zero-terminated=1): list of devices for lvm commands to work on
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the devices filter was successfully set or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error) {
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    g_mutex_lock (&global_config_lock);
3b3b27
+
3b3b27
+    /* first free the old value */
3b3b27
+    g_free (global_devices_str);
3b3b27
+
3b3b27
+    /* now store the new one */
3b3b27
+    if (!devices || !(*devices))
3b3b27
+        global_devices_str = NULL;
3b3b27
+    else
3b3b27
+        global_devices_str = g_strjoinv (",", (gchar **) devices);
3b3b27
+
3b3b27
+    g_mutex_unlock (&global_config_lock);
3b3b27
+    return TRUE;
3b3b27
+}
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_get_devices_filter:
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: (transfer full) (array zero-terminated=1): a copy of a string representation of
3b3b27
+ *                                                     the currently set LVM devices filter
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gchar** bd_lvm_get_devices_filter (GError **error UNUSED) {
3b3b27
+    gchar **ret = NULL;
3b3b27
+
3b3b27
+    g_mutex_lock (&global_config_lock);
3b3b27
+
3b3b27
+    if (global_devices_str)
3b3b27
+        ret = g_strsplit (global_devices_str, ",", -1);
3b3b27
+    else
3b3b27
+        ret = NULL;
3b3b27
+
3b3b27
+    g_mutex_unlock (&global_config_lock);
3b3b27
+
3b3b27
+    return ret;
3b3b27
+}
3b3b27
+
3b3b27
 /**
3b3b27
  * bd_lvm_cache_get_default_md_size:
3b3b27
  * @cache_size: size of the cache to determine MD size for
3b3b27
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
3b3b27
index 2162d76..8063693 100644
3b3b27
--- a/src/plugins/lvm.h
3b3b27
+++ b/src/plugins/lvm.h
3b3b27
@@ -216,6 +216,7 @@ typedef enum {
3b3b27
     BD_LVM_TECH_CACHE_CALCS,
3b3b27
     BD_LVM_TECH_GLOB_CONF,
3b3b27
     BD_LVM_TECH_VDO,
3b3b27
+    BD_LVM_TECH_DEVICES,
3b3b27
 } BDLVMTech;
3b3b27
 
3b3b27
 typedef enum {
3b3b27
@@ -289,6 +290,9 @@ gboolean bd_lvm_thsnapshotcreate (const gchar *vg_name, const gchar *origin_name
3b3b27
 gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error);
3b3b27
 gchar* bd_lvm_get_global_config (GError **error);
3b3b27
 
3b3b27
+gboolean bd_lvm_set_devices_filter (const gchar **devices, GError **error);
3b3b27
+gchar** bd_lvm_get_devices_filter (GError **error);
3b3b27
+
3b3b27
 guint64 bd_lvm_cache_get_default_md_size (guint64 cache_size, GError **error);
3b3b27
 const gchar* bd_lvm_cache_get_mode_str (BDLVMCacheMode mode, GError **error);
3b3b27
 BDLVMCacheMode bd_lvm_cache_get_mode_from_str (const gchar *mode_str, GError **error);
3b3b27
diff --git a/tests/library_test.py b/tests/library_test.py
3b3b27
index 08e44fd..efd17bd 100644
3b3b27
--- a/tests/library_test.py
3b3b27
+++ b/tests/library_test.py
3b3b27
@@ -13,18 +13,178 @@ class LibraryOpsTestCase(unittest.TestCase):
3b3b27
     # all plugins except for 'btrfs', 'fs' and 'mpath' -- these don't have all
3b3b27
     # the dependencies on CentOS/Debian and we don't need them for this test
3b3b27
     requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "dm",
3b3b27
-                                                          "kbd", "loop", "lvm",
3b3b27
+                                                          "kbd", "loop",
3b3b27
                                                           "mdraid", "part", "swap"))
3b3b27
 
3b3b27
+    @classmethod
3b3b27
+    def setUpClass(cls):
3b3b27
+        if not BlockDev.is_initialized():
3b3b27
+            BlockDev.init(cls.requested_plugins, None)
3b3b27
+        else:
3b3b27
+            BlockDev.reinit(cls.requested_plugins, True, None)
3b3b27
+
3b3b27
+    @classmethod
3b3b27
+    def tearDownClass(cls):
3b3b27
+        BlockDev.switch_init_checks(True)
3b3b27
+
3b3b27
+    def my_log_func(self, level, msg):
3b3b27
+        # not much to verify here
3b3b27
+        self.assertTrue(isinstance(level, int))
3b3b27
+        self.assertTrue(isinstance(msg, str))
3b3b27
+
3b3b27
+        self.log += msg + "\n"
3b3b27
+
3b3b27
+    @tag_test(TestTags.CORE)
3b3b27
+    def test_logging_setup(self):
3b3b27
+        """Verify that setting up logging works as expected"""
3b3b27
+
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self.my_log_func))
3b3b27
+
3b3b27
+        succ = BlockDev.utils_exec_and_report_error(["true"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        # reinit with no logging function should change nothing about logging
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, None))
3b3b27
+
3b3b27
+        succ, out = BlockDev.utils_exec_and_capture_output(["echo", "hi"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertEqual(out, "hi\n")
3b3b27
+
3b3b27
+        match = re.search(r'Running \[(\d+)\] true', self.log)
3b3b27
+        self.assertIsNot(match, None)
3b3b27
+        task_id1 = match.group(1)
3b3b27
+        match = re.search(r'Running \[(\d+)\] echo hi', self.log)
3b3b27
+        self.assertIsNot(match, None)
3b3b27
+        task_id2 = match.group(1)
3b3b27
+
3b3b27
+        self.assertIn("...done [%s] (exit code: 0)" % task_id1, self.log)
3b3b27
+        self.assertIn("stdout[%s]:" % task_id1, self.log)
3b3b27
+        self.assertIn("stderr[%s]:" % task_id1, self.log)
3b3b27
+
3b3b27
+        self.assertIn("stdout[%s]: hi" % task_id2, self.log)
3b3b27
+        self.assertIn("stderr[%s]:" % task_id2, self.log)
3b3b27
+        self.assertIn("...done [%s] (exit code: 0)" % task_id2, self.log)
3b3b27
+
3b3b27
+    @tag_test(TestTags.CORE)
3b3b27
+    def test_require_plugins(self):
3b3b27
+        """Verify that loading only required plugins works as expected"""
3b3b27
+
3b3b27
+        ps = BlockDev.PluginSpec()
3b3b27
+        ps.name = BlockDev.Plugin.SWAP
3b3b27
+        ps.so_name = ""
3b3b27
+        self.assertTrue(BlockDev.reinit([ps], True, None))
3b3b27
+        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+
3b3b27
+    @tag_test(TestTags.CORE)
3b3b27
+    def test_not_implemented(self):
3b3b27
+        """Verify that unloaded/unimplemented functions report errors"""
3b3b27
+
3b3b27
+        # should be loaded and working
3b3b27
+        self.assertTrue(BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236"))
3b3b27
+
3b3b27
+        ps = BlockDev.PluginSpec()
3b3b27
+        ps.name = BlockDev.Plugin.SWAP
3b3b27
+        ps.so_name = ""
3b3b27
+        self.assertTrue(BlockDev.reinit([ps], True, None))
3b3b27
+        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
3b3b27
+
3b3b27
+        # no longer loaded
3b3b27
+        with self.assertRaises(GLib.GError):
3b3b27
+            BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
3b3b27
+
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+
3b3b27
+        # loaded again
3b3b27
+        self.assertTrue(BlockDev.md_canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236"))
3b3b27
+
3b3b27
+    def test_ensure_init(self):
3b3b27
+        """Verify that ensure_init just returns when already initialized"""
3b3b27
+
3b3b27
+        # the library is already initialized, ensure_init() shonuld do nothing
3b3b27
+        avail_plugs = BlockDev.get_available_plugin_names()
3b3b27
+        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
3b3b27
+        self.assertEqual(avail_plugs, BlockDev.get_available_plugin_names())
3b3b27
+
3b3b27
+        # reinit with a subset of plugins
3b3b27
+        plugins = BlockDev.plugin_specs_from_names(["swap", "part"])
3b3b27
+        self.assertTrue(BlockDev.reinit(plugins, True, None))
3b3b27
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part"]))
3b3b27
+
3b3b27
+        # ensure_init with the same subset -> nothing should change
3b3b27
+        self.assertTrue(BlockDev.ensure_init(plugins, None))
3b3b27
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part"]))
3b3b27
+
3b3b27
+        # ensure_init with more plugins -> extra plugins should be loaded
3b3b27
+        plugins = BlockDev.plugin_specs_from_names(["swap", "part", "crypto"])
3b3b27
+        self.assertTrue(BlockDev.ensure_init(plugins, None))
3b3b27
+        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "part", "crypto"]))
3b3b27
+
3b3b27
+        # reinit to unload all plugins
3b3b27
+        self.assertTrue(BlockDev.reinit([], True, None))
3b3b27
+        self.assertEqual(BlockDev.get_available_plugin_names(), [])
3b3b27
+
3b3b27
+        # ensure_init to load all plugins back
3b3b27
+        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
3b3b27
+        self.assertGreaterEqual(len(BlockDev.get_available_plugin_names()), 7)
3b3b27
+
3b3b27
+    def test_try_reinit(self):
3b3b27
+        """Verify that try_reinit() works as expected"""
3b3b27
+
3b3b27
+        # try reinitializing with only some utilities being available and thus
3b3b27
+        # only some plugins able to load
3b3b27
+        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "swaplabel"]):
3b3b27
+            succ, loaded = BlockDev.try_reinit(self.requested_plugins, True, None)
3b3b27
+            self.assertFalse(succ)
3b3b27
+            for plug_name in ("swap", "crypto"):
3b3b27
+                self.assertIn(plug_name, loaded)
3b3b27
+
3b3b27
+        # reset back to all plugins
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+
3b3b27
+        # now the same with a subset of plugins requested
3b3b27
+        plugins = BlockDev.plugin_specs_from_names(["swap", "crypto"])
3b3b27
+        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "swaplabel"]):
3b3b27
+            succ, loaded = BlockDev.try_reinit(plugins, True, None)
3b3b27
+            self.assertTrue(succ)
3b3b27
+            self.assertEqual(set(loaded), set(["swap", "crypto"]))
3b3b27
+
3b3b27
+    def test_non_en_init(self):
3b3b27
+        """Verify that the library initializes with lang different from en_US"""
3b3b27
+
3b3b27
+        orig_lang = os.environ.get("LANG")
3b3b27
+        os.environ["LANG"] = "cs.CZ_UTF-8"
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+        if orig_lang:
3b3b27
+            os.environ["LANG"] = orig_lang
3b3b27
+        else:
3b3b27
+            del os.environ["LANG"]
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+
3b3b27
+
3b3b27
+class PluginsTestCase(unittest.TestCase):
3b3b27
+    # only LVM plugin for this test
3b3b27
+    requested_plugins = BlockDev.plugin_specs_from_names(("lvm",))
3b3b27
+
3b3b27
     orig_config_dir = ""
3b3b27
 
3b3b27
     @classmethod
3b3b27
     def setUpClass(cls):
3b3b27
+        BlockDev.switch_init_checks(False)
3b3b27
         if not BlockDev.is_initialized():
3b3b27
             BlockDev.init(cls.requested_plugins, None)
3b3b27
         else:
3b3b27
             BlockDev.reinit(cls.requested_plugins, True, None)
3b3b27
 
3b3b27
+        try:
3b3b27
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
3b3b27
+        except:
3b3b27
+            cls.devices_avail = False
3b3b27
+
3b3b27
+    @classmethod
3b3b27
+    def tearDownClass(cls):
3b3b27
+        BlockDev.switch_init_checks(True)
3b3b27
+
3b3b27
     def setUp(self):
3b3b27
         self.orig_config_dir = os.environ.get("LIBBLOCKDEV_CONFIG_DIR", "")
3b3b27
         self.addCleanup(self._clean_up)
3b3b27
@@ -185,6 +345,12 @@ class LibraryOpsTestCase(unittest.TestCase):
3b3b27
     def test_plugin_fallback(self):
3b3b27
         """Verify that fallback when loading plugins works as expected"""
3b3b27
 
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping plugin fallback test: missing some LVM dependencies")
3b3b27
+
3b3b27
+        BlockDev.switch_init_checks(True)
3b3b27
+        self.addCleanup(BlockDev.switch_init_checks, False)
3b3b27
+
3b3b27
         # library should be successfully initialized
3b3b27
         self.assertTrue(BlockDev.is_initialized())
3b3b27
 
3b3b27
@@ -206,7 +372,7 @@ class LibraryOpsTestCase(unittest.TestCase):
3b3b27
 
3b3b27
         # now reinit the library with the config preferring the new build
3b3b27
         orig_conf_dir = os.environ.get("LIBBLOCKDEV_CONFIG_DIR")
3b3b27
-        os.environ["LIBBLOCKDEV_CONFIG_DIR"] = "tests/plugin_prio_conf.d"
3b3b27
+        os.environ["LIBBLOCKDEV_CONFIG_DIR"] = "tests/test_configs/plugin_prio_conf.d"
3b3b27
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
 
3b3b27
         # the original plugin should be loaded because the new one should fail
3b3b27
@@ -243,139 +409,9 @@ class LibraryOpsTestCase(unittest.TestCase):
3b3b27
 
3b3b27
         self.assertEqual(BlockDev.lvm_get_max_lv_size(), orig_max_size)
3b3b27
 
3b3b27
-    def my_log_func(self, level, msg):
3b3b27
-        # not much to verify here
3b3b27
-        self.assertTrue(isinstance(level, int))
3b3b27
-        self.assertTrue(isinstance(msg, str))
3b3b27
-
3b3b27
-        self.log += msg + "\n"
3b3b27
-
3b3b27
-    @tag_test(TestTags.CORE)
3b3b27
-    def test_logging_setup(self):
3b3b27
-        """Verify that setting up logging works as expected"""
3b3b27
-
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self.my_log_func))
3b3b27
-
3b3b27
-        succ = BlockDev.utils_exec_and_report_error(["true"])
3b3b27
-        self.assertTrue(succ)
3b3b27
-
3b3b27
-        # reinit with no logging function should change nothing about logging
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, None))
3b3b27
-
3b3b27
-        succ, out = BlockDev.utils_exec_and_capture_output(["echo", "hi"])
3b3b27
-        self.assertTrue(succ)
3b3b27
-        self.assertEqual(out, "hi\n")
3b3b27
-
3b3b27
-        match = re.search(r'Running \[(\d+)\] true', self.log)
3b3b27
-        self.assertIsNot(match, None)
3b3b27
-        task_id1 = match.group(1)
3b3b27
-        match = re.search(r'Running \[(\d+)\] echo hi', self.log)
3b3b27
-        self.assertIsNot(match, None)
3b3b27
-        task_id2 = match.group(1)
3b3b27
-
3b3b27
-        self.assertIn("...done [%s] (exit code: 0)" % task_id1, self.log)
3b3b27
-        self.assertIn("stdout[%s]:" % task_id1, self.log)
3b3b27
-        self.assertIn("stderr[%s]:" % task_id1, self.log)
3b3b27
-
3b3b27
-        self.assertIn("stdout[%s]: hi" % task_id2, self.log)
3b3b27
-        self.assertIn("stderr[%s]:" % task_id2, self.log)
3b3b27
-        self.assertIn("...done [%s] (exit code: 0)" % task_id2, self.log)
3b3b27
-
3b3b27
-    @tag_test(TestTags.CORE)
3b3b27
-    def test_require_plugins(self):
3b3b27
-        """Verify that loading only required plugins works as expected"""
3b3b27
-
3b3b27
-        ps = BlockDev.PluginSpec()
3b3b27
-        ps.name = BlockDev.Plugin.SWAP
3b3b27
-        ps.so_name = ""
3b3b27
-        self.assertTrue(BlockDev.reinit([ps], True, None))
3b3b27
-        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
-
3b3b27
-    @tag_test(TestTags.CORE)
3b3b27
-    def test_not_implemented(self):
3b3b27
-        """Verify that unloaded/unimplemented functions report errors"""
3b3b27
-
3b3b27
-        # should be loaded and working
3b3b27
-        self.assertTrue(BlockDev.lvm_get_max_lv_size() > 0)
3b3b27
 
3b3b27
-        ps = BlockDev.PluginSpec()
3b3b27
-        ps.name = BlockDev.Plugin.SWAP
3b3b27
-        ps.so_name = ""
3b3b27
-        self.assertTrue(BlockDev.reinit([ps], True, None))
3b3b27
-        self.assertEqual(BlockDev.get_available_plugin_names(), ["swap"])
3b3b27
-
3b3b27
-        # no longer loaded
3b3b27
-        with self.assertRaises(GLib.GError):
3b3b27
-            BlockDev.lvm_get_max_lv_size()
3b3b27
-
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
-
3b3b27
-        # loaded again
3b3b27
-        self.assertTrue(BlockDev.lvm_get_max_lv_size() > 0)
3b3b27
-
3b3b27
-    def test_ensure_init(self):
3b3b27
-        """Verify that ensure_init just returns when already initialized"""
3b3b27
-
3b3b27
-        # the library is already initialized, ensure_init() shonuld do nothing
3b3b27
-        avail_plugs = BlockDev.get_available_plugin_names()
3b3b27
-        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
3b3b27
-        self.assertEqual(avail_plugs, BlockDev.get_available_plugin_names())
3b3b27
-
3b3b27
-        # reinit with a subset of plugins
3b3b27
-        plugins = BlockDev.plugin_specs_from_names(["swap", "lvm"])
3b3b27
-        self.assertTrue(BlockDev.reinit(plugins, True, None))
3b3b27
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm"]))
3b3b27
-
3b3b27
-        # ensure_init with the same subset -> nothing should change
3b3b27
-        self.assertTrue(BlockDev.ensure_init(plugins, None))
3b3b27
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm"]))
3b3b27
-
3b3b27
-        # ensure_init with more plugins -> extra plugins should be loaded
3b3b27
-        plugins = BlockDev.plugin_specs_from_names(["swap", "lvm", "crypto"])
3b3b27
-        self.assertTrue(BlockDev.ensure_init(plugins, None))
3b3b27
-        self.assertEqual(set(BlockDev.get_available_plugin_names()), set(["swap", "lvm", "crypto"]))
3b3b27
-
3b3b27
-        # reinit to unload all plugins
3b3b27
-        self.assertTrue(BlockDev.reinit([], True, None))
3b3b27
-        self.assertEqual(BlockDev.get_available_plugin_names(), [])
3b3b27
-
3b3b27
-        # ensure_init to load all plugins back
3b3b27
-        self.assertTrue(BlockDev.ensure_init(self.requested_plugins, None))
3b3b27
-        self.assertGreaterEqual(len(BlockDev.get_available_plugin_names()), 8)
3b3b27
-
3b3b27
-    def test_try_reinit(self):
3b3b27
-        """Verify that try_reinit() works as expected"""
3b3b27
-
3b3b27
-        # try reinitializing with only some utilities being available and thus
3b3b27
-        # only some plugins able to load
3b3b27
-        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "lvm", "swaplabel"]):
3b3b27
-            succ, loaded = BlockDev.try_reinit(self.requested_plugins, True, None)
3b3b27
-            self.assertFalse(succ)
3b3b27
-            for plug_name in ("swap", "lvm", "crypto"):
3b3b27
-                self.assertIn(plug_name, loaded)
3b3b27
-
3b3b27
-        # reset back to all plugins
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
-
3b3b27
-        # now the same with a subset of plugins requested
3b3b27
-        plugins = BlockDev.plugin_specs_from_names(["lvm", "swap", "crypto"])
3b3b27
-        with fake_path("tests/lib_missing_utils", keep_utils=["swapon", "swapoff", "mkswap", "lvm","swaplabel"]):
3b3b27
-            succ, loaded = BlockDev.try_reinit(plugins, True, None)
3b3b27
-            self.assertTrue(succ)
3b3b27
-            self.assertEqual(set(loaded), set(["swap", "lvm", "crypto"]))
3b3b27
-
3b3b27
-    def test_non_en_init(self):
3b3b27
-        """Verify that the library initializes with lang different from en_US"""
3b3b27
-
3b3b27
-        orig_lang = os.environ.get("LANG")
3b3b27
-        os.environ["LANG"] = "cs.CZ_UTF-8"
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
-        if orig_lang:
3b3b27
-            os.environ["LANG"] = orig_lang
3b3b27
-        else:
3b3b27
-            del os.environ["LANG"]
3b3b27
-        self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
+class DepChecksTestCase(unittest.TestCase):
3b3b27
+    requested_plugins = BlockDev.plugin_specs_from_names(( "swap",))
3b3b27
 
3b3b27
     def test_dep_checks_disabled(self):
3b3b27
         """Verify that disabling runtime dep checks works"""
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index 4882da8..35ace37 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -33,6 +33,11 @@ class LVMTestCase(unittest.TestCase):
3b3b27
             else:
3b3b27
                 BlockDev.reinit([cls.ps, cls.ps2], True, None)
3b3b27
 
3b3b27
+        try:
3b3b27
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
3b3b27
+        except:
3b3b27
+            cls.devices_avail = False
3b3b27
+
3b3b27
     @classmethod
3b3b27
     def _get_lvm_version(cls):
3b3b27
         _ret, out, _err = run_command("lvm version")
3b3b27
@@ -44,8 +49,7 @@ class LVMTestCase(unittest.TestCase):
3b3b27
 @unittest.skipUnless(lvm_dbus_running, "LVM DBus not running")
3b3b27
 class LvmNoDevTestCase(LVMTestCase):
3b3b27
 
3b3b27
-    def __init__(self, *args, **kwargs):
3b3b27
-        super(LvmNoDevTestCase, self).__init__(*args, **kwargs)
3b3b27
+    def setUp(self):
3b3b27
         self._log = ""
3b3b27
 
3b3b27
     @tag_test(TestTags.NOSTORAGE)
3b3b27
@@ -227,6 +231,45 @@ class LvmNoDevTestCase(LVMTestCase):
3b3b27
         succ = BlockDev.lvm_set_global_config(None)
3b3b27
         self.assertTrue(succ)
3b3b27
 
3b3b27
+    @tag_test(TestTags.NOSTORAGE)
3b3b27
+    def test_get_set_global_devices_filter(self):
3b3b27
+        """Verify that getting and setting LVM devices filter works as expected"""
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices filter test: not supported")
3b3b27
+
3b3b27
+        # setup logging
3b3b27
+        self.assertTrue(BlockDev.reinit([self.ps], False, self._store_log))
3b3b27
+
3b3b27
+        # no global config set initially
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
3b3b27
+
3b3b27
+        # set and try to get back
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sda"])
3b3b27
+
3b3b27
+        # reset and try to get back
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(None)
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
3b3b27
+
3b3b27
+        # set twice and try to get back twice
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sdb"])
3b3b27
+
3b3b27
+        # set something sane and check it's really used
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb", "/dev/sdc"])
3b3b27
+        BlockDev.lvm_pvscan()
3b3b27
+        self.assertIn("'--devices'", self._log)
3b3b27
+        self.assertIn("'/dev/sdb,/dev/sdc'", self._log)
3b3b27
+
3b3b27
+        # reset back to default
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(None)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
     @tag_test(TestTags.NOSTORAGE)
3b3b27
     def test_cache_get_default_md_size(self):
3b3b27
         """Verify that default cache metadata size is calculated properly"""
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index eb94c91..b37a879 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -22,10 +22,17 @@ class LVMTestCase(unittest.TestCase):
3b3b27
         ps.so_name = "libbd_lvm.so.2"
3b3b27
         cls.requested_plugins = [ps]
3b3b27
 
3b3b27
+        BlockDev.switch_init_checks(False)
3b3b27
         if not BlockDev.is_initialized():
3b3b27
             BlockDev.init(cls.requested_plugins, None)
3b3b27
         else:
3b3b27
             BlockDev.reinit(cls.requested_plugins, True, None)
3b3b27
+        BlockDev.switch_init_checks(True)
3b3b27
+
3b3b27
+        try:
3b3b27
+            cls.devices_avail = BlockDev.lvm_is_tech_avail(BlockDev.LVMTech.DEVICES, 0)
3b3b27
+        except:
3b3b27
+            cls.devices_avail = False
3b3b27
 
3b3b27
     @classmethod
3b3b27
     def _get_lvm_version(cls):
3b3b27
@@ -39,6 +46,8 @@ class LVMTestCase(unittest.TestCase):
3b3b27
 class LvmNoDevTestCase(LVMTestCase):
3b3b27
     def __init__(self, *args, **kwargs):
3b3b27
         super(LvmNoDevTestCase, self).__init__(*args, **kwargs)
3b3b27
+
3b3b27
+    def setUp(self):
3b3b27
         self._log = ""
3b3b27
 
3b3b27
     @tag_test(TestTags.NOSTORAGE)
3b3b27
@@ -213,6 +222,44 @@ class LvmNoDevTestCase(LVMTestCase):
3b3b27
         succ = BlockDev.lvm_set_global_config(None)
3b3b27
         self.assertTrue(succ)
3b3b27
 
3b3b27
+    @tag_test(TestTags.NOSTORAGE)
3b3b27
+    def test_get_set_global_devices_filter(self):
3b3b27
+        """Verify that getting and setting LVM devices filter works as expected"""
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices filter test: not supported")
3b3b27
+
3b3b27
+        # setup logging
3b3b27
+        self.assertTrue(BlockDev.reinit(self.requested_plugins, False, self._store_log))
3b3b27
+
3b3b27
+        # no global config set initially
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
3b3b27
+
3b3b27
+        # set and try to get back
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sda"])
3b3b27
+
3b3b27
+        # reset and try to get back
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(None)
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertListEqual(BlockDev.lvm_get_devices_filter(), [])
3b3b27
+
3b3b27
+        # set twice and try to get back twice
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sda"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb"])
3b3b27
+        self.assertTrue(succ)
3b3b27
+        self.assertEqual(BlockDev.lvm_get_devices_filter(), ["/dev/sdb"])
3b3b27
+
3b3b27
+        # set something sane and check it's really used
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(["/dev/sdb", "/dev/sdc"])
3b3b27
+        BlockDev.lvm_lvs(None)
3b3b27
+        self.assertIn("--devices=/dev/sdb,/dev/sdc", self._log)
3b3b27
+
3b3b27
+        # reset back to default
3b3b27
+        succ = BlockDev.lvm_set_devices_filter(None)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
     @tag_test(TestTags.NOSTORAGE)
3b3b27
     def test_cache_get_default_md_size(self):
3b3b27
         """Verify that default cache metadata size is calculated properly"""
3b3b27
@@ -1335,6 +1382,9 @@ class LvmPVVGcachedThpoolstatsTestCase(LvmPVVGLVTestCase):
3b3b27
 
3b3b27
 class LVMUnloadTest(LVMTestCase):
3b3b27
     def setUp(self):
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM unload test: missing some LVM dependencies")
3b3b27
+
3b3b27
         # make sure the library is initialized with all plugins loaded for other
3b3b27
         # tests
3b3b27
         self.addCleanup(BlockDev.reinit, self.requested_plugins, True, None)
3b3b27
diff --git a/tests/overrides_test.py b/tests/overrides_test.py
3b3b27
index 8e7f5a5..d3faf3c 100644
3b3b27
--- a/tests/overrides_test.py
3b3b27
+++ b/tests/overrides_test.py
3b3b27
@@ -15,10 +15,12 @@ class OverridesTest(unittest.TestCase):
3b3b27
 
3b3b27
     @classmethod
3b3b27
     def setUpClass(cls):
3b3b27
+        BlockDev.switch_init_checks(False)
3b3b27
         if not BlockDev.is_initialized():
3b3b27
             BlockDev.init(cls.requested_plugins, None)
3b3b27
         else:
3b3b27
             BlockDev.reinit(cls.requested_plugins, True, None)
3b3b27
+        BlockDev.switch_init_checks(True)
3b3b27
 
3b3b27
 class OverridesTestCase(OverridesTest):
3b3b27
     @tag_test(TestTags.NOSTORAGE, TestTags.CORE)
3b3b27
@@ -65,7 +67,20 @@ class OverridesTestCase(OverridesTest):
3b3b27
         self.assertEqual(BlockDev.lvm_get_thpool_padding(11 * 1024**2),
3b3b27
                          expected_padding)
3b3b27
 
3b3b27
-class OverridesUnloadTestCase(OverridesTest):
3b3b27
+class OverridesUnloadTestCase(unittest.TestCase):
3b3b27
+    # all plugins except for 'btrfs', 'fs' and 'mpath' -- these don't have all
3b3b27
+    # the dependencies on CentOS/Debian and we don't need them for this test
3b3b27
+    requested_plugins = BlockDev.plugin_specs_from_names(("crypto", "dm",
3b3b27
+                                                          "kbd", "loop",
3b3b27
+                                                          "mdraid", "part", "swap"))
3b3b27
+
3b3b27
+    @classmethod
3b3b27
+    def setUpClass(cls):
3b3b27
+        if not BlockDev.is_initialized():
3b3b27
+            BlockDev.init(cls.requested_plugins, None)
3b3b27
+        else:
3b3b27
+            BlockDev.reinit(cls.requested_plugins, True, None)
3b3b27
+
3b3b27
     def tearDown(self):
3b3b27
         # make sure the library is initialized with all plugins loaded for other
3b3b27
         # tests
3b3b27
@@ -80,7 +95,7 @@ class OverridesUnloadTestCase(OverridesTest):
3b3b27
 
3b3b27
         # no longer loaded
3b3b27
         with self.assertRaises(BlockDev.BlockDevNotImplementedError):
3b3b27
-            BlockDev.lvm.get_max_lv_size()
3b3b27
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
3b3b27
 
3b3b27
         # load the plugins back
3b3b27
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
@@ -92,9 +107,9 @@ class OverridesUnloadTestCase(OverridesTest):
3b3b27
 
3b3b27
         # the exception should be properly inherited from two classes
3b3b27
         with self.assertRaises(NotImplementedError):
3b3b27
-            BlockDev.lvm.get_max_lv_size()
3b3b27
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
3b3b27
         with self.assertRaises(BlockDev.BlockDevError):
3b3b27
-            BlockDev.lvm.get_max_lv_size()
3b3b27
+            BlockDev.md.canonicalize_uuid("3386ff85:f5012621:4a435f06:1eb47236")
3b3b27
 
3b3b27
         # load the plugins back
3b3b27
         self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From bebd74962db6fb7b5314be411a4d02b21554d80f Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Tue, 13 Jul 2021 13:27:32 +0200
3b3b27
Subject: [PATCH 2/8] lvm: Add functions for managing LVM devices file
3b3b27
3b3b27
Currently covers only --adddev and --deldev from the lvmdevices
3b3b27
command.
3b3b27
---
3b3b27
 src/lib/plugin_apis/lvm.api         | 26 +++++++++++++++
3b3b27
 src/plugins/lvm-dbus.c              | 52 +++++++++++++++++++++++++++++
3b3b27
 src/plugins/lvm.c                   | 52 +++++++++++++++++++++++++++++
3b3b27
 src/plugins/lvm.h                   |  3 ++
3b3b27
 src/python/gi/overrides/BlockDev.py | 15 +++++++++
3b3b27
 tests/lvm_dbus_tests.py             | 37 +++++++++++++++++++-
3b3b27
 tests/lvm_test.py                   | 37 +++++++++++++++++++-
3b3b27
 7 files changed, 220 insertions(+), 2 deletions(-)
3b3b27
3b3b27
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
3b3b27
index 62f602f..bce2920 100644
3b3b27
--- a/src/lib/plugin_apis/lvm.api
3b3b27
+++ b/src/lib/plugin_apis/lvm.api
3b3b27
@@ -1685,4 +1685,30 @@ GHashTable* bd_lvm_vdo_get_stats_full (const gchar *vg_name, const gchar *pool_n
3b3b27
  */
3b3b27
 BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_name, GError **error);
3b3b27
 
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_add:
3b3b27
+ * @device: device (PV) to add to the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully added to @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_delete:
3b3b27
+ * @device: device (PV) to delete from the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully removed from @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
3b3b27
+
3b3b27
 #endif  /* BD_LVM_API */
3b3b27
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
3b3b27
index d1726ed..44d2794 100644
3b3b27
--- a/src/plugins/lvm-dbus.c
3b3b27
+++ b/src/plugins/lvm-dbus.c
3b3b27
@@ -3938,3 +3938,55 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
3b3b27
 
3b3b27
     return stats;
3b3b27
 }
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_add:
3b3b27
+ * @device: device (PV) to add to the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully added to @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
3b3b27
+    const gchar *args[5] = {"lvmdevices", "--adddev", device, NULL, NULL};
3b3b27
+    g_autofree gchar *devfile = NULL;
3b3b27
+
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    if (devices_file) {
3b3b27
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
+        args[3] = devfile;
3b3b27
+    }
3b3b27
+
3b3b27
+    return bd_utils_exec_and_report_error (args, extra, error);
3b3b27
+}
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_delete:
3b3b27
+ * @device: device (PV) to delete from the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully removed from @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
3b3b27
+    const gchar *args[5] = {"lvmdevices", "--deldev", device, NULL, NULL};
3b3b27
+    g_autofree gchar *devfile = NULL;
3b3b27
+
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    if (devices_file) {
3b3b27
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
+        args[3] = devfile;
3b3b27
+    }
3b3b27
+
3b3b27
+    return bd_utils_exec_and_report_error (args, extra, error);
3b3b27
+}
3b3b27
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
3b3b27
index c0d8198..94c6a22 100644
3b3b27
--- a/src/plugins/lvm.c
3b3b27
+++ b/src/plugins/lvm.c
3b3b27
@@ -3235,3 +3235,55 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
3b3b27
 
3b3b27
     return stats;
3b3b27
 }
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_add:
3b3b27
+ * @device: device (PV) to add to the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully added to @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
3b3b27
+    const gchar *args[5] = {"lvmdevices", "--adddev", device, NULL, NULL};
3b3b27
+    g_autofree gchar *devfile = NULL;
3b3b27
+
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    if (devices_file) {
3b3b27
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
+        args[3] = devfile;
3b3b27
+    }
3b3b27
+
3b3b27
+    return bd_utils_exec_and_report_error (args, extra, error);
3b3b27
+}
3b3b27
+
3b3b27
+/**
3b3b27
+ * bd_lvm_devices_delete:
3b3b27
+ * @device: device (PV) to delete from the devices file
3b3b27
+ * @devices_file: (allow-none): LVM devices file or %NULL for default
3b3b27
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the lvmdevices command
3b3b27
+ * @error: (out): place to store error (if any)
3b3b27
+ *
3b3b27
+ * Returns: whether the @device was successfully removed from @devices_file or not
3b3b27
+ *
3b3b27
+ * Tech category: %BD_LVM_TECH_DEVICES no mode (it is ignored)
3b3b27
+ */
3b3b27
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error) {
3b3b27
+    const gchar *args[5] = {"lvmdevices", "--deldev", device, NULL, NULL};
3b3b27
+    g_autofree gchar *devfile = NULL;
3b3b27
+
3b3b27
+    if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
+        return FALSE;
3b3b27
+
3b3b27
+    if (devices_file) {
3b3b27
+        devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
+        args[3] = devfile;
3b3b27
+    }
3b3b27
+
3b3b27
+    return bd_utils_exec_and_report_error (args, extra, error);
3b3b27
+}
3b3b27
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
3b3b27
index 8063693..5ca2a9d 100644
3b3b27
--- a/src/plugins/lvm.h
3b3b27
+++ b/src/plugins/lvm.h
3b3b27
@@ -333,4 +333,7 @@ BDLVMVDOWritePolicy bd_lvm_get_vdo_write_policy_from_str (const gchar *policy_st
3b3b27
 BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_name, GError **error);
3b3b27
 GHashTable* bd_lvm_vdo_get_stats_full (const gchar *vg_name, const gchar *pool_name, GError **error);
3b3b27
 
3b3b27
+gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
3b3b27
+gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file, const BDExtraArg **extra, GError **error);
3b3b27
+
3b3b27
 #endif /* BD_LVM */
3b3b27
diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py
3b3b27
index f768c8b..715a262 100644
3b3b27
--- a/src/python/gi/overrides/BlockDev.py
3b3b27
+++ b/src/python/gi/overrides/BlockDev.py
3b3b27
@@ -724,6 +724,21 @@ def lvm_vdo_pool_convert(vg_name, lv_name, pool_name, virtual_size, index_memory
3b3b27
     return _lvm_vdo_pool_convert(vg_name, lv_name, pool_name, virtual_size, index_memory, compression, deduplication, write_policy, extra)
3b3b27
 __all__.append("lvm_vdo_pool_convert")
3b3b27
 
3b3b27
+_lvm_devices_add = BlockDev.lvm_devices_add
3b3b27
+@override(BlockDev.lvm_devices_add)
3b3b27
+def lvm_devices_add(device, devices_file=None, extra=None, **kwargs):
3b3b27
+    extra = _get_extra(extra, kwargs)
3b3b27
+    return _lvm_devices_add(device, devices_file, extra)
3b3b27
+__all__.append("lvm_devices_add")
3b3b27
+
3b3b27
+_lvm_devices_delete = BlockDev.lvm_devices_delete
3b3b27
+@override(BlockDev.lvm_devices_delete)
3b3b27
+def lvm_devices_delete(device, devices_file=None, extra=None, **kwargs):
3b3b27
+    extra = _get_extra(extra, kwargs)
3b3b27
+    return _lvm_devices_delete(device, devices_file, extra)
3b3b27
+__all__.append("lvm_devices_delete")
3b3b27
+
3b3b27
+
3b3b27
 _md_get_superblock_size = BlockDev.md_get_superblock_size
3b3b27
 @override(BlockDev.md_get_superblock_size)
3b3b27
 def md_get_superblock_size(size, version=None):
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index 35ace37..fb1a9ed 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -10,7 +10,7 @@ import subprocess
3b3b27
 from distutils.version import LooseVersion
3b3b27
 from itertools import chain
3b3b27
 
3b3b27
-from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, run_command, TestTags, tag_test
3b3b27
+from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, run_command, TestTags, tag_test, read_file
3b3b27
 from gi.repository import BlockDev, GLib
3b3b27
 
3b3b27
 import dbus
3b3b27
@@ -1696,3 +1696,38 @@ class LVMVDOTest(LVMTestCase):
3b3b27
 
3b3b27
         full_stats = BlockDev.lvm_vdo_get_stats_full("testVDOVG", "vdoPool")
3b3b27
         self.assertIn("writeAmplificationRatio", full_stats.keys())
3b3b27
+
3b3b27
+
3b3b27
+class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
+    devicefile = "bd_lvm_dbus_tests.devices"
3b3b27
+
3b3b27
+    @classmethod
3b3b27
+    def tearDownClass(cls):
3b3b27
+        shutil.rmtree("/etc/lvm/devices/" + cls.devicefile, ignore_errors=True)
3b3b27
+
3b3b27
+        super(LvmTestDevicesFile, cls).tearDownClass()
3b3b27
+
3b3b27
+    def test_devices_add_delete(self):
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices file test: not supported")
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        with self.assertRaises(GLib.GError):
3b3b27
+            BlockDev.lvm_devices_add("/non/existing/device", self.devicefile)
3b3b27
+
3b3b27
+        with self.assertRaises(GLib.GError):
3b3b27
+            BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_devices_add(self.loop_dev, self.devicefile)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
+        self.assertIn(self.loop_dev, dfile)
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
+        self.assertNotIn(self.loop_dev, dfile)
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index b37a879..786434f 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -9,7 +9,7 @@ import shutil
3b3b27
 import subprocess
3b3b27
 from distutils.version import LooseVersion
3b3b27
 
3b3b27
-from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, TestTags, tag_test, run_command
3b3b27
+from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, TestTags, tag_test, run_command, read_file
3b3b27
 from gi.repository import BlockDev, GLib
3b3b27
 
3b3b27
 
3b3b27
@@ -1682,3 +1682,38 @@ class LVMVDOTest(LVMTestCase):
3b3b27
 
3b3b27
         full_stats = BlockDev.lvm_vdo_get_stats_full("testVDOVG", "vdoPool")
3b3b27
         self.assertIn("writeAmplificationRatio", full_stats.keys())
3b3b27
+
3b3b27
+
3b3b27
+class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
+    devicefile = "bd_lvm_test.devices"
3b3b27
+
3b3b27
+    @classmethod
3b3b27
+    def tearDownClass(cls):
3b3b27
+        shutil.rmtree("/etc/lvm/devices/" + cls.devicefile, ignore_errors=True)
3b3b27
+
3b3b27
+        super(LvmTestDevicesFile, cls).tearDownClass()
3b3b27
+
3b3b27
+    def test_devices_add_delete(self):
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices file test: not supported")
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        with self.assertRaises(GLib.GError):
3b3b27
+            BlockDev.lvm_devices_add("/non/existing/device", self.devicefile)
3b3b27
+
3b3b27
+        with self.assertRaises(GLib.GError):
3b3b27
+            BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_devices_add(self.loop_dev, self.devicefile)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
+        self.assertIn(self.loop_dev, dfile)
3b3b27
+
3b3b27
+        succ = BlockDev.lvm_devices_delete(self.loop_dev, self.devicefile)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
+        self.assertNotIn(self.loop_dev, dfile)
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 8d8cbe7169cb94b01e7064a0d00b7d86baf5e652 Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Fri, 15 Oct 2021 13:18:54 +0200
3b3b27
Subject: [PATCH 3/8] lvm: Report special error when system.devices file is not
3b3b27
 enabled
3b3b27
3b3b27
This can be disabled either in LVM by a compile time option or
3b3b27
by a lvm.conf option so we should report a specific error for this
3b3b27
case so users can distinguish between the feature not being enabled
3b3b27
and not being supported at all.
3b3b27
---
3b3b27
 src/lib/plugin_apis/lvm.api |  1 +
3b3b27
 src/plugins/lvm-dbus.c      | 70 +++++++++++++++++++++++++++++++++++++
3b3b27
 src/plugins/lvm.c           | 60 +++++++++++++++++++++++++++++++
3b3b27
 src/plugins/lvm.h           |  1 +
3b3b27
 tests/lvm_dbus_tests.py     | 15 ++++++++
3b3b27
 tests/lvm_test.py           | 15 ++++++++
3b3b27
 6 files changed, 162 insertions(+)
3b3b27
3b3b27
diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api
3b3b27
index bce2920..b96bcfd 100644
3b3b27
--- a/src/lib/plugin_apis/lvm.api
3b3b27
+++ b/src/lib/plugin_apis/lvm.api
3b3b27
@@ -44,6 +44,7 @@ typedef enum {
3b3b27
     BD_LVM_ERROR_FAIL,
3b3b27
     BD_LVM_ERROR_NOT_SUPPORTED,
3b3b27
     BD_LVM_ERROR_VDO_POLICY_INVAL,
3b3b27
+    BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
 } BDLVMError;
3b3b27
 
3b3b27
 typedef enum {
3b3b27
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
3b3b27
index 44d2794..22204d5 100644
3b3b27
--- a/src/plugins/lvm-dbus.c
3b3b27
+++ b/src/plugins/lvm-dbus.c
3b3b27
@@ -3939,6 +3939,64 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
3b3b27
     return stats;
3b3b27
 }
3b3b27
 
3b3b27
+/* check whether the LVM devices file is enabled by LVM
3b3b27
+ * we use the existence of the "lvmdevices" command to check whether the feature is available
3b3b27
+ * or not, but this can still be disabled either in LVM or in lvm.conf
3b3b27
+ */
3b3b27
+static gboolean _lvm_devices_enabled () {
3b3b27
+    const gchar *args[6] = {"lvmconfig", "--typeconfig", NULL, "devices/use_devicesfile", NULL, NULL};
3b3b27
+    gboolean ret = FALSE;
3b3b27
+    GError *loc_error = NULL;
3b3b27
+    gchar *output = NULL;
3b3b27
+    gboolean enabled = FALSE;
3b3b27
+    gint scanned = 0;
3b3b27
+    g_autofree gchar *config_arg = NULL;
3b3b27
+
3b3b27
+    /* try current config first -- if we get something from this it means the feature is
3b3b27
+       explicitly enabled or disabled by system lvm.conf or using the --config option */
3b3b27
+    args[2] = "current";
3b3b27
+
3b3b27
+    /* make sure to include the global config from us when getting the current config value */
3b3b27
+    g_mutex_lock (&global_config_lock);
3b3b27
+    if (global_config_str) {
3b3b27
+        config_arg = g_strdup_printf ("--config=%s", global_config_str);
3b3b27
+        args[4] = config_arg;
3b3b27
+    }
3b3b27
+
3b3b27
+    ret = bd_utils_exec_and_capture_output (args, NULL, &output, &loc_error);
3b3b27
+    g_mutex_unlock (&global_config_lock);
3b3b27
+    if (ret) {
3b3b27
+        scanned = sscanf (output, "use_devicesfile=%u", &enabled);
3b3b27
+        g_free (output);
3b3b27
+        if (scanned != 1)
3b3b27
+            return FALSE;
3b3b27
+
3b3b27
+        return enabled;
3b3b27
+    } else {
3b3b27
+        g_clear_error (&loc_error);
3b3b27
+        g_free (output);
3b3b27
+    }
3b3b27
+
3b3b27
+    output = NULL;
3b3b27
+
3b3b27
+    /* now try default */
3b3b27
+    args[2] = "default";
3b3b27
+    ret = bd_utils_exec_and_capture_output (args, NULL, &output, &loc_error);
3b3b27
+    if (ret) {
3b3b27
+        scanned = sscanf (output, "# use_devicesfile=%u", &enabled);
3b3b27
+        g_free (output);
3b3b27
+        if (scanned != 1)
3b3b27
+            return FALSE;
3b3b27
+
3b3b27
+        return enabled;
3b3b27
+    } else {
3b3b27
+        g_clear_error (&loc_error);
3b3b27
+        g_free (output);
3b3b27
+    }
3b3b27
+
3b3b27
+    return FALSE;
3b3b27
+}
3b3b27
+
3b3b27
 /**
3b3b27
  * bd_lvm_devices_add:
3b3b27
  * @device: device (PV) to add to the devices file
3b3b27
@@ -3957,6 +4015,12 @@ gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, con
3b3b27
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
         return FALSE;
3b3b27
 
3b3b27
+    if (!_lvm_devices_enabled ()) {
3b3b27
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
+                     "LVM devices file not enabled.");
3b3b27
+        return FALSE;
3b3b27
+    }
3b3b27
+
3b3b27
     if (devices_file) {
3b3b27
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
         args[3] = devfile;
3b3b27
@@ -3983,6 +4047,12 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
3b3b27
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
         return FALSE;
3b3b27
 
3b3b27
+    if (!_lvm_devices_enabled ()) {
3b3b27
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
+                     "LVM devices file not enabled.");
3b3b27
+        return FALSE;
3b3b27
+    }
3b3b27
+
3b3b27
     if (devices_file) {
3b3b27
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
         args[3] = devfile;
3b3b27
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
3b3b27
index 94c6a22..605fcb0 100644
3b3b27
--- a/src/plugins/lvm.c
3b3b27
+++ b/src/plugins/lvm.c
3b3b27
@@ -3236,6 +3236,54 @@ BDLVMVDOStats* bd_lvm_vdo_get_stats (const gchar *vg_name, const gchar *pool_nam
3b3b27
     return stats;
3b3b27
 }
3b3b27
 
3b3b27
+/* check whether the LVM devices file is enabled by LVM
3b3b27
+ * we use the existence of the "lvmdevices" command to check whether the feature is available
3b3b27
+ * or not, but this can still be disabled either in LVM or in lvm.conf
3b3b27
+ */
3b3b27
+static gboolean _lvm_devices_enabled () {
3b3b27
+    const gchar *args[5] = {"config", "--typeconfig", NULL, "devices/use_devicesfile", NULL};
3b3b27
+    gboolean ret = FALSE;
3b3b27
+    GError *loc_error = NULL;
3b3b27
+    gchar *output = NULL;
3b3b27
+    gboolean enabled = FALSE;
3b3b27
+    gint scanned = 0;
3b3b27
+
3b3b27
+    /* try current config first -- if we get something from this it means the feature is
3b3b27
+       explicitly enabled or disabled by system lvm.conf or using the --config option */
3b3b27
+    args[2] = "current";
3b3b27
+    ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
3b3b27
+    if (ret) {
3b3b27
+        scanned = sscanf (output, "use_devicesfile=%u", &enabled);
3b3b27
+        g_free (output);
3b3b27
+        if (scanned != 1)
3b3b27
+            return FALSE;
3b3b27
+
3b3b27
+        return enabled;
3b3b27
+    } else {
3b3b27
+        g_clear_error (&loc_error);
3b3b27
+        g_free (output);
3b3b27
+    }
3b3b27
+
3b3b27
+    output = NULL;
3b3b27
+
3b3b27
+    /* now try default */
3b3b27
+    args[2] = "default";
3b3b27
+    ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
3b3b27
+    if (ret) {
3b3b27
+        scanned = sscanf (output, "# use_devicesfile=%u", &enabled);
3b3b27
+        g_free (output);
3b3b27
+        if (scanned != 1)
3b3b27
+            return FALSE;
3b3b27
+
3b3b27
+        return enabled;
3b3b27
+    } else {
3b3b27
+        g_clear_error (&loc_error);
3b3b27
+        g_free (output);
3b3b27
+    }
3b3b27
+
3b3b27
+    return FALSE;
3b3b27
+}
3b3b27
+
3b3b27
 /**
3b3b27
  * bd_lvm_devices_add:
3b3b27
  * @device: device (PV) to add to the devices file
3b3b27
@@ -3254,6 +3302,12 @@ gboolean bd_lvm_devices_add (const gchar *device, const gchar *devices_file, con
3b3b27
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
         return FALSE;
3b3b27
 
3b3b27
+    if (!_lvm_devices_enabled ()) {
3b3b27
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
+                     "LVM devices file not enabled.");
3b3b27
+        return FALSE;
3b3b27
+    }
3b3b27
+
3b3b27
     if (devices_file) {
3b3b27
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
         args[3] = devfile;
3b3b27
@@ -3280,6 +3334,12 @@ gboolean bd_lvm_devices_delete (const gchar *device, const gchar *devices_file,
3b3b27
     if (!bd_lvm_is_tech_avail (BD_LVM_TECH_DEVICES, 0, error))
3b3b27
         return FALSE;
3b3b27
 
3b3b27
+    if (!_lvm_devices_enabled ()) {
3b3b27
+        g_set_error (error, BD_LVM_ERROR, BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
+                     "LVM devices file not enabled.");
3b3b27
+        return FALSE;
3b3b27
+    }
3b3b27
+
3b3b27
     if (devices_file) {
3b3b27
         devfile = g_strdup_printf ("--devicesfile=%s", devices_file);
3b3b27
         args[3] = devfile;
3b3b27
diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h
3b3b27
index 5ca2a9d..fabf091 100644
3b3b27
--- a/src/plugins/lvm.h
3b3b27
+++ b/src/plugins/lvm.h
3b3b27
@@ -53,6 +53,7 @@ typedef enum {
3b3b27
     BD_LVM_ERROR_FAIL,
3b3b27
     BD_LVM_ERROR_NOT_SUPPORTED,
3b3b27
     BD_LVM_ERROR_VDO_POLICY_INVAL,
3b3b27
+    BD_LVM_ERROR_DEVICES_DISABLED,
3b3b27
 } BDLVMError;
3b3b27
 
3b3b27
 typedef enum {
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index fb1a9ed..c411c9e 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -1731,3 +1731,18 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
 
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
+
3b3b27
+    def test_devices_enabled(self):
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices file test: not supported")
3b3b27
+
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+
3b3b27
+        # checking if the feature is enabled or disabled is hard so lets just disable
3b3b27
+        # the devices file using the global config and check lvm_devices_add fails
3b3b27
+        # with the correct exception message
3b3b27
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=0 }")
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
3b3b27
+            BlockDev.lvm_devices_add("", self.devicefile)
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index 786434f..315dd07 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -1717,3 +1717,18 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
 
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
+
3b3b27
+    def test_devices_enabled(self):
3b3b27
+        if not self.devices_avail:
3b3b27
+            self.skipTest("skipping LVM devices file test: not supported")
3b3b27
+
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+
3b3b27
+        # checking if the feature is enabled or disabled is hard so lets just disable
3b3b27
+        # the devices file using the global config and check lvm_devices_add fails
3b3b27
+        # with the correct exception message
3b3b27
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=0 }")
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
3b3b27
+            BlockDev.lvm_devices_add("", self.devicefile)
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 81df85e7ea6e129e78074b6967f80c505d1b08f0 Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Fri, 15 Oct 2021 14:21:03 +0200
3b3b27
Subject: [PATCH 4/8] lvm: Force enable LVM devices file for LvmTestDevicesFile
3b3b27
3b3b27
This feauture might be disabled in lvm.conf so to be able to test
3b3b27
it we need to override this. The correct handling of the disabled
3b3b27
state is checked in a separate test case.
3b3b27
---
3b3b27
 tests/lvm_dbus_tests.py | 8 ++++++++
3b3b27
 tests/lvm_test.py       | 8 ++++++++
3b3b27
 2 files changed, 16 insertions(+)
3b3b27
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index c411c9e..9cfc647 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -1711,6 +1711,12 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+
3b3b27
+        # force-enable the feature, it might be disabled by default
3b3b27
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
         succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
         self.assertTrue(succ)
3b3b27
 
3b3b27
@@ -1732,6 +1738,8 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
 
3b3b27
+        BlockDev.lvm_set_global_config("")
3b3b27
+
3b3b27
     def test_devices_enabled(self):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index 315dd07..ea3b7f8 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -1697,6 +1697,12 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+
3b3b27
+        # force-enable the feature, it might be disabled by default
3b3b27
+        succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
         succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
         self.assertTrue(succ)
3b3b27
 
3b3b27
@@ -1718,6 +1724,8 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
 
3b3b27
+        BlockDev.lvm_set_global_config("")
3b3b27
+
3b3b27
     def test_devices_enabled(self):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 01237b62bb8ad67def7c937185c42152503fbc6f Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Fri, 12 Nov 2021 14:51:39 +0100
3b3b27
Subject: [PATCH 5/8] tests: Fix resetting global LVM config after LVM devices
3b3b27
 file test
3b3b27
3b3b27
We need to set the config to None/NULL not to an empty string.
3b3b27
---
3b3b27
 tests/lvm_dbus_tests.py | 6 +++---
3b3b27
 tests/lvm_test.py       | 6 +++---
3b3b27
 2 files changed, 6 insertions(+), 6 deletions(-)
3b3b27
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index 9cfc647..d422869 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -1711,7 +1711,7 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
3b3b27
 
3b3b27
         # force-enable the feature, it might be disabled by default
3b3b27
         succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
3b3b27
@@ -1738,13 +1738,13 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
 
3b3b27
-        BlockDev.lvm_set_global_config("")
3b3b27
+        BlockDev.lvm_set_global_config(None)
3b3b27
 
3b3b27
     def test_devices_enabled(self):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
3b3b27
 
3b3b27
         # checking if the feature is enabled or disabled is hard so lets just disable
3b3b27
         # the devices file using the global config and check lvm_devices_add fails
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index ea3b7f8..882cdf2 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -1697,7 +1697,7 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
3b3b27
 
3b3b27
         # force-enable the feature, it might be disabled by default
3b3b27
         succ = BlockDev.lvm_set_global_config("devices { use_devicesfile=1 }")
3b3b27
@@ -1724,13 +1724,13 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
         dfile = read_file("/etc/lvm/devices/" + self.devicefile)
3b3b27
         self.assertNotIn(self.loop_dev, dfile)
3b3b27
 
3b3b27
-        BlockDev.lvm_set_global_config("")
3b3b27
+        BlockDev.lvm_set_global_config(None)
3b3b27
 
3b3b27
     def test_devices_enabled(self):
3b3b27
         if not self.devices_avail:
3b3b27
             self.skipTest("skipping LVM devices file test: not supported")
3b3b27
 
3b3b27
-        self.addCleanup(BlockDev.lvm_set_global_config, "")
3b3b27
+        self.addCleanup(BlockDev.lvm_set_global_config, None)
3b3b27
 
3b3b27
         # checking if the feature is enabled or disabled is hard so lets just disable
3b3b27
         # the devices file using the global config and check lvm_devices_add fails
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 2f33f2af18efa0b337f8383cb6f137d6211fe7fb Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Fri, 12 Nov 2021 15:10:45 +0100
3b3b27
Subject: [PATCH 6/8] lvm: Do not set global config to and empty string
3b3b27
3b3b27
If we set it to an empty string we end up running "--config"
3b3b27
without a parameter and lvm will use whatever is next parameter
3b3b27
like the device path for pvremove.
3b3b27
---
3b3b27
 src/plugins/lvm-dbus.c  |  5 ++++-
3b3b27
 src/plugins/lvm.c       |  5 ++++-
3b3b27
 tests/lvm_dbus_tests.py | 12 ++++++++++++
3b3b27
 tests/lvm_test.py       | 12 ++++++++++++
3b3b27
 4 files changed, 32 insertions(+), 2 deletions(-)
3b3b27
3b3b27
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
3b3b27
index 22204d5..b7bd019 100644
3b3b27
--- a/src/plugins/lvm-dbus.c
3b3b27
+++ b/src/plugins/lvm-dbus.c
3b3b27
@@ -2644,7 +2644,10 @@ gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error UNUSE
3b3b27
     g_free (global_config_str);
3b3b27
 
3b3b27
     /* now store the new one */
3b3b27
-    global_config_str = g_strdup (new_config);
3b3b27
+    if (!new_config || g_strcmp0 (new_config, "") == 0)
3b3b27
+         global_config_str = NULL;
3b3b27
+    else
3b3b27
+        global_config_str = g_strdup (new_config);
3b3b27
 
3b3b27
     g_mutex_unlock (&global_config_lock);
3b3b27
     return TRUE;
3b3b27
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
3b3b27
index 605fcb0..124fce7 100644
3b3b27
--- a/src/plugins/lvm.c
3b3b27
+++ b/src/plugins/lvm.c
3b3b27
@@ -2016,7 +2016,10 @@ gboolean bd_lvm_set_global_config (const gchar *new_config, GError **error UNUSE
3b3b27
     g_free (global_config_str);
3b3b27
 
3b3b27
     /* now store the new one */
3b3b27
-    global_config_str = g_strdup (new_config);
3b3b27
+    if (!new_config || g_strcmp0 (new_config, "") == 0)
3b3b27
+         global_config_str = NULL;
3b3b27
+    else
3b3b27
+        global_config_str = g_strdup (new_config);
3b3b27
 
3b3b27
     g_mutex_unlock (&global_config_lock);
3b3b27
     return TRUE;
3b3b27
diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py
3b3b27
index d422869..5516afe 100644
3b3b27
--- a/tests/lvm_dbus_tests.py
3b3b27
+++ b/tests/lvm_dbus_tests.py
3b3b27
@@ -1754,3 +1754,15 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
 
3b3b27
         with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
3b3b27
             BlockDev.lvm_devices_add("", self.devicefile)
3b3b27
+
3b3b27
+
3b3b27
+class LvmConfigTestPvremove(LvmPVonlyTestCase):
3b3b27
+
3b3b27
+    @tag_test(TestTags.REGRESSION)
3b3b27
+    def test_set_empty_config(self):
3b3b27
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        BlockDev.lvm_set_global_config("")
3b3b27
+        succ = BlockDev.lvm_pvremove(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
diff --git a/tests/lvm_test.py b/tests/lvm_test.py
3b3b27
index 882cdf2..e349817 100644
3b3b27
--- a/tests/lvm_test.py
3b3b27
+++ b/tests/lvm_test.py
3b3b27
@@ -1740,3 +1740,15 @@ class LvmTestDevicesFile(LvmPVonlyTestCase):
3b3b27
 
3b3b27
         with self.assertRaisesRegex(GLib.GError, "LVM devices file not enabled."):
3b3b27
             BlockDev.lvm_devices_add("", self.devicefile)
3b3b27
+
3b3b27
+
3b3b27
+class LvmConfigTestPvremove(LvmPVonlyTestCase):
3b3b27
+
3b3b27
+    @tag_test(TestTags.REGRESSION)
3b3b27
+    def test_set_empty_config(self):
3b3b27
+        succ = BlockDev.lvm_pvcreate(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
+
3b3b27
+        BlockDev.lvm_set_global_config("")
3b3b27
+        succ = BlockDev.lvm_pvremove(self.loop_dev)
3b3b27
+        self.assertTrue(succ)
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 2a4e610027a2c2a315054b84a323ce973939ca2d Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Tue, 16 Mar 2021 12:05:37 +0100
3b3b27
Subject: [PATCH 7/8] vdo: Do not use g_memdup in bd_vdo_stats_copy
3b3b27
3b3b27
g_memdup is deprecated and the replacement g_memdup2 is not yet
3b3b27
available so lets just do the copy manually.
3b3b27
---
3b3b27
 src/lib/plugin_apis/vdo.api | 17 ++++++++++++++++-
3b3b27
 src/plugins/vdo.c           | 17 ++++++++++++++++-
3b3b27
 2 files changed, 32 insertions(+), 2 deletions(-)
3b3b27
3b3b27
diff --git a/src/lib/plugin_apis/vdo.api b/src/lib/plugin_apis/vdo.api
3b3b27
index 936f8e0..312de4e 100644
3b3b27
--- a/src/lib/plugin_apis/vdo.api
3b3b27
+++ b/src/lib/plugin_apis/vdo.api
3b3b27
@@ -170,7 +170,22 @@ void bd_vdo_stats_free (BDVDOStats *stats) {
3b3b27
  * Deprecated: 2.24: Use LVM-VDO integration instead.
3b3b27
  */
3b3b27
 BDVDOStats* bd_vdo_stats_copy (BDVDOStats *stats) {
3b3b27
-    return g_memdup (stats, sizeof (BDVDOStats));
3b3b27
+    if (stats == NULL)
3b3b27
+        return NULL;
3b3b27
+
3b3b27
+    BDVDOStats *new_stats = g_new0 (BDVDOStats, 1);
3b3b27
+
3b3b27
+    new_stats->block_size = stats->block_size;
3b3b27
+    new_stats->logical_block_size = stats->logical_block_size;
3b3b27
+    new_stats->physical_blocks = stats->physical_blocks;
3b3b27
+    new_stats->data_blocks_used = stats->data_blocks_used;
3b3b27
+    new_stats->overhead_blocks_used = stats->overhead_blocks_used;
3b3b27
+    new_stats->logical_blocks_used = stats->logical_blocks_used;
3b3b27
+    new_stats->used_percent = stats->used_percent;
3b3b27
+    new_stats->saving_percent = stats->saving_percent;
3b3b27
+    new_stats->write_amplification_ratio = stats->write_amplification_ratio;
3b3b27
+
3b3b27
+    return new_stats;
3b3b27
 }
3b3b27
 
3b3b27
 GType bd_vdo_stats_get_type () {
3b3b27
diff --git a/src/plugins/vdo.c b/src/plugins/vdo.c
3b3b27
index 2352394..d443099 100644
3b3b27
--- a/src/plugins/vdo.c
3b3b27
+++ b/src/plugins/vdo.c
3b3b27
@@ -81,7 +81,22 @@ void bd_vdo_stats_free (BDVDOStats *stats) {
3b3b27
 }
3b3b27
 
3b3b27
 BDVDOStats* bd_vdo_stats_copy (BDVDOStats *stats) {
3b3b27
-    return g_memdup (stats, sizeof (BDVDOStats));
3b3b27
+    if (stats == NULL)
3b3b27
+        return NULL;
3b3b27
+
3b3b27
+    BDVDOStats *new_stats = g_new0 (BDVDOStats, 1);
3b3b27
+
3b3b27
+    new_stats->block_size = stats->block_size;
3b3b27
+    new_stats->logical_block_size = stats->logical_block_size;
3b3b27
+    new_stats->physical_blocks = stats->physical_blocks;
3b3b27
+    new_stats->data_blocks_used = stats->data_blocks_used;
3b3b27
+    new_stats->overhead_blocks_used = stats->overhead_blocks_used;
3b3b27
+    new_stats->logical_blocks_used = stats->logical_blocks_used;
3b3b27
+    new_stats->used_percent = stats->used_percent;
3b3b27
+    new_stats->saving_percent = stats->saving_percent;
3b3b27
+    new_stats->write_amplification_ratio = stats->write_amplification_ratio;
3b3b27
+
3b3b27
+    return new_stats;
3b3b27
 }
3b3b27
 
3b3b27
 
3b3b27
-- 
3b3b27
2.31.1
3b3b27
3b3b27
3b3b27
From 577ea466e3b7af464137e087907ba980ad3994ee Mon Sep 17 00:00:00 2001
3b3b27
From: Vojtech Trefny <vtrefny@redhat.com>
3b3b27
Date: Fri, 26 Nov 2021 15:19:55 +0100
3b3b27
Subject: [PATCH 8/8] lvm: Use "lvmconfig full" to get valid config instead of
3b3b27
 "current"
3b3b27
3b3b27
"lvmconfig current" doesn't work together with --config even if we
3b3b27
don't override the "use_devicefile" key. "lvmconfig full" seems to
3b3b27
be working in all cases.
3b3b27
---
3b3b27
 src/plugins/lvm-dbus.c | 4 ++--
3b3b27
 src/plugins/lvm.c      | 4 ++--
3b3b27
 2 files changed, 4 insertions(+), 4 deletions(-)
3b3b27
3b3b27
diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c
3b3b27
index b7bd019..825c5e9 100644
3b3b27
--- a/src/plugins/lvm-dbus.c
3b3b27
+++ b/src/plugins/lvm-dbus.c
3b3b27
@@ -3955,9 +3955,9 @@ static gboolean _lvm_devices_enabled () {
3b3b27
     gint scanned = 0;
3b3b27
     g_autofree gchar *config_arg = NULL;
3b3b27
 
3b3b27
-    /* try current config first -- if we get something from this it means the feature is
3b3b27
+    /* try full config first -- if we get something from this it means the feature is
3b3b27
        explicitly enabled or disabled by system lvm.conf or using the --config option */
3b3b27
-    args[2] = "current";
3b3b27
+    args[2] = "full";
3b3b27
 
3b3b27
     /* make sure to include the global config from us when getting the current config value */
3b3b27
     g_mutex_lock (&global_config_lock);
3b3b27
diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c
3b3b27
index 124fce7..21320f3 100644
3b3b27
--- a/src/plugins/lvm.c
3b3b27
+++ b/src/plugins/lvm.c
3b3b27
@@ -3251,9 +3251,9 @@ static gboolean _lvm_devices_enabled () {
3b3b27
     gboolean enabled = FALSE;
3b3b27
     gint scanned = 0;
3b3b27
 
3b3b27
-    /* try current config first -- if we get something from this it means the feature is
3b3b27
+    /* try full config first -- if we get something from this it means the feature is
3b3b27
        explicitly enabled or disabled by system lvm.conf or using the --config option */
3b3b27
-    args[2] = "current";
3b3b27
+    args[2] = "full";
3b3b27
     ret = call_lvm_and_capture_output (args, NULL, &output, &loc_error);
3b3b27
     if (ret) {
3b3b27
         scanned = sscanf (output, "use_devicesfile=%u", &enabled);
3b3b27
-- 
3b3b27
2.31.1
3b3b27