Blame SOURCES/0047-vdo-support-vdosettings.patch

4d51e5
From 9c6954bc61b22ca03df8897d88eb9618e65fc3c6 Mon Sep 17 00:00:00 2001
4d51e5
From: Zdenek Kabelac <zkabelac@redhat.com>
4d51e5
Date: Wed, 13 Apr 2022 15:09:08 +0200
4d51e5
Subject: [PATCH 47/54] vdo: support --vdosettings
4d51e5
4d51e5
Allow to use --vdosettings with lvcreate,lvconvert,lvchange.
4d51e5
Support settings currenly only configurable via lvm.conf.
4d51e5
With lvchange we require inactivate LV for changes to be applied.
4d51e5
4d51e5
Settings block_map_era_length has supported alias block_map_period.
4d51e5
---
4d51e5
 device_mapper/vdo/target.h  |   6 +-
4d51e5
 man/lvmvdo.7_main           |  39 ++++++--
4d51e5
 test/shell/lvchange-vdo.sh  |   8 ++
4d51e5
 test/shell/lvconvert-vdo.sh |   8 +-
4d51e5
 test/shell/lvcreate-vdo.sh  |   6 +-
4d51e5
 tools/args.h                |   9 ++
4d51e5
 tools/command-lines.in      |   6 +-
4d51e5
 tools/lvchange.c            |  43 ++++++++-
4d51e5
 tools/lvconvert.c           |   9 +-
4d51e5
 tools/lvcreate.c            |  34 ++++---
4d51e5
 tools/toollib.c             | 177 ++++++++++++++++++++++++++++++++++++
4d51e5
 tools/toollib.h             |   6 ++
4d51e5
 12 files changed, 312 insertions(+), 39 deletions(-)
