From 1536c3fcc0e887a2116ff035bda187a4eab4ef47 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Wed, 17 May 2023 15:49:14 +0200 Subject: [PATCH] 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 | 30 +++++++++++++++++++++++++++--- tests/lvm_dbus_tests.py | 4 ++++ tests/lvm_test.py | 4 ++++ tests/skip.yml | 6 ++++++ 5 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/plugins/lvm-dbus.c b/src/plugins/lvm-dbus.c index 51572c9a..1408236a 100644 --- a/src/plugins/lvm-dbus.c +++ b/src/plugins/lvm-dbus.c @@ -63,6 +63,8 @@ static gchar *global_config_str = NULL; #define METHOD_CALL_TIMEOUT 5000 #define PROGRESS_WAIT 500 * 1000 /* microseconds */ +#define LVM_VERSION_FSRESIZE "2.03.19" + #define UNUSED __attribute__((unused)) static GDBusConnection *bus = NULL; @@ -2102,6 +2104,15 @@ 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; + 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)); @@ -2111,7 +2122,22 @@ 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); + 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 ("lvm", LVM_VERSION_FSRESIZE, + "version", "LVM version:\\s+([\\d\\.]+)", &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); + } + 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 26af0d19..a07db65b 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; @@ -1583,15 +1585,37 @@ 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"; + } + 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 3fb7946a..b9493642 100644 --- a/tests/lvm_dbus_tests.py +++ b/tests/lvm_dbus_tests.py @@ -901,6 +901,10 @@ class LvmTestLVresize(LvmPVVGLVTestCase): succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) self.assertTrue(succ) + # try to shrink when deactivated + succ = BlockDev.lvm_lvresize("testVG", "testLV", 400 * 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 7be8f1ab..8baae513 100644 --- a/tests/lvm_test.py +++ b/tests/lvm_test.py @@ -830,6 +830,10 @@ class LvmTestLVresize(LvmPVVGLVTestCase): succ = BlockDev.lvm_lvdeactivate("testVG", "testLV", None) self.assertTrue(succ) + # try to shrink when deactivated + succ = BlockDev.lvm_lvresize("testVG", "testLV", 400 * 1024**2, None) + self.assertTrue(succ) + class LvmTestLVrename(LvmPVVGLVTestCase): def test_lvrename(self): """Verify that it's possible to rename an LV""" diff --git a/tests/skip.yml b/tests/skip.yml index b06d05da..543d1396 100644 --- a/tests/skip.yml +++ b/tests/skip.yml @@ -143,3 +143,9 @@ - distro: "centos" version: "9" reason: "Creating RAID 1 LV on CentOS/RHEL 9 causes a system deadlock" + +- test: (lvm_test|lvm_dbus_tests).LvmTestLVresize.test_lvresize + skip_on: + - distro: "centos" + version: "9" + reason: "LVM >= 2.03.19 is not yet available breaking our check for LVM resize on CentOS 9 Stream" -- 2.40.1