From 4a6eb9c2c51c614fb0b20f8b244d9b79d3e34ffa Mon Sep 17 00:00:00 2001 From: eabdullin Date: Wed, 15 May 2024 07:38:37 +0000 Subject: [PATCH] Import from AlmaLinux stable repository --- ...zing-of-inactive-LVs-with-latest-LVM.patch | 219 +++ ...wapon_pagesize-on-systems-with-64k-p.patch | 41 + ...t-when-adding-a-partition-too-big-fo.patch | 32 + ...s-in-tests-when-running-in-FIPS-mode.patch | 70 + ...ction-to-activate-LVs-in-shared-mode.patch | 300 ++++ ...0011-nvme_libblockdev-3.0.4_backport.patch | 1395 +++++++++++++++++ ...for-starting-and-stopping-VG-locking.patch | 299 ++++ SPECS/libblockdev.spec | 47 +- 8 files changed, 2395 insertions(+), 8 deletions(-) create mode 100644 SOURCES/0006-Allow-resizing-of-inactive-LVs-with-latest-LVM.patch create mode 100644 SOURCES/0007-tests-Fix-test_swapon_pagesize-on-systems-with-64k-p.patch create mode 100644 SOURCES/0008-part-Fix-segfault-when-adding-a-partition-too-big-fo.patch create mode 100644 SOURCES/0009-Fix-issues-in-tests-when-running-in-FIPS-mode.patch create mode 100644 SOURCES/0010-lvm-Add-a-function-to-activate-LVs-in-shared-mode.patch create mode 100644 SOURCES/0011-nvme_libblockdev-3.0.4_backport.patch create mode 100644 SOURCES/0012-lvm-Add-support-for-starting-and-stopping-VG-locking.patch diff --git a/SOURCES/0006-Allow-resizing-of-inactive-LVs-with-latest-LVM.patch b/SOURCES/0006-Allow-resizing-of-inactive-LVs-with-latest-LVM.patch new file mode 100644 index 0000000..194ec15 --- /dev/null +++ b/SOURCES/0006-Allow-resizing-of-inactive-LVs-with-latest-LVM.patch @@ -0,0 +1,219 @@ +From 08d0ab8b93907ed3e2c7588dcaecb76bc4b26055 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Mon, 27 Feb 2023 11:29:29 +0100 +Subject: [PATCH 1/2] Include LVM cli in the LVM DBus plugin dependencies + +Strictly speaking the lvm command is not needed by the plugin, but +the LVM DBus daemon uses it so it must be present on the system +and we are already calling "lvm segtypes" from the plugin so if +the command is not available for us (for example not in $PATH) the +plugin wouldn't load anyway so an extra check isn't going to +change anything. +--- + src/plugins/lvm-dbus.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c +index d4b542e2..8496a697 100644 +--- a/src/plugins/lvm-dbus.c ++++ b/src/plugins/lvm-dbus.c +@@ -249,11 +249,14 @@ static volatile guint avail_features = 0; + static volatile guint avail_module_deps = 0; + static GMutex deps_check_lock; + +-#define DEPS_LVMDEVICES 0 ++#define DEPS_LVM 0 ++#define DEPS_LVM_MASK (1 << DEPS_LVM) ++#define DEPS_LVMDEVICES 1 + #define DEPS_LVMDEVICES_MASK (1 << DEPS_LVMDEVICES) +-#define DEPS_LAST 1 ++#define DEPS_LAST 2 + + static const UtilDep deps[DEPS_LAST] = { ++ {"lvm", LVM_MIN_VERSION, "version", "LVM version:\\s+([\\d\\.]+)"}, + {"lvmdevices", NULL, NULL, NULL}, + }; + +@@ -2121,6 +2124,7 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + GVariantBuilder builder; + GVariantType *type = NULL; + GVariant *params = NULL; ++ GVariant *extra_params = NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add_value (&builder, g_variant_new ("t", size)); +@@ -2130,7 +2134,12 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + params = g_variant_builder_end (&builder); + g_variant_builder_clear (&builder); + +- call_lv_method_sync (vg_name, lv_name, "Resize", params, NULL, extra, TRUE, error); ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); ++ g_variant_builder_add (&builder, "{sv}", "--fs", g_variant_new ("s", "ignore")); ++ extra_params = g_variant_builder_end (&builder); ++ g_variant_builder_clear (&builder); ++ ++ call_lv_method_sync (vg_name, lv_name, "Resize", params, extra_params, extra, TRUE, error); + return (*error == NULL); + } + +-- +2.39.2 + + +From cfb23f424c2f318efea7d9fd60ec1bcdb365ee35 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Mon, 27 Feb 2023 14:00:21 +0100 +Subject: [PATCH 2/2] Allow resizing of inactive LVs with latest LVM + +Latest LVM doesn't allow resizing of inactive LVs without the +"--fs ignore" option to protect users from corrupting their +filesystems. As a low level API we don't really want to offer this +kind of protection and we should allow to resize an inactive LV. +--- + src/plugins/lvm-dbus.c | 28 ++++++++++++++++++++++++---- + src/plugins/lvm.c | 31 ++++++++++++++++++++++++++++--- + tests/lvm_dbus_tests.py | 4 ++++ + tests/lvm_test.py | 4 ++++ + 4 files changed, 60 insertions(+), 7 deletions(-) + +diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c +index 8496a697..28f3bb25 100644 +--- a/src/plugins/lvm-dbus.c ++++ b/src/plugins/lvm-dbus.c +@@ -32,6 +32,8 @@ + #define SECTOR_SIZE 512 + #define VDO_POOL_SUFFIX "vpool" + ++#define LVM_VERSION_FSRESIZE "2.03.19" ++ + static GMutex global_config_lock; + static gchar *global_config_str = NULL; + +@@ -2125,6 +2127,14 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + GVariantType *type = NULL; + GVariant *params = NULL; + GVariant *extra_params = NULL; ++ gboolean success = FALSE; ++ BDLVMLVdata *lvinfo = NULL; ++ GError *l_error = NULL; ++ ++ lvinfo = bd_lvm_lvinfo (vg_name, lv_name, error); ++ if (!lvinfo) ++ /* error is already populated */ ++ return FALSE; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + g_variant_builder_add_value (&builder, g_variant_new ("t", size)); +@@ -2134,10 +2144,20 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + params = g_variant_builder_end (&builder); + g_variant_builder_clear (&builder); + +- g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); +- g_variant_builder_add (&builder, "{sv}", "--fs", g_variant_new ("s", "ignore")); +- extra_params = g_variant_builder_end (&builder); +- g_variant_builder_clear (&builder); ++ if (lvinfo->attr[4] != 'a') { ++ /* starting with 2.03.19 we need to add extra option to allow resizing of inactive LVs */ ++ success = bd_utils_check_util_version (deps[DEPS_LVM].name, LVM_VERSION_FSRESIZE, ++ deps[DEPS_LVM].ver_arg, deps[DEPS_LVM].ver_regexp, &l_error); ++ if (success) { ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); ++ g_variant_builder_add (&builder, "{sv}", "--fs", g_variant_new ("s", "ignore")); ++ extra_params = g_variant_builder_end (&builder); ++ g_variant_builder_clear (&builder); ++ } else ++ g_clear_error (&l_error); ++ } ++ ++ bd_lvm_lvdata_free (lvinfo); + + call_lv_method_sync (vg_name, lv_name, "Resize", params, extra_params, extra, TRUE, error); + return (*error == NULL); +diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c +index 03211f8a..f1e2941b 100644 +--- a/src/plugins/lvm.c ++++ b/src/plugins/lvm.c +@@ -31,6 +31,8 @@ + #define SECTOR_SIZE 512 + #define VDO_POOL_SUFFIX "vpool" + ++#define LVM_VERSION_FSRESIZE "2.03.19" ++ + static GMutex global_config_lock; + static gchar *global_config_str = NULL; + +@@ -1606,15 +1608,38 @@ gboolean bd_lvm_lvrename (const gchar *vg_name, const gchar *lv_name, const gcha + * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY + */ + gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error) { +- const gchar *args[6] = {"lvresize", "--force", "-L", NULL, NULL, NULL}; ++ const gchar *args[8] = {"lvresize", "--force", "-L", NULL, NULL, NULL, NULL, NULL}; + gboolean success = FALSE; ++ guint8 next_arg = 4; ++ g_autofree gchar *lvspec = NULL; ++ BDLVMLVdata *lvinfo = NULL; ++ GError *l_error = NULL; ++ ++ lvinfo = bd_lvm_lvinfo (vg_name, lv_name, error); ++ if (!lvinfo) ++ /* error is already populated */ ++ return FALSE; + + args[3] = g_strdup_printf ("%"G_GUINT64_FORMAT"K", size/1024); +- args[4] = g_strdup_printf ("%s/%s", vg_name, lv_name); ++ ++ if (lvinfo->attr[4] != 'a') { ++ /* starting with 2.03.19 we need to add extra option to allow resizing of inactive LVs */ ++ success = bd_utils_check_util_version (deps[DEPS_LVM].name, LVM_VERSION_FSRESIZE, ++ deps[DEPS_LVM].ver_arg, deps[DEPS_LVM].ver_regexp, &l_error); ++ if (success) { ++ args[next_arg++] = "--fs"; ++ args[next_arg++] = "ignore"; ++ } else ++ g_clear_error (&l_error); ++ } ++ ++ bd_lvm_lvdata_free (lvinfo); ++ ++ lvspec = g_strdup_printf ("%s/%s", vg_name, lv_name); ++ args[next_arg++] = lvspec; + + success = call_lvm_and_report_error (args, extra, TRUE, error); + g_free ((gchar *) args[3]); +- g_free ((gchar *) args[4]); + + return success; + } +diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py +index 61c898c1..fc12b55d 100644 +--- a/tests/lvm_dbus_tests.py ++++ b/tests/lvm_dbus_tests.py +@@ -944,6 +944,10 @@ class LvmTestLVresize(LvmPVVGLVTestCase): + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) + self.assertTrue(succ) + ++ # try to resize when deactivated ++ succ = BlockDev.lvm_lvresize("testVG", "testLV", 768 * 1024**2, None) ++ self.assertTrue(succ) ++ + @unittest.skipUnless(lvm_dbus_running, "LVM DBus not running") + class LvmTestLVrename(LvmPVVGLVTestCase): + def test_lvrename(self): +diff --git a/tests/lvm_test.py b/tests/lvm_test.py +index 36ff10ec..7ede4b59 100644 +--- a/tests/lvm_test.py ++++ b/tests/lvm_test.py +@@ -877,6 +877,10 @@ class LvmTestLVresize(LvmPVVGLVTestCase): + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) + self.assertTrue(succ) + ++ # try to resize when deactivated ++ succ = BlockDev.lvm_lvresize("testVG", "testLV", 768 * 1024**2, None) ++ self.assertTrue(succ) ++ + class LvmTestLVrename(LvmPVVGLVTestCase): + def test_lvrename(self): + """Verify that it's possible to rename an LV""" +-- +2.39.2 + diff --git a/SOURCES/0007-tests-Fix-test_swapon_pagesize-on-systems-with-64k-p.patch b/SOURCES/0007-tests-Fix-test_swapon_pagesize-on-systems-with-64k-p.patch new file mode 100644 index 0000000..79e285d --- /dev/null +++ b/SOURCES/0007-tests-Fix-test_swapon_pagesize-on-systems-with-64k-p.patch @@ -0,0 +1,41 @@ +From 2c59bc22d30ebfc16d5d06b1f31c4d7bbede68e9 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Mon, 31 Oct 2022 12:43:17 +0100 +Subject: [PATCH] tests: Fix test_swapon_pagesize on systems with 64k pages + +--- + tests/swap_test.py | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/tests/swap_test.py b/tests/swap_test.py +index 0a0f333d..e350f8e8 100644 +--- a/tests/swap_test.py ++++ b/tests/swap_test.py +@@ -1,5 +1,6 @@ + import unittest + import os ++import resource + import overrides_hack + + from utils import create_sparse_tempfile, create_lio_device, delete_lio_device, fake_utils, fake_path, run_command, run, TestTags, tag_test +@@ -102,8 +103,15 @@ class SwapTestCase(SwapTest): + def test_swapon_pagesize(self): + """Verify that activating swap with different pagesize fails""" + +- # create swap with 64k pagesize +- ret, out, err = run_command("mkswap --pagesize 65536 %s" % self.loop_dev) ++ # pick some wrong page size: 8k on 64k and 64k everywhere else ++ pagesize = resource.getpagesize() ++ if pagesize == 65536: ++ wrong_pagesize = 8192 ++ else: ++ wrong_pagesize = 65536 ++ ++ # create swap with "wrong" pagesize ++ ret, out, err = run_command("mkswap --pagesize %s %s" % (wrong_pagesize, self.loop_dev)) + if ret != 0: + self.fail("Failed to prepare swap for pagesize test: %s %s" % (out, err)) + +-- +2.39.2 + diff --git a/SOURCES/0008-part-Fix-segfault-when-adding-a-partition-too-big-fo.patch b/SOURCES/0008-part-Fix-segfault-when-adding-a-partition-too-big-fo.patch new file mode 100644 index 0000000..84b753d --- /dev/null +++ b/SOURCES/0008-part-Fix-segfault-when-adding-a-partition-too-big-fo.patch @@ -0,0 +1,32 @@ +From 9c96e621e9abb0649118d2e1731a09b1fa139579 Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Wed, 19 Apr 2023 09:50:38 +0200 +Subject: [PATCH] part: Fix segfault when adding a partition too big for MSDOS + +Resolves: rhbz#2185564 +--- + src/plugins/part.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/plugins/part.c b/src/plugins/part.c +index 8b2285f5..28e20c28 100644 +--- a/src/plugins/part.c ++++ b/src/plugins/part.c +@@ -841,6 +841,14 @@ static gboolean resize_part (PedPartition *part, PedDevice *dev, PedDisk *disk, + constr = ped_constraint_any (dev); + + geom = ped_disk_get_max_partition_geometry (disk, part, constr); ++ if (!geom) { ++ set_parted_error (error, BD_PART_ERROR_FAIL); ++ g_prefix_error (error, "Failed to create geometry for partition on device '%s'", dev->path); ++ ped_constraint_destroy (constr); ++ finish_alignment_constraint (disk, orig_flag_state); ++ return FALSE; ++ } ++ + if (!ped_geometry_set_start (geom, start)) { + set_parted_error (error, BD_PART_ERROR_FAIL); + g_prefix_error (error, "Failed to set partition start on device '%s'", dev->path); +-- +2.40.1 + diff --git a/SOURCES/0009-Fix-issues-in-tests-when-running-in-FIPS-mode.patch b/SOURCES/0009-Fix-issues-in-tests-when-running-in-FIPS-mode.patch new file mode 100644 index 0000000..ed81651 --- /dev/null +++ b/SOURCES/0009-Fix-issues-in-tests-when-running-in-FIPS-mode.patch @@ -0,0 +1,70 @@ +From bc8c4fa2b3ba76647de9742c28bae751757dc2dd Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Thu, 18 May 2023 14:45:42 +0200 +Subject: [PATCH 1/2] tests: Use longer passphrase for LUKS in dm_test + +The short passphrase doesn't work when running in FIPS mode. +--- + tests/dm_test.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/dm_test.py b/tests/dm_test.py +index 936e3055..3b491d89 100644 +--- a/tests/dm_test.py ++++ b/tests/dm_test.py +@@ -59,8 +59,8 @@ class DevMapperGetSubsystemFromName(DevMapperTestCase): + def test_get_subsystem_from_name_crypt(self): + """Verify that it is possible to get luks device subsystem from its name""" + self.addCleanup(self._destroy_crypt) +- run("echo \"key\" | cryptsetup luksFormat %s -" %self.loop_dev) +- run("echo \"key\" | cryptsetup open %s libbd_dm_tests-subsystem_crypt --key-file=-" %self.loop_dev) ++ run("echo \"supersecretkey\" | cryptsetup luksFormat %s -" %self.loop_dev) ++ run("echo \"supersecretkey\" | cryptsetup open %s libbd_dm_tests-subsystem_crypt --key-file=-" %self.loop_dev) + subsystem = BlockDev.dm_get_subsystem_from_name("libbd_dm_tests-subsystem_crypt") + self.assertEqual(subsystem, "CRYPT") + +-- +2.40.1 + + +From b1f6d1484a980885b9870d27d2b113c98400851b Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Thu, 18 May 2023 14:56:32 +0200 +Subject: [PATCH 2/2] tests: Skip crypto tests with argon2 in FIPS mode + +argon is not available when running in FIPS mode. +--- + tests/crypto_test.py | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/tests/crypto_test.py b/tests/crypto_test.py +index 94b89131..91ea1f35 100644 +--- a/tests/crypto_test.py ++++ b/tests/crypto_test.py +@@ -175,6 +175,23 @@ class CryptoTestFormat(CryptoTestCase): + self.fail("Failed to get pbkdf information from:\n%s %s" % (out, err)) + self.assertEqual(m.group(1), "pbkdf2") + ++ def _is_fips_enabled(self): ++ if not os.path.exists("/proc/sys/crypto/fips_enabled"): ++ # if the file doesn't exist, we are definitely not in FIPS mode ++ return False ++ ++ with open("/proc/sys/crypto/fips_enabled", "r") as f: ++ enabled = f.read() ++ return enabled.strip() == "1" ++ ++ @tag_test(TestTags.SLOW, TestTags.CORE) ++ @unittest.skipUnless(HAVE_LUKS2, "LUKS 2 not supported") ++ def test_luks2_format_pbkdf_options(self): ++ """Verify that formatting device as LUKS 2 works""" ++ ++ if self._is_fips_enabled(): ++ self.skipTest("FIPS mode is enabled, cannot use argon2, skipping") ++ + # different options for argon2 -- all parameters set + pbkdf = BlockDev.CryptoLUKSPBKDF(type="argon2id", max_memory_kb=100*1024, iterations=10, parallel_threads=1) + extra = BlockDev.CryptoLUKSExtra(pbkdf=pbkdf) +-- +2.40.1 + diff --git a/SOURCES/0010-lvm-Add-a-function-to-activate-LVs-in-shared-mode.patch b/SOURCES/0010-lvm-Add-a-function-to-activate-LVs-in-shared-mode.patch new file mode 100644 index 0000000..b2e4add --- /dev/null +++ b/SOURCES/0010-lvm-Add-a-function-to-activate-LVs-in-shared-mode.patch @@ -0,0 +1,300 @@ +From 6bdbafc79e5bcdf2087148c6caa88a6c50c1e94a Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Mon, 24 Apr 2023 11:57:18 +0200 +Subject: [PATCH] lvm: Add a function to activate LVs in shared mode + +Needed by the new blivet feature to support shared LVM setups. +--- + src/lib/plugin_apis/lvm.api | 16 +++++++++ + src/plugins/lvm-dbus.c | 51 ++++++++++++++++++++------- + src/plugins/lvm.c | 53 ++++++++++++++++++++++------- + src/plugins/lvm.h | 1 + + src/python/gi/overrides/BlockDev.py | 5 ++- + tests/lvm_dbus_tests.py | 18 +++++++--- + tests/lvm_test.py | 18 +++++++--- + 7 files changed, 124 insertions(+), 38 deletions(-) + +diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api +index b8cde70b..640eee49 100644 +--- a/src/lib/plugin_apis/lvm.api ++++ b/src/lib/plugin_apis/lvm.api +@@ -1057,6 +1057,22 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + */ + gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, const BDExtraArg **extra, GError **error); + ++/** ++ * bd_lvm_lvactivate_shared: ++ * @vg_name: name of the VG containing the to-be-activated LV ++ * @lv_name: name of the to-be-activated LV ++ * @ignore_skip: whether to ignore the skip flag or not ++ * @shared: whether to activate the LV in shared mode ++ * @extra: (allow-none) (array zero-terminated=1): extra options for the LV activation ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the @vg_name/@lv_name LV was successfully activated or not ++ * ++ * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_lvactivate_shared (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error); ++ + /** + * bd_lvm_lvdeactivate: + * @vg_name: name of the VG containing the to-be-deactivated LV +diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c +index 28f3bb25..46e09833 100644 +--- a/src/plugins/lvm-dbus.c ++++ b/src/plugins/lvm-dbus.c +@@ -2163,6 +2163,27 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + return (*error == NULL); + } + ++static gboolean _lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) { ++ GVariant *params = NULL; ++ GVariantBuilder builder; ++ GVariant *extra_params = NULL; ++ ++ if (shared) ++ params = g_variant_new ("(t)", (guint64) 1 << 6); ++ else ++ params = g_variant_new ("(t)", (guint64) 0); ++ ++ if (ignore_skip) { ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); ++ g_variant_builder_add (&builder, "{sv}", "-K", g_variant_new ("s", "")); ++ extra_params = g_variant_builder_end (&builder); ++ g_variant_builder_clear (&builder); ++ } ++ call_lv_method_sync (vg_name, lv_name, "Activate", params, extra_params, extra, TRUE, error); ++ ++ return (*error == NULL); ++} ++ + /** + * bd_lvm_lvactivate: + * @vg_name: name of the VG containing the to-be-activated LV +@@ -2177,19 +2198,25 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY + */ + gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, const BDExtraArg **extra, GError **error) { +- GVariant *params = g_variant_new ("(t)", (guint64) 0); +- GVariantBuilder builder; +- GVariant *extra_params = NULL; +- +- if (ignore_skip) { +- g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); +- g_variant_builder_add (&builder, "{sv}", "-K", g_variant_new ("s", "")); +- extra_params = g_variant_builder_end (&builder); +- g_variant_builder_clear (&builder); +- } +- call_lv_method_sync (vg_name, lv_name, "Activate", params, extra_params, extra, TRUE, error); ++ return _lvm_lvactivate (vg_name, lv_name, ignore_skip, FALSE, extra, error); ++} + +- return (*error == NULL); ++/** ++ * bd_lvm_lvactivate_shared: ++ * @vg_name: name of the VG containing the to-be-activated LV ++ * @lv_name: name of the to-be-activated LV ++ * @ignore_skip: whether to ignore the skip flag or not ++ * @shared: whether to activate the LV in shared mode ++ * @extra: (allow-none) (array zero-terminated=1): extra options for the LV activation ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the @vg_name/@lv_name LV was successfully activated or not ++ * ++ * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_lvactivate_shared (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) { ++ return _lvm_lvactivate (vg_name, lv_name, ignore_skip, shared, extra, error); + } + + /** +diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c +index f1e2941b..0db3bf4a 100644 +--- a/src/plugins/lvm.c ++++ b/src/plugins/lvm.c +@@ -1644,6 +1644,28 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + return success; + } + ++static gboolean _lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) { ++ const gchar *args[5] = {"lvchange", NULL, NULL, NULL, NULL}; ++ guint8 next_arg = 2; ++ gboolean success = FALSE; ++ ++ if (shared) ++ args[1] = "-asy"; ++ else ++ args[1] = "-ay"; ++ ++ if (ignore_skip) { ++ args[next_arg] = "-K"; ++ next_arg++; ++ } ++ args[next_arg] = g_strdup_printf ("%s/%s", vg_name, lv_name); ++ ++ success = call_lvm_and_report_error (args, extra, TRUE, error); ++ g_free ((gchar *) args[next_arg]); ++ ++ return success; ++} ++ + /** + * bd_lvm_lvactivate: + * @vg_name: name of the VG containing the to-be-activated LV +@@ -1658,20 +1680,25 @@ gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 si + * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY + */ + gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, const BDExtraArg **extra, GError **error) { +- const gchar *args[5] = {"lvchange", "-ay", NULL, NULL, NULL}; +- guint8 next_arg = 2; +- gboolean success = FALSE; +- +- if (ignore_skip) { +- args[next_arg] = "-K"; +- next_arg++; +- } +- args[next_arg] = g_strdup_printf ("%s/%s", vg_name, lv_name); +- +- success = call_lvm_and_report_error (args, extra, TRUE, error); +- g_free ((gchar *) args[next_arg]); ++ return _lvm_lvactivate (vg_name, lv_name, ignore_skip, FALSE, extra, error); ++} + +- return success; ++/** ++ * bd_lvm_lvactivate_shared: ++ * @vg_name: name of the VG containing the to-be-activated LV ++ * @lv_name: name of the to-be-activated LV ++ * @ignore_skip: whether to ignore the skip flag or not ++ * @shared: whether to activate the LV in shared mode ++ * @extra: (allow-none) (array zero-terminated=1): extra options for the LV activation ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the @vg_name/@lv_name LV was successfully activated or not ++ * ++ * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_lvactivate_shared (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error) { ++ return _lvm_lvactivate (vg_name, lv_name, ignore_skip, shared, extra, error); + } + + /** +diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h +index fabf091f..c85c043d 100644 +--- a/src/plugins/lvm.h ++++ b/src/plugins/lvm.h +@@ -277,6 +277,7 @@ gboolean bd_lvm_lvremove (const gchar *vg_name, const gchar *lv_name, gboolean f + gboolean bd_lvm_lvrename (const gchar *vg_name, const gchar *lv_name, const gchar *new_name, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_lvresize (const gchar *vg_name, const gchar *lv_name, guint64 size, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_lvactivate (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, const BDExtraArg **extra, GError **error); ++gboolean bd_lvm_lvactivate_shared (const gchar *vg_name, const gchar *lv_name, gboolean ignore_skip, gboolean shared, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_lvdeactivate (const gchar *vg_name, const gchar *lv_name, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_lvsnapshotcreate (const gchar *vg_name, const gchar *origin_name, const gchar *snapshot_name, guint64 size, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_lvsnapshotmerge (const gchar *vg_name, const gchar *snapshot_name, const BDExtraArg **extra, GError **error); +diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py +index 795e0de4..3e074260 100644 +--- a/src/python/gi/overrides/BlockDev.py ++++ b/src/python/gi/overrides/BlockDev.py +@@ -605,11 +605,10 @@ def lvm_lvresize(vg_name, lv_name, size, extra=None, **kwargs): + return _lvm_lvresize(vg_name, lv_name, size, extra) + __all__.append("lvm_lvresize") + +-_lvm_lvactivate = BlockDev.lvm_lvactivate + @override(BlockDev.lvm_lvactivate) +-def lvm_lvactivate(vg_name, lv_name, ignore_skip=False, extra=None, **kwargs): ++def lvm_lvactivate(vg_name, lv_name, ignore_skip=False, shared=False, extra=None, **kwargs): + extra = _get_extra(extra, kwargs) +- return _lvm_lvactivate(vg_name, lv_name, ignore_skip, extra) ++ return BlockDev.lvm_lvactivate_shared(vg_name, lv_name, ignore_skip, shared, extra) + __all__.append("lvm_lvactivate") + + _lvm_lvdeactivate = BlockDev.lvm_lvdeactivate +diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py +index fc12b55d..a821636e 100644 +--- a/tests/lvm_dbus_tests.py ++++ b/tests/lvm_dbus_tests.py +@@ -873,15 +873,15 @@ class LvmTestLVactivateDeactivate(LvmPVVGLVTestCase): + self.assertTrue(succ) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("nonexistingVG", "testLV", True, None) ++ BlockDev.lvm_lvactivate("nonexistingVG", "testLV", True) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("testVG", "nonexistingLV", True, None) ++ BlockDev.lvm_lvactivate("testVG", "nonexistingLV", True) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("nonexistingVG", "nonexistingLV", True, None) ++ BlockDev.lvm_lvactivate("nonexistingVG", "nonexistingLV", True) + +- succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, None) ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True) + self.assertTrue(succ) + + with self.assertRaises(GLib.GError): +@@ -896,7 +896,15 @@ class LvmTestLVactivateDeactivate(LvmPVVGLVTestCase): + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) + self.assertTrue(succ) + +- succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, None) ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) ++ self.assertTrue(succ) ++ ++ # try activating in shared mode, unfortunately no way to check whether it really ++ # works or not ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, True) + self.assertTrue(succ) + + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) +diff --git a/tests/lvm_test.py b/tests/lvm_test.py +index 7ede4b59..63f43afb 100644 +--- a/tests/lvm_test.py ++++ b/tests/lvm_test.py +@@ -807,15 +807,15 @@ class LvmTestLVactivateDeactivate(LvmPVVGLVTestCase): + self.assertTrue(succ) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("nonexistingVG", "testLV", True, None) ++ BlockDev.lvm_lvactivate("nonexistingVG", "testLV", True) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("testVG", "nonexistingLV", True, None) ++ BlockDev.lvm_lvactivate("testVG", "nonexistingLV", True) + + with self.assertRaises(GLib.GError): +- BlockDev.lvm_lvactivate("nonexistingVG", "nonexistingLV", True, None) ++ BlockDev.lvm_lvactivate("nonexistingVG", "nonexistingLV", True) + +- succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, None) ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True) + self.assertTrue(succ) + + with self.assertRaises(GLib.GError): +@@ -830,7 +830,15 @@ class LvmTestLVactivateDeactivate(LvmPVVGLVTestCase): + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) + self.assertTrue(succ) + +- succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, None) ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) ++ self.assertTrue(succ) ++ ++ # try activating in shared mode, unfortunately no way to check whether it really ++ # works or not ++ succ = BlockDev.lvm_lvactivate("testVG", "testLV", True, True) + self.assertTrue(succ) + + succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) +-- +2.41.0 + diff --git a/SOURCES/0011-nvme_libblockdev-3.0.4_backport.patch b/SOURCES/0011-nvme_libblockdev-3.0.4_backport.patch new file mode 100644 index 0000000..fae7aae --- /dev/null +++ b/SOURCES/0011-nvme_libblockdev-3.0.4_backport.patch @@ -0,0 +1,1395 @@ +From 2c4324b658931882bfb664e05673cd5c9082429d Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Fri, 7 Oct 2022 15:42:44 +0200 +Subject: [PATCH] nvme: Rework the disconnect device topology crawl + +This is more sane regarding to memory ownership and +the scanned topology tree. +--- + src/plugins/nvme/nvme-fabrics.c | 93 +++++++++++++++++---------------- + tests/nvme_test.py | 2 +- + 2 files changed, 50 insertions(+), 45 deletions(-) + +diff --git a/src/plugins/nvme/nvme-fabrics.c b/src/plugins/nvme/nvme-fabrics.c +index 20ed57f5d..26e2fa6ec 100644 +--- a/src/plugins/nvme/nvme-fabrics.c ++++ b/src/plugins/nvme/nvme-fabrics.c +@@ -281,6 +281,47 @@ gboolean bd_nvme_connect (const gchar *subsysnqn, const gchar *transport, const + return TRUE; + } + ++static gboolean _disconnect (const gchar *subsysnqn, const gchar *path, GError **error, gboolean *found) { ++ nvme_root_t root; ++ nvme_host_t host; ++ nvme_subsystem_t subsys; ++ nvme_ctrl_t ctrl; ++ int ret; ++ ++ root = nvme_create_root (NULL, -1); ++ if (root == NULL) { ++ g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, ++ "Failed to create topology root: %s", ++ strerror_l (errno, _C_LOCALE)); ++ return FALSE; ++ } ++ ret = nvme_scan_topology (root, NULL, NULL); ++ if (ret < 0) { ++ g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, ++ "Failed to scan topology: %s", ++ strerror_l (errno, _C_LOCALE)); ++ nvme_free_tree (root); ++ return FALSE; ++ } ++ nvme_for_each_host (root, host) ++ nvme_for_each_subsystem (host, subsys) ++ if (!subsysnqn || g_strcmp0 (nvme_subsystem_get_nqn (subsys), subsysnqn) == 0) ++ nvme_subsystem_for_each_ctrl (subsys, ctrl) ++ if (!path || g_strcmp0 (nvme_ctrl_get_name (ctrl), path) == 0) { ++ ret = nvme_disconnect_ctrl (ctrl); ++ if (ret != 0) { ++ g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, ++ "Error disconnecting the controller: %s", ++ strerror_l (errno, _C_LOCALE)); ++ nvme_free_tree (root); ++ return FALSE; ++ } ++ *found = TRUE; ++ } ++ nvme_free_tree (root); ++ return TRUE; ++} ++ + /** + * bd_nvme_disconnect: + * @subsysnqn: The name of the NVMe subsystem to disconnect. +@@ -296,37 +337,16 @@ gboolean bd_nvme_connect (const gchar *subsysnqn, const gchar *transport, const + * Tech category: %BD_NVME_TECH_FABRICS-%BD_NVME_TECH_MODE_INITIATOR + */ + gboolean bd_nvme_disconnect (const gchar *subsysnqn, GError **error) { +- nvme_root_t root; +- nvme_host_t host; +- nvme_subsystem_t subsys; +- nvme_ctrl_t ctrl; + gboolean found = FALSE; + +- root = nvme_scan (NULL); +- nvme_init_logging (root, -1, false, false); +- nvme_for_each_host (root, host) +- nvme_for_each_subsystem (host, subsys) +- if (g_strcmp0 (nvme_subsystem_get_nqn (subsys), subsysnqn) == 0) +- nvme_subsystem_for_each_ctrl (subsys, ctrl) { +- int ret; +- +- ret = nvme_disconnect_ctrl (ctrl); +- if (ret != 0) { +- g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, +- "Error disconnecting the controller: %s", +- strerror_l (errno, _C_LOCALE)); +- nvme_free_tree (root); +- return FALSE; +- } +- found = TRUE; +- } +- nvme_free_tree (root); ++ if (!_disconnect (subsysnqn, NULL, error, &found)) ++ return FALSE; ++ + if (!found) { + g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_NO_MATCH, + "No subsystems matching '%s' NQN found.", subsysnqn); + return FALSE; + } +- + return TRUE; + } + +@@ -344,36 +364,21 @@ gboolean bd_nvme_disconnect (const gchar *subsysnqn, GError **error) { + * Tech category: %BD_NVME_TECH_FABRICS-%BD_NVME_TECH_MODE_INITIATOR + */ + gboolean bd_nvme_disconnect_by_path (const gchar *path, GError **error) { +- nvme_root_t root; +- nvme_ctrl_t ctrl; + const gchar *p; +- int ret; ++ gboolean found = FALSE; + + p = path; + if (g_str_has_prefix (p, "/dev/")) + p += 5; + +- root = nvme_scan (NULL); +- nvme_init_logging (root, -1, false, false); +- ctrl = nvme_scan_ctrl (root, p); +- if (!ctrl) { +- g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_NO_MATCH, +- "Unable to match a NVMeoF controller for the specified block device %s.", +- path); +- nvme_free_tree (root); ++ if (!_disconnect (NULL, p, error, &found)) + return FALSE; +- } + +- ret = nvme_disconnect_ctrl (ctrl); +- if (ret != 0) { +- g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, +- "Error disconnecting the controller: %s", +- strerror_l (errno, _C_LOCALE)); +- nvme_free_tree (root); ++ if (!found) { ++ g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_NO_MATCH, ++ "No controllers matching the %s device name found.", path); + return FALSE; + } +- nvme_free_tree (root); +- + return TRUE; + } + +diff --git a/tests/nvme_test.py b/tests/nvme_test.py +index f205e5391..696d594c9 100644 +--- a/tests/nvme_test.py ++++ b/tests/nvme_test.py +@@ -387,7 +387,7 @@ def test_connect_single_ns(self): + # disconnect + with self.assertRaisesRegexp(GLib.GError, r"No subsystems matching '.*' NQN found."): + BlockDev.nvme_disconnect(self.SUBNQN + "xx") +- with self.assertRaisesRegexp(GLib.GError, r"Unable to match a NVMeoF controller for the specified block device /dev/nvme.*xx"): ++ with self.assertRaisesRegexp(GLib.GError, r"No controllers matching the /dev/nvme.*xx device name found."): + BlockDev.nvme_disconnect_by_path(ctrls[0] + "xx") + # should disconnect both connections as long the SUBNQN matches + BlockDev.nvme_disconnect(self.SUBNQN) +From ac1e0c50dd7bab21a7837c806b82bf34090127d1 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Sun, 5 Feb 2023 21:51:42 +0100 +Subject: [PATCH] nvme: Strip trailing whitespaces from subsysnqn when matching + the device tree + +--- + src/plugins/nvme/nvme-fabrics.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/plugins/nvme/nvme-fabrics.c b/src/plugins/nvme/nvme-fabrics.c +index 5cc7f670d..27f6ed444 100644 +--- a/src/plugins/nvme/nvme-fabrics.c ++++ b/src/plugins/nvme/nvme-fabrics.c +@@ -721,6 +721,12 @@ gchar ** bd_nvme_find_ctrls_for_ns (const gchar *ns_sysfs_path, const gchar *sub + nvme_ctrl_t c; + nvme_ns_t n; + char realp[PATH_MAX]; ++ gchar *subsysnqn_p; ++ ++ /* libnvme strips trailing spaces and newlines when reading values from sysfs */ ++ subsysnqn_p = g_strdup (subsysnqn); ++ if (subsysnqn_p) ++ g_strchomp (subsysnqn_p); + + ptr_array = g_ptr_array_new (); + +@@ -736,7 +742,7 @@ gchar ** bd_nvme_find_ctrls_for_ns (const gchar *ns_sysfs_path, const gchar *sub + nvme_for_each_subsystem (h, s) { + gboolean found = FALSE; + +- if (subsysnqn && g_strcmp0 (nvme_subsystem_get_nqn (s), subsysnqn) != 0) ++ if (subsysnqn && g_strcmp0 (nvme_subsystem_get_nqn (s), subsysnqn_p) != 0) + continue; + + nvme_subsystem_for_each_ctrl (s, c) +@@ -767,6 +773,7 @@ gchar ** bd_nvme_find_ctrls_for_ns (const gchar *ns_sysfs_path, const gchar *sub + } + } + nvme_free_tree (root); ++ g_free (subsysnqn_p); + + g_ptr_array_add (ptr_array, NULL); /* trailing NULL element */ + return (gchar **) g_ptr_array_free (ptr_array, FALSE); +From 29b4defc50451dd54f1a7a988b92bdf5fadb22df Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Mon, 6 Feb 2023 11:29:43 +0100 +Subject: [PATCH] nvme: Return NULL in case the supported NVMe revision is not + reported + +...as is often the case for older, pre-1.2 NVMe devices. +--- + src/lib/plugin_apis/nvme.api | 2 +- + src/plugins/nvme/nvme-info.c | 2 ++ + src/plugins/nvme/nvme.h | 2 +- + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/lib/plugin_apis/nvme.api b/src/lib/plugin_apis/nvme.api +index 7bc2cf9ef..6e73870e5 100644 +--- a/src/lib/plugin_apis/nvme.api ++++ b/src/lib/plugin_apis/nvme.api +@@ -142,7 +142,7 @@ GType bd_nvme_controller_info_get_type (); + * @model_number: The model number. + * @serial_number: The serial number. + * @firmware_ver: The currently active firmware revision. +- * @nvme_ver: The NVM Express base specification that the controller implementation supports. ++ * @nvme_ver: The NVM Express base specification that the controller implementation supports or %NULL when not reported by the device. + * @features: features and capabilities present for this controller, see #BDNVMEControllerFeature. + * @controller_type: The controller type. + * @selftest_ext_time: Extended Device Self-test Time, if #BD_NVME_CTRL_FEAT_SELFTEST is supported then this field +diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c +index ec5cae332..23ee8afde 100644 +--- a/src/plugins/nvme/nvme-info.c ++++ b/src/plugins/nvme/nvme-info.c +@@ -401,6 +401,8 @@ static gchar *decode_nvme_rev (guint32 ver) { + if (mjr >= 2 || mnr >= 2) + ter = ver & 0xFF; + ++ if (mjr == 0 && mnr == 0) ++ return NULL; + if (ter == 0) + return g_strdup_printf ("%u.%u", mjr, mnr); + else +diff --git a/src/plugins/nvme/nvme.h b/src/plugins/nvme/nvme.h +index ad456a82e..fa6f6abcc 100644 +--- a/src/plugins/nvme/nvme.h ++++ b/src/plugins/nvme/nvme.h +@@ -129,7 +129,7 @@ typedef enum { + * @model_number: The model number. + * @serial_number: The serial number. + * @firmware_ver: The currently active firmware revision. +- * @nvme_ver: The NVM Express base specification that the controller implementation supports. ++ * @nvme_ver: The NVM Express base specification that the controller implementation supports or %NULL when not reported by the device. + * @features: features and capabilities present for this controller, see #BDNVMEControllerFeature. + * @controller_type: The controller type. + * @selftest_ext_time: Extended Device Self-test Time, if #BD_NVME_CTRL_FEAT_SELFTEST is supported then this field +From 5a709aa3475ee083237c3faf4fff8c316767bd71 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Wed, 26 Apr 2023 18:39:57 +0200 +Subject: [PATCH] nvme: Add support for ENVME_CONNECT_CONNREFUSED + +Requires libnvme-1.3 +--- + configure.ac | 2 +- + src/lib/plugin_apis/nvme.api | 2 ++ + src/plugins/nvme/nvme-error.c | 3 +++ + src/plugins/nvme/nvme.h | 2 ++ + 4 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 727465c9b..16fe3a0c2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -238,7 +238,7 @@ AS_IF([test "x$with_nvdimm" != "xno"], + []) + + AS_IF([test "x$with_nvme" != "xno"], +- [LIBBLOCKDEV_PKG_CHECK_MODULES([NVME], [libnvme >= 1.2])], ++ [LIBBLOCKDEV_PKG_CHECK_MODULES([NVME], [libnvme >= 1.3])], + []) + + AS_IF([test "x$with_vdo" != "xno"], +diff --git a/src/lib/plugin_apis/nvme.api b/src/lib/plugin_apis/nvme.api +index 6e73870e5..1099da7db 100644 +--- a/src/lib/plugin_apis/nvme.api ++++ b/src/lib/plugin_apis/nvme.api +@@ -31,6 +31,7 @@ GQuark bd_nvme_error_quark (void) { + * @BD_NVME_ERROR_CONNECT_ADDRINUSE: HostNQN already in use. + * @BD_NVME_ERROR_CONNECT_NODEV: Invalid interface. + * @BD_NVME_ERROR_CONNECT_OPNOTSUPP: Operation not supported. ++ * @BD_NVME_ERROR_CONNECT_REFUSED: Connection refused. + */ + /* BpG-skip-end */ + typedef enum { +@@ -51,6 +52,7 @@ typedef enum { + BD_NVME_ERROR_CONNECT_ADDRINUSE, + BD_NVME_ERROR_CONNECT_NODEV, + BD_NVME_ERROR_CONNECT_OPNOTSUPP, ++ BD_NVME_ERROR_CONNECT_REFUSED, + } BDNVMEError; + + typedef enum { +diff --git a/src/plugins/nvme/nvme-error.c b/src/plugins/nvme/nvme-error.c +index cb95a46dc..4bd4d7712 100644 +--- a/src/plugins/nvme/nvme-error.c ++++ b/src/plugins/nvme/nvme-error.c +@@ -137,6 +137,9 @@ void _nvme_fabrics_errno_to_gerror (int result, int _errno, GError **error) + case ENVME_CONNECT_OPNOTSUPP: + code = BD_NVME_ERROR_CONNECT_OPNOTSUPP; + break; ++ case ENVME_CONNECT_CONNREFUSED: ++ code = BD_NVME_ERROR_CONNECT_REFUSED; ++ break; + default: + code = BD_NVME_ERROR_CONNECT; + } +diff --git a/src/plugins/nvme/nvme.h b/src/plugins/nvme/nvme.h +index 438d66334..afd41b267 100644 +--- a/src/plugins/nvme/nvme.h ++++ b/src/plugins/nvme/nvme.h +@@ -27,6 +27,7 @@ GQuark bd_nvme_error_quark (void); + * @BD_NVME_ERROR_CONNECT_ADDRINUSE: HostNQN already in use. + * @BD_NVME_ERROR_CONNECT_NODEV: Invalid interface. + * @BD_NVME_ERROR_CONNECT_OPNOTSUPP: Operation not supported. ++ * @BD_NVME_ERROR_CONNECT_REFUSED: Connection refused. + */ + typedef enum { + BD_NVME_ERROR_TECH_UNAVAIL, +@@ -46,6 +47,7 @@ typedef enum { + BD_NVME_ERROR_CONNECT_ADDRINUSE, + BD_NVME_ERROR_CONNECT_NODEV, + BD_NVME_ERROR_CONNECT_OPNOTSUPP, ++ BD_NVME_ERROR_CONNECT_REFUSED, + } BDNVMEError; + + typedef enum { +From b19600de73233317cd9de68dba356ec4bb80a0f3 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 27 Apr 2023 17:32:25 +0200 +Subject: [PATCH] nvme: Add support for 'keyring' and 'tls_key' fabrics + attributes + +Requires libnvme-1.4 +--- + configure.ac | 5 ++++- + src/lib/plugin_apis/nvme.api | 2 ++ + src/plugins/nvme/nvme-fabrics.c | 21 +++++++++++++++++++++ + 3 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 16fe3a0c2..12d007a53 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -238,7 +238,10 @@ AS_IF([test "x$with_nvdimm" != "xno"], + []) + + AS_IF([test "x$with_nvme" != "xno"], +- [LIBBLOCKDEV_PKG_CHECK_MODULES([NVME], [libnvme >= 1.3])], ++ [LIBBLOCKDEV_PKG_CHECK_MODULES([NVME], [libnvme >= 1.3]) ++ AS_IF([$PKG_CONFIG --atleast-version=1.4 libnvme], ++ [AC_DEFINE([HAVE_LIBNVME_1_4])], []) ++ ], + []) + + AS_IF([test "x$with_vdo" != "xno"], +diff --git a/src/lib/plugin_apis/nvme.api b/src/lib/plugin_apis/nvme.api +index 1099da7db..667dbe9e0 100644 +--- a/src/lib/plugin_apis/nvme.api ++++ b/src/lib/plugin_apis/nvme.api +@@ -1415,6 +1415,8 @@ gboolean bd_nvme_set_host_id (const gchar *host_id, GError **error); + * - `"data_digest"`: Generates/verifies data digest (TCP). Boolean value. + * - `"tls"`: Enable TLS encryption (TCP). Boolean value. + * - `"hostsymname"`: TP8010: NVMe host symbolic name. ++ * - `"keyring"`: Keyring to store and lookup keys. String value. ++ * - `"tls_key"`: TLS PSK for the connection. String value. + * + * Boolean values can be expressed by "0"/"1", "on"/"off" or "True"/"False" case-insensitive + * strings. Failed numerical or boolean string conversions will result in the option being ignored. +diff --git a/src/plugins/nvme/nvme-fabrics.c b/src/plugins/nvme/nvme-fabrics.c +index 27f6ed444..0c64fb513 100644 +--- a/src/plugins/nvme/nvme-fabrics.c ++++ b/src/plugins/nvme/nvme-fabrics.c +@@ -125,6 +125,25 @@ static void parse_extra_args (const BDExtraArg **extra, struct nvme_fabrics_conf + else + if (g_strcmp0 ((*extra_i)->opt, "tls") == 0) + SAFE_BOOL_CONV (cfg->tls) ++#ifdef HAVE_LIBNVME_1_4 ++ else ++ if (g_strcmp0 ((*extra_i)->opt, "keyring") == 0) { ++ int keyring; ++ ++ keyring = nvme_lookup_keyring ((*extra_i)->val); ++ if (keyring) { ++ cfg->keyring = keyring; ++ nvme_set_keyring (cfg->keyring); ++ } ++ } else ++ if (g_strcmp0 ((*extra_i)->opt, "tls_key") == 0) { ++ int key; ++ ++ key = nvme_lookup_key ("psk", (*extra_i)->val); ++ if (key) ++ cfg->tls_key = key; ++ } ++#endif + } + + #undef SAFE_INT_CONV +@@ -179,6 +198,8 @@ static void parse_extra_args (const BDExtraArg **extra, struct nvme_fabrics_conf + * - `"data_digest"`: Generates/verifies data digest (TCP). Boolean value. + * - `"tls"`: Enable TLS encryption (TCP). Boolean value. + * - `"hostsymname"`: TP8010: NVMe host symbolic name. ++ * - `"keyring"`: Keyring to store and lookup keys. String value. ++ * - `"tls_key"`: TLS PSK for the connection. String value. + * + * Boolean values can be expressed by "0"/"1", "on"/"off" or "True"/"False" case-insensitive + * strings. Failed numerical or boolean string conversions will result in the option being ignored. +From 941448f5ec9f465266e1baf5de23e36692a17274 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 27 Apr 2023 19:05:00 +0200 +Subject: [PATCH] nvme: Fix 128-bit int conversion + +Still using target 64-bit int and expecting overflow. This change +at least handles endianness conversion properly. + +Futher experiments reveal shortcomings during gobject-introspection +data type translation so until 128-bit int is properly supported +throughout the stack, we can only hope numbers won't be that high. +--- + src/plugins/nvme/nvme-info.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c +index 23ee8afde..bbc7de4f2 100644 +--- a/src/plugins/nvme/nvme-info.c ++++ b/src/plugins/nvme/nvme-info.c +@@ -365,15 +365,26 @@ BDNVMESanitizeLog * bd_nvme_sanitize_log_copy (BDNVMESanitizeLog *log) { + } + + +-static guint64 int128_to_guint64 (__u8 *data) ++/* can't use real __int128 due to gobject-introspection */ ++static guint64 int128_to_guint64 (__u8 data[16]) + { + int i; ++ __u8 d[16]; + guint64 result = 0; + +- /* FIXME: would overflow, need to find 128-bit int */ ++ /* endianness conversion */ ++#if G_BYTE_ORDER == G_BIG_ENDIAN ++ for (i = 0; i < 16; i++) ++ d[i] = data[15 - i]; ++#else ++ memcpy (d, data, sizeof (d)); ++#endif ++ ++ /* FIXME: would overflow */ ++ /* https://github.com/linux-nvme/libnvme/issues/475 */ + for (i = 0; i < 16; i++) { + result *= 256; +- result += data[15 - i]; ++ result += d[15 - i]; + } + return result; + } +From 5f118338e52a9096fdbac5ee9aa9c1e43f8b038b Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Fri, 23 Jun 2023 13:05:24 +0200 +Subject: [PATCH] docs: Change NVMe plugin description to be consistent with + other plugins + +--- + src/plugins/nvme/nvme.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/plugins/nvme/nvme.c b/src/plugins/nvme/nvme.c +index c0f4759de..c319f088c 100644 +--- a/src/plugins/nvme/nvme.c ++++ b/src/plugins/nvme/nvme.c +@@ -36,7 +36,7 @@ + + /** + * SECTION: nvme +- * @short_description: NVMe device reporting and management. ++ * @short_description: plugin for NVMe device reporting and management + * @title: NVMe + * @include: nvme.h + * +From 0f91582182f1680e979ff5b6e0d7c48a19917abc Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 29 Jun 2023 14:42:41 +0200 +Subject: [PATCH] nvme: Mark private symbols as hidden + +--- + src/plugins/nvme/nvme-private.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/plugins/nvme/nvme-private.h b/src/plugins/nvme/nvme-private.h +index 3d4b2a996..8b6d13253 100644 +--- a/src/plugins/nvme/nvme-private.h ++++ b/src/plugins/nvme/nvme-private.h +@@ -16,10 +16,13 @@ + #define _C_LOCALE (locale_t) 0 + + /* nvme-error.c */ ++G_GNUC_INTERNAL + void _nvme_status_to_error (gint status, gboolean fabrics, GError **error); ++G_GNUC_INTERNAL + void _nvme_fabrics_errno_to_gerror (int result, int _errno, GError **error); + + /* nvme-info.c */ ++G_GNUC_INTERNAL + gint _open_dev (const gchar *device, GError **error); + + #endif /* BD_NVME_PRIVATE */ +From ddfb806da578541c7a5a0947e29b81e33f594b11 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Tue, 8 Aug 2023 16:51:26 +0200 +Subject: [PATCH] nvme: Use interim buffer for nvme_get_log_sanitize() + +Certain drives tend to return more data than expected resulting +in stack corruption. Use an interim buffer large enough to handle +the excess bytes. + +https://github.com/storaged-project/udisks/issues/1152 +https://github.com/linux-nvme/libnvme/issues/684 +--- + src/plugins/nvme/nvme-info.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c +index bbc7de4f2..2a3d87cff 100644 +--- a/src/plugins/nvme/nvme-info.c ++++ b/src/plugins/nvme/nvme-info.c +@@ -1026,7 +1026,8 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **error) { + int ret; + int fd; +- struct nvme_sanitize_log_page sanitize_log = ZERO_INIT; ++ char buf[65536] = ZERO_INIT; ++ struct nvme_sanitize_log_page *sanitize_log; + BDNVMESanitizeLog *log; + __u16 sstat; + +@@ -1036,7 +1037,7 @@ BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **erro + return NULL; + + /* send the NVME_LOG_LID_SANITIZE ioctl */ +- ret = nvme_get_log_sanitize (fd, FALSE /* rae */, &sanitize_log); ++ ret = nvme_get_log_sanitize (fd, FALSE /* rae */, (struct nvme_sanitize_log_page *) &buf); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Get Log Page - Sanitize Status Log command error: "); +@@ -1045,12 +1046,16 @@ BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **erro + } + close (fd); + +- sstat = GUINT16_FROM_LE (sanitize_log.sstat); ++ /* need to use interim buffer that is large enough for broken drives ++ * returning more data than expected ++ */ ++ sanitize_log = (struct nvme_sanitize_log_page *) &buf; + + log = g_new0 (BDNVMESanitizeLog, 1); + log->sanitize_progress = 0; ++ sstat = GUINT16_FROM_LE (sanitize_log->sstat); + if ((sstat & NVME_SANITIZE_SSTAT_STATUS_MASK) == NVME_SANITIZE_SSTAT_STATUS_IN_PROGESS) +- log->sanitize_progress = ((gdouble) GUINT16_FROM_LE (sanitize_log.sprog) * 100) / 0x10000; ++ log->sanitize_progress = ((gdouble) GUINT16_FROM_LE (sanitize_log->sprog) * 100) / 0x10000; + log->global_data_erased = sstat & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED; + log->overwrite_passes = (sstat >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) & NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK; + +@@ -1073,12 +1078,12 @@ BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **erro + break; + } + +- log->time_for_overwrite = (GUINT32_FROM_LE (sanitize_log.eto) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.eto); +- log->time_for_block_erase = (GUINT32_FROM_LE (sanitize_log.etbe) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.etbe); +- log->time_for_crypto_erase = (GUINT32_FROM_LE (sanitize_log.etce) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.etce); +- log->time_for_overwrite_nd = (GUINT32_FROM_LE (sanitize_log.etond) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.etond); +- log->time_for_block_erase_nd = (GUINT32_FROM_LE (sanitize_log.etbend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.etbend); +- log->time_for_crypto_erase_nd = (GUINT32_FROM_LE (sanitize_log.etcend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log.etcend); ++ log->time_for_overwrite = (GUINT32_FROM_LE (sanitize_log->eto) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->eto); ++ log->time_for_block_erase = (GUINT32_FROM_LE (sanitize_log->etbe) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etbe); ++ log->time_for_crypto_erase = (GUINT32_FROM_LE (sanitize_log->etce) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etce); ++ log->time_for_overwrite_nd = (GUINT32_FROM_LE (sanitize_log->etond) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etond); ++ log->time_for_block_erase_nd = (GUINT32_FROM_LE (sanitize_log->etbend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etbend); ++ log->time_for_crypto_erase_nd = (GUINT32_FROM_LE (sanitize_log->etcend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etcend); + + return log; + } +From c9c3740e20dc891bddb3cfea79e589ad2bf4419f Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Wed, 16 Aug 2023 16:03:11 +0200 +Subject: [PATCH] nvme: Generate HostID when missing + +Newer kernels tend to refuse connection when no HostID is supplied. +Even non-matching UUIDs within HostNQN/HostID seems to be working +fine with kernel 6.5-rc6. + +This should bring us closer to the new HostNQN <--> HostID +mapping validation introduced in kernel-6.5. +--- + src/plugins/nvme/nvme-fabrics.c | 41 +++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 9 deletions(-) + +diff --git a/src/plugins/nvme/nvme-fabrics.c b/src/plugins/nvme/nvme-fabrics.c +index c79d9e6de..1877845f2 100644 +--- a/src/plugins/nvme/nvme-fabrics.c ++++ b/src/plugins/nvme/nvme-fabrics.c +@@ -161,7 +161,7 @@ static void parse_extra_args (const BDExtraArg **extra, struct nvme_fabrics_conf + * @host_iface: (nullable): The network interface used on the host to connect to the Controller (e.g. IP `eth1`, `enp2s0`). This forces the connection to be made on a specific interface instead of letting the system decide. + * @host_nqn: (nullable): Overrides the default Host NQN that identifies the NVMe Host. If this option is %NULL, the default is read from `/etc/nvme/hostnqn` first. + * If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next. The Host NQN uniquely identifies the NVMe Host. +- * @host_id: (nullable): User-defined host UUID or %NULL to use default (as defined in `/etc/nvme/hostid`) ++ * @host_id: (nullable): User-defined host UUID or %NULL to use default (as defined in `/etc/nvme/hostid`). + * @extra: (nullable) (array zero-terminated=1): Additional arguments. + * @error: (out) (nullable): Place to store error (if any). + * +@@ -244,18 +244,41 @@ gboolean bd_nvme_connect (const gchar *subsysnqn, const gchar *transport, const + return FALSE; + } + +- /* parse extra arguments */ +- nvmf_default_config (&cfg); +- parse_extra_args (extra, &cfg, &config_file, &hostkey, &ctrlkey, &hostsymname); +- ++ /* HostNQN checks */ + host_nqn_val = g_strdup (host_nqn); ++ host_id_val = g_strdup (host_id); + if (host_nqn_val == NULL) + host_nqn_val = nvmf_hostnqn_from_file (); +- if (host_nqn_val == NULL) +- host_nqn_val = nvmf_hostnqn_generate (); +- host_id_val = g_strdup (host_id); + if (host_id_val == NULL) + host_id_val = nvmf_hostid_from_file (); ++ if (host_nqn_val == NULL) ++ host_nqn_val = nvmf_hostnqn_generate (); ++ if (host_nqn_val == NULL) { ++ g_set_error_literal (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT, ++ "Could not determine HostNQN"); ++ g_free (host_nqn_val); ++ g_free (host_id_val); ++ return FALSE; ++ } ++ if (host_id_val == NULL) { ++ /* derive hostid from hostnqn, newer kernels refuse empty hostid */ ++ host_id_val = g_strrstr (host_nqn_val, "uuid:"); ++ if (host_id_val) ++ host_id_val = g_strdup (host_id_val + strlen ("uuid:")); ++ /* TODO: in theory generating arbitrary uuid might work as a fallback */ ++ } ++ if (host_id_val == NULL) { ++ g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT, ++ "Could not determine HostID value from HostNQN '%s'", ++ host_nqn_val); ++ g_free (host_nqn_val); ++ g_free (host_id_val); ++ return FALSE; ++ } ++ ++ /* parse extra arguments */ ++ nvmf_default_config (&cfg); ++ parse_extra_args (extra, &cfg, &config_file, &hostkey, &ctrlkey, &hostsymname); + + root = nvme_scan (config_file); + g_assert (root != NULL); +@@ -263,7 +286,7 @@ gboolean bd_nvme_connect (const gchar *subsysnqn, const gchar *transport, const + host = nvme_lookup_host (root, host_nqn_val, host_id_val); + if (host == NULL) { + g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED, +- "Unable to lookup host for nqn '%s' and id '%s'", ++ "Unable to lookup host for HostNQN '%s' and HostID '%s'", + host_nqn_val, host_id_val); + g_free (host_nqn_val); + g_free (host_id_val); +From 2ae0d949eb87142b0212e5953a0e5ad1a146ed6b Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 5 Oct 2023 17:27:57 +0200 +Subject: [PATCH] nvme: Rework memory allocation for device ioctls + +Make sure to provide pagesize-aligned and large enough buffer +for ioctls that may involve DMA buffer mapping. +--- + src/plugins/nvme/nvme-info.c | 311 +++++++++++++++++++------------- + src/plugins/nvme/nvme-op.c | 30 ++- + src/plugins/nvme/nvme-private.h | 2 + + 3 files changed, 204 insertions(+), 139 deletions(-) + +diff --git a/src/plugins/nvme/nvme-info.c b/src/plugins/nvme/nvme-info.c +index 2a3d87cff..eaf77473c 100644 +--- a/src/plugins/nvme/nvme-info.c ++++ b/src/plugins/nvme/nvme-info.c +@@ -402,6 +402,21 @@ gint _open_dev (const gchar *device, GError **error) { + return fd; + } + ++/* backported from nvme-cli: https://github.com/linux-nvme/nvme-cli/pull/2051 */ ++#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) ++ ++void *_nvme_alloc (size_t len) ++{ ++ size_t _len = ROUND_UP (len, 0x1000); ++ void *p; ++ ++ if (posix_memalign ((void *) &p, getpagesize (), _len)) ++ return NULL; ++ ++ memset (p, 0, _len); ++ return p; ++} ++ + static gchar *decode_nvme_rev (guint32 ver) { + guint16 mjr; + guint8 mnr, ter = 0; +@@ -452,7 +467,7 @@ static gboolean _nvme_a_is_zero (const __u8 a[], int len) { + BDNVMEControllerInfo * bd_nvme_get_controller_info (const gchar *device, GError **error) { + int ret; + int fd; +- struct nvme_id_ctrl ctrl_id = ZERO_INIT; ++ struct nvme_id_ctrl *ctrl_id; + BDNVMEControllerInfo *info; + + /* open the block device */ +@@ -460,53 +475,56 @@ BDNVMEControllerInfo * bd_nvme_get_controller_info (const gchar *device, GError + if (fd < 0) + return NULL; + ++ ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl)); ++ g_warn_if_fail (ctrl_id != NULL); + /* send the NVME_IDENTIFY_CNS_CTRL ioctl */ +- ret = nvme_identify_ctrl (fd, &ctrl_id); ++ ret = nvme_identify_ctrl (fd, ctrl_id); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Identify Controller command error: "); + close (fd); ++ free (ctrl_id); + return NULL; + } + close (fd); + + info = g_new0 (BDNVMEControllerInfo, 1); +- if ((ctrl_id.cmic & NVME_CTRL_CMIC_MULTI_PORT) == NVME_CTRL_CMIC_MULTI_PORT) ++ if ((ctrl_id->cmic & NVME_CTRL_CMIC_MULTI_PORT) == NVME_CTRL_CMIC_MULTI_PORT) + info->features |= BD_NVME_CTRL_FEAT_MULTIPORT; +- if ((ctrl_id.cmic & NVME_CTRL_CMIC_MULTI_CTRL) == NVME_CTRL_CMIC_MULTI_CTRL) ++ if ((ctrl_id->cmic & NVME_CTRL_CMIC_MULTI_CTRL) == NVME_CTRL_CMIC_MULTI_CTRL) + info->features |= BD_NVME_CTRL_FEAT_MULTICTRL; +- if ((ctrl_id.cmic & NVME_CTRL_CMIC_MULTI_SRIOV) == NVME_CTRL_CMIC_MULTI_SRIOV) ++ if ((ctrl_id->cmic & NVME_CTRL_CMIC_MULTI_SRIOV) == NVME_CTRL_CMIC_MULTI_SRIOV) + info->features |= BD_NVME_CTRL_FEAT_SRIOV; +- if ((ctrl_id.cmic & NVME_CTRL_CMIC_MULTI_ANA_REPORTING) == NVME_CTRL_CMIC_MULTI_ANA_REPORTING) ++ if ((ctrl_id->cmic & NVME_CTRL_CMIC_MULTI_ANA_REPORTING) == NVME_CTRL_CMIC_MULTI_ANA_REPORTING) + info->features |= BD_NVME_CTRL_FEAT_ANA_REPORTING; +- if ((ctrl_id.nvmsr & NVME_CTRL_NVMSR_NVMESD) == NVME_CTRL_NVMSR_NVMESD) ++ if ((ctrl_id->nvmsr & NVME_CTRL_NVMSR_NVMESD) == NVME_CTRL_NVMSR_NVMESD) + info->features |= BD_NVME_CTRL_FEAT_STORAGE_DEVICE; +- if ((ctrl_id.nvmsr & NVME_CTRL_NVMSR_NVMEE) == NVME_CTRL_NVMSR_NVMEE) ++ if ((ctrl_id->nvmsr & NVME_CTRL_NVMSR_NVMEE) == NVME_CTRL_NVMSR_NVMEE) + info->features |= BD_NVME_CTRL_FEAT_ENCLOSURE; +- if ((ctrl_id.mec & NVME_CTRL_MEC_PCIEME) == NVME_CTRL_MEC_PCIEME) ++ if ((ctrl_id->mec & NVME_CTRL_MEC_PCIEME) == NVME_CTRL_MEC_PCIEME) + info->features |= BD_NVME_CTRL_FEAT_MGMT_PCIE; +- if ((ctrl_id.mec & NVME_CTRL_MEC_SMBUSME) == NVME_CTRL_MEC_SMBUSME) ++ if ((ctrl_id->mec & NVME_CTRL_MEC_SMBUSME) == NVME_CTRL_MEC_SMBUSME) + info->features |= BD_NVME_CTRL_FEAT_MGMT_SMBUS; +- info->pci_vendor_id = GUINT16_FROM_LE (ctrl_id.vid); +- info->pci_subsys_vendor_id = GUINT16_FROM_LE (ctrl_id.ssvid); +- info->ctrl_id = GUINT16_FROM_LE (ctrl_id.cntlid); +- if (!_nvme_a_is_zero (ctrl_id.fguid, sizeof (ctrl_id.fguid))) +- info->fguid = _uuid_to_str (ctrl_id.fguid); +- info->model_number = g_strndup (ctrl_id.mn, sizeof (ctrl_id.mn)); ++ info->pci_vendor_id = GUINT16_FROM_LE (ctrl_id->vid); ++ info->pci_subsys_vendor_id = GUINT16_FROM_LE (ctrl_id->ssvid); ++ info->ctrl_id = GUINT16_FROM_LE (ctrl_id->cntlid); ++ if (!_nvme_a_is_zero (ctrl_id->fguid, sizeof (ctrl_id->fguid))) ++ info->fguid = _uuid_to_str (ctrl_id->fguid); ++ info->model_number = g_strndup (ctrl_id->mn, sizeof (ctrl_id->mn)); + g_strstrip (info->model_number); +- info->serial_number = g_strndup (ctrl_id.sn, sizeof (ctrl_id.sn)); ++ info->serial_number = g_strndup (ctrl_id->sn, sizeof (ctrl_id->sn)); + g_strstrip (info->serial_number); +- info->firmware_ver = g_strndup (ctrl_id.fr, sizeof (ctrl_id.fr)); ++ info->firmware_ver = g_strndup (ctrl_id->fr, sizeof (ctrl_id->fr)); + g_strstrip (info->firmware_ver); +- info->nvme_ver = decode_nvme_rev (GUINT32_FROM_LE (ctrl_id.ver)); ++ info->nvme_ver = decode_nvme_rev (GUINT32_FROM_LE (ctrl_id->ver)); + /* TODO: vwci: VPD Write Cycle Information */ +- if ((ctrl_id.oacs & NVME_CTRL_OACS_FORMAT) == NVME_CTRL_OACS_FORMAT) ++ if ((ctrl_id->oacs & NVME_CTRL_OACS_FORMAT) == NVME_CTRL_OACS_FORMAT) + info->features |= BD_NVME_CTRL_FEAT_FORMAT; +- if ((ctrl_id.oacs & NVME_CTRL_OACS_NS_MGMT) == NVME_CTRL_OACS_NS_MGMT) ++ if ((ctrl_id->oacs & NVME_CTRL_OACS_NS_MGMT) == NVME_CTRL_OACS_NS_MGMT) + info->features |= BD_NVME_CTRL_FEAT_NS_MGMT; +- if ((ctrl_id.oacs & NVME_CTRL_OACS_SELF_TEST) == NVME_CTRL_OACS_SELF_TEST) ++ if ((ctrl_id->oacs & NVME_CTRL_OACS_SELF_TEST) == NVME_CTRL_OACS_SELF_TEST) + info->features |= BD_NVME_CTRL_FEAT_SELFTEST; +- switch (ctrl_id.cntrltype) { ++ switch (ctrl_id->cntrltype) { + case NVME_CTRL_CNTRLTYPE_IO: + info->controller_type = BD_NVME_CTRL_TYPE_IO; + break; +@@ -519,36 +537,37 @@ BDNVMEControllerInfo * bd_nvme_get_controller_info (const gchar *device, GError + default: + info->controller_type = BD_NVME_CTRL_TYPE_UNKNOWN; + } +- info->hmb_pref_size = GUINT32_FROM_LE (ctrl_id.hmpre) * 4096LL; +- info->hmb_min_size = GUINT32_FROM_LE (ctrl_id.hmmin) * 4096LL; +- info->size_total = int128_to_guint64 (ctrl_id.tnvmcap); +- info->size_unalloc = int128_to_guint64 (ctrl_id.unvmcap); +- info->selftest_ext_time = GUINT16_FROM_LE (ctrl_id.edstt); ++ info->hmb_pref_size = GUINT32_FROM_LE (ctrl_id->hmpre) * 4096LL; ++ info->hmb_min_size = GUINT32_FROM_LE (ctrl_id->hmmin) * 4096LL; ++ info->size_total = int128_to_guint64 (ctrl_id->tnvmcap); ++ info->size_unalloc = int128_to_guint64 (ctrl_id->unvmcap); ++ info->selftest_ext_time = GUINT16_FROM_LE (ctrl_id->edstt); + /* TODO: lpa: Log Page Attributes - NVME_CTRL_LPA_PERSETENT_EVENT: Persistent Event log */ +- if ((ctrl_id.dsto & NVME_CTRL_DSTO_ONE_DST) == NVME_CTRL_DSTO_ONE_DST) ++ if ((ctrl_id->dsto & NVME_CTRL_DSTO_ONE_DST) == NVME_CTRL_DSTO_ONE_DST) + info->features |= BD_NVME_CTRL_FEAT_SELFTEST_SINGLE; +- if ((ctrl_id.sanicap & NVME_CTRL_SANICAP_CES) == NVME_CTRL_SANICAP_CES) ++ if ((ctrl_id->sanicap & NVME_CTRL_SANICAP_CES) == NVME_CTRL_SANICAP_CES) + info->features |= BD_NVME_CTRL_FEAT_SANITIZE_CRYPTO; +- if ((ctrl_id.sanicap & NVME_CTRL_SANICAP_BES) == NVME_CTRL_SANICAP_BES) ++ if ((ctrl_id->sanicap & NVME_CTRL_SANICAP_BES) == NVME_CTRL_SANICAP_BES) + info->features |= BD_NVME_CTRL_FEAT_SANITIZE_BLOCK; +- if ((ctrl_id.sanicap & NVME_CTRL_SANICAP_OWS) == NVME_CTRL_SANICAP_OWS) ++ if ((ctrl_id->sanicap & NVME_CTRL_SANICAP_OWS) == NVME_CTRL_SANICAP_OWS) + info->features |= BD_NVME_CTRL_FEAT_SANITIZE_OVERWRITE; + /* struct nvme_id_ctrl.nn: If the &struct nvme_id_ctrl.mnan field is cleared to 0h, + * then the struct nvme_id_ctrl.nn field also indicates the maximum number of namespaces + * supported by the NVM subsystem. + */ +- info->num_namespaces = GUINT32_FROM_LE (ctrl_id.mnan) == 0 ? GUINT32_FROM_LE (ctrl_id.nn) : GUINT32_FROM_LE (ctrl_id.mnan); +- if ((ctrl_id.fna & NVME_CTRL_FNA_FMT_ALL_NAMESPACES) == NVME_CTRL_FNA_FMT_ALL_NAMESPACES) ++ info->num_namespaces = GUINT32_FROM_LE (ctrl_id->mnan) == 0 ? GUINT32_FROM_LE (ctrl_id->nn) : GUINT32_FROM_LE (ctrl_id->mnan); ++ if ((ctrl_id->fna & NVME_CTRL_FNA_FMT_ALL_NAMESPACES) == NVME_CTRL_FNA_FMT_ALL_NAMESPACES) + info->features |= BD_NVME_CTRL_FEAT_FORMAT_ALL_NS; +- if ((ctrl_id.fna & NVME_CTRL_FNA_SEC_ALL_NAMESPACES) == NVME_CTRL_FNA_SEC_ALL_NAMESPACES) ++ if ((ctrl_id->fna & NVME_CTRL_FNA_SEC_ALL_NAMESPACES) == NVME_CTRL_FNA_SEC_ALL_NAMESPACES) + info->features |= BD_NVME_CTRL_FEAT_SECURE_ERASE_ALL_NS; +- if ((ctrl_id.fna & NVME_CTRL_FNA_CRYPTO_ERASE) == NVME_CTRL_FNA_CRYPTO_ERASE) ++ if ((ctrl_id->fna & NVME_CTRL_FNA_CRYPTO_ERASE) == NVME_CTRL_FNA_CRYPTO_ERASE) + info->features |= BD_NVME_CTRL_FEAT_SECURE_ERASE_CRYPTO; + /* TODO: enum nvme_id_ctrl_oncs: NVME_CTRL_ONCS_WRITE_UNCORRECTABLE, NVME_CTRL_ONCS_WRITE_ZEROES... */ + /* TODO: nwpc: Namespace Write Protection Capabilities */ +- info->subsysnqn = g_strndup (ctrl_id.subnqn, sizeof (ctrl_id.subnqn)); ++ info->subsysnqn = g_strndup (ctrl_id->subnqn, sizeof (ctrl_id->subnqn)); + g_strstrip (info->subsysnqn); + ++ free (ctrl_id); + return info; + } + +@@ -572,10 +591,10 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e + int ret_ns_ind = -1; + int fd; + __u32 nsid = 0; +- struct nvme_id_ctrl ctrl_id = ZERO_INIT; +- struct nvme_id_ns ns_info = ZERO_INIT; +- struct nvme_id_independent_id_ns ns_info_ind = ZERO_INIT; +- uint8_t desc[NVME_IDENTIFY_DATA_SIZE] = ZERO_INIT; ++ struct nvme_id_ctrl *ctrl_id; ++ struct nvme_id_ns *ns_info; ++ struct nvme_id_independent_id_ns *ns_info_ind = NULL; ++ struct nvme_ns_id_desc *descs = NULL; + guint8 flbas; + guint i; + guint len; +@@ -597,44 +616,55 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e + } + + /* send the NVME_IDENTIFY_CNS_NS ioctl */ +- ret = nvme_identify_ns (fd, nsid, &ns_info); ++ ns_info = _nvme_alloc (sizeof (struct nvme_id_ns)); ++ g_warn_if_fail (ns_info != NULL); ++ ret = nvme_identify_ns (fd, nsid, ns_info); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Identify Namespace command error: "); + close (fd); ++ free (ns_info); + return NULL; + } + + /* send the NVME_IDENTIFY_CNS_CTRL ioctl */ +- ret_ctrl = nvme_identify_ctrl (fd, &ctrl_id); ++ ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl)); ++ g_warn_if_fail (ctrl_id != NULL); ++ ret_ctrl = nvme_identify_ctrl (fd, ctrl_id); + + /* send the NVME_IDENTIFY_CNS_NS_DESC_LIST ioctl, NVMe 1.3 */ +- if (ret_ctrl == 0 && GUINT32_FROM_LE (ctrl_id.ver) >= 0x10300) +- ret_desc = nvme_identify_ns_descs (fd, nsid, (struct nvme_ns_id_desc *) &desc); ++ if (ret_ctrl == 0 && GUINT32_FROM_LE (ctrl_id->ver) >= 0x10300) { ++ descs = _nvme_alloc (NVME_IDENTIFY_DATA_SIZE); ++ g_warn_if_fail (descs != NULL); ++ ret_desc = nvme_identify_ns_descs (fd, nsid, descs); ++ } + + /* send the NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS ioctl, NVMe 2.0 */ +- if (ret_ctrl == 0 && GUINT32_FROM_LE (ctrl_id.ver) >= 0x20000) +- ret_ns_ind = nvme_identify_independent_identify_ns (fd, nsid, &ns_info_ind); ++ if (ret_ctrl == 0 && GUINT32_FROM_LE (ctrl_id->ver) >= 0x20000) { ++ ns_info_ind = _nvme_alloc (sizeof (struct nvme_id_independent_id_ns)); ++ g_warn_if_fail (ns_info_ind != NULL); ++ ret_ns_ind = nvme_identify_independent_identify_ns (fd, nsid, ns_info_ind); ++ } + close (fd); + + info = g_new0 (BDNVMENamespaceInfo, 1); + info->nsid = nsid; +- info->nsize = GUINT64_FROM_LE (ns_info.nsze); +- info->ncap = GUINT64_FROM_LE (ns_info.ncap); +- info->nuse = GUINT64_FROM_LE (ns_info.nuse); +- if ((ns_info.nsfeat & NVME_NS_FEAT_THIN) == NVME_NS_FEAT_THIN) ++ info->nsize = GUINT64_FROM_LE (ns_info->nsze); ++ info->ncap = GUINT64_FROM_LE (ns_info->ncap); ++ info->nuse = GUINT64_FROM_LE (ns_info->nuse); ++ if ((ns_info->nsfeat & NVME_NS_FEAT_THIN) == NVME_NS_FEAT_THIN) + info->features |= BD_NVME_NS_FEAT_THIN; +- if ((ns_info.nmic & NVME_NS_NMIC_SHARED) == NVME_NS_NMIC_SHARED) ++ if ((ns_info->nmic & NVME_NS_NMIC_SHARED) == NVME_NS_NMIC_SHARED) + info->features |= BD_NVME_NS_FEAT_MULTIPATH_SHARED; +- if ((ns_info.fpi & NVME_NS_FPI_SUPPORTED) == NVME_NS_FPI_SUPPORTED) ++ if ((ns_info->fpi & NVME_NS_FPI_SUPPORTED) == NVME_NS_FPI_SUPPORTED) + info->features |= BD_NVME_NS_FEAT_FORMAT_PROGRESS; +- info->format_progress_remaining = ns_info.fpi & NVME_NS_FPI_REMAINING; +- /* TODO: what the ns_info.nvmcap really stands for? */ +- info->write_protected = (ns_info.nsattr & NVME_NS_NSATTR_WRITE_PROTECTED) == NVME_NS_NSATTR_WRITE_PROTECTED; ++ info->format_progress_remaining = ns_info->fpi & NVME_NS_FPI_REMAINING; ++ /* TODO: what the ns_info->nvmcap really stands for? */ ++ info->write_protected = (ns_info->nsattr & NVME_NS_NSATTR_WRITE_PROTECTED) == NVME_NS_NSATTR_WRITE_PROTECTED; + + if (ret_desc == 0) { + for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) { +- struct nvme_ns_id_desc *d = (void *) desc + i; ++ struct nvme_ns_id_desc *d = descs + i; + + if (!d->nidl) + break; +@@ -661,29 +691,29 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e + } + } + +- if (info->nguid == NULL && !_nvme_a_is_zero (ns_info.nguid, sizeof (ns_info.nguid))) { +- info->nguid = g_malloc0 (sizeof (ns_info.nguid) * 2 + 1); +- for (i = 0; i < sizeof (ns_info.nguid); i++) +- snprintf (info->nguid + i * 2, 3, "%02x", ns_info.nguid[i]); ++ if (info->nguid == NULL && !_nvme_a_is_zero (ns_info->nguid, sizeof (ns_info->nguid))) { ++ info->nguid = g_malloc0 (sizeof (ns_info->nguid) * 2 + 1); ++ for (i = 0; i < sizeof (ns_info->nguid); i++) ++ snprintf (info->nguid + i * 2, 3, "%02x", ns_info->nguid[i]); + } +- if (info->eui64 == NULL && !_nvme_a_is_zero (ns_info.eui64, sizeof (ns_info.eui64))) { +- info->eui64 = g_malloc0 (sizeof (ns_info.eui64) * 2 + 1); +- for (i = 0; i < sizeof (ns_info.eui64); i++) +- snprintf (info->eui64 + i * 2, 3, "%02x", ns_info.eui64[i]); ++ if (info->eui64 == NULL && !_nvme_a_is_zero (ns_info->eui64, sizeof (ns_info->eui64))) { ++ info->eui64 = g_malloc0 (sizeof (ns_info->eui64) * 2 + 1); ++ for (i = 0; i < sizeof (ns_info->eui64); i++) ++ snprintf (info->eui64 + i * 2, 3, "%02x", ns_info->eui64[i]); + } + if (ret_ns_ind == 0) { +- if ((ns_info_ind.nsfeat & 1 << 4) == 1 << 4) ++ if ((ns_info_ind->nsfeat & 1 << 4) == 1 << 4) + info->features |= BD_NVME_NS_FEAT_ROTATIONAL; + } + + /* translate the LBA Format array */ + ptr_array = g_ptr_array_new (); +- nvme_id_ns_flbas_to_lbaf_inuse (ns_info.flbas, &flbas); +- for (i = 0; i <= ns_info.nlbaf + ns_info.nulbaf; i++) { ++ nvme_id_ns_flbas_to_lbaf_inuse (ns_info->flbas, &flbas); ++ for (i = 0; i <= ns_info->nlbaf + ns_info->nulbaf; i++) { + BDNVMELBAFormat *lbaf = g_new0 (BDNVMELBAFormat, 1); +- lbaf->data_size = 1 << ns_info.lbaf[i].ds; +- lbaf->metadata_size = GUINT16_FROM_LE (ns_info.lbaf[i].ms); +- lbaf->relative_performance = ns_info.lbaf[i].rp + 1; ++ lbaf->data_size = 1 << ns_info->lbaf[i].ds; ++ lbaf->metadata_size = GUINT16_FROM_LE (ns_info->lbaf[i].ms); ++ lbaf->relative_performance = ns_info->lbaf[i].rp + 1; + g_ptr_array_add (ptr_array, lbaf); + if (i == flbas) { + info->current_lba_format.data_size = lbaf->data_size; +@@ -694,6 +724,10 @@ BDNVMENamespaceInfo *bd_nvme_get_namespace_info (const gchar *device, GError **e + g_ptr_array_add (ptr_array, NULL); /* trailing NULL element */ + info->lba_formats = (BDNVMELBAFormat **) g_ptr_array_free (ptr_array, FALSE); + ++ free (ctrl_id); ++ free (ns_info); ++ free (ns_info_ind); ++ free (descs); + return info; + } + +@@ -714,8 +748,8 @@ BDNVMESmartLog * bd_nvme_get_smart_log (const gchar *device, GError **error) { + int ret; + int ret_identify; + int fd; +- struct nvme_id_ctrl ctrl_id = ZERO_INIT; +- struct nvme_smart_log smart_log = ZERO_INIT; ++ struct nvme_id_ctrl *ctrl_id; ++ struct nvme_smart_log *smart_log; + BDNVMESmartLog *log; + guint i; + +@@ -724,59 +758,66 @@ BDNVMESmartLog * bd_nvme_get_smart_log (const gchar *device, GError **error) { + if (fd < 0) + return NULL; + +- /* send the NVME_IDENTIFY_CNS_NS + NVME_IDENTIFY_CNS_CTRL ioctl */ +- ret_identify = nvme_identify_ctrl (fd, &ctrl_id); ++ /* send the NVME_IDENTIFY_CNS_CTRL ioctl */ ++ ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl)); ++ g_warn_if_fail (ctrl_id != NULL); ++ ret_identify = nvme_identify_ctrl (fd, ctrl_id); + if (ret_identify != 0) { + _nvme_status_to_error (ret_identify, FALSE, error); + g_prefix_error (error, "NVMe Identify Controller command error: "); + close (fd); ++ free (ctrl_id); + return NULL; + } + + /* send the NVME_LOG_LID_SMART ioctl */ +- ret = nvme_get_log_smart (fd, NVME_NSID_ALL, FALSE /* rae */, &smart_log); ++ smart_log = _nvme_alloc (sizeof (struct nvme_smart_log)); ++ g_warn_if_fail (smart_log != NULL); ++ ret = nvme_get_log_smart (fd, NVME_NSID_ALL, FALSE /* rae */, smart_log); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Get Log Page - SMART / Health Information Log command error: "); + close (fd); ++ free (ctrl_id); ++ free (smart_log); + return NULL; + } + close (fd); + + log = g_new0 (BDNVMESmartLog, 1); +- if ((smart_log.critical_warning & NVME_SMART_CRIT_SPARE) == NVME_SMART_CRIT_SPARE) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_SPARE) == NVME_SMART_CRIT_SPARE) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_SPARE; +- if ((smart_log.critical_warning & NVME_SMART_CRIT_TEMPERATURE) == NVME_SMART_CRIT_TEMPERATURE) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_TEMPERATURE) == NVME_SMART_CRIT_TEMPERATURE) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_TEMPERATURE; +- if ((smart_log.critical_warning & NVME_SMART_CRIT_DEGRADED) == NVME_SMART_CRIT_DEGRADED) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_DEGRADED) == NVME_SMART_CRIT_DEGRADED) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_DEGRADED; +- if ((smart_log.critical_warning & NVME_SMART_CRIT_MEDIA) == NVME_SMART_CRIT_MEDIA) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_MEDIA) == NVME_SMART_CRIT_MEDIA) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_READONLY; +- if ((smart_log.critical_warning & NVME_SMART_CRIT_VOLATILE_MEMORY) == NVME_SMART_CRIT_VOLATILE_MEMORY) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_VOLATILE_MEMORY) == NVME_SMART_CRIT_VOLATILE_MEMORY) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_VOLATILE_MEM; +- if ((smart_log.critical_warning & NVME_SMART_CRIT_PMR_RO) == NVME_SMART_CRIT_PMR_RO) ++ if ((smart_log->critical_warning & NVME_SMART_CRIT_PMR_RO) == NVME_SMART_CRIT_PMR_RO) + log->critical_warning |= BD_NVME_SMART_CRITICAL_WARNING_PMR_READONLY; +- log->avail_spare = smart_log.avail_spare; +- log->spare_thresh = smart_log.spare_thresh; +- log->percent_used = smart_log.percent_used; +- log->total_data_read = int128_to_guint64 (smart_log.data_units_read) * 1000 * 512; +- log->total_data_written = int128_to_guint64 (smart_log.data_units_written) * 1000 * 512; +- log->ctrl_busy_time = int128_to_guint64 (smart_log.ctrl_busy_time); +- log->power_cycles = int128_to_guint64 (smart_log.power_cycles); +- log->power_on_hours = int128_to_guint64 (smart_log.power_on_hours); +- log->unsafe_shutdowns = int128_to_guint64 (smart_log.unsafe_shutdowns); +- log->media_errors = int128_to_guint64 (smart_log.media_errors); +- log->num_err_log_entries = int128_to_guint64 (smart_log.num_err_log_entries); +- +- log->temperature = (smart_log.temperature[1] << 8) | smart_log.temperature[0]; +- for (i = 0; i < G_N_ELEMENTS (smart_log.temp_sensor); i++) +- log->temp_sensors[i] = GUINT16_FROM_LE (smart_log.temp_sensor[i]); +- log->warning_temp_time = GUINT32_FROM_LE (smart_log.warning_temp_time); +- log->critical_temp_time = GUINT32_FROM_LE (smart_log.critical_comp_time); ++ log->avail_spare = smart_log->avail_spare; ++ log->spare_thresh = smart_log->spare_thresh; ++ log->percent_used = smart_log->percent_used; ++ log->total_data_read = int128_to_guint64 (smart_log->data_units_read) * 1000 * 512; ++ log->total_data_written = int128_to_guint64 (smart_log->data_units_written) * 1000 * 512; ++ log->ctrl_busy_time = int128_to_guint64 (smart_log->ctrl_busy_time); ++ log->power_cycles = int128_to_guint64 (smart_log->power_cycles); ++ log->power_on_hours = int128_to_guint64 (smart_log->power_on_hours); ++ log->unsafe_shutdowns = int128_to_guint64 (smart_log->unsafe_shutdowns); ++ log->media_errors = int128_to_guint64 (smart_log->media_errors); ++ log->num_err_log_entries = int128_to_guint64 (smart_log->num_err_log_entries); ++ ++ log->temperature = (smart_log->temperature[1] << 8) | smart_log->temperature[0]; ++ for (i = 0; i < G_N_ELEMENTS (smart_log->temp_sensor); i++) ++ log->temp_sensors[i] = GUINT16_FROM_LE (smart_log->temp_sensor[i]); ++ log->warning_temp_time = GUINT32_FROM_LE (smart_log->warning_temp_time); ++ log->critical_temp_time = GUINT32_FROM_LE (smart_log->critical_comp_time); + + if (ret_identify == 0) { +- log->wctemp = GUINT16_FROM_LE (ctrl_id.wctemp); +- log->cctemp = GUINT16_FROM_LE (ctrl_id.cctemp); ++ log->wctemp = GUINT16_FROM_LE (ctrl_id->wctemp); ++ log->cctemp = GUINT16_FROM_LE (ctrl_id->cctemp); + } + + /* FIXME: intentionally not providing Host Controlled Thermal Management attributes +@@ -784,6 +825,8 @@ BDNVMESmartLog * bd_nvme_get_smart_log (const gchar *device, GError **error) { + * Power State attributes. Subject to re-evaluation in the future. + */ + ++ free (ctrl_id); ++ free (smart_log); + return log; + } + +@@ -810,7 +853,7 @@ BDNVMEErrorLogEntry ** bd_nvme_get_error_log_entries (const gchar *device, GErro + int ret; + int fd; + guint elpe; +- struct nvme_id_ctrl ctrl_id = ZERO_INIT; ++ struct nvme_id_ctrl *ctrl_id; + struct nvme_error_log_page *err_log; + GPtrArray *ptr_array; + guint i; +@@ -821,23 +864,29 @@ BDNVMEErrorLogEntry ** bd_nvme_get_error_log_entries (const gchar *device, GErro + return NULL; + + /* find out the maximum number of error log entries as reported by the controller */ +- ret = nvme_identify_ctrl (fd, &ctrl_id); ++ ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl)); ++ g_warn_if_fail (ctrl_id != NULL); ++ ret = nvme_identify_ctrl (fd, ctrl_id); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Identify Controller command error: "); + close (fd); ++ free (ctrl_id); + return NULL; + } + ++ elpe = ctrl_id->elpe + 1; ++ free (ctrl_id); ++ + /* send the NVME_LOG_LID_ERROR ioctl */ +- elpe = ctrl_id.elpe + 1; +- err_log = g_new0 (struct nvme_error_log_page, elpe); ++ err_log = _nvme_alloc (sizeof (struct nvme_error_log_page) * elpe); ++ g_warn_if_fail (err_log != NULL); + ret = nvme_get_log_error (fd, elpe, FALSE /* rae */, err_log); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Get Log Page - Error Information Log Entry command error: "); +- g_free (err_log); + close (fd); ++ free (err_log); + return NULL; + } + close (fd); +@@ -863,7 +912,7 @@ BDNVMEErrorLogEntry ** bd_nvme_get_error_log_entries (const gchar *device, GErro + } + } + g_ptr_array_add (ptr_array, NULL); /* trailing NULL element */ +- g_free (err_log); ++ free (err_log); + + return (BDNVMEErrorLogEntry **) g_ptr_array_free (ptr_array, FALSE); + } +@@ -885,7 +934,7 @@ BDNVMEErrorLogEntry ** bd_nvme_get_error_log_entries (const gchar *device, GErro + BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **error) { + int ret; + int fd; +- struct nvme_self_test_log self_test_log = ZERO_INIT; ++ struct nvme_self_test_log *self_test_log; + BDNVMESelfTestLog *log; + GPtrArray *ptr_array; + guint i; +@@ -896,17 +945,20 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + return NULL; + + /* send the NVME_LOG_LID_DEVICE_SELF_TEST ioctl */ +- ret = nvme_get_log_device_self_test (fd, &self_test_log); ++ self_test_log = _nvme_alloc (sizeof (struct nvme_self_test_log)); ++ g_warn_if_fail (self_test_log != NULL); ++ ret = nvme_get_log_device_self_test (fd, self_test_log); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Get Log Page - Device Self-test Log command error: "); + close (fd); ++ free (self_test_log); + return NULL; + } + close (fd); + + log = g_new0 (BDNVMESelfTestLog, 1); +- switch (self_test_log.current_operation & NVME_ST_CURR_OP_MASK) { ++ switch (self_test_log->current_operation & NVME_ST_CURR_OP_MASK) { + case NVME_ST_CURR_OP_NOT_RUNNING: + log->current_operation = BD_NVME_SELF_TEST_ACTION_NOT_RUNNING; + break; +@@ -921,8 +973,8 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + default: + log->current_operation = BD_NVME_SELF_TEST_ACTION_VENDOR_SPECIFIC; + } +- if ((self_test_log.current_operation & NVME_ST_CURR_OP_MASK) > 0) +- log->current_operation_completion = self_test_log.completion & NVME_ST_CURR_OP_CMPL_MASK; ++ if ((self_test_log->current_operation & NVME_ST_CURR_OP_MASK) > 0) ++ log->current_operation_completion = self_test_log->completion & NVME_ST_CURR_OP_CMPL_MASK; + + ptr_array = g_ptr_array_new (); + for (i = 0; i < NVME_LOG_ST_MAX_RESULTS; i++) { +@@ -930,8 +982,8 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + guint8 dsts; + guint8 code; + +- dsts = self_test_log.result[i].dsts & NVME_ST_RESULT_MASK; +- code = self_test_log.result[i].dsts >> NVME_ST_CODE_SHIFT; ++ dsts = self_test_log->result[i].dsts & NVME_ST_RESULT_MASK; ++ code = self_test_log->result[i].dsts >> NVME_ST_CODE_SHIFT; + if (dsts == NVME_ST_RESULT_NOT_USED) + continue; + +@@ -987,21 +1039,22 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + g_warning ("Unhandled self-test log entry action code: %d", code); + entry->action = BD_NVME_SELF_TEST_ACTION_VENDOR_SPECIFIC; + } +- entry->segment = self_test_log.result[i].seg; +- entry->power_on_hours = GUINT64_FROM_LE (self_test_log.result[i].poh); +- if (self_test_log.result[i].vdi & NVME_ST_VALID_DIAG_INFO_NSID) +- entry->nsid = GUINT32_FROM_LE (self_test_log.result[i].nsid); +- if (self_test_log.result[i].vdi & NVME_ST_VALID_DIAG_INFO_FLBA) +- entry->failing_lba = GUINT64_FROM_LE (self_test_log.result[i].flba); +- if ((self_test_log.result[i].vdi & NVME_ST_VALID_DIAG_INFO_SC) && +- (self_test_log.result[i].vdi & NVME_ST_VALID_DIAG_INFO_SCT)) +- _nvme_status_to_error ((self_test_log.result[i].sct & 7) << 8 | self_test_log.result[i].sc, ++ entry->segment = self_test_log->result[i].seg; ++ entry->power_on_hours = GUINT64_FROM_LE (self_test_log->result[i].poh); ++ if (self_test_log->result[i].vdi & NVME_ST_VALID_DIAG_INFO_NSID) ++ entry->nsid = GUINT32_FROM_LE (self_test_log->result[i].nsid); ++ if (self_test_log->result[i].vdi & NVME_ST_VALID_DIAG_INFO_FLBA) ++ entry->failing_lba = GUINT64_FROM_LE (self_test_log->result[i].flba); ++ if ((self_test_log->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SC) && ++ (self_test_log->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SCT)) ++ _nvme_status_to_error ((self_test_log->result[i].sct & 7) << 8 | self_test_log->result[i].sc, + FALSE, &entry->status_code_error); + + g_ptr_array_add (ptr_array, entry); + } + g_ptr_array_add (ptr_array, NULL); + log->entries = (BDNVMESelfTestLogEntry **) g_ptr_array_free (ptr_array, FALSE); ++ free (self_test_log); + + return log; + } +@@ -1026,7 +1079,6 @@ BDNVMESelfTestLog * bd_nvme_get_self_test_log (const gchar *device, GError **err + BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **error) { + int ret; + int fd; +- char buf[65536] = ZERO_INIT; + struct nvme_sanitize_log_page *sanitize_log; + BDNVMESanitizeLog *log; + __u16 sstat; +@@ -1037,20 +1089,18 @@ BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **erro + return NULL; + + /* send the NVME_LOG_LID_SANITIZE ioctl */ +- ret = nvme_get_log_sanitize (fd, FALSE /* rae */, (struct nvme_sanitize_log_page *) &buf); ++ sanitize_log = _nvme_alloc (sizeof (struct nvme_sanitize_log_page)); ++ g_warn_if_fail (sanitize_log != NULL); ++ ret = nvme_get_log_sanitize (fd, FALSE /* rae */, sanitize_log); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Get Log Page - Sanitize Status Log command error: "); + close (fd); ++ free (sanitize_log); + return NULL; + } + close (fd); + +- /* need to use interim buffer that is large enough for broken drives +- * returning more data than expected +- */ +- sanitize_log = (struct nvme_sanitize_log_page *) &buf; +- + log = g_new0 (BDNVMESanitizeLog, 1); + log->sanitize_progress = 0; + sstat = GUINT16_FROM_LE (sanitize_log->sstat); +@@ -1085,5 +1135,6 @@ BDNVMESanitizeLog * bd_nvme_get_sanitize_log (const gchar *device, GError **erro + log->time_for_block_erase_nd = (GUINT32_FROM_LE (sanitize_log->etbend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etbend); + log->time_for_crypto_erase_nd = (GUINT32_FROM_LE (sanitize_log->etcend) == 0xffffffff) ? -1 : (gint64) GUINT32_FROM_LE (sanitize_log->etcend); + ++ free (sanitize_log); + return log; + } +diff --git a/src/plugins/nvme/nvme-op.c b/src/plugins/nvme/nvme-op.c +index c9e92697c..dbef4f3a2 100644 +--- a/src/plugins/nvme/nvme-op.c ++++ b/src/plugins/nvme/nvme-op.c +@@ -116,30 +116,37 @@ gboolean bd_nvme_device_self_test (const gchar *device, BDNVMESelfTestAction act + /* returns 0xff in case of error (the NVMe standard defines total of 16 flba records) */ + static __u8 find_lbaf_for_size (int fd, __u32 nsid, guint16 lba_data_size, guint16 metadata_size, GError **error) { + int ret; +- struct nvme_id_ns ns_info = ZERO_INIT; ++ struct nvme_id_ns *ns_info; + __u8 flbas = 0; + guint i; + + /* TODO: find first attached namespace instead of hardcoding NSID = 1 */ +- ret = nvme_identify_ns (fd, nsid == 0xffffffff ? 1 : nsid, &ns_info); ++ ns_info = _nvme_alloc (sizeof (struct nvme_id_ns)); ++ g_warn_if_fail (ns_info != NULL); ++ ret = nvme_identify_ns (fd, nsid == 0xffffffff ? 1 : nsid, ns_info); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Identify Namespace command error: "); ++ free (ns_info); + return 0xff; + } + + /* return currently used lbaf */ + if (lba_data_size == 0) { +- nvme_id_ns_flbas_to_lbaf_inuse (ns_info.flbas, &flbas); +- return flbas; ++ nvme_id_ns_flbas_to_lbaf_inuse (ns_info->flbas, &flbas); ++ free (ns_info); ++ return flbas; + } + +- for (i = 0; i <= ns_info.nlbaf + ns_info.nulbaf; i++) +- if (1UL << ns_info.lbaf[i].ds == lba_data_size && GUINT16_FROM_LE (ns_info.lbaf[i].ms) == metadata_size) ++ for (i = 0; i <= ns_info->nlbaf + ns_info->nulbaf; i++) ++ if (1UL << ns_info->lbaf[i].ds == lba_data_size && GUINT16_FROM_LE (ns_info->lbaf[i].ms) == metadata_size) { ++ free (ns_info); + return i; ++ } + + g_set_error_literal (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT, + "Couldn't match desired LBA data block size in a device supported LBA format data sizes"); ++ free (ns_info); + return 0xff; + } + +@@ -176,7 +183,7 @@ static __u8 find_lbaf_for_size (int fd, __u32 nsid, guint16 lba_data_size, guint + gboolean bd_nvme_format (const gchar *device, guint16 lba_data_size, guint16 metadata_size, BDNVMEFormatSecureErase secure_erase, GError **error) { + int ret; + gboolean ctrl_device = FALSE; +- struct nvme_id_ctrl ctrl_id = ZERO_INIT; ++ struct nvme_id_ctrl *ctrl_id; + struct nvme_format_nvm_args args = { + .args_size = sizeof(args), + .result = NULL, +@@ -207,11 +214,14 @@ gboolean bd_nvme_format (const gchar *device, guint16 lba_data_size, guint16 met + + /* check the FNA controller bit when formatting a single namespace */ + if (! ctrl_device) { +- ret = nvme_identify_ctrl (args.fd, &ctrl_id); ++ ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl)); ++ g_warn_if_fail (ctrl_id != NULL); ++ ret = nvme_identify_ctrl (args.fd, ctrl_id); + if (ret != 0) { + _nvme_status_to_error (ret, FALSE, error); + g_prefix_error (error, "NVMe Identify Controller command error: "); + close (args.fd); ++ free (ctrl_id); + return FALSE; + } + /* from nvme-cli: +@@ -219,14 +229,16 @@ gboolean bd_nvme_format (const gchar *device, guint16 lba_data_size, guint16 met + * attributes and a format (excluding secure erase) of any namespace results in a + * format of all namespaces. + */ +- if ((ctrl_id.fna & NVME_CTRL_FNA_FMT_ALL_NAMESPACES) == NVME_CTRL_FNA_FMT_ALL_NAMESPACES) { ++ if ((ctrl_id->fna & NVME_CTRL_FNA_FMT_ALL_NAMESPACES) == NVME_CTRL_FNA_FMT_ALL_NAMESPACES) { + /* tell user that it would format other namespaces and that bd_nvme_format() + * should be called on a controller device instead */ + g_set_error_literal (error, BD_NVME_ERROR, BD_NVME_ERROR_WOULD_FORMAT_ALL_NS, + "The NVMe controller indicates it would format all namespaces."); + close (args.fd); ++ free (ctrl_id); + return FALSE; + } ++ free (ctrl_id); + } + + /* find out the desired LBA data format index */ +diff --git a/src/plugins/nvme/nvme-private.h b/src/plugins/nvme/nvme-private.h +index 8b6d13253..0d15fbb64 100644 +--- a/src/plugins/nvme/nvme-private.h ++++ b/src/plugins/nvme/nvme-private.h +@@ -24,5 +24,7 @@ void _nvme_fabrics_errno_to_gerror (int result, int _errno, GError **error); + /* nvme-info.c */ + G_GNUC_INTERNAL + gint _open_dev (const gchar *device, GError **error); ++G_GNUC_INTERNAL ++void *_nvme_alloc (size_t len); + + #endif /* BD_NVME_PRIVATE */ diff --git a/SOURCES/0012-lvm-Add-support-for-starting-and-stopping-VG-locking.patch b/SOURCES/0012-lvm-Add-support-for-starting-and-stopping-VG-locking.patch new file mode 100644 index 0000000..601528d --- /dev/null +++ b/SOURCES/0012-lvm-Add-support-for-starting-and-stopping-VG-locking.patch @@ -0,0 +1,299 @@ +From f72ba6aded6093d34d5e8a1666a844ec2b0ee5eb Mon Sep 17 00:00:00 2001 +From: Vojtech Trefny +Date: Tue, 18 Apr 2023 12:05:35 +0200 +Subject: [PATCH] lvm: Add support for starting and stopping VG locking + +--- + docs/libblockdev-sections.txt | 2 ++ + src/lib/plugin_apis/lvm.api | 27 +++++++++++++++++++ + src/plugins/lvm-dbus.c | 49 ++++++++++++++++++++++++++++++++++- + src/plugins/lvm.c | 41 +++++++++++++++++++++++++++++ + src/plugins/lvm.h | 3 +++ + tests/lvm_dbus_tests.py | 33 +++++++++++++++++++++++ + tests/lvm_test.py | 32 +++++++++++++++++++++++ + 7 files changed, 186 insertions(+), 1 deletion(-) + +diff --git a/docs/libblockdev-sections.txt b/docs/libblockdev-sections.txt +index 540e2b96..08ea309c 100644 +--- a/docs/libblockdev-sections.txt ++++ b/docs/libblockdev-sections.txt +@@ -286,6 +286,8 @@ bd_lvm_vgactivate + bd_lvm_vgdeactivate + bd_lvm_vgextend + bd_lvm_vgreduce ++bd_lvm_vglock_start ++bd_lvm_vglock_stop + bd_lvm_vginfo + bd_lvm_vgs + bd_lvm_lvorigin +diff --git a/src/lib/plugin_apis/lvm.api b/src/lib/plugin_apis/lvm.api +index 640eee49..1343fbdb 100644 +--- a/src/lib/plugin_apis/lvm.api ++++ b/src/lib/plugin_apis/lvm.api +@@ -603,6 +603,7 @@ typedef enum { + BD_LVM_TECH_GLOB_CONF, + BD_LVM_TECH_VDO, + BD_LVM_TECH_DEVICES, ++ BD_LVM_TECH_SHARED, + } BDLVMTech; + + typedef enum { +@@ -943,6 +944,32 @@ gboolean bd_lvm_vgextend (const gchar *vg_name, const gchar *device, const BDExt + */ + gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error); + ++/** ++ * bd_lvm_vglock_start: ++ * @vg_name: a shared VG to start the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully started for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error); ++ ++/** ++ * bd_lvm_vglock_stop: ++ * @vg_name: a shared VG to stop the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully stopped for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error); ++ + /** + * bd_lvm_vginfo: + * @vg_name: a VG to get information about +diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c +index 46e09833..a129d884 100644 +--- a/src/plugins/lvm-dbus.c ++++ b/src/plugins/lvm-dbus.c +@@ -1872,10 +1872,57 @@ gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExt + return ((*error) == NULL); + } + ++gboolean _vglock_start_stop (const gchar *vg_name, gboolean start, const BDExtraArg **extra, GError **error) { ++ GVariantBuilder builder; ++ GVariant *params = NULL; ++ ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_DICTIONARY); ++ if (start) ++ g_variant_builder_add (&builder, "{sv}", "--lockstart", g_variant_new ("s", "")); ++ else ++ g_variant_builder_add (&builder, "{sv}", "--lockstop", g_variant_new ("s", "")); ++ params = g_variant_builder_end (&builder); ++ g_variant_builder_clear (&builder); ++ ++ call_lvm_obj_method_sync (vg_name, VG_INTF, "Change", NULL, params, extra, TRUE, error); ++ ++ return ((*error) == NULL); ++} ++ ++/** ++ * bd_lvm_vglock_start: ++ * @vg_name: a shared VG to start the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully started for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error) { ++ return _vglock_start_stop (vg_name, TRUE, extra, error); ++} ++ ++/** ++ * bd_lvm_vglock_stop: ++ * @vg_name: a shared VG to stop the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully stopped for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_BASIC-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error) { ++ return _vglock_start_stop (vg_name, FALSE, extra, error); ++} ++ + /** + * bd_lvm_vginfo: + * @vg_name: a VG to get information about +- * @error: (out): place to store error (if any) ++ * @error: (out) (optional): place to store error (if any) + * + * Returns: (transfer full): information about the @vg_name VG or %NULL in case + * of error (the @error) gets populated in those cases) +diff --git a/src/plugins/lvm.c b/src/plugins/lvm.c +index 0db3bf4a..b0a71224 100644 +--- a/src/plugins/lvm.c ++++ b/src/plugins/lvm.c +@@ -1341,6 +1341,47 @@ gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExt + return call_lvm_and_report_error (args, extra, TRUE, error); + } + ++gboolean _vglock_start_stop (const gchar *vg_name, gboolean start, const BDExtraArg **extra, GError **error) { ++ const gchar *args[4] = {"vgchange", NULL, vg_name, NULL}; ++ ++ if (start) ++ args[1] = "--lockstart"; ++ else ++ args[1] = "--lockstop"; ++ ++ return call_lvm_and_report_error (args, extra, TRUE, error); ++} ++ ++/** ++ * bd_lvm_vglock_start: ++ * @vg_name: a shared VG to start the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully started for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error) { ++ return _vglock_start_stop (vg_name, TRUE, extra, error); ++} ++ ++/** ++ * bd_lvm_vglock_stop: ++ * @vg_name: a shared VG to stop the lockspace in lvmlockd ++ * @extra: (nullable) (array zero-terminated=1): extra options for the vgchange command ++ * (just passed to LVM as is) ++ * @error: (out): place to store error (if any) ++ * ++ * Returns: whether the lock was successfully stopped for @vg_name or not ++ * ++ * Tech category: %BD_LVM_TECH_SHARED-%BD_LVM_TECH_MODE_MODIFY ++ */ ++gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error) { ++ return _vglock_start_stop (vg_name, FALSE, extra, error); ++} ++ + /** + * bd_lvm_vginfo: + * @vg_name: a VG to get information about +diff --git a/src/plugins/lvm.h b/src/plugins/lvm.h +index c85c043d..2e47b06f 100644 +--- a/src/plugins/lvm.h ++++ b/src/plugins/lvm.h +@@ -218,6 +218,7 @@ typedef enum { + BD_LVM_TECH_GLOB_CONF, + BD_LVM_TECH_VDO, + BD_LVM_TECH_DEVICES, ++ BD_LVM_TECH_SHARED, + } BDLVMTech; + + typedef enum { +@@ -268,6 +269,8 @@ gboolean bd_lvm_vgactivate (const gchar *vg_name, const BDExtraArg **extra, GErr + gboolean bd_lvm_vgdeactivate (const gchar *vg_name, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_vgextend (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error); + gboolean bd_lvm_vgreduce (const gchar *vg_name, const gchar *device, const BDExtraArg **extra, GError **error); ++gboolean bd_lvm_vglock_start (const gchar *vg_name, const BDExtraArg **extra, GError **error); ++gboolean bd_lvm_vglock_stop (const gchar *vg_name, const BDExtraArg **extra, GError **error); + BDLVMVGdata* bd_lvm_vginfo (const gchar *vg_name, GError **error); + BDLVMVGdata** bd_lvm_vgs (GError **error); + +diff --git a/tests/lvm_dbus_tests.py b/tests/lvm_dbus_tests.py +index a821636e..bc8b3052 100644 +--- a/tests/lvm_dbus_tests.py ++++ b/tests/lvm_dbus_tests.py +@@ -655,6 +655,39 @@ class LvmTestVGs(LvmPVVGTestCase): + succ = BlockDev.lvm_pvremove(self.loop_dev, None) + self.assertTrue(succ) + ++@unittest.skipUnless(lvm_dbus_running, "LVM DBus not running") ++class LvmTestVGLocking(LvmPVVGTestCase): ++ @tag_test(TestTags.UNSAFE) ++ def test_vglock_stop_start(self): ++ """Verify that it is possible to start and stop locking on a VG""" ++ ++ # better not do anything if lvmlockd is running, shared VGs have ++ # a tendency to wreak havoc on your system if you look at them wrong ++ ret, _out, _err = run_command("systemctl is-active lvmlockd") ++ if ret == 0: ++ self.skipTest("lvmlockd is running, skipping") ++ ++ _ret, out, _err = run_command("lvm config 'global/use_lvmlockd'") ++ if "use_lvmlockd=0" not in out: ++ self.skipTest("lvmlockd is enabled, skipping") ++ ++ succ = BlockDev.lvm_pvcreate(self.loop_dev, 0, 0, None) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_pvcreate(self.loop_dev2, 0, 0, None) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_vgcreate("testVG", [self.loop_dev, self.loop_dev2], 0, None) ++ self.assertTrue(succ) ++ ++ # this actually doesn't "test" anything, the commands will just say lvmlockd is not ++ # running and return 0, but that's good enough for us ++ succ = BlockDev.lvm_vglock_start("testVG") ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_vglock_stop("testVG") ++ self.assertTrue(succ) ++ + @unittest.skipUnless(lvm_dbus_running, "LVM DBus not running") + class LvmPVVGLVTestCase(LvmPVVGTestCase): + def _clean_up(self): +diff --git a/tests/lvm_test.py b/tests/lvm_test.py +index 63f43afb..d517001b 100644 +--- a/tests/lvm_test.py ++++ b/tests/lvm_test.py +@@ -632,6 +632,38 @@ class LvmTestVGs(LvmPVVGTestCase): + succ = BlockDev.lvm_pvremove(self.loop_dev, None) + self.assertTrue(succ) + ++class LvmTestVGLocking(LvmPVVGTestCase): ++ @tag_test(TestTags.UNSAFE) ++ def test_vglock_stop_start(self): ++ """Verify that it is possible to start and stop locking on a VG""" ++ ++ # better not do anything if lvmlockd is running, shared VGs have ++ # a tendency to wreak havoc on your system if you look at them wrong ++ ret, _out, _err = run_command("systemctl is-active lvmlockd") ++ if ret == 0: ++ self.skipTest("lvmlockd is running, skipping") ++ ++ _ret, out, _err = run_command("lvm config 'global/use_lvmlockd'") ++ if "use_lvmlockd=0" not in out: ++ self.skipTest("lvmlockd is enabled, skipping") ++ ++ succ = BlockDev.lvm_pvcreate(self.loop_dev, 0, 0, None) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_pvcreate(self.loop_dev2, 0, 0, None) ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_vgcreate("testVG", [self.loop_dev, self.loop_dev2], 0, None) ++ self.assertTrue(succ) ++ ++ # this actually doesn't "test" anything, the commands will just say lvmlockd is not ++ # running and return 0, but that's good enough for us ++ succ = BlockDev.lvm_vglock_start("testVG") ++ self.assertTrue(succ) ++ ++ succ = BlockDev.lvm_vglock_stop("testVG") ++ self.assertTrue(succ) ++ + class LvmPVVGLVTestCase(LvmPVVGTestCase): + def _clean_up(self): + try: +-- +2.41.0 + diff --git a/SPECS/libblockdev.spec b/SPECS/libblockdev.spec index 9d01c1e..c13da05 100644 --- a/SPECS/libblockdev.spec +++ b/SPECS/libblockdev.spec @@ -129,7 +129,7 @@ Name: libblockdev Version: 2.28 -Release: 4%{?dist} +Release: 10%{?dist} Summary: A library for low-level manipulation with block devices License: LGPLv2+ URL: https://github.com/storaged-project/libblockdev @@ -140,6 +140,13 @@ Patch2: 0002-Add-support-for-creating-and-activating-integrity-de.patch Patch3: 0003-NVMe-plugin-backport.patch Patch4: 0004-Fix-double-free-in-write_escrow_data_file.patch Patch5: 0005-nvme-Fix-namespace-identifiers.patch +Patch6: 0006-Allow-resizing-of-inactive-LVs-with-latest-LVM.patch +Patch7: 0007-tests-Fix-test_swapon_pagesize-on-systems-with-64k-p.patch +Patch8: 0008-part-Fix-segfault-when-adding-a-partition-too-big-fo.patch +Patch9: 0009-Fix-issues-in-tests-when-running-in-FIPS-mode.patch +Patch10: 0010-lvm-Add-a-function-to-activate-LVs-in-shared-mode.patch +Patch11: 0011-nvme_libblockdev-3.0.4_backport.patch +Patch12: 0012-lvm-Add-support-for-starting-and-stopping-VG-locking.patch BuildRequires: make BuildRequires: glib2-devel @@ -719,13 +726,7 @@ A meta-package that pulls all the libblockdev plugins as dependencies. %prep -%setup -q -n %{name}-%{version} -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 +%autosetup -n %{name}-%{version} -p1 %build autoreconf -ivf @@ -1044,6 +1045,36 @@ find %{buildroot} -type f -name "*.la" | xargs %{__rm} %files plugins-all %changelog +* Wed Nov 08 2023 Vojtech Trefny - 2.28-10 +- lvm: Add support for starting and stopping VG locking + Resolves: RHEL-15921 + +* Wed Nov 01 2023 Tomas Bzatek - 2.28-9 +- nvme: HostID fixes for TP4126 + Resolves: RHEL-1375 +- nvme: Stack smashing fixes + Resolves: RHEL-13127 + Resolves: RHEL-8037 + +* Tue Oct 17 2023 Vojtech Trefny - 2.28-8 +- lvm: Add a function to activate LVs in shared mode + Resolves: RHEL-14018 + +* Wed May 24 2023 Vojtech Trefny - 2.28-7 +- Fix issues in tests when running in FIPS mode + Resolves: rhbz#2188749 + Resolves: rhbz#2188603 + +* Tue May 16 2023 Vojtech Trefny - 2.28-6 +- Fix segfault when adding a partition too big for MSDOS + Resolves: rhbz#2185564 + +* Mon Apr 03 2023 Vojtech Trefny - 2.28-5 +- Allow resizing of inactive LVs with latest LVM + Resolves: rhbz#2161181 +- Fix test_swapon_pagesize on systems with 64k pages + Resolves: rhbz#2168220 + * Thu Jan 05 2023 Vojtech Trefny - 2.28-4 - nvme: Fix namespace identifiers Resolves: rhbz#2151535