4d51e5
4d51e5
diff --git a/device_mapper/vdo/target.h b/device_mapper/vdo/target.h
4d51e5
index 51dde3f4d..60c5bff56 100644
4d51e5
--- a/device_mapper/vdo/target.h
4d51e5
+++ b/device_mapper/vdo/target.h
4d51e5
@@ -77,8 +77,10 @@ enum dm_vdo_write_policy {
4d51e5
 struct dm_vdo_target_params {
4d51e5
 	uint32_t minimum_io_size;       // in sectors
4d51e5
 	uint32_t block_map_cache_size_mb;
4d51e5
-	uint32_t block_map_era_length;	// format period
4d51e5
-
4d51e5
+	union {
4d51e5
+		uint32_t block_map_era_length;	// format period
4d51e5
+		uint32_t block_map_period;      // supported alias
4d51e5
+	};
4d51e5
 	uint32_t check_point_frequency;
4d51e5
 	uint32_t index_memory_size_mb;  // format
4d51e5
 
4d51e5
diff --git a/man/lvmvdo.7_main b/man/lvmvdo.7_main
4d51e5
index 3b77173c4..14bd640b5 100644
4d51e5
--- a/man/lvmvdo.7_main
4d51e5
+++ b/man/lvmvdo.7_main
4d51e5
@@ -132,6 +132,19 @@ that can keep 100% incompressible data there.
4d51e5
 # lvconvert --type vdo-pool -n vdo0 -V10G vg/ExistingLV
4d51e5
 .fi
4d51e5
 .
4d51e5
+.SS \n+[step]. Change the compression and deduplication of a VDOPoolLV
4d51e5
+.
4d51e5
+Disable or enable the compression and deduplication for VDOPoolLV
4d51e5
+(the volume that maintains all VDO LV(s) associated with it).
4d51e5
+.P
4d51e5
+.B lvchange --compression y|n --deduplication y|n VG/VDOPoolLV
4d51e5
+.P
4d51e5
+.I Example
4d51e5
+.nf
4d51e5
+# lvchange --compression n  vg/vdopool0
4d51e5
+# lvchange --deduplication y vg/vdopool1
4d51e5
+.fi
4d51e5
+.
4d51e5
 .SS \n+[step]. Change the default settings used for creating a VDOPoolLV
4d51e5
 .
4d51e5
 VDO allows to set a large variety of options. Lots of these settings
4d51e5
@@ -173,17 +186,27 @@ EOF
4d51e5
 # lvcreate --vdo -L10G --config 'allocation/vdo_cpu_threads=4' vg/vdopool1
4d51e5
 .fi
4d51e5
 .
4d51e5
-.SS \n+[step]. Change the compression and deduplication of a VDOPoolLV
4d51e5
-.
4d51e5
-Disable or enable the compression and deduplication for VDOPoolLV
4d51e5
-(the volume that maintains all VDO LV(s) associated with it).
4d51e5
-.P
4d51e5
-.B lvchange --compression y|n --deduplication y|n VG/VDOPoolLV
4d51e5
+.SS \n+[step]. Set or change VDO settings with option --vdosettings
4d51e5
+.
4d51e5
+Use the form 'option=value' or 'option1=value option2=value',
4d51e5
+or repeat --vdosettings for each option being set.
4d51e5
+Options are listed in the Example section above, for the full description see
4d51e5
+.BR lvm.conf (5).
4d51e5
+Options can omit 'vdo_' and 'vdo_use_' prefixes and all its underscores.
4d51e5
+So i.e.  vdo_use_metadata_hints=1  and  metadatahints=1 are equivalent.
4d51e5
+To change the option for an already existing VDOPoolLV use
4d51e5
+.BR lvchange (8)
4d51e5
+command. However not all option can be changed.
4d51e5
+Only compression and deduplication options can be also changed for an active VDO LV.
4d51e5
+Lowest priority options are specified with configuration file,
4d51e5
+then with --vdosettings and highest are expliction option --compression
4d51e5
+and --deduplication.
4d51e5
 .P
4d51e5
 .I Example
4d51e5
+.P
4d51e5
 .nf
4d51e5
-# lvchange --compression n  vg/vdopool0
4d51e5
-# lvchange --deduplication y vg/vdopool1
4d51e5
+# lvcreate --vdo -L10G --vdosettings 'ack_threads=1 hash_zone_threads=2' vg/vdopool0
4d51e5
+# lvchange --vdosettings 'bio_threads=2 deduplication=1' vg/vdopool0
4d51e5
 .fi
4d51e5
 .
4d51e5
 .SS \n+[step]. Checking the usage of VDOPoolLV
4d51e5
diff --git a/test/shell/lvchange-vdo.sh b/test/shell/lvchange-vdo.sh
4d51e5
index 461b7821f..7cc44d6bc 100644
4d51e5
--- a/test/shell/lvchange-vdo.sh
4d51e5
+++ b/test/shell/lvchange-vdo.sh
4d51e5
@@ -48,9 +48,17 @@ check grep_dmsetup status $vg-vdopool-vpool " online online "
4d51e5
 lvchange --compression n --deduplication n $vg/vdopool
4d51e5
 check grep_dmsetup status $vg-vdopool-vpool " offline offline "
4d51e5
 
4d51e5
+# --vdosettings needs inactive LV
4d51e5
+not lvchange --vdosettings 'ack_threads=8' $vg/vdopool
4d51e5
 
4d51e5
 lvchange -an $vg/$lv1
4d51e5
 
4d51e5
+# With inactive vdo-pool changes are applied
4d51e5
+# explicit option --compression has highest priority
4d51e5
+lvchange --vdosettings 'ack_threads=5 compression=0' --compression y $vg/vdopool
4d51e5
+check lv_field $vg/$lv1 vdo_ack_threads "5"
4d51e5
+check lv_field $vg/$lv1 vdo_compression "enabled"
4d51e5
+
4d51e5
 # Test activation
4d51e5
 lvchange -aly $vg/$lv1
4d51e5
 check active $vg $lv1
4d51e5
diff --git a/test/shell/lvconvert-vdo.sh b/test/shell/lvconvert-vdo.sh
4d51e5
index 529f325bd..c42d8f25a 100644
4d51e5
--- a/test/shell/lvconvert-vdo.sh
4d51e5
+++ b/test/shell/lvconvert-vdo.sh
4d51e5
@@ -28,12 +28,12 @@ lvcreate -L5G -n $lv1 $vg
4d51e5
 not lvconvert --type vdo-pool $vg/$lv1 |& tee out
4d51e5
 grep "WARNING" out
4d51e5
 
4d51e5
-
4d51e5
-lvconvert -y --type vdo-pool $vg/$lv1
4d51e5
+# Check --vdosettings is also applied to converted vdo-pool
4d51e5
+lvconvert -y --type vdo-pool --vdosettings 'ack_threads=5' $vg/$lv1
4d51e5
+check lv_field $vg/$lv1 vdo_ack_threads "5"
4d51e5
 lvremove -f $vg
4d51e5
 
4d51e5
-
4d51e5
-# 
4d51e5
+#
4d51e5
 lvcreate -L5G -n $lv1 $vg
4d51e5
 lvconvert -y --vdopool $vg/$lv1
4d51e5
 lvremove -f $vg
4d51e5
diff --git a/test/shell/lvcreate-vdo.sh b/test/shell/lvcreate-vdo.sh
4d51e5
index 44f8bf094..3e807ac94 100644
4d51e5
--- a/test/shell/lvcreate-vdo.sh
4d51e5
+++ b/test/shell/lvcreate-vdo.sh
4d51e5
@@ -79,8 +79,12 @@ not fsck -n "$DM_DEV_DIR/mapper/$vg-${lv2}"
4d51e5
 
4d51e5
 lvremove -ff $vg
4d51e5
 
4d51e5
+# Unknown settings does not pass
4d51e5
+# TODO: try to catch this in parser and 'fail'
4d51e5
+not lvcreate --type vdo --vdosettings 'ack_Xthreads=4' -L10G -V1T -ky -n $lv1 $vg
4d51e5
 
4d51e5
-lvcreate --type vdo -L10G -V1T -ky -n $lv1 $vg
4d51e5
+lvcreate --type vdo --vdosettings 'ack_threads=4' -L10G -V1T -ky -n $lv1 $vg
4d51e5
+check lv_field $vg/$lv1 vdo_ack_threads "4"
4d51e5
 lvs -a $vg
4d51e5
 lvremove -ff $vg
4d51e5
 
4d51e5
diff --git a/tools/args.h b/tools/args.h
4d51e5
index 00a2ec817..bfd848ce9 100644
4d51e5
--- a/tools/args.h
4d51e5
+++ b/tools/args.h
4d51e5
@@ -900,6 +900,15 @@ arg(vdopool_ARG, '\0', "vdopool", lv_VAL, 0, 0,
4d51e5
     "The name of a VDO pool LV.\n"
4d51e5
     "See \\fBlvmvdo\\fP(7) for more information about VDO usage.\n")
4d51e5
 
4d51e5
+arg(vdosettings_ARG, '\0', "vdosettings", string_VAL, ARG_GROUPABLE, 0,
4d51e5
+    "Specifies tunable VDO options for VDO LVs.\n"
4d51e5
+    "Use the form 'option=value' or 'option1=value option2=value', or\n"
4d51e5
+    "repeat --vdosettings for each option being set.\n"
4d51e5
+    "These settings override the default VDO behaviors.\n"
4d51e5
+    "To remove vdosettings and revert to the default\n"
4d51e5
+    "VDO behaviors, use --vdosettings 'default'.\n"
4d51e5
+    "See \\fBlvmvdo\\fP(7) for more information.\n")
4d51e5
+
4d51e5
 arg(version_ARG, '\0', "version", 0, 0, 0,
4d51e5
     "Display version information.\n")
4d51e5
 
4d51e5
diff --git a/tools/command-lines.in b/tools/command-lines.in
4d51e5
index 00ac08934..08302b34f 100644
4d51e5
--- a/tools/command-lines.in
4d51e5
+++ b/tools/command-lines.in
4d51e5
@@ -243,6 +243,7 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
4d51e5
 --setautoactivation Bool, --errorwhenfull Bool, --discards Discards, --zero Bool,
4d51e5
 --cachemode CacheMode, --cachepolicy String, --cachesettings String,
4d51e5
 --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
4d51e5
+--vdosettings String,
4d51e5
 --writebehind Number, --writemostly WriteMostlyPV, --persistent n
4d51e5
 
4d51e5
 # It's unfortunate that activate needs to be optionally allowed here;
4d51e5
@@ -341,7 +342,8 @@ OO_LVCONVERT_CACHE: --cachemetadataformat CacheMetadataFormat,
4d51e5
 --cachesettings String, --zero Bool
4d51e5
 
4d51e5
 OO_LVCONVERT_VDO: --metadataprofile String, --readahead Readahead,
4d51e5
---compression Bool, --deduplication Bool, --zero Bool
4d51e5
+--compression Bool, --deduplication Bool, --vdosettings String,
4d51e5
+--zero Bool
4d51e5
 
4d51e5
 OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync
4d51e5
 
4d51e5
@@ -839,7 +841,7 @@ OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksi
4d51e5
 
4d51e5
 OO_LVCREATE_THINPOOL: --discards Discards, --errorwhenfull Bool
4d51e5
 
4d51e5
-OO_LVCREATE_VDO: --compression Bool, --deduplication Bool
4d51e5
+OO_LVCREATE_VDO: --compression Bool, --deduplication Bool, --vdosettings String
4d51e5
 ---
4d51e5
 
4d51e5
 lvcreate --type error --size SizeMB VG
4d51e5
diff --git a/tools/lvchange.c b/tools/lvchange.c
4d51e5
index 0525bc53c..dc51786d7 100644
4d51e5
--- a/tools/lvchange.c
4d51e5
+++ b/tools/lvchange.c
4d51e5
@@ -755,6 +755,43 @@ out:
4d51e5
 	return r;
4d51e5
 }
4d51e5
 
4d51e5
+static int _lvchange_vdo(struct cmd_context *cmd,
4d51e5
+			 struct logical_volume *lv,
4d51e5
+			 uint32_t *mr)
4d51e5
+{
4d51e5
+	struct lv_segment *seg;
4d51e5
+	int updated = 0;
4d51e5
+
4d51e5
+	seg = first_seg(lv);
4d51e5
+
4d51e5
+	// With VDO LV given flip to VDO pool
4d51e5
+	if (seg_is_vdo(seg))
4d51e5
+		seg = first_seg(seg_lv(seg, 0));
4d51e5
+
4d51e5
+	if (!get_vdo_settings(cmd, &seg->vdo_params, &updated))
4d51e5
+		return_0;
4d51e5
+
4d51e5
+	if ((updated & VDO_CHANGE_OFFLINE) &&
4d51e5
+	    lv_info(cmd, seg->lv, 1, NULL, 0, 0)) {
4d51e5
+		log_error("Cannot change VDO settings for active VDO pool %s.",
4d51e5
+			  display_lvname(seg->lv));
4d51e5
+		// TODO maybe add --force support with prompt here
4d51e5
+		log_print_unless_silent("VDO pool %s with all its LVs needs to be deactivated.",
4d51e5
+					display_lvname(seg->lv));
4d51e5
+		return 0;
4d51e5
+	}
4d51e5
+
4d51e5
+	if (updated) {
4d51e5
+		if (!dm_vdo_validate_target_params(&seg->vdo_params, 0 /* vdo_size */))
4d51e5
+			return_0;
4d51e5
+
4d51e5
+		/* Request caller to commit and reload metadata */
4d51e5
+		*mr |= MR_RELOAD;
4d51e5
+	}
4d51e5
+
4d51e5
+	return 1;
4d51e5
+}
4d51e5
+
4d51e5
 static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
4d51e5
 			 int arg, uint32_t *mr)
