From 5e8429d004445c6f6e6f16cab67cf14cb4d32a65 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 512820c2..7377dd17 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 54c47a93..14f2620a 100644 --- a/src/lib/plugin_apis/lvm.api +++ b/src/lib/plugin_apis/lvm.api @@ -601,6 +601,7 @@ typedef enum { BD_LVM_TECH_CACHE_CALCS, BD_LVM_TECH_GLOB_CONF, BD_LVM_TECH_VDO, + BD_LVM_TECH_SHARED, } BDLVMTech; typedef enum { @@ -941,6 +942,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 e1f946fe..ad44dfb3 100644 --- a/src/plugins/lvm-dbus.c +++ b/src/plugins/lvm-dbus.c @@ -1848,10 +1848,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 8bb3ae24..1aaf6747 100644 --- a/src/plugins/lvm.c +++ b/src/plugins/lvm.c @@ -1316,6 +1316,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 244663a4..da14cc1a 100644 --- a/src/plugins/lvm.h +++ b/src/plugins/lvm.h @@ -216,6 +216,7 @@ typedef enum { BD_LVM_TECH_CACHE_CALCS, BD_LVM_TECH_GLOB_CONF, BD_LVM_TECH_VDO, + BD_LVM_TECH_SHARED, } BDLVMTech; typedef enum { @@ -266,6 +267,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 862a44cf..2a92c7c1 100644 --- a/tests/lvm_dbus_tests.py +++ b/tests/lvm_dbus_tests.py @@ -612,6 +612,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 96f1670d..3ab11f04 100644 --- a/tests/lvm_test.py +++ b/tests/lvm_test.py @@ -585,6 +585,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