4d51e5
 {
4d51e5
@@ -1154,6 +1191,7 @@ static int _option_requires_direct_commit(int opt_enum)
4d51e5
 		cachemode_ARG,
4d51e5
 		cachepolicy_ARG,
4d51e5
 		cachesettings_ARG,
4d51e5
+		vdosettings_ARG,
4d51e5
 		-1
4d51e5
 	};
4d51e5
 
4d51e5
@@ -1354,7 +1392,10 @@ static int _lvchange_properties_single(struct cmd_context *cmd,
4d51e5
 			docmds++;
4d51e5
 			doit += _lvchange_cache(cmd, lv, &mr;;
4d51e5
 			break;
4d51e5
-
4d51e5
+		case vdosettings_ARG:
4d51e5
+			docmds++;
4d51e5
+			doit += _lvchange_vdo(cmd, lv, &mr;;
4d51e5
+			break;
4d51e5
 		default:
4d51e5
 			log_error(INTERNAL_ERROR "Failed to check for option %s",
4d51e5
 				  arg_long_option_name(i));
4d51e5
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
4d51e5
index a90946173..3d4b24fe3 100644
4d51e5
--- a/tools/lvconvert.c
4d51e5
+++ b/tools/lvconvert.c
4d51e5
@@ -5456,13 +5456,8 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
4d51e5
 	if (!fill_vdo_target_params(cmd, &vdo_params, &vdo_pool_header_size, vg->profile))
4d51e5
 		goto_out;
4d51e5
 
4d51e5
-	if (arg_is_set(cmd, compression_ARG))
4d51e5
-		vdo_params.use_compression =
4d51e5
-			arg_int_value(cmd, compression_ARG, 0);
4d51e5
-
4d51e5
-	if (arg_is_set(cmd, deduplication_ARG))
4d51e5
-		vdo_params.use_deduplication =
4d51e5
-			arg_int_value(cmd, deduplication_ARG, 0);
4d51e5
+	if (!get_vdo_settings(cmd, &vdo_params, NULL))
4d51e5
+		return_0;
4d51e5
 
4d51e5
 	if (!activate_lv(cmd, lv)) {
4d51e5
 		log_error("Cannot activate %s.", display_lvname(lv));
4d51e5
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
4d51e5
index 79af42685..8de6f3408 100644
4d51e5
--- a/tools/lvcreate.c
4d51e5
+++ b/tools/lvcreate.c
4d51e5
@@ -698,6 +698,23 @@ static int _read_cache_params(struct cmd_context *cmd,
4d51e5
 	return 1;
4d51e5
 }
4d51e5
 
4d51e5
+static int _read_vdo_params(struct cmd_context *cmd,
4d51e5
+			    struct lvcreate_params *lp)
4d51e5
+{
4d51e5
+	if (!seg_is_vdo(lp))
4d51e5
+		return 1;
4d51e5
+
4d51e5
+	// prefiling settings here
4d51e5
+	if (!fill_vdo_target_params(cmd, &lp->vdo_params,  &lp->vdo_pool_header_size, NULL))
4d51e5
+		return_0;
4d51e5
+
4d51e5
+	// override with optional vdo settings
4d51e5
+	if (!get_vdo_settings(cmd, &lp->vdo_params, NULL))
4d51e5
+		return_0;
4d51e5
+
4d51e5
+	return 1;
4d51e5
+}
4d51e5
+
4d51e5
 static int _read_activation_params(struct cmd_context *cmd,
4d51e5
 				   struct volume_group *vg,
4d51e5
 				   struct lvcreate_params *lp)
4d51e5
@@ -888,7 +905,8 @@ static int _lvcreate_params(struct cmd_context *cmd,
4d51e5
 #define VDO_POOL_ARGS \
4d51e5
 	vdopool_ARG,\
4d51e5
 	compression_ARG,\
4d51e5
-	deduplication_ARG
4d51e5
+	deduplication_ARG,\
4d51e5
+	vdosettings_ARG
4d51e5
 
4d51e5
 	/* Cache and cache-pool segment type */
4d51e5
 	if (seg_is_cache(lp)) {
4d51e5
@@ -1098,19 +1116,6 @@ static int _lvcreate_params(struct cmd_context *cmd,
4d51e5
 						zero_ARG,
4d51e5
 						-1))
4d51e5
 			return_0;
4d51e5
-
4d51e5
-		// FIXME: prefiling here - this is wrong place
4d51e5
-		// but will work for this moment
4d51e5
-		if (!fill_vdo_target_params(cmd, &lp->vdo_params, &lp->vdo_pool_header_size, NULL))
4d51e5
-			return_0;
4d51e5
-
4d51e5
-		if (arg_is_set(cmd, compression_ARG))
4d51e5
-			lp->vdo_params.use_compression =
4d51e5
-				arg_int_value(cmd, compression_ARG, 0);
4d51e5
-
4d51e5
-		if (arg_is_set(cmd, deduplication_ARG))
4d51e5
-			lp->vdo_params.use_deduplication =
4d51e5
-				arg_int_value(cmd, deduplication_ARG, 0);
4d51e5
 	}
4d51e5
 
4d51e5
 	/* Check options shared between more segment types */
4d51e5
@@ -1198,6 +1203,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
4d51e5
 			      &lp->pool_metadata_size, &lp->pool_metadata_spare,
4d51e5
 			      &lp->chunk_size, &lp->discards, &lp->zero_new_blocks)) ||
4d51e5
 	    !_read_cache_params(cmd, lp) ||
4d51e5
+	    !_read_vdo_params(cmd, lp) ||
4d51e5
 	    !_read_mirror_and_raid_params(cmd, lp))
4d51e5
 		return_0;
4d51e5
 
4d51e5
diff --git a/tools/toollib.c b/tools/toollib.c
4d51e5
index 16be336d4..697baee82 100644
4d51e5
--- a/tools/toollib.c
4d51e5
+++ b/tools/toollib.c
4d51e5
@@ -1192,6 +1192,183 @@ out:
4d51e5
 	return ok;
4d51e5
 }
4d51e5
 
4d51e5
+/*
4d51e5
+ * Compare VDO option name, skip any '_' in name
4d51e5
+ * and also allow to use it without  vdo_[use_] prefix
4d51e5
+ */
4d51e5
+static int _compare_vdo_option(const char *b1, const char *b2)
4d51e5
+{
4d51e5
+	if (strncasecmp(b1, "vdo", 3) == 0) // skip vdo prefix
4d51e5
+		b1 += 3;
4d51e5
+
4d51e5
+	if ((tolower(*b1) != tolower(*b2)) &&
4d51e5
+	    (strncmp(b2, "use_", 4) == 0))
4d51e5
+		b2 += 4;  // try again with skipped prefix 'use_'
4d51e5
+
4d51e5
+	while (*b1 && *b2) {
4d51e5
+		if (tolower(*b1) == tolower(*b2)) {
4d51e5
+			++b1;
4d51e5
+			++b2;
4d51e5
+			continue;	// matching char
4d51e5
+		}
4d51e5
+
4d51e5
+		if (*b1 == '_')
4d51e5
+			++b1;           // skip to next char
4d51e5
+		else if (*b2 == '_')
4d51e5
+			++b2;           // skip to next char
4d51e5
+		else
4d51e5
+			break;          // mismatch
4d51e5
+	}
4d51e5
+
4d51e5
+	return (*b1 || *b2) ? 0 : 1;
4d51e5
+}
4d51e5
+
4d51e5
+#define CHECK_AND_SET(var, onoff) \
4d51e5
+	option = #var;\
4d51e5
+	if (_compare_vdo_option(cn->key, option)) {\
4d51e5
+		if (is_lvchange || !cn->v || (cn->v->type != DM_CFG_INT))\
4d51e5
+			goto err;\
4d51e5
+		if (vtp->var != cn->v->v.i) {\
4d51e5
+			vtp->var = cn->v->v.i;\
4d51e5
+			u |= onoff;\
4d51e5
+		}\
4d51e5
+		continue;\
4d51e5
+	}
4d51e5
+
4d51e5
+#define DO_OFFLINE(var) \
4d51e5
+	CHECK_AND_SET(var, VDO_CHANGE_OFFLINE)
4d51e5
+
4d51e5
+#define DO_ONLINE(var) \
4d51e5
+	CHECK_AND_SET(var, VDO_CHANGE_ONLINE)
4d51e5
+
4d51e5
+int get_vdo_settings(struct cmd_context *cmd,
4d51e5
+		     struct dm_vdo_target_params *vtp,
4d51e5
+		     int *updated)
4d51e5
+{
4d51e5
+	const char *str, *option = NULL;
4d51e5
+	struct arg_value_group_list *group;
4d51e5
+	struct dm_config_tree *result = NULL, *prev = NULL, *current = NULL;
4d51e5
+	struct dm_config_node *cn;
4d51e5
+	int r = 0, u = 0, is_lvchange;
4d51e5
+	int use_compression = vtp->use_compression;
4d51e5
+	int use_deduplication = vtp->use_deduplication;
4d51e5
+	int checked_lvchange;
4d51e5
+
4d51e5
+	if (updated)
4d51e5
+		*updated = 0;
4d51e5
+
4d51e5
+	// Group all --vdosettings
4d51e5
+	dm_list_iterate_items(group, &cmd->arg_value_groups) {
4d51e5
+		if (!grouped_arg_is_set(group->arg_values, vdosettings_ARG))
4d51e5
+			continue;
4d51e5
+
4d51e5
+		if (!(current = dm_config_create()))
4d51e5
+			goto_out;
4d51e5
+		if (prev)
4d51e5
+			current->cascade = prev;
4d51e5
+		prev = current;
4d51e5
+
4d51e5
+		if (!(str = grouped_arg_str_value(group->arg_values,
4d51e5
+						  vdosettings_ARG,
4d51e5
+						  NULL)))
4d51e5
+			goto_out;
4d51e5
+
4d51e5
+		if (!dm_config_parse_without_dup_node_check(current, str, str + strlen(str)))
4d51e5
+			goto_out;
4d51e5
+	}
4d51e5
+
4d51e5
+	if (current) {
4d51e5
+		if (!(result = dm_config_flatten(current)))
4d51e5
+			goto_out;
4d51e5
+
4d51e5
+		checked_lvchange = !strcmp(cmd->name, "lvchange");
4d51e5
+
4d51e5
+		/* Use all acceptable VDO options */
4d51e5
+		for (cn = result->root; cn; cn = cn->sib) {
4d51e5
+			is_lvchange = 0;
4d51e5
+			DO_OFFLINE(ack_threads);
4d51e5
+			DO_OFFLINE(bio_rotation);
4d51e5
+			DO_OFFLINE(bio_threads);
4d51e5
+			DO_OFFLINE(block_map_cache_size_mb);
4d51e5
+			DO_OFFLINE(block_map_era_length);
4d51e5
+			DO_OFFLINE(block_map_period); // alias for block_map_era_length
4d51e5
+			DO_OFFLINE(cpu_threads);
4d51e5
+			DO_OFFLINE(hash_zone_threads);
4d51e5
+			DO_OFFLINE(logical_threads);
4d51e5
+			DO_OFFLINE(max_discard);
4d51e5
+			DO_OFFLINE(physical_threads);
4d51e5
+
4d51e5
+			// Support also these - even when we have regular opts for them
4d51e5
+			DO_ONLINE(use_compression);
4d51e5
+			DO_ONLINE(use_deduplication);
4d51e5
+
4d51e5
+			// Settings bellow cannot be changed with lvchange command
4d51e5
+			is_lvchange = checked_lvchange;
4d51e5
+
4d51e5
+			DO_OFFLINE(check_point_frequency);
4d51e5
+			DO_OFFLINE(index_memory_size_mb);
4d51e5
+			DO_OFFLINE(minimum_io_size);
4d51e5
+			DO_OFFLINE(slab_size_mb);
4d51e5
+			DO_OFFLINE(use_metadata_hints);
4d51e5
+			DO_OFFLINE(use_sparse_index);
4d51e5
+
4d51e5
+			option = "write_policy";
4d51e5
+			if (_compare_vdo_option(cn->key, option)) {
4d51e5
+				if (is_lvchange || !cn->v || (cn->v->type != DM_CFG_STRING))
4d51e5
+					goto err;
4d51e5
+				if (!set_vdo_write_policy(&vtp->write_policy, cn->v->v.str))
4d51e5
+					goto_out;
4d51e5
+				u |= VDO_CHANGE_OFFLINE;
4d51e5
+				continue;
4d51e5
+			}
4d51e5
+
4d51e5
+			log_error("Unknown VDO setting \"%s\".", cn->key);
4d51e5
+			goto out;
4d51e5
+		}
4d51e5
+	}
4d51e5
+
4d51e5
+	if (arg_is_set(cmd, compression_ARG)) {
4d51e5
+		vtp->use_compression = arg_int_value(cmd, compression_ARG, 0);
4d51e5
+		if (vtp->use_compression != use_compression)
4d51e5
+			u |= VDO_CHANGE_ONLINE;
4d51e5
+	}
4d51e5
+
4d51e5
+	if (arg_is_set(cmd, deduplication_ARG)) {
4d51e5
+		vtp->use_deduplication = arg_int_value(cmd, deduplication_ARG, 0);
4d51e5
+		if (vtp->use_deduplication != use_deduplication)
4d51e5
+			u |= VDO_CHANGE_ONLINE;
4d51e5
+	}
4d51e5
+
4d51e5
+	if (updated) {
4d51e5
+		// validation of updated VDO option
4d51e5
+		if (!dm_vdo_validate_target_params(vtp, 0 /* vdo_size */)) {
4d51e5
+err:
4d51e5
+			if (is_lvchange)
4d51e5
+				log_error("Cannot change VDO setting \"vdo_%s\" in existing VDO pool.",
4d51e5
+					  option);
4d51e5
+			else
4d51e5
+				log_error("Invalid argument for VDO setting \"vdo_%s\".",
4d51e5
+					  option);
4d51e5
+			goto out;
4d51e5
+		}
4d51e5
+
4d51e5
+		*updated = u;
4d51e5
+	}
4d51e5
+
4d51e5
+	r = 1;
4d51e5
+out:
4d51e5
+	if (result)
4d51e5
+		dm_config_destroy(result);
4d51e5
+
4d51e5
+	while (prev) {
4d51e5
+		current = prev->cascade;
4d51e5
+		dm_config_destroy(prev);
4d51e5
+		prev = current;
4d51e5
+	}
4d51e5
+
4d51e5
+	return r;
4d51e5
+}
4d51e5
+
4d51e5
 static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
4d51e5
 				       char *key, char *val, uint32_t *block_size_sectors)
4d51e5
 {
4d51e5
diff --git a/tools/toollib.h b/tools/toollib.h
4d51e5
index f3a60fbc4..2b38e4e4f 100644
4d51e5
--- a/tools/toollib.h
4d51e5
+++ b/tools/toollib.h
4d51e5
@@ -217,6 +217,12 @@ int get_cache_params(struct cmd_context *cmd,
4d51e5
 		     const char **name,
4d51e5
 		     struct dm_config_tree **settings);
4d51e5
 
4d51e5
+#define VDO_CHANGE_ONLINE  1
4d51e5
+#define VDO_CHANGE_OFFLINE 2
4d51e5
+int get_vdo_settings(struct cmd_context *cmd,
4d51e5
+		     struct dm_vdo_target_params *vtp,
4d51e5
+		     int *updated);
4d51e5
+
4d51e5
 int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
4d51e5
                             uint32_t *block_size_sectors);
4d51e5
 
4d51e5
-- 
4d51e5
2.34.3
4d51e5