diff --git a/.gitignore b/.gitignore
index 24421d5..91f7498 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/LVM2.2.03.09.tgz
+SOURCES/lvm2-8801a86.tar.gz
diff --git a/.lvm2.metadata b/.lvm2.metadata
index e2642d8..3935ffd 100644
--- a/.lvm2.metadata
+++ b/.lvm2.metadata
@@ -1 +1 @@
-15a90d5039a2a1e9f67611a2a6c2faa72e8996aa SOURCES/LVM2.2.03.09.tgz
+210aa94efb7d4523b6d095e7ec53ab773a1739a2 SOURCES/lvm2-8801a86.tar.gz
diff --git a/SOURCES/0001-Merge-master-up-to-commit-53803821de16.patch b/SOURCES/0001-Merge-master-up-to-commit-53803821de16.patch
deleted file mode 100644
index 1dbef5b..0000000
--- a/SOURCES/0001-Merge-master-up-to-commit-53803821de16.patch
+++ /dev/null
@@ -1,3317 +0,0 @@
- base/data-struct/list.h                      |   4 +-
- daemons/lvmlockd/lvmlockd-client.h           |   1 +
- daemons/lvmlockd/lvmlockd-core.c             | 370 +++++++--------
- daemons/lvmlockd/lvmlockd-dlm.c              |   8 +-
- daemons/lvmlockd/lvmlockd-internal.h         |   7 +-
- lib/cache/lvmcache.c                         | 551 ++++++++++------------
- lib/cache/lvmcache.h                         |  12 +-
- lib/commands/toolcontext.c                   |   3 +-
- lib/device/dev-io.c                          |   3 +
- lib/format_text/archiver.c                   |   2 +-
- lib/format_text/format-text.c                |  28 +-
- lib/format_text/text_label.c                 |   8 +-
- lib/label/hints.c                            |   6 +
- lib/label/label.c                            |   2 +-
- lib/label/label.h                            |   2 +-
- lib/locking/lvmlockd.c                       |  14 +-
- lib/metadata/metadata-exported.h             |   3 -
- lib/metadata/metadata.c                      |  68 +--
- lib/metadata/metadata.h                      |   8 +-
- man/lvmlockd.8_main                          |  14 +-
- test/shell/duplicate-vgnames.sh              | 660 +++++++++++++++++++++++++++
- test/shell/duplicate-vgrename.sh             | 319 +++++++++++++
- test/shell/integrity-dmeventd.sh             |   6 +-
- test/shell/integrity-large.sh                |   6 +-
- test/shell/integrity-misc.sh                 |   6 +-
- test/shell/integrity.sh                      |   6 +-
- test/shell/process-each-duplicate-vgnames.sh |  55 ---
- test/shell/thin-foreign-repair.sh            |   4 +-
- tools/command.c                              |  12 +-
- tools/lvconvert.c                            |   3 +-
- tools/pvck.c                                 |   8 +-
- tools/pvscan.c                               |   2 +-
- tools/toollib.c                              |   2 -
- tools/vgchange.c                             |   9 +-
- tools/vgimportclone.c                        |   4 +-
- tools/vgmerge.c                              |   4 +-
- tools/vgrename.c                             |   2 +-
- tools/vgsplit.c                              |   2 +-
- 39 files changed, 1571 insertions(+), 654 deletions(-)
- create mode 100644 test/shell/duplicate-vgnames.sh
- create mode 100644 test/shell/duplicate-vgrename.sh
- delete mode 100644 test/shell/process-each-duplicate-vgnames.sh
-
-diff --git a/base/data-struct/list.h b/base/data-struct/list.h
-index 54cb1c1..e0a6256 100644
---- a/base/data-struct/list.h
-+++ b/base/data-struct/list.h
-@@ -1,7 +1,7 @@
- #ifndef BASE_DATA_STRUCT_LIST_H
- #define BASE_DATA_STRUCT_LIST_H
- 
--#include <stddef.h> /* offsetof */
-+#include "base/memory/container_of.h"
- 
- //----------------------------------------------------------------
- 
-@@ -100,7 +100,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e
-  * contained in a structure of type t, return the containing structure.
-  */
- #define dm_list_struct_base(v, t, head) \
--    ((t *)((const char *)(v) - offsetof(t, head)))
-+    container_of(v, t, head)
- 
- /*
-  * Given the address v of an instance of 'struct dm_list list' contained in
-diff --git a/daemons/lvmlockd/lvmlockd-client.h b/daemons/lvmlockd/lvmlockd-client.h
-index 16d1613..62ffb73 100644
---- a/daemons/lvmlockd/lvmlockd-client.h
-+++ b/daemons/lvmlockd/lvmlockd-client.h
-@@ -14,6 +14,7 @@
- #include "libdaemon/client/daemon-client.h"
- 
- #define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket"
-+#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt"
- 
- /* Wrappers to open/close connection */
- 
-diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
-index 39275fb..84272c4 100644
---- a/daemons/lvmlockd/lvmlockd-core.c
-+++ b/daemons/lvmlockd/lvmlockd-core.c
-@@ -38,6 +38,8 @@
- #define EXTERN
- #include "lvmlockd-internal.h"
- 
-+static int str_to_mode(const char *str);
-+
- /*
-  * Basic operation of lvmlockd
-  *
-@@ -142,6 +144,8 @@ static const char *lvmlockd_protocol = "lvmlockd";
- static const int lvmlockd_protocol_version = 1;
- static int daemon_quit;
- static int adopt_opt;
-+static uint32_t adopt_update_count;
-+static const char *adopt_file;
- 
- /*
-  * We use a separate socket for dumping daemon info.
-@@ -812,6 +816,144 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi
- }
- 
- /*
-+ * Write new info when a command exits if that command has acquired a new LV
-+ * lock.  If the command has released an LV lock we don't bother updating the
-+ * info.  When adopting, we eliminate any LV lock adoptions if there is no dm
-+ * device for that LV.  If lvmlockd is terminated after acquiring but before
-+ * writing this file, those LV locks would not be adopted on restart.
-+ */
-+
-+#define ADOPT_VERSION_MAJOR 1
-+#define ADOPT_VERSION_MINOR 0
-+
-+static void write_adopt_file(void)
-+{
-+	struct lockspace *ls;
-+	struct resource *r;
-+	struct lock *lk;
-+	time_t t;
-+	FILE *fp;
-+
-+	if (!(fp = fopen(adopt_file, "w")))
-+		return;
-+
-+	adopt_update_count++;
-+
-+	t = time(NULL);
-+	fprintf(fp, "lvmlockd adopt_version %u.%u pid %d updates %u %s",
-+		ADOPT_VERSION_MAJOR, ADOPT_VERSION_MINOR, getpid(), adopt_update_count, ctime(&t));
-+
-+	pthread_mutex_lock(&lockspaces_mutex);
-+	list_for_each_entry(ls, &lockspaces, list) {
-+		if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm))
-+			continue;
-+		fprintf(fp, "VG: %38s %s %s %s\n",
-+			ls->vg_uuid, ls->vg_name, lm_str(ls->lm_type), ls->vg_args);
-+		list_for_each_entry(r, &ls->resources, list) {
-+			if (r->type != LD_RT_LV)
-+				continue;
-+			if ((r->mode != LD_LK_EX) && (r->mode != LD_LK_SH))
-+				continue;
-+			list_for_each_entry(lk, &r->locks, list) {
-+				fprintf(fp, "LV: %38s %s %s %s %u\n",
-+					ls->vg_uuid, r->name, r->lv_args, mode_str(r->mode), r->version);
-+			}
-+		}
-+	}
-+	pthread_mutex_unlock(&lockspaces_mutex);
-+
-+	fflush(fp);
-+	fclose(fp);
-+}
-+
-+static int read_adopt_file(struct list_head *vg_lockd)
-+{
-+	char adopt_line[512];
-+	char vg_uuid[72];
-+	char lm_type_str[16];
-+	char mode[8];
-+	struct lockspace *ls, *ls2;
-+	struct resource *r;
-+	FILE *fp;
-+
-+	if (MAX_ARGS != 64 || MAX_NAME != 64)
-+		return -1;
-+
-+	if (!(fp = fopen(adopt_file, "r")))
-+		return 0;
-+
-+	while (fgets(adopt_line, sizeof(adopt_line), fp)) {
-+		if (adopt_line[0] == '#')
-+			continue;
-+		else if (!strncmp(adopt_line, "lvmlockd", 8)) {
-+			unsigned int v_major = 0, v_minor = 0;
-+			sscanf(adopt_line, "lvmlockd adopt_version %u.%u", &v_major, &v_minor);
-+			if (v_major != ADOPT_VERSION_MAJOR)
-+				goto fail;
-+
-+		} else if (!strncmp(adopt_line, "VG:", 3)) {
-+			if (!(ls = alloc_lockspace()))
-+				goto fail;
-+
-+			memset(vg_uuid, 0, sizeof(vg_uuid));
-+
-+			if (sscanf(adopt_line, "VG: %63s %64s %16s %64s",
-+				   vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) {
-+				goto fail;
-+			}
-+
-+			memcpy(ls->vg_uuid, vg_uuid, 64);
-+
-+			if ((ls->lm_type = str_to_lm(lm_type_str)) < 0)
-+				goto fail;
-+
-+			list_add(&ls->list, vg_lockd);
-+
-+		} else if (!strncmp(adopt_line, "LV:", 3)) {
-+			if (!(r = alloc_resource()))
-+				goto fail;
-+
-+			r->type = LD_RT_LV;
-+
-+			memset(vg_uuid, 0, sizeof(vg_uuid));
-+
-+			if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u",
-+				   vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
-+				goto fail;
-+			}
-+
-+			if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV)
-+				goto fail;
-+
-+			if (ls && !memcmp(ls->vg_uuid, vg_uuid, 64)) {
-+				list_add(&r->list, &ls->resources);
-+				r = NULL;
-+			} else {
-+				list_for_each_entry(ls2, vg_lockd, list) {
-+					if (memcmp(ls2->vg_uuid, vg_uuid, 64))
-+						continue;
-+					list_add(&r->list, &ls2->resources);
-+					r = NULL;
-+					break;
-+				}
-+			}
-+
-+			if (r) {
-+				log_error("No lockspace found for resource %s vg_uuid %s", r->name, vg_uuid);
-+				goto fail;
-+			}
-+		}
-+	}
-+
-+	fclose(fp);
-+	return 0;
-+
-+fail:
-+	fclose(fp);
-+	return -1;
-+}
-+
-+/*
-  * These are few enough that arrays of function pointers can
-  * be avoided.
-  */
-@@ -4689,6 +4831,7 @@ static void *client_thread_main(void *arg_in)
- 	struct client *cl;
- 	struct action *act;
- 	struct action *act_un;
-+	uint32_t lock_acquire_count = 0, lock_acquire_written = 0;
- 	int rv;
- 
- 	while (1) {
-@@ -4720,6 +4863,9 @@ static void *client_thread_main(void *arg_in)
- 				rv = -1;
- 			}
- 
-+			if (act->flags & LD_AF_LV_LOCK)
-+				lock_acquire_count++;
-+
- 			/*
- 			 * The client failed after we acquired an LV lock for
- 			 * it, but before getting this reply saying it's done.
-@@ -4741,6 +4887,11 @@ static void *client_thread_main(void *arg_in)
- 			continue;
- 		}
- 
-+		if (adopt_opt && (lock_acquire_count > lock_acquire_written)) {
-+			lock_acquire_written = lock_acquire_count;
-+			write_adopt_file();
-+		}
-+
- 		/*
- 		 * Queue incoming actions for lockspace threads
- 		 */
-@@ -4814,6 +4965,8 @@ static void *client_thread_main(void *arg_in)
- 			pthread_mutex_unlock(&client_mutex);
- 	}
- out:
-+	if (adopt_opt && lock_acquire_written)
-+		unlink(adopt_file);
- 	return NULL;
- }
- 
-@@ -4846,180 +4999,6 @@ static void close_client_thread(void)
- 		log_error("pthread_join client_thread error %d", perrno);
- }
- 
--/*
-- * Get a list of all VGs with a lockd type (sanlock|dlm).
-- * We'll match this list against a list of existing lockspaces that are
-- * found in the lock manager.
-- *
-- * For each of these VGs, also create a struct resource on ls->resources to
-- * represent each LV in the VG that uses a lock.  For each of these LVs
-- * that are active, we'll attempt to adopt a lock.
-- */
--
--static int get_lockd_vgs(struct list_head *vg_lockd)
--{
--	/* FIXME: get VGs some other way */
--	return -1;
--#if 0
--	struct list_head update_vgs;
--	daemon_reply reply;
--	struct dm_config_node *cn;
--	struct dm_config_node *metadata;
--	struct dm_config_node *md_cn;
--	struct dm_config_node *lv_cn;
--	struct lockspace *ls, *safe;
--	struct resource *r;
--	const char *vg_name;
--	const char *vg_uuid;
--	const char *lv_uuid;
--	const char *lock_type;
--	const char *lock_args;
--	char find_str_path[PATH_MAX];
--	int rv = 0;
--
--	INIT_LIST_HEAD(&update_vgs);
--
--	reply = send_lvmetad("vg_list", "token = %s", "skip", NULL);
--
--	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
--		log_error("vg_list from lvmetad failed %d", reply.error);
--		rv = -EINVAL;
--		goto destroy;
--	}
--
--	if (!(cn = dm_config_find_node(reply.cft->root, "volume_groups"))) {
--		log_error("get_lockd_vgs no vgs");
--		rv = -EINVAL;
--		goto destroy;
--	}
--
--	/* create an update_vgs list of all vg uuids */
--
--	for (cn = cn->child; cn; cn = cn->sib) {
--		vg_uuid = cn->key;
--
--		if (!(ls = alloc_lockspace())) {
--			rv = -ENOMEM;
--			break;
--		}
--
--		strncpy(ls->vg_uuid, vg_uuid, 64);
--		list_add_tail(&ls->list, &update_vgs);
--		log_debug("get_lockd_vgs %s", vg_uuid);
--	}
-- destroy:
--	daemon_reply_destroy(reply);
--
--	if (rv < 0)
--		goto out;
--
--	/* get vg_name and lock_type for each vg uuid entry in update_vgs */
--
--	list_for_each_entry(ls, &update_vgs, list) {
--		reply = send_lvmetad("vg_lookup",
--				     "token = %s", "skip",
--				     "uuid = %s", ls->vg_uuid,
--				     NULL);
--
--		if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
--			log_error("vg_lookup from lvmetad failed %d", reply.error);
--			rv = -EINVAL;
--			goto next;
--		}
--
--		vg_name = daemon_reply_str(reply, "name", NULL);
--		if (!vg_name) {
--			log_error("get_lockd_vgs %s no name", ls->vg_uuid);
--			rv = -EINVAL;
--			goto next;
--		}
--
--		strncpy(ls->vg_name, vg_name, MAX_NAME);
--
--		metadata = dm_config_find_node(reply.cft->root, "metadata");
--		if (!metadata) {
--			log_error("get_lockd_vgs %s name %s no metadata",
--				  ls->vg_uuid, ls->vg_name);
--			rv = -EINVAL;
--			goto next;
--		}
--
--		lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL);
--		ls->lm_type = str_to_lm(lock_type);
--
--		if ((ls->lm_type != LD_LM_SANLOCK) && (ls->lm_type != LD_LM_DLM)) {
--			log_debug("get_lockd_vgs %s not lockd type", ls->vg_name);
--			continue;
--		}
--
--		lock_args = dm_config_find_str(metadata, "metadata/lock_args", NULL);
--		if (lock_args)
--			strncpy(ls->vg_args, lock_args, MAX_ARGS);
--
--		log_debug("get_lockd_vgs %s lock_type %s lock_args %s",
--			  ls->vg_name, lock_type, lock_args ?: "none");
--
--		/*
--		 * Make a record (struct resource) of each lv that uses a lock.
--		 * For any lv that uses a lock, we'll check if the lv is active
--		 * and if so try to adopt a lock for it.
--		 */
--
--		for (md_cn = metadata->child; md_cn; md_cn = md_cn->sib) {
--			if (strcmp(md_cn->key, "logical_volumes"))
--				continue;
--
--			for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) {
--				snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key);
--				lock_args = dm_config_find_str(lv_cn, find_str_path, NULL);
--				if (!lock_args)
--					continue;
--
--				snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key);
--				lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL);
--
--				if (!lv_uuid) {
--					log_error("get_lock_vgs no lv id for name %s", lv_cn->key);
--					continue;
--				}
--
--				if (!(r = alloc_resource())) {
--					rv = -ENOMEM;
--					goto next;
--				}
--
--				r->use_vb = 0;
--				r->type = LD_RT_LV;
--				strncpy(r->name, lv_uuid, MAX_NAME);
--				if (lock_args)
--					strncpy(r->lv_args, lock_args, MAX_ARGS);
--				list_add_tail(&r->list, &ls->resources);
--				log_debug("get_lockd_vgs %s lv %s %s (name %s)",
--					  ls->vg_name, r->name, lock_args ? lock_args : "", lv_cn->key);
--			}
--		}
-- next:
--		daemon_reply_destroy(reply);
--
--		if (rv < 0)
--			break;
--	}
--out:
--	/* Return lockd VG's on the vg_lockd list. */
--
--	list_for_each_entry_safe(ls, safe, &update_vgs, list) {
--		list_del(&ls->list);
--
--		if ((ls->lm_type == LD_LM_SANLOCK) || (ls->lm_type == LD_LM_DLM))
--			list_add_tail(&ls->list, vg_lockd);
--		else
--			free(ls);
--	}
--
--	return rv;
--#endif
--}
--
- static char _dm_uuid[DM_UUID_LEN];
- 
- static char *get_dm_uuid(char *dm_name)
-@@ -5236,9 +5215,9 @@ static void adopt_locks(void)
- 	INIT_LIST_HEAD(&to_unlock);
- 
- 	/*
--	 * Get list of lockspaces from lock managers.
--	 * Get list of VGs from lvmetad with a lockd type.
--	 * Get list of active lockd type LVs from /dev.
-+	 * Get list of lockspaces from currently running lock managers.
-+	 * Get list of shared VGs from file written by prior lvmlockd.
-+	 * Get list of active LVs (in the shared VGs) from the file.
- 	 */
- 
- 	if (lm_support_dlm() && lm_is_running_dlm()) {
-@@ -5262,12 +5241,17 @@ static void adopt_locks(void)
- 	 * Adds a struct lockspace to vg_lockd for each lockd VG.
- 	 * Adds a struct resource to ls->resources for each LV.
- 	 */
--	rv = get_lockd_vgs(&vg_lockd);
-+	rv = read_adopt_file(&vg_lockd);
- 	if (rv < 0) {
--		log_error("adopt_locks get_lockd_vgs failed");
-+		log_error("adopt_locks read_adopt_file failed");
- 		goto fail;
- 	}
- 
-+	if (list_empty(&vg_lockd)) {
-+		log_debug("No lockspaces in adopt file");
-+		return;
-+	}
-+
- 	/*
- 	 * For each resource on each lockspace, check if the
- 	 * corresponding LV is active.  If so, leave the
-@@ -5506,7 +5490,7 @@ static void adopt_locks(void)
- 				goto fail;
- 			act->op = LD_OP_LOCK;
- 			act->rt = LD_RT_LV;
--			act->mode = LD_LK_EX;
-+			act->mode = r->adopt_mode;
- 			act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT);
- 			act->client_id = INTERNAL_CLIENT_ID;
- 			act->lm_type = ls->lm_type;
-@@ -5604,8 +5588,9 @@ static void adopt_locks(void)
- 			 * Adopt failed because the orphan has a different mode
- 			 * than initially requested.  Repeat the lock-adopt operation
- 			 * with the other mode.  N.B. this logic depends on first
--			 * trying sh then ex for GL/VG locks, and ex then sh for
--			 * LV locks.
-+			 * trying sh then ex for GL/VG locks; for LV locks the mode
-+			 * from the adopt file is tried first, the alternate
-+			 * (if the mode in adopt file was wrong somehow.)
- 			 */
- 
- 			if ((act->rt != LD_RT_LV) && (act->mode == LD_LK_SH)) {
-@@ -5613,9 +5598,12 @@ static void adopt_locks(void)
- 				act->mode = LD_LK_EX;
- 				rv = add_lock_action(act);
- 
--			} else if ((act->rt == LD_RT_LV) && (act->mode == LD_LK_EX)) {
--				/* LV locks: attempt to adopt sh after ex failed. */
--				act->mode = LD_LK_SH;
-+			} else if (act->rt == LD_RT_LV) {
-+				/* LV locks: attempt to adopt the other mode. */
-+				if (act->mode == LD_LK_EX)
-+					act->mode = LD_LK_SH;
-+				else if (act->mode == LD_LK_SH)
-+					act->mode = LD_LK_EX;
- 				rv = add_lock_action(act);
- 
- 			} else {
-@@ -5750,10 +5738,13 @@ static void adopt_locks(void)
- 	if (count_start_fail || count_adopt_fail)
- 		goto fail;
- 
-+	unlink(adopt_file);
-+	write_adopt_file();
- 	log_debug("adopt_locks done");
- 	return;
- 
- fail:
-+	unlink(adopt_file);
- 	log_error("adopt_locks failed, reset host");
- }
- 
-@@ -6028,6 +6019,8 @@ static void usage(char *prog, FILE *file)
- 	fprintf(file, "        Set path to the pid file. [%s]\n", LVMLOCKD_PIDFILE);
- 	fprintf(file, "  --socket-path | -s <path>\n");
- 	fprintf(file, "        Set path to the socket to listen on. [%s]\n", LVMLOCKD_SOCKET);
-+	fprintf(file, "  --adopt-file <path>\n");
-+	fprintf(file, "        Set path to the adopt file. [%s]\n", LVMLOCKD_ADOPT_FILE);
- 	fprintf(file, "  --syslog-priority | -S err|warning|debug\n");
- 	fprintf(file, "        Write log messages from this level up to syslog. [%s]\n", _syslog_num_to_name(LOG_SYSLOG_PRIO));
- 	fprintf(file, "  --gl-type | -g <str>\n");
-@@ -6063,6 +6056,7 @@ int main(int argc, char *argv[])
- 		{"daemon-debug",    no_argument,       0, 'D' },
- 		{"pid-file",        required_argument, 0, 'p' },
- 		{"socket-path",     required_argument, 0, 's' },
-+		{"adopt-file",      required_argument, 0, 128 },
- 		{"gl-type",         required_argument, 0, 'g' },
- 		{"host-id",         required_argument, 0, 'i' },
- 		{"host-id-file",    required_argument, 0, 'F' },
-@@ -6085,6 +6079,9 @@ int main(int argc, char *argv[])
- 		switch (c) {
- 		case '0':
- 			break;
-+		case 128:
-+			adopt_file = strdup(optarg);
-+			break;
- 		case 'h':
- 			usage(argv[0], stdout);
- 			exit(EXIT_SUCCESS);
-@@ -6146,6 +6143,9 @@ int main(int argc, char *argv[])
- 	if (!ds.socket_path)
- 		ds.socket_path = LVMLOCKD_SOCKET;
- 
-+	if (!adopt_file)
-+		adopt_file = LVMLOCKD_ADOPT_FILE;
-+
- 	/* runs daemon_main/main_loop */
- 	daemon_start(ds);
- 
-diff --git a/daemons/lvmlockd/lvmlockd-dlm.c b/daemons/lvmlockd/lvmlockd-dlm.c
-index 75e6dee..7915cc0 100644
---- a/daemons/lvmlockd/lvmlockd-dlm.c
-+++ b/daemons/lvmlockd/lvmlockd-dlm.c
-@@ -398,12 +398,18 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
- 			  (void *)1, (void *)1, (void *)1,
- 			  NULL, NULL);
- 
--	if (rv == -1 && errno == -EAGAIN) {
-+	if (rv == -1 && (errno == EAGAIN)) {
- 		log_debug("S %s R %s adopt_dlm adopt mode %d try other mode",
- 			  ls->name, r->name, ld_mode);
- 		rv = -EUCLEAN;
- 		goto fail;
- 	}
-+	if (rv == -1 && (errno == ENOENT)) {
-+		log_debug("S %s R %s adopt_dlm adopt mode %d no lock",
-+			  ls->name, r->name, ld_mode);
-+		rv = -ENOENT;
-+		goto fail;
-+	}
- 	if (rv < 0) {
- 		log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d",
- 			  ls->name, r->name, mode, flags, rv, errno);
-diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h
-index 85e8caf..191c449 100644
---- a/daemons/lvmlockd/lvmlockd-internal.h
-+++ b/daemons/lvmlockd/lvmlockd-internal.h
-@@ -11,6 +11,8 @@
- #ifndef _LVM_LVMLOCKD_INTERNAL_H
- #define _LVM_LVMLOCKD_INTERNAL_H
- 
-+#include "base/memory/container_of.h"
-+
- #define MAX_NAME 64
- #define MAX_ARGS 64
- 
-@@ -145,6 +147,7 @@ struct resource {
- 	char name[MAX_NAME+1];		/* vg name or lv name */
- 	int8_t type;			/* resource type LD_RT_ */
- 	int8_t mode;
-+	int8_t adopt_mode;
- 	unsigned int sh_count;		/* number of sh locks on locks list */
- 	uint32_t version;
- 	uint32_t last_client_id;	/* last client_id to lock or unlock resource */
-@@ -216,10 +219,6 @@ struct val_blk {
- /* lm_unlock flags */
- #define LMUF_FREE_VG 0x00000001
- 
--#define container_of(ptr, type, member) ({                      \
--	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
--	(type *)( (char *)__mptr - offsetof(type,member) );})
--
- static inline void INIT_LIST_HEAD(struct list_head *list)
- {
- 	list->next = list;
-diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
-index 2c8c614..6cb5ff0 100644
---- a/lib/cache/lvmcache.c
-+++ b/lib/cache/lvmcache.c
-@@ -49,7 +49,7 @@ struct lvmcache_info {
- 
- /* One per VG */
- struct lvmcache_vginfo {
--	struct dm_list list;	/* Join these vginfos together */
-+	struct dm_list list;	 /* _vginfos */
- 	struct dm_list infos;	/* List head for lvmcache_infos */
- 	struct dm_list outdated_infos; /* vg_read moves info from infos to outdated_infos */
- 	struct dm_list pvsummaries; /* pv_list taken directly from vgsummary */
-@@ -58,7 +58,6 @@ struct lvmcache_vginfo {
- 	uint32_t status;
- 	char vgid[ID_LEN + 1];
- 	char _padding[7];
--	struct lvmcache_vginfo *next; /* Another VG with same name? */
- 	char *creation_host;
- 	char *system_id;
- 	char *lock_type;
-@@ -66,8 +65,16 @@ struct lvmcache_vginfo {
- 	size_t mda_size;
- 	int seqno;
- 	bool scan_summary_mismatch; /* vgsummary from devs had mismatching seqno or checksum */
-+	bool has_duplicate_local_vgname;   /* this local vg and another local vg have same name */
-+	bool has_duplicate_foreign_vgname; /* this foreign vg and another foreign vg have same name */
- };
- 
-+/*
-+ * Each VG found during scan gets a vginfo struct.
-+ * Each vginfo is in _vginfos and _vgid_hash, and
-+ * _vgname_hash (unless disabled due to duplicate vgnames).
-+ */
-+
- static struct dm_hash_table *_pvid_hash = NULL;
- static struct dm_hash_table *_vgid_hash = NULL;
- static struct dm_hash_table *_vgname_hash = NULL;
-@@ -262,16 +269,6 @@ void lvmcache_get_mdas(struct cmd_context *cmd,
- 	}
- }
- 
--static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
--				struct lvmcache_info *info)
--{
--	if (!vginfo)
--		return;
--
--	info->vginfo = vginfo;
--	dm_list_add(&vginfo->infos, &info->list);
--}
--
- static void _vginfo_detach_info(struct lvmcache_info *info)
- {
- 	if (!dm_list_empty(&info->list)) {
-@@ -282,57 +279,80 @@ static void _vginfo_detach_info(struct lvmcache_info *info)
- 	info->vginfo = NULL;
- }
- 
--/* If vgid supplied, require a match. */
--struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid)
-+static struct lvmcache_vginfo *_search_vginfos_list(const char *vgname, const char *vgid)
- {
- 	struct lvmcache_vginfo *vginfo;
- 
--	if (!vgname)
--		return lvmcache_vginfo_from_vgid(vgid);
--
--	if (!_vgname_hash) {
--		log_debug_cache(INTERNAL_ERROR "Internal lvmcache is no yet initialized.");
--		return NULL;
--	}
--
--	if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) {
--		log_debug_cache("lvmcache has no info for vgname \"%s\"%s" FMTVGID ".",
--				vgname, (vgid) ? " with VGID " : "", (vgid) ? : "");
--		return NULL;
--	}
--
--	if (vgid)
--		do
--			if (!strncmp(vgid, vginfo->vgid, ID_LEN))
-+	if (vgid) {
-+		dm_list_iterate_items(vginfo, &_vginfos) {
-+			if (!strcmp(vgid, vginfo->vgid))
- 				return vginfo;
--		while ((vginfo = vginfo->next));
--
--	if  (!vginfo)
--		log_debug_cache("lvmcache has not found vgname \"%s\"%s" FMTVGID ".",
--				vgname, (vgid) ? " with VGID " : "", (vgid) ? : "");
--
--	return vginfo;
-+		}
-+	} else {
-+		dm_list_iterate_items(vginfo, &_vginfos) {
-+			if (!strcmp(vgname, vginfo->vgname))
-+				return vginfo;
-+		}
-+	}
-+	return NULL;
- }
- 
--struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid)
-+static struct lvmcache_vginfo *_vginfo_lookup(const char *vgname, const char *vgid)
- {
- 	struct lvmcache_vginfo *vginfo;
- 	char id[ID_LEN + 1] __attribute__((aligned(8)));
- 
--	if (!_vgid_hash || !vgid) {
--		log_debug_cache(INTERNAL_ERROR "Internal cache cannot lookup vgid.");
--		return NULL;
-+	if (vgid) {
-+		/* vgid not necessarily NULL-terminated */
-+		(void) dm_strncpy(id, vgid, sizeof(id));
-+
-+		if ((vginfo = dm_hash_lookup(_vgid_hash, id))) {
-+			if (vgname && strcmp(vginfo->vgname, vgname)) {
-+				/* should never happen */
-+				log_error(INTERNAL_ERROR "vginfo_lookup vgid %s has two names %s %s",
-+					  id, vginfo->vgname, vgname);
-+				return NULL;
-+			}
-+			return vginfo;
-+		} else {
-+			/* lookup by vgid that doesn't exist */
-+			return NULL;
-+		}
- 	}
- 
--	/* vgid not necessarily NULL-terminated */
--	(void) dm_strncpy(id, vgid, sizeof(id));
-+	if (vgname && !_found_duplicate_vgnames) {
-+		if ((vginfo = dm_hash_lookup(_vgname_hash, vgname))) {
-+			if (vginfo->has_duplicate_local_vgname) {
-+				/* should never happen, found_duplicate_vgnames should be set */
-+				log_error(INTERNAL_ERROR "vginfo_lookup %s %s has_duplicate_local_vgname", vgname, vgid);
-+				return NULL;
-+			}
-+			return vginfo;
-+		}
-+	}
- 
--	if (!(vginfo = dm_hash_lookup(_vgid_hash, id))) {
--		log_debug_cache("lvmcache has no info for vgid \"%s\"", id);
--		return NULL;
-+	if (vgname && _found_duplicate_vgnames) {
-+		if ((vginfo = _search_vginfos_list(vgname, vgid))) {
-+			if (vginfo->has_duplicate_local_vgname) {
-+				log_debug("vginfo_lookup %s %s has_duplicate_local_vgname return none", vgname, vgid);
-+				return NULL;
-+			}
-+			return vginfo;
-+		}
- 	}
- 
--	return vginfo;
-+	/* lookup by vgname that doesn't exist */
-+	return NULL;
-+}
-+
-+struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid)
-+{
-+	return _vginfo_lookup(vgname, vgid);
-+}
-+
-+struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid)
-+{
-+	return _vginfo_lookup(NULL, vgid);
- }
- 
- const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid)
-@@ -353,17 +373,43 @@ const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgnam
- {
- 	struct lvmcache_vginfo *vginfo;
- 
--	if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
--		return_NULL;
-+	if (_found_duplicate_vgnames) {
-+		if (!(vginfo = _search_vginfos_list(vgname, NULL)))
-+			return_NULL;
-+	} else {
-+		if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
-+			return_NULL;
-+	}
- 
--	if (!vginfo->next)
--		return dm_pool_strdup(cmd->mem, vginfo->vgid);
-+	if (vginfo->has_duplicate_local_vgname) {
-+		/*
-+		 * return NULL if there is a local VG with the same name since
-+		 * we don't know which to use.
-+		 */
-+		return NULL;
-+	}
- 
--	/*
--	 * There are multiple VGs with this name to choose from.
--	 * Return an error because we don't know which VG is intended.
--	 */
--	return NULL;
-+	if (vginfo->has_duplicate_foreign_vgname)
-+		return NULL;
-+
-+	return dm_pool_strdup(cmd->mem, vginfo->vgid);
-+}
-+
-+bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname)
-+{
-+	struct lvmcache_vginfo *vginfo;
-+
-+	if (_found_duplicate_vgnames) {
-+		if (!(vginfo = _search_vginfos_list(vgname, vgid)))
-+			return false;
-+	} else {
-+		if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
-+			return false;
-+	}
-+
-+	if (vginfo->has_duplicate_local_vgname)
-+		return true;
-+	return false;
- }
- 
- /*
-@@ -986,15 +1032,6 @@ int lvmcache_label_scan(struct cmd_context *cmd)
- 
- 	log_debug_cache("Finding VG info");
- 
--	/* FIXME: can this happen? */
--	if (!cmd->filter) {
--		log_error("label scan is missing filter");
--		goto out;
--	}
--
--	if (!refresh_filters(cmd))
--		log_error("Scan failed to refresh device filter.");
--
- 	/*
- 	 * Duplicates found during this label scan are added to _initial_duplicates.
- 	 */
-@@ -1057,7 +1094,6 @@ int lvmcache_label_scan(struct cmd_context *cmd)
- 
- 	r = 1;
- 
--      out:
- 	dm_list_iterate_items(vginfo, &_vginfos) {
- 		if (is_orphan_vg(vginfo->vgname))
- 			continue;
-@@ -1148,49 +1184,20 @@ int lvmcache_pvid_in_unused_duplicates(const char *pvid)
- 	return 0;
- }
- 
--static int _free_vginfo(struct lvmcache_vginfo *vginfo)
-+static void _free_vginfo(struct lvmcache_vginfo *vginfo)
- {
--	struct lvmcache_vginfo *primary_vginfo, *vginfo2;
--	int r = 1;
--
--	vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL);
--
--	if (vginfo == primary_vginfo) {
--		dm_hash_remove(_vgname_hash, vginfo->vgname);
--		if (vginfo->next && !dm_hash_insert(_vgname_hash, vginfo->vgname,
--						    vginfo->next)) {
--			log_error("_vgname_hash re-insertion for %s failed",
--				  vginfo->vgname);
--			r = 0;
--		}
--	} else
--		while (vginfo2) {
--			if (vginfo2->next == vginfo) {
--				vginfo2->next = vginfo->next;
--				break;
--			}
--			vginfo2 = vginfo2->next;
--		}
--
--	free(vginfo->system_id);
- 	free(vginfo->vgname);
-+	free(vginfo->system_id);
- 	free(vginfo->creation_host);
--
--	if (*vginfo->vgid && _vgid_hash &&
--	    lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo)
--		dm_hash_remove(_vgid_hash, vginfo->vgid);
--
--	dm_list_del(&vginfo->list);
--
-+	if (vginfo->lock_type)
-+		free(vginfo->lock_type);
- 	free(vginfo);
--
--	return r;
- }
- 
- /*
-- * vginfo must be info->vginfo unless info is NULL
-+ * Remove vginfo from standard lists/hashes.
-  */
--static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo)
-+static void _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo)
- {
- 	if (info)
- 		_vginfo_detach_info(info);
-@@ -1198,12 +1205,16 @@ static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vgin
- 	/* vginfo still referenced? */
- 	if (!vginfo || is_orphan_vg(vginfo->vgname) ||
- 	    !dm_list_empty(&vginfo->infos))
--		return 1;
-+		return;
- 
--	if (!_free_vginfo(vginfo))
--		return_0;
-+	if (dm_hash_lookup(_vgname_hash, vginfo->vgname) == vginfo)
-+		dm_hash_remove(_vgname_hash, vginfo->vgname);
- 
--	return 1;
-+	dm_hash_remove(_vgid_hash, vginfo->vgid);
-+
-+	dm_list_del(&vginfo->list); /* _vginfos list */
-+
-+	_free_vginfo(vginfo);
- }
- 
- void lvmcache_del(struct lvmcache_info *info)
-@@ -1261,180 +1272,150 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info,
- 	return 1;
- }
- 
--static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
--			  uint32_t vgstatus, const char *creation_host,
--			  struct lvmcache_vginfo *primary_vginfo)
-+static int _lvmcache_update_vgname(struct cmd_context *cmd,
-+				   struct lvmcache_info *info,
-+				   const char *vgname, const char *vgid,
-+				   const char *system_id,
-+				   const struct format_type *fmt)
- {
--	struct lvmcache_vginfo *last_vginfo = primary_vginfo;
--	char uuid_primary[64] __attribute__((aligned(8)));
--	char uuid_new[64] __attribute__((aligned(8)));
--	int use_new = 0;
--
--	/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
--	if (primary_vginfo) {
--		if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new)))
--			return_0;
-+	char vgid_str[64] __attribute__((aligned(8)));
-+	char other_str[64] __attribute__((aligned(8)));
-+	struct lvmcache_vginfo *vginfo;
-+	struct lvmcache_vginfo *other;
-+	int vginfo_is_allowed;
-+	int other_is_allowed;
- 
--		if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary,
--				     sizeof(uuid_primary)))
--			return_0;
-+	if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
-+		return 1;
- 
--		_found_duplicate_vgnames = 1;
-+	if (!id_write_format((const struct id *)vgid, vgid_str, sizeof(vgid_str)))
-+		stack;
- 
--		/*
--		 * vginfo is kept for each VG with the same name.
--		 * They are saved with the vginfo->next list.
--		 * These checks just decide the ordering of
--		 * that list.
--		 *
--		 * FIXME: it should no longer matter what order
--		 * the vginfo's are kept in, so we can probably
--		 * remove these comparisons and reordering entirely.
--		 *
--		 * If   Primary not exported, new exported => keep
--		 * Else Primary exported, new not exported => change
--		 * Else Primary has hostname for this machine => keep
--		 * Else Primary has no hostname, new has one => change
--		 * Else New has hostname for this machine => change
--		 * Else Keep primary.
--		 */
--		if (!(primary_vginfo->status & EXPORTED_VG) &&
--		    (vgstatus & EXPORTED_VG))
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "Existing %s takes precedence over "
--				    "exported %s", new_vginfo->vgname,
--				    uuid_primary, uuid_new);
--		else if ((primary_vginfo->status & EXPORTED_VG) &&
--			   !(vgstatus & EXPORTED_VG)) {
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "%s takes precedence over exported %s",
--				    new_vginfo->vgname, uuid_new,
--				    uuid_primary);
--			use_new = 1;
--		} else if (primary_vginfo->creation_host &&
--			   !strcmp(primary_vginfo->creation_host,
--				   primary_vginfo->fmt->cmd->hostname))
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "Existing %s (created here) takes precedence "
--				    "over %s", new_vginfo->vgname, uuid_primary,
--				    uuid_new);
--		else if (!primary_vginfo->creation_host && creation_host) {
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "%s (with creation_host) takes precedence over %s",
--				    new_vginfo->vgname, uuid_new,
--				    uuid_primary);
--			use_new = 1;
--		} else if (creation_host &&
--			   !strcmp(creation_host,
--				   primary_vginfo->fmt->cmd->hostname)) {
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "%s (created here) takes precedence over %s",
--				    new_vginfo->vgname, uuid_new,
--				    uuid_primary);
--			use_new = 1;
--		} else {
--			log_verbose("Cache: Duplicate VG name %s: "
--				    "Prefer existing %s vs new %s",
--				    new_vginfo->vgname, uuid_primary, uuid_new);
-+	/*
-+	 * Add vginfo for orphan VG
-+	 */
-+	if (!info) {
-+		if (!(vginfo = zalloc(sizeof(*vginfo)))) {
-+			log_error("lvmcache adding vg list alloc failed %s", vgname);
-+			return 0;
- 		}
--
--		if (!use_new) {
--			while (last_vginfo->next)
--				last_vginfo = last_vginfo->next;
--			last_vginfo->next = new_vginfo;
--			return 1;
-+		if (!(vginfo->vgname = strdup(vgname))) {
-+			free(vginfo);
-+			log_error("lvmcache adding vg name alloc failed %s", vgname);
-+			return 0;
- 		}
-+		dm_list_init(&vginfo->infos);
-+		dm_list_init(&vginfo->outdated_infos);
-+		dm_list_init(&vginfo->pvsummaries);
-+		vginfo->fmt = fmt;
- 
--		dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
--	}
--
--	if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
--		log_error("cache_update: vg hash insertion failed: %s",
--		  	new_vginfo->vgname);
--		return 0;
--	}
--
--	if (primary_vginfo)
--		new_vginfo->next = primary_vginfo;
--
--	return 1;
--}
-+		if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) {
-+			free(vginfo->vgname);
-+			free(vginfo);
-+			return_0;
-+		}
- 
--static int _lvmcache_update_vgname(struct lvmcache_info *info,
--				   const char *vgname, const char *vgid,
--				   uint32_t vgstatus, const char *creation_host,
--				   const struct format_type *fmt)
--{
--	struct lvmcache_vginfo *vginfo, *primary_vginfo;
--	char mdabuf[32];
-+		if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) {
-+			free(vginfo->vgname);
-+			free(vginfo);
-+			return_0;
-+		}
- 
--	if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
-+		/* Ensure orphans appear last on list_iterate */
-+		dm_list_add(&_vginfos, &vginfo->list);
- 		return 1;
-+	}
- 
--	/* Remove existing vginfo entry */
--	if (info)
--		_drop_vginfo(info, info->vginfo);
-+	_drop_vginfo(info, info->vginfo);
- 
--	if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
-+	if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) {
- 		/*
- 	 	 * Create a vginfo struct for this VG and put the vginfo
- 	 	 * into the hash table.
- 	 	 */
- 
-+		log_debug_cache("lvmcache adding vginfo for %s %s", vgname, vgid_str);
-+
- 		if (!(vginfo = zalloc(sizeof(*vginfo)))) {
--			log_error("lvmcache_update_vgname: list alloc failed");
-+			log_error("lvmcache adding vg list alloc failed %s", vgname);
- 			return 0;
- 		}
- 		if (!(vginfo->vgname = strdup(vgname))) {
- 			free(vginfo);
--			log_error("cache vgname alloc failed for %s", vgname);
-+			log_error("lvmcache adding vg name alloc failed %s", vgname);
- 			return 0;
- 		}
- 		dm_list_init(&vginfo->infos);
- 		dm_list_init(&vginfo->outdated_infos);
- 		dm_list_init(&vginfo->pvsummaries);
- 
--		/*
--		 * A different VG (different uuid) can exist with the same name.
--		 * In this case, the two VGs will have separate vginfo structs,
--		 * but the second will be linked onto the existing vginfo->next,
--		 * not in the hash.
--		 */
--		primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL);
-+		if ((other = dm_hash_lookup(_vgname_hash, vgname))) {
-+			log_debug_cache("lvmcache adding vginfo found duplicate VG name %s", vgname);
- 
--		if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host, primary_vginfo)) {
--			free(vginfo->vgname);
--			free(vginfo);
--			return 0;
-+			/*
-+			 * A different VG (different uuid) can exist with the
-+			 * same name.  In this case, the two VGs will have
-+			 * separate vginfo structs, but one will be in the
-+			 * vgname_hash.  If both vginfos are local/accessible,
-+			 * then _found_duplicate_vgnames is set which will
-+			 * disable any further use of the vgname_hash.
-+			 */
-+
-+			if (!memcmp(other->vgid, vgid, ID_LEN)) {
-+				/* shouldn't happen since we looked up by vgid above */
-+				log_error(INTERNAL_ERROR "lvmcache_update_vgname %s %s %s %s",
-+					  vgname, vgid_str, other->vgname, other->vgid);
-+				free(vginfo->vgname);
-+				free(vginfo);
-+				return 0;
-+			}
-+
-+			vginfo_is_allowed = is_system_id_allowed(cmd, system_id);
-+			other_is_allowed = is_system_id_allowed(cmd, other->system_id);
-+
-+			if (vginfo_is_allowed && other_is_allowed) {
-+				if (!id_write_format((const struct id *)other->vgid, other_str, sizeof(other_str)))
-+					stack;
-+
-+				vginfo->has_duplicate_local_vgname = 1;
-+				other->has_duplicate_local_vgname = 1;
-+				_found_duplicate_vgnames = 1;
-+
-+				log_warn("WARNING: VG name %s is used by VGs %s and %s.",
-+					 vgname, vgid_str, other_str);
-+				log_warn("Fix duplicate VG names with vgrename uuid, a device filter, or system IDs.");
-+			}
-+
-+			if (!vginfo_is_allowed && !other_is_allowed) {
-+				vginfo->has_duplicate_foreign_vgname = 1;
-+				other->has_duplicate_foreign_vgname = 1;
-+			}
-+
-+			if (!other_is_allowed && vginfo_is_allowed) {
-+				/* the accessible vginfo must be in vgnames_hash */
-+				dm_hash_remove(_vgname_hash, vgname);
-+				if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) {
-+					log_error("lvmcache adding vginfo to name hash failed %s", vgname);
-+					return 0;
-+				}
-+			}
-+		} else {
-+			if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) {
-+				log_error("lvmcache adding vg to name hash failed %s", vgname);
-+				free(vginfo->vgname);
-+				free(vginfo);
-+				return 0;
-+			}
- 		}
- 
--		/* Ensure orphans appear last on list_iterate */
--		if (is_orphan_vg(vgname))
--			dm_list_add(&_vginfos, &vginfo->list);
--		else
--			dm_list_add_h(&_vginfos, &vginfo->list);
-+		dm_list_add_h(&_vginfos, &vginfo->list);
- 	}
- 
--	if (info)
--		_vginfo_attach_info(vginfo, info);
--	else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */
--		return_0;
--
--	/* FIXME Check consistency of list! */
- 	vginfo->fmt = fmt;
-+	info->vginfo = vginfo;
-+	dm_list_add(&vginfo->infos, &info->list);
- 
--	if (info) {
--		if (info->mdas.n)
--			sprintf(mdabuf, " with %u mda(s)", dm_list_size(&info->mdas));
--		else
--			mdabuf[0] = '\0';
--		log_debug_cache("lvmcache %s: now in VG %s%s%s%s%s.",
--				dev_name(info->dev),
--				vgname, vginfo->vgid[0] ? " (" : "",
--				vginfo->vgid[0] ? vginfo->vgid : "",
--				vginfo->vgid[0] ? ")" : "", mdabuf);
--	} else
--		log_debug_cache("lvmcache: Initialised VG %s.", vgname);
-+	log_debug_cache("lvmcache %s: now in VG %s %s", dev_name(info->dev), vgname, vgid_str);
- 
- 	return 1;
- }
-@@ -1511,9 +1492,9 @@ out:
- 	return 1;
- }
- 
--int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
-+int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt)
- {
--	return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
-+	return _lvmcache_update_vgname(cmd, NULL, vgname, vgname, "", fmt);
- }
- 
- static void _lvmcache_update_pvsummaries(struct lvmcache_vginfo *vginfo, struct lvmcache_vgsummary *vgsummary)
-@@ -1532,7 +1513,7 @@ static void _lvmcache_update_pvsummaries(struct lvmcache_vginfo *vginfo, struct
-  * Returning 0 causes the caller to remove the info struct for this
-  * device from lvmcache, which will make it look like a missing device.
-  */
--int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
-+int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
- {
- 	const char *vgname = vgsummary->vgname;
- 	const char *vgid = (char *)&vgsummary->vgid;
-@@ -1545,6 +1526,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
- 		vgid = vgname;
- 	}
- 
-+	/* FIXME: remove this, it shouldn't be needed */
- 	/* If PV without mdas is already in a real VG, don't make it orphan */
- 	if (is_orphan_vg(vgname) && info->vginfo &&
- 	    mdas_empty_or_ignored(&info->mdas) &&
-@@ -1556,7 +1538,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
- 	 * and attaches the info struct for the dev to the vginfo.
- 	 * Puts the vginfo into the vgname hash table.
- 	 */
--	if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus, vgsummary->creation_host, info->fmt)) {
-+	if (!_lvmcache_update_vgname(cmd, info, vgname, vgid, vgsummary->system_id, info->fmt)) {
- 		/* shouldn't happen, internal error */
- 		log_error("Failed to update VG %s info in lvmcache.", vgname);
- 		return 0;
-@@ -1735,7 +1717,7 @@ int lvmcache_update_vg_from_write(struct volume_group *vg)
- 		(void) dm_strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s));
- 		/* FIXME Could pvl->pv->dev->pvid ever be different? */
- 		if ((info = lvmcache_info_from_pvid(pvid_s, pvl->pv->dev, 0)) &&
--		    !lvmcache_update_vgname_and_id(info, &vgsummary))
-+		    !lvmcache_update_vgname_and_id(vg->cmd, info, &vgsummary))
- 			return_0;
- 	}
- 
-@@ -1819,7 +1801,7 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
- 		 * info's for PVs without metadata were not connected to the
- 		 * vginfo by label_scan, so do it here.
- 		 */
--		if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
-+		if (!lvmcache_update_vgname_and_id(vg->cmd, info, &vgsummary)) {
- 			log_debug_cache("lvmcache_update_vg %s failed to update info for %s",
- 					vg->name, dev_name(info->dev));
- 		}
-@@ -1927,7 +1909,7 @@ static struct lvmcache_info * _create_info(struct labeller *labeller, struct dev
- 	return info;
- }
- 
--struct lvmcache_info *lvmcache_add(struct labeller *labeller,
-+struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller,
- 				   const char *pvid, struct device *dev, uint64_t label_sector,
- 				   const char *vgname, const char *vgid, uint32_t vgstatus,
- 				   int *is_duplicate)
-@@ -2042,7 +2024,7 @@ update_vginfo:
- 	if (vgid)
- 		strncpy((char *)&vgsummary.vgid, vgid, sizeof(vgsummary.vgid));
- 
--	if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
-+	if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) {
- 		if (created) {
- 			dm_hash_remove(_pvid_hash, pvid_s);
- 			strcpy(info->dev->pvid, "");
-@@ -2055,7 +2037,7 @@ update_vginfo:
- 	return info;
- }
- 
--static void _lvmcache_destroy_entry(struct lvmcache_info *info)
-+static void _lvmcache_destroy_info(struct lvmcache_info *info)
- {
- 	_vginfo_detach_info(info);
- 	info->dev->pvid[0] = 0;
-@@ -2063,20 +2045,11 @@ static void _lvmcache_destroy_entry(struct lvmcache_info *info)
- 	free(info);
- }
- 
--static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
--{
--	struct lvmcache_vginfo *next;
--
--	do {
--		next = vginfo->next;
--		if (!_free_vginfo(vginfo))
--			stack;
--	} while ((vginfo = next));
--}
--
- void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
- {
--	log_debug_cache("Dropping VG info");
-+	struct lvmcache_vginfo *vginfo, *vginfo2;
-+
-+	log_debug_cache("Destroy lvmcache content");
- 
- 	if (_vgid_hash) {
- 		dm_hash_destroy(_vgid_hash);
-@@ -2084,20 +2057,24 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
- 	}
- 
- 	if (_pvid_hash) {
--		dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_entry);
-+		dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_info);
- 		dm_hash_destroy(_pvid_hash);
- 		_pvid_hash = NULL;
- 	}
- 
- 	if (_vgname_hash) {
--		dm_hash_iter(_vgname_hash,
--			  (dm_hash_iterate_fn) _lvmcache_destroy_vgnamelist);
- 		dm_hash_destroy(_vgname_hash);
- 		_vgname_hash = NULL;
- 	}
- 
-+	dm_list_iterate_items_safe(vginfo, vginfo2, &_vginfos) {
-+		dm_list_del(&vginfo->list);
-+		_free_vginfo(vginfo);
-+	}
-+
- 	if (!dm_list_empty(&_vginfos))
--		log_error(INTERNAL_ERROR "_vginfos list should be empty");
-+		log_error(INTERNAL_ERROR "vginfos list should be empty");
-+
- 	dm_list_init(&_vginfos);
- 
- 	/*
-@@ -2109,6 +2086,8 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
- 	 * We want the same preferred devices to be chosen each time, so save
- 	 * the unpreferred devs here so that _choose_preferred_devs can use
- 	 * this to make the same choice each time.
-+	 *
-+	 * FIXME: I don't think is is needed any more.
- 	 */
- 	_destroy_device_list(&_prev_unused_duplicate_devs);
- 	dm_list_splice(&_prev_unused_duplicate_devs, &_unused_duplicates);
-@@ -2122,7 +2101,7 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
- 			stack;
- 
- 		dm_list_iterate_items(fmt, &cmd->formats) {
--			if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt))
-+			if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt))
- 				stack;
- 		}
- 	}
-@@ -2567,36 +2546,6 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid)
- 	return 0;
- }
- 
--struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd,
--				       const char *vgname,
--				       struct device *dev,
--				       int use_mda_num)
--{
--	struct lvmcache_vginfo *vginfo;
--	struct lvmcache_info *info;
--	struct metadata_area *mda;
--
--	if (!use_mda_num)
--		use_mda_num = 1;
--
--	if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
--		return NULL;
--
--	dm_list_iterate_items(info, &vginfo->infos) {
--		if (info->dev != dev)
--			continue;
--
--		dm_list_iterate_items(mda, &info->mdas) {
--			if ((use_mda_num == 1) && (mda->status & MDA_PRIMARY))
--				return mda;
--			if ((use_mda_num == 2) && !(mda->status & MDA_PRIMARY))
--				return mda;
--		}
--		return NULL;
--	}
--	return NULL;
--}
--
- /*
-  * This is used by the metadata repair command to check if
-  * the metadata on a dev needs repair because it's old.
-diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
-index 0c8c789..6cef4d1 100644
---- a/lib/cache/lvmcache.h
-+++ b/lib/cache/lvmcache.h
-@@ -71,16 +71,16 @@ int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const
- int lvmcache_label_rescan_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid);
- 
- /* Add/delete a device */
--struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
-+struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller, const char *pvid,
-                                    struct device *dev, uint64_t label_sector,
-                                    const char *vgname, const char *vgid,
-                                    uint32_t vgstatus, int *is_duplicate);
--int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt);
-+int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt);
- void lvmcache_del(struct lvmcache_info *info);
- void lvmcache_del_dev(struct device *dev);
- 
- /* Update things */
--int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
-+int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info,
- 				  struct lvmcache_vgsummary *vgsummary);
- int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted);
- int lvmcache_update_vg_from_write(struct volume_group *vg);
-@@ -161,11 +161,6 @@ struct device *lvmcache_device(struct lvmcache_info *info);
- unsigned lvmcache_mda_count(struct lvmcache_info *info);
- uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
- 
--struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd,
--                                      const char *vgname,
--                                      struct device *dev,
--                                      int use_mda_num);
--
- bool lvmcache_has_duplicate_devs(void);
- void lvmcache_del_dev_from_duplicates(struct device *dev);
- bool lvmcache_dev_is_unused_duplicate(struct device *dev);
-@@ -174,6 +169,7 @@ int lvmcache_get_unused_duplicates(struct cmd_context *cmd, struct dm_list *head
- int vg_has_duplicate_pvs(struct volume_group *vg);
- 
- int lvmcache_found_duplicate_vgnames(void);
-+bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname);
- 
- int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
- 
-diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
-index 88d5b3e..63b6811 100644
---- a/lib/commands/toolcontext.c
-+++ b/lib/commands/toolcontext.c
-@@ -1276,7 +1276,7 @@ int init_lvmcache_orphans(struct cmd_context *cmd)
- 	struct format_type *fmt;
- 
- 	dm_list_iterate_items(fmt, &cmd->formats)
--		if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt))
-+		if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt))
- 			return_0;
- 
- 	return 1;
-@@ -1598,6 +1598,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
- 	dm_list_init(&cmd->formats);
- 	dm_list_init(&cmd->segtypes);
- 	dm_list_init(&cmd->tags);
-+	dm_list_init(&cmd->hints);
- 	dm_list_init(&cmd->config_files);
- 	label_init();
- 
-diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
-index 735441f..33b9345 100644
---- a/lib/device/dev-io.c
-+++ b/lib/device/dev-io.c
-@@ -86,6 +86,9 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
- 	int fd = dev->bcache_fd;
- 	int do_close = 0;
- 
-+	if (dm_list_empty(&dev->aliases))
-+		return 0;
-+
- 	if (dev->size_seqno == _dev_size_seqno) {
- 		log_very_verbose("%s: using cached size %" PRIu64 " sectors",
- 				 name, dev->size);
-diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
-index 3a741da..733e62b 100644
---- a/lib/format_text/archiver.c
-+++ b/lib/format_text/archiver.c
-@@ -315,7 +315,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
- 	}
- 
- 	dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
--		if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL)))
-+		if (!(vg = mda->ops->vg_read(cmd, tf, vg_name, mda, NULL, NULL)))
- 			stack;
- 		break;
- 	}
-diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
-index 268bd64..e448712 100644
---- a/lib/format_text/format-text.c
-+++ b/lib/format_text/format-text.c
-@@ -290,7 +290,8 @@ static int _raw_write_mda_header(const struct format_type *fmt,
-  * in the label scanning path.
-  */
- 
--static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
-+static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
-+				       struct device_area *dev_area,
- 				       struct mda_header *mdah, int primary_mda,
- 				       const char *vgname,
- 				       int *precommitted)
-@@ -369,7 +370,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
- 		  vgnamebuf, vgname);
- 
- 	if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
--	    !lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
-+	    !lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan))
- 		stack;
- 
- 	return NULL;
-@@ -447,7 +448,8 @@ static uint64_t _next_rlocn_offset(struct volume_group *vg, struct raw_locn *rlo
- 	return new_start;
- }
- 
--static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
-+static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
-+					      struct format_instance *fid,
- 					      const char *vgname,
- 					      struct device_area *area,
- 					      struct cached_vg_fmtdata **vg_fmtdata,
-@@ -468,7 +470,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
- 		goto out;
- 	}
- 
--	if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) {
-+	if (!(rlocn = _read_metadata_location_vg(cmd, area, mdah, primary_mda, vgname, &precommitted))) {
- 		log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev));
- 		goto out;
- 	}
-@@ -503,7 +505,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
- 	return vg;
- }
- 
--static struct volume_group *_vg_read_raw(struct format_instance *fid,
-+static struct volume_group *_vg_read_raw(struct cmd_context *cmd,
-+					 struct format_instance *fid,
- 					 const char *vgname,
- 					 struct metadata_area *mda,
- 					 struct cached_vg_fmtdata **vg_fmtdata,
-@@ -512,12 +515,13 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
- 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
- 	struct volume_group *vg;
- 
--	vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
-+	vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
- 
- 	return vg;
- }
- 
--static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
-+static struct volume_group *_vg_read_precommit_raw(struct cmd_context *cmd,
-+						   struct format_instance *fid,
- 						   const char *vgname,
- 						   struct metadata_area *mda,
- 						   struct cached_vg_fmtdata **vg_fmtdata,
-@@ -526,7 +530,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
- 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
- 	struct volume_group *vg;
- 
--	vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
-+	vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
- 
- 	return vg;
- }
-@@ -1321,7 +1325,7 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
- 	return vg;
- }
- 
--static struct volume_group *_vg_read_file(struct format_instance *fid,
-+static struct volume_group *_vg_read_file(struct cmd_context *cmd, struct format_instance *fid,
- 					  const char *vgname,
- 					  struct metadata_area *mda,
- 					  struct cached_vg_fmtdata **vg_fmtdata,
-@@ -1332,7 +1336,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
- 	return _vg_read_file_name(fid, vgname, tc->path_live);
- }
- 
--static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
-+static struct volume_group *_vg_read_precommit_file(struct cmd_context *cmd, struct format_instance *fid,
- 						    const char *vgname,
- 						    struct metadata_area *mda,
- 						    struct cached_vg_fmtdata **vg_fmtdata,
-@@ -1713,7 +1717,7 @@ static int _set_ext_flags(struct physical_volume *pv, struct lvmcache_info *info
- }
- 
- /* Only for orphans - FIXME That's not true any more */
--static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv)
-+static int _text_pv_write(struct cmd_context *cmd, const struct format_type *fmt, struct physical_volume *pv)
- {
- 	struct format_instance *fid = pv->fid;
- 	const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id);
-@@ -1725,7 +1729,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
- 	unsigned mda_index;
- 
- 	/* Add a new cache entry with PV info or update existing one. */
--	if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id,
-+	if (!(info = lvmcache_add(cmd, fmt->labeller, (const char *) &pv->id,
- 				  pv->dev,  pv->label_sector, pv->vg_name,
- 				  is_orphan_vg(pv->vg_name) ? pv->vg_name : pv->vg ? (const char *) &pv->vg->id : NULL, 0, NULL)))
- 		return_0;
-diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
-index 9241eca..1674126 100644
---- a/lib/format_text/text_label.c
-+++ b/lib/format_text/text_label.c
-@@ -370,7 +370,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
-  * the metadata is at for those PVs.
-  */
- 
--static int _text_read(struct labeller *labeller, struct device *dev, void *label_buf,
-+static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct device *dev, void *label_buf,
- 		      uint64_t label_sector, int *is_duplicate)
- {
- 	struct lvmcache_vgsummary vgsummary;
-@@ -410,7 +410,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
- 	 *
- 	 * Other reasons for lvmcache_add to return NULL are internal errors.
- 	 */
--	if (!(info = lvmcache_add(labeller, (char *)pvhdr->pv_uuid, dev, label_sector,
-+	if (!(info = lvmcache_add(cmd, labeller, (char *)pvhdr->pv_uuid, dev, label_sector,
- 				  FMT_TEXT_ORPHAN_VG_NAME,
- 				  FMT_TEXT_ORPHAN_VG_NAME, 0, is_duplicate)))
- 		return_0;
-@@ -503,7 +503,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
- 		rv1 = _read_mda_header_and_metadata(fmt, mda1, &vgsummary, &bad_fields);
- 
- 		if (rv1 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
--			if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
-+			if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) {
- 				/* I believe this is only an internal error. */
- 
- 				dm_list_del(&mda1->list);
-@@ -554,7 +554,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label
- 		rv2 = _read_mda_header_and_metadata(fmt, mda2, &vgsummary, &bad_fields);
- 
- 		if (rv2 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
--			if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
-+			if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) {
- 				dm_list_del(&mda2->list);
- 
- 				/* Are there other cases besides mismatch and internal error? */
-diff --git a/lib/label/hints.c b/lib/label/hints.c
-index 48fb661..9546f48 100644
---- a/lib/label/hints.c
-+++ b/lib/label/hints.c
-@@ -351,6 +351,7 @@ static void _unlock_hints(struct cmd_context *cmd)
- 
- void hints_exit(struct cmd_context *cmd)
- {
-+	free_hints(&cmd->hints);
- 	if (_hints_fd == -1)
- 		return;
- 	return _unlock_hints(cmd);
-@@ -419,6 +420,9 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev)
- {
- 	uint64_t devsize = 0;
- 
-+	if (dm_list_empty(&dev->aliases))
-+		return 0;
-+
- 	if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "regex"))
- 		return 0;
- 
-@@ -1318,6 +1322,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
- 	 */
- 	if (!_read_hint_file(cmd, &hints_list, &needs_refresh)) {
- 		log_debug("get_hints: read fail");
-+		free_hints(&hints_list);
- 		_unlock_hints(cmd);
- 		return 0;
- 	}
-@@ -1330,6 +1335,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
- 	 */
- 	if (needs_refresh) {
- 		log_debug("get_hints: needs refresh");
-+		free_hints(&hints_list);
- 
- 		if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
- 			return 0;
-diff --git a/lib/label/label.c b/lib/label/label.c
-index 0458313..4d37cef 100644
---- a/lib/label/label.c
-+++ b/lib/label/label.c
-@@ -431,7 +431,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
- 	 * info/vginfo structs.  That lvmcache info is used later when the
- 	 * command wants to read the VG to do something to it.
- 	 */
--	ret = labeller->ops->read(labeller, dev, label_buf, sector, &is_duplicate);
-+	ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate);
- 
- 	if (!ret) {
- 		if (is_duplicate) {
-diff --git a/lib/label/label.h b/lib/label/label.h
-index 4108906..9a4b630 100644
---- a/lib/label/label.h
-+++ b/lib/label/label.h
-@@ -64,7 +64,7 @@ struct label_ops {
- 	/*
- 	 * Read a label from a volume.
- 	 */
--	int (*read) (struct labeller * l, struct device * dev,
-+	int (*read) (struct cmd_context *cmd, struct labeller * l, struct device * dev,
- 		     void *label_buf, uint64_t label_sector, int *is_duplicate);
- 
- 	/*
-diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
-index e378fe6..dca7954 100644
---- a/lib/locking/lvmlockd.c
-+++ b/lib/locking/lvmlockd.c
-@@ -635,7 +635,6 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
- 	const char *vg_lock_args = NULL;
- 	const char *opts = NULL;
- 	struct pv_list *pvl;
--	struct device *sector_dev;
- 	uint32_t sector_size = 0;
- 	unsigned int physical_block_size, logical_block_size;
- 	int num_mb = 0;
-@@ -656,16 +655,11 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
- 	dm_list_iterate_items(pvl, &vg->pvs) {
- 		if (!dev_get_direct_block_sizes(pvl->pv->dev, &physical_block_size, &logical_block_size))
- 			continue;
--
--		if (!sector_size) {
--			sector_size = logical_block_size;
--			sector_dev = pvl->pv->dev;
--		} else if (sector_size != logical_block_size) {
--			log_error("Inconsistent logical block sizes for %s and %s.",
--				  dev_name(pvl->pv->dev), dev_name(sector_dev));
--			return 0;
--		}
-+		if ((physical_block_size == 4096) || (logical_block_size == 4096))
-+			sector_size = 4096;
- 	}
-+	if (!sector_size)
-+		sector_size = 512;
- 
- 	log_debug("Using sector size %u for sanlock LV", sector_size);
- 
-diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
-index 52bc776..083f74a 100644
---- a/lib/metadata/metadata-exported.h
-+++ b/lib/metadata/metadata-exported.h
-@@ -744,9 +744,6 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_
- 			 const char *vgid, uint32_t read_flags, uint32_t lockd_state);
- struct volume_group *vg_read_orphans(struct cmd_context *cmd, const char *orphan_vgname);
- 
--/* this is historical and being removed, don't use */
--uint32_t vg_read_error(struct volume_group *vg_handle);
--
- /* pe_start and pe_end relate to any existing data so that new metadata
- * areas can avoid overlap */
- struct physical_volume *pv_create(const struct cmd_context *cmd,
-diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
-index 9c44388..4b8dce9 100644
---- a/lib/metadata/metadata.c
-+++ b/lib/metadata/metadata.c
-@@ -3666,7 +3666,7 @@ int pv_write(struct cmd_context *cmd,
- 		return 0;
- 	}
- 
--	if (!pv->fmt->ops->pv_write(pv->fmt, pv))
-+	if (!pv->fmt->ops->pv_write(cmd, pv->fmt, pv))
- 		return_0;
- 
- 	pv->status &= ~UNLABELLED_PV;
-@@ -4010,17 +4010,6 @@ static int _access_vg_exported(struct cmd_context *cmd, struct volume_group *vg)
- 	return 0;
- }
- 
--/*
-- * Test the validity of a VG handle returned by vg_read() or vg_read_for_update().
-- */
--uint32_t vg_read_error(struct volume_group *vg_handle)
--{
--	if (!vg_handle)
--		return FAILED_ALLOCATION;
--
--	return SUCCESS;
--}
--
- struct format_instance *alloc_fid(const struct format_type *fmt,
- 				  const struct format_instance_ctx *fic)
- {
-@@ -4751,18 +4740,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
- 			lvmcache_label_rescan_vg(cmd, vgname, vgid);
- 	}
- 
--	/* Now determine the correct vgname if none was supplied */
--	if (!vgname && !(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
--		log_debug_metadata("Cache did not find VG name from vgid %s", vgid);
--		return NULL;
--	}
--
--	/* Determine the correct vgid if none was supplied */
--	if (!vgid && !(vgid = lvmcache_vgid_from_vgname(cmd, vgname))) {
--		log_debug_metadata("Cache did not find VG vgid from name %s", vgname);
--		return NULL;
--	}
--
- 	/*
- 	 * A "format instance" is an abstraction for a VG location,
- 	 * i.e. where a VG's metadata exists on disk.
-@@ -4841,7 +4818,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
- 			log_debug_metadata("Reading VG %s precommit metadata from %s %llu",
- 				 vgname, dev_name(mda_dev), (unsigned long long)mda->header_start);
- 
--			vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg);
-+			vg = mda->ops->vg_read_precommit(cmd, fid, vgname, mda, &vg_fmtdata, &use_previous_vg);
- 
- 			if (!vg && !use_previous_vg) {
- 				log_warn("WARNING: Reading VG %s precommit on %s failed.", vgname, dev_name(mda_dev));
-@@ -4852,7 +4829,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
- 			log_debug_metadata("Reading VG %s metadata from %s %llu",
- 				 vgname, dev_name(mda_dev), (unsigned long long)mda->header_start);
- 
--			vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg);
-+			vg = mda->ops->vg_read(cmd, fid, vgname, mda, &vg_fmtdata, &use_previous_vg);
- 
- 			if (!vg && !use_previous_vg) {
- 				log_warn("WARNING: Reading VG %s on %s failed.", vgname, dev_name(mda_dev));
-@@ -4999,6 +4976,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
- 	int missing_pv_dev = 0;
- 	int missing_pv_flag = 0;
- 	uint32_t failure = 0;
-+	int original_vgid_set = vgid ? 1 : 0;
- 	int writing = (vg_read_flags & READ_FOR_UPDATE);
- 	int activating = (vg_read_flags & READ_FOR_ACTIVATE);
- 
-@@ -5033,7 +5011,45 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
- 		goto bad;
- 	}
- 
-+	/* I belive this is unused, the name is always set. */
-+	if (!vg_name && !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
-+		unlock_vg(cmd, NULL, vg_name);
-+		log_error("VG name not found for vgid %s", vgid);
-+		failure |= FAILED_NOTFOUND;
-+		goto_bad;
-+	}
-+
-+	/*
-+	 * If the command is process all vgs, process_each will get a list of vgname+vgid
-+	 * pairs, and then call vg_read() for each vgname+vigd.  In this case we know
-+	 * which VG to read even if there are duplicate names, and we don't fail.
-+	 *
-+	 * If the user has requested one VG by name, process_each passes only the vgname
-+	 * to vg_read(), and we look up the vgid from lvmcache.  lvmcache finds duplicate
-+	 * vgnames, doesn't know which is intended, returns a NULL vgid, and we fail.
-+	 */
-+
-+	if (!vgid)
-+		vgid = lvmcache_vgid_from_vgname(cmd, vg_name);
-+
-+	if (!vgid) {
-+		unlock_vg(cmd, NULL, vg_name);
-+		/* Some callers don't care if the VG doesn't exist and don't want an error message. */
-+		if (!(vg_read_flags & READ_OK_NOTFOUND))
-+			log_error("Volume group \"%s\" not found", vg_name);
-+		failure |= FAILED_NOTFOUND;
-+		goto_bad;
-+	}
-+
-+	/*
-+	 * vgchange -ay (no vgname arg) will activate multiple local VGs with the same
-+	 * name, but if the vgs have the same lv name, activating those lvs will fail.
-+	 */
-+	if (activating && original_vgid_set && lvmcache_has_duplicate_local_vgname(vgid, vg_name))
-+		log_warn("WARNING: activating multiple VGs with the same name is dangerous and may fail.");
-+
- 	if (!(vg = _vg_read(cmd, vg_name, vgid, 0, writing))) {
-+		unlock_vg(cmd, NULL, vg_name);
- 		/* Some callers don't care if the VG doesn't exist and don't want an error message. */
- 		if (!(vg_read_flags & READ_OK_NOTFOUND))
- 			log_error("Volume group \"%s\" not found.", vg_name);
-diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
-index f199fc4..2c22450 100644
---- a/lib/metadata/metadata.h
-+++ b/lib/metadata/metadata.h
-@@ -76,12 +76,14 @@ struct cached_vg_fmtdata;
- /* Per-format per-metadata area operations */
- struct metadata_area_ops {
- 	struct dm_list list;
--	struct volume_group *(*vg_read) (struct format_instance * fi,
-+	struct volume_group *(*vg_read) (struct cmd_context *cmd,
-+					 struct format_instance * fi,
- 					 const char *vg_name,
- 					 struct metadata_area * mda,
- 					 struct cached_vg_fmtdata **vg_fmtdata,
- 					 unsigned *use_previous_vg);
--	struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
-+	struct volume_group *(*vg_read_precommit) (struct cmd_context *cmd,
-+					 struct format_instance * fi,
- 					 const char *vg_name,
- 					 struct metadata_area * mda,
- 					 struct cached_vg_fmtdata **vg_fmtdata,
-@@ -326,7 +328,7 @@ struct format_handler {
- 	 * Write a PV structure to disk. Fails if the PV is in a VG ie
- 	 * pv->vg_name must be a valid orphan VG name
- 	 */
--	int (*pv_write) (const struct format_type * fmt,
-+	int (*pv_write) (struct cmd_context *cmd, const struct format_type * fmt,
- 			 struct physical_volume * pv);
- 
- 	/*
-diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main
-index 8ed5400..c21f7a9 100644
---- a/man/lvmlockd.8_main
-+++ b/man/lvmlockd.8_main
-@@ -58,6 +58,10 @@ For default settings, see lvmlockd -h.
- .I path
-         Set path to the socket to listen on.
- 
-+.B  --adopt-file
-+.I path
-+        Set path to the adopt file.
-+
- .B  --syslog-priority | -S err|warning|debug
-         Write log messages from this level up to syslog.
- 
-@@ -76,6 +80,8 @@ For default settings, see lvmlockd -h.
- .I seconds
-         Override the default sanlock I/O timeout.
- 
-+.B --adopt | -A 0|1
-+        Enable (1) or disable (0) lock adoption.
- 
- .SH USAGE
- 
-@@ -548,7 +554,13 @@ necessary locks.
- .B lvmlockd failure
- 
- If lvmlockd fails or is killed while holding locks, the locks are orphaned
--in the lock manager.
-+in the lock manager.  Orphaned locks must be cleared or adopted before the
-+associated resources can be accessed normally.  If lock adoption is
-+enabled, lvmlockd keeps a record of locks in the adopt-file.  A subsequent
-+instance of lvmlockd will then adopt locks orphaned by the previous
-+instance.  Adoption must be enabled in both instances (--adopt|-A 1).
-+Without adoption, the lock manager or host would require a reset to clear
-+orphaned lock state.
- 
- .B dlm/corosync failure
- 
-diff --git a/test/shell/duplicate-vgnames.sh b/test/shell/duplicate-vgnames.sh
-new file mode 100644
-index 0000000..0f98f9c
---- /dev/null
-+++ b/test/shell/duplicate-vgnames.sh
-@@ -0,0 +1,660 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+
-+SKIP_WITH_LVMLOCKD=1
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux prepare_devs 7
-+
-+# test setups:
-+#    # local vgs named foo  # foreign vg named foo
-+# a. 0                      1
-+# b. 0                      2
-+# c. 1                      1
-+# d. 1                      2
-+# e. 2                      0
-+# f. 2                      1
-+# g. 2                      2
-+# h. 3                      3
-+#
-+# commands to run for each test setup:
-+#
-+# vgs
-+# all cases show all local
-+#
-+# vgs --foreign
-+# all cases show all local and foreign
-+#
-+# vgs foo
-+# a. not found
-+# b. not found
-+# c. show 1 local
-+# d. show 1 local
-+# e-g. dup error
-+#
-+# vgs --foreign foo
-+# a. show 1 foreign
-+# b. dup error
-+# c. show 1 local
-+# d. show 1 local
-+# e-g. dup error
-+#
-+# vgchange -ay
-+# a. none
-+# b. none
-+# c. activate 1 local
-+# d. activate 1 local
-+# e-g. activate 2 local
-+# (if both local vgs have lvs with same name the second will fail to activate)
-+#
-+# vgchange -ay foo
-+# a. none
-+# b. none
-+# c. activate 1 local
-+# d. activate 1 local
-+# e-g. dup error
-+#
-+# lvcreate foo
-+# a. none
-+# b. none
-+# c. create 1 local
-+# d. create 1 local
-+# e-g. dup error
-+#
-+# vgremove foo
-+# a. none
-+# b. none
-+# c. remove 1 local
-+# d. remove 1 local
-+# e-g. dup error
-+# (in a couple cases test that vgremove -S vg_uuid=N works for local vg when local dups exist)
-+
-+
-+# a. 0 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+
-+vgs -o+uuid |tee out
-+not grep $vg1 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+vgs --foreign -o+uuid $vg1 |tee out
-+grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+not grep active out
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+not grep active out
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs --foreign -o+uuid |tee out
-+grep $UUID1 out
-+vgremove -y -S vg_uuid=$UUID1
-+vgs --foreign -o+uuid |tee out
-+grep $UUID1 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+
-+# b. 0 local, 2 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux enable_dev "$dev1"
-+
-+vgs -o+uuid |tee out
-+not grep $vg1 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+not vgs --foreign -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+not grep active out
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+not grep active out
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+grep $UUID2 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs --foreign -o+uuid |tee out
-+grep $UUID1 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-+# c. 1 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux enable_dev "$dev1"
-+
-+vgs -o+uuid |tee out
-+cat out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+vgs -o+uuid $vg1 |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+vgs --foreign -o+uuid $vg1 |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | not grep active
-+vgchange -an
-+
-+vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | not grep active
-+vgchange -an
-+
-+lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | grep $lv2
-+grep $UUID2 out | not grep $lv2
-+
-+vgremove -y $vg1
-+vgs -o+uuid |tee out
-+not grep $UUID1 out
-+vgs --foreign -o+uuid |tee out
-+grep $UUID2 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-+# d. 1 local, 2 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+not grep $UUID3 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+vgs -o+uuid $vg1 |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+not grep $UUID3 out
-+vgs --foreign -o+uuid $vg1 |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+not grep $UUID2 out
-+not grep $UUID3 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | not grep active
-+grep $UUID3 out | not grep active
-+vgchange -an
-+
-+vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | not grep active
-+grep $UUID3 out | not grep active
-+vgchange -an
-+
-+lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | grep $lv2
-+grep $UUID2 out | not grep $lv2
-+grep $UUID3 out | not grep $lv2
-+
-+vgremove -y $vg1
-+vgs -o+uuid |tee out
-+not grep $UUID1 out
-+vgs --foreign -o+uuid |tee out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+aux wipefs_a "$dev4"
-+
-+# e. 2 local, 0 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+# diff lvname to prevent clash in vgchange -ay
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux enable_dev "$dev1"
-+
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+not vgs --foreign -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | grep active
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | not grep active
-+grep $UUID2 out | not grep active
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+grep $UUID2 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+vgremove -y -S vg_uuid=$UUID1
-+vgs -o+uuid |tee out
-+not grep $UUID1 out
-+grep $UUID2 out
-+vgremove -y -S vg_uuid=$UUID2
-+vgs -o+uuid |tee out
-+not grep $UUID1 out
-+not grep $UUID2 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-+# f. 2 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+# diff lvname to prevent clash in vgchange -ay
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+not group $UUID3 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+not vgs --foreign -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | grep active
-+grep $UUID3 out | not grep active
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | not grep active
-+grep $UUID2 out | not grep active
-+grep $UUID3 out | not grep active
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+grep $UUID2 out | not grep $lv2
-+grep $UUID3 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgremove -y -S vg_uuid=$UUID1
-+vgs --foreign -o+uuid |tee out
-+not grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgremove -y -S vg_uuid=$UUID2
-+vgs --foreign -o+uuid |tee out
-+not grep $UUID1 out
-+not grep $UUID2 out
-+grep $UUID3 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+aux wipefs_a "$dev4"
-+
-+# g. 2 local, 2 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+# diff lvname to prevent clash in vgchange -ay
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev3"
-+vgcreate $vg1 "$dev4"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+aux enable_dev "$dev3"
-+
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+not group $UUID3 out
-+not group $UUID4 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+grep $UUID4 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+not vgs --foreign -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | grep active
-+grep $UUID3 out | not grep active
-+grep $UUID4 out | not grep active
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | not grep active
-+grep $UUID2 out | not grep active
-+grep $UUID3 out | not grep active
-+grep $UUID4 out | not grep active
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+grep $UUID2 out | not grep $lv2
-+grep $UUID3 out | not grep $lv2
-+grep $UUID4 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+grep $UUID4 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+aux wipefs_a "$dev4"
-+aux wipefs_a "$dev5"
-+
-+# h. 3 local, 3 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+# diff lvname to prevent clash in vgchange -ay
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+# diff lvname to prevent clash in vgchange -ay
-+lvcreate -n ${lv1}_bb -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev3"
-+vgcreate $vg1 "$dev4"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev4"
-+vgcreate $vg1 "$dev5"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID5=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux disable_dev "$dev5"
-+vgcreate $vg1 "$dev6"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID6=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other3" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+aux enable_dev "$dev3"
-+aux enable_dev "$dev4"
-+aux enable_dev "$dev5"
-+
-+vgs -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not group $UUID4 out
-+not group $UUID5 out
-+not group $UUID6 out
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+grep $UUID4 out
-+grep $UUID5 out
-+grep $UUID6 out
-+
-+not vgs -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+not vgs --foreign -o+uuid $vg1 |tee out
-+not grep $vg1 out
-+
-+vgchange -ay
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | grep active
-+grep $UUID2 out | grep active
-+grep $UUID3 out | grep active
-+grep $UUID4 out | not grep active
-+grep $UUID5 out | not grep active
-+grep $UUID6 out | not grep active
-+vgchange -an
-+
-+not vgchange -ay $vg1
-+lvs --foreign -o vguuid,active |tee out
-+grep $UUID1 out | not grep active
-+grep $UUID2 out | not grep active
-+grep $UUID3 out | not grep active
-+grep $UUID4 out | not grep active
-+grep $UUID5 out | not grep active
-+grep $UUID6 out | not grep active
-+vgchange -an
-+
-+not lvcreate -l1 -an -n $lv2 $vg1
-+lvs --foreign -o vguuid,name |tee out
-+grep $UUID1 out | not grep $lv2
-+grep $UUID2 out | not grep $lv2
-+grep $UUID3 out | not grep $lv2
-+grep $UUID4 out | not grep $lv2
-+grep $UUID5 out | not grep $lv2
-+grep $UUID6 out | not grep $lv2
-+
-+not vgremove $vg1
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+grep $UUID4 out
-+grep $UUID5 out
-+grep $UUID6 out
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+aux wipefs_a "$dev4"
-+aux wipefs_a "$dev5"
-+aux wipefs_a "$dev6"
-+
-+# vgreduce test with 1 local and 1 foreign vg.
-+# setup
-+vgcreate $vg1 "$dev1" "$dev7"
-+lvcreate -n $lv1 -l1 -an $vg1 "$dev1"
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+PV1UUID=$(pvs --noheading -o uuid "$dev1")
-+PV7UUID=$(pvs --noheading -o uuid "$dev7")
-+aux disable_dev "$dev1"
-+aux disable_dev "$dev7"
-+vgcreate $vg1 "$dev2"
-+PV2UUID=$(pvs --noheading -o uuid "$dev2")
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev7"
-+
-+vgs --foreign -o+uuid |tee out
-+grep $vg1 out
-+grep $UUID1 out
-+grep $UUID2 out
-+pvs --foreign -o+uuid |tee out
-+grep $PV1UUID out
-+grep $PV7UUID out
-+grep $PV2UUID out
-+
-+vgreduce $vg1 "$dev7"
-+
-+pvs --foreign -o+uuid |tee out
-+grep $PV1UUID out
-+grep $PV7UUID out
-+grep $PV2UUID out
-+
-+grep $PV7UUID out >out2
-+not grep $vg1 out2
-+
-+vgremove -ff $vg1
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev7"
-diff --git a/test/shell/duplicate-vgrename.sh b/test/shell/duplicate-vgrename.sh
-new file mode 100644
-index 0000000..8628220
---- /dev/null
-+++ b/test/shell/duplicate-vgrename.sh
-@@ -0,0 +1,319 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+
-+SKIP_WITH_LVMLOCKD=1
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux prepare_devs 4
-+
-+# a. 0 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+
-+not vgrename $vg1 $vg2
-+vgs --foreign -o+uuid |tee out
-+grep $UUID1 out
-+not vgrename $UUID1 $vg2
-+vgs --foreign -o+uuid |tee out
-+grep $UUID1 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+
-+# b. 0 local, 2 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux enable_dev "$dev1"
-+
-+not vgrename $vg1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+not grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+not vgrename $UUID1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+not grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+
-+# c. 1 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux enable_dev "$dev1"
-+
-+vgrename $vg1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+not vgrename $vg2 $vg1
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+
-+# d. 1 local, 2 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other2" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+
-+vgrename $vg1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $vg2 $vg1
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-+# e. 2 local, 0 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux enable_dev "$dev1"
-+
-+not vgrename $vg1 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+not grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+vgrename $UUID1 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+not vgrename $UUID2 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+
-+# f. 2 local, 1 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+vgchange -y --systemid "other" $vg1
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+lvs --foreign
-+
-+not vgrename $vg1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+not grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgrename $UUID1 $vg2
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgrename $vg1 $vg3
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $vg2 $vg1
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $vg2 $vg3
-+vgs --foreign -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-+# g. 3 local, 0 foreign
-+# setup
-+vgcreate $vg1 "$dev1"
-+lvcreate -n $lv1 -l1 -an $vg1
-+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev1"
-+vgcreate $vg1 "$dev2"
-+lvcreate -n ${lv1}_b -l1 -an $vg1
-+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux disable_dev "$dev2"
-+vgcreate $vg1 "$dev3"
-+lvcreate -n ${lv1}_c -l1 -an $vg1
-+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+
-+not vgrename $vg1 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+not grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgrename $UUID1 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $vg1 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $vg1 $vg3
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+not grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+not vgrename $UUID2 $vg2
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+not grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+vgrename $UUID2 $vg3
-+vgs -o+uuid |tee out
-+lvs --foreign
-+grep $vg1 out
-+grep $vg2 out
-+grep $vg3 out
-+grep $UUID1 out
-+grep $UUID2 out
-+grep $UUID3 out
-+
-+lvs --foreign
-+
-+aux wipefs_a "$dev1"
-+aux wipefs_a "$dev2"
-+aux wipefs_a "$dev3"
-+
-diff --git a/test/shell/integrity-dmeventd.sh b/test/shell/integrity-dmeventd.sh
-index 58899ca..ed2436a 100644
---- a/test/shell/integrity-dmeventd.sh
-+++ b/test/shell/integrity-dmeventd.sh
-@@ -22,9 +22,9 @@ mkdir -p $mnt
- 
- aux prepare_devs 6 64
- 
--for i in `seq 1 16384`; do echo -n "A" >> fileA; done
--for i in `seq 1 16384`; do echo -n "B" >> fileB; done
--for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+printf "%0.sA" {1..16384} >> fileA
-+printf "%0.sB" {1..16384} >> fileB
-+printf "%0.sC" {1..16384} >> fileC
- 
- # generate random data
- dd if=/dev/urandom of=randA bs=512K count=2
-diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh
-index 0c36e4d..7a333c1 100644
---- a/test/shell/integrity-large.sh
-+++ b/test/shell/integrity-large.sh
-@@ -25,9 +25,9 @@ mkdir -p $mnt
- # raid1 LV needs to be extended to 512MB to test imeta being exended
- aux prepare_devs 4 600
- 
--for i in `seq 1 16384`; do echo -n "A" >> fileA; done
--for i in `seq 1 16384`; do echo -n "B" >> fileB; done
--for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+printf "%0.sA" {1..16384} >> fileA
-+printf "%0.sB" {1..16384} >> fileB
-+printf "%0.sC" {1..16384} >> fileC
- 
- # generate random data
- dd if=/dev/urandom of=randA bs=512K count=2
-diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh
-index 73b0a67..a176f18 100644
---- a/test/shell/integrity-misc.sh
-+++ b/test/shell/integrity-misc.sh
-@@ -22,9 +22,9 @@ mkdir -p $mnt
- 
- aux prepare_devs 5 64
- 
--for i in `seq 1 16384`; do echo -n "A" >> fileA; done
--for i in `seq 1 16384`; do echo -n "B" >> fileB; done
--for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+printf "%0.sA" {1..16384} >> fileA
-+printf "%0.sB" {1..16384} >> fileB
-+printf "%0.sC" {1..16384} >> fileC
- 
- # generate random data
- dd if=/dev/urandom of=randA bs=512K count=2
-diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh
-index 7e4f2cb..6baccf0 100644
---- a/test/shell/integrity.sh
-+++ b/test/shell/integrity.sh
-@@ -23,9 +23,9 @@ mkdir -p $mnt
- 
- aux prepare_devs 5 64
- 
--for i in `seq 1 16384`; do echo -n "A" >> fileA; done
--for i in `seq 1 16384`; do echo -n "B" >> fileB; done
--for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+printf "%0.sA" {1..16384} >> fileA
-+printf "%0.sB" {1..16384} >> fileB
-+printf "%0.sC" {1..16384} >> fileC
- 
- # generate random data
- dd if=/dev/urandom of=randA bs=512K count=2
-diff --git a/test/shell/process-each-duplicate-vgnames.sh b/test/shell/process-each-duplicate-vgnames.sh
-deleted file mode 100644
-index a59c3bd..0000000
---- a/test/shell/process-each-duplicate-vgnames.sh
-+++ /dev/null
-@@ -1,55 +0,0 @@
--#!/usr/bin/env bash
--
--# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
--#
--# This copyrighted material is made available to anyone wishing to use,
--# modify, copy, or redistribute it subject to the terms and conditions
--# of the GNU General Public License v.2.
--
--test_description='Test vgs with duplicate vg names'
--SKIP_WITH_LVMLOCKD=1
--SKIP_WITH_LVMPOLLD=1
--
--. lib/inittest
--
--aux prepare_devs 2
--
--pvcreate "$dev1"
--pvcreate "$dev2"
--
--aux disable_dev "$dev1" "$dev2"
--
--aux enable_dev "$dev1"
--vgcreate $vg1 "$dev1"
--UUID1=$(vgs --noheading -o vg_uuid $vg1)
--aux disable_dev "$dev1"
--
--aux enable_dev "$dev2"
--vgcreate $vg1 "$dev2"
--UUID2=$(vgs --noheading -o vg_uuid $vg1)
--
--aux enable_dev "$dev1"
--pvscan --cache "$dev1"
--pvs "$dev1"
--pvs "$dev2"
--
--vgs -o+vg_uuid | tee err
--grep $UUID1 err
--grep $UUID2 err
--
--# should we specify and test which should be displayed?
--# vgs --noheading -o vg_uuid $vg1 >err
--# grep $UUID1 err
--
--aux disable_dev "$dev2"
--vgs -o+vg_uuid | tee err
--grep $UUID1 err
--not grep $UUID2 err
--aux enable_dev "$dev2"
--pvscan --cache "$dev2"
--
--aux disable_dev "$dev1"
--vgs -o+vg_uuid | tee err
--grep $UUID2 err
--not grep $UUID1 err
--aux enable_dev "$dev1"
-diff --git a/test/shell/thin-foreign-repair.sh b/test/shell/thin-foreign-repair.sh
-index 147a9a0..8b4018e 100644
---- a/test/shell/thin-foreign-repair.sh
-+++ b/test/shell/thin-foreign-repair.sh
-@@ -56,7 +56,9 @@ dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
- 
- mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN"
- 
--dmsetup remove "$THIN"
-+aux udev_wait
-+
-+dmsetup remove "$THIN" || { sleep .5 ; dmsetup remove "$THIN" }
- 
- lvchange -an $vg/pool
- 
-diff --git a/tools/command.c b/tools/command.c
-index 50791b1..511dda1 100644
---- a/tools/command.c
-+++ b/tools/command.c
-@@ -2319,7 +2319,8 @@ static void _print_val_man(struct command_name *cname, int opt_enum, int val_enu
- 	}
- 
- 	if (strchr(str, '|')) {
--		line = strdup(str);
-+		if (!(line = strdup(str)))
-+			return;
- 		_split_line(line, &line_argc, line_argv, '|');
- 		for (i = 0; i < line_argc; i++) {
- 			if (i)
-@@ -3606,9 +3607,12 @@ int main(int argc, char *argv[])
- 		goto out_free;
- 	}
- 
--	if (optind < argc)
--		cmdname = strdup(argv[optind++]);
--	else {
-+	if (optind < argc) {
-+		if (!(cmdname = strdup(argv[optind++]))) {
-+			log_error("Out of memory.");
-+			goto out_free;
-+		}
-+	} else {
- 		log_error("Missing command name.");
- 		goto out_free;
- 	}
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index e969b44..cf93538 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -5589,7 +5589,8 @@ static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
- 
- 	memcpy(&seg->writecache_settings, settings, sizeof(struct writecache_settings));
- 
--	add_seg_to_segs_using_this_lv(lv_fast, seg);
-+	if (!add_seg_to_segs_using_this_lv(lv_fast, seg))
-+		return_NULL;
- 
- 	return lv_wcorig;
- }
-diff --git a/tools/pvck.c b/tools/pvck.c
-index 71bfc1b..a0f567e 100644
---- a/tools/pvck.c
-+++ b/tools/pvck.c
-@@ -3065,11 +3065,9 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
- 
- 	label_scan_setup_bcache();
- 
--	if (arg_is_set(cmd, dump_ARG)) {
-+	if ((dump = arg_str_value(cmd, dump_ARG, NULL))) {
- 		cmd->use_hints = 0;
- 
--		dump = arg_str_value(cmd, dump_ARG, NULL);
--
- 		if (!strcmp(dump, "metadata"))
- 			ret = _dump_metadata(cmd, dump, &set, labelsector, dev, def, PRINT_CURRENT, 0);
- 
-@@ -3096,11 +3094,9 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
- 		return ECMD_PROCESSED;
- 	}
- 
--	if (arg_is_set(cmd, repairtype_ARG)) {
-+	if ((repair = arg_str_value(cmd, repairtype_ARG, NULL))) {
- 		cmd->use_hints = 0;
- 
--		repair = arg_str_value(cmd, repairtype_ARG, NULL);
--
- 		if (!strcmp(repair, "label_header"))
- 			ret = _repair_label_header(cmd, repair, &set, labelsector, dev);
- 
-diff --git a/tools/pvscan.c b/tools/pvscan.c
-index 1bf543c..4d811da 100644
---- a/tools/pvscan.c
-+++ b/tools/pvscan.c
-@@ -582,7 +582,7 @@ static int _online_pvscan_single(struct metadata_area *mda, void *baton)
- 
- 	if (mda_is_ignored(mda))
- 		return 1;
--	vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL);
-+	vg = mda->ops->vg_read(b->cmd, b->fid, "", mda, NULL, NULL);
- 	if (!vg) {
- 		/*
- 		 * Many or most cases of bad metadata would be found in
-diff --git a/tools/toollib.c b/tools/toollib.c
-index 96d0d6d..89b6374 100644
---- a/tools/toollib.c
-+++ b/tools/toollib.c
-@@ -1853,8 +1853,6 @@ static int _resolve_duplicate_vgnames(struct cmd_context *cmd,
- 			if (lvmcache_vg_is_foreign(cmd, vgnl->vg_name, vgnl->vgid)) {
- 				if (!id_write_format((const struct id*)vgnl->vgid, uuid, sizeof(uuid)))
- 					stack;
--				log_warn("WARNING: Ignoring foreign VG with matching name %s UUID %s.",
--					 vgnl->vg_name, uuid);
- 				dm_list_del(&vgnl->list);
- 			} else {
- 				found++;
-diff --git a/tools/vgchange.c b/tools/vgchange.c
-index a10bf11..58c8ddc 100644
---- a/tools/vgchange.c
-+++ b/tools/vgchange.c
-@@ -991,8 +991,13 @@ static int _vgchange_locktype_single(struct cmd_context *cmd, const char *vg_nam
- 	 * deactivate it.
- 	 */
- 	if (vg->lock_type && !strcmp(vg->lock_type, "sanlock") &&
--	    (cmd->command->command_enum == vgchange_locktype_CMD))
--		deactivate_lv(cmd, vg->sanlock_lv);
-+	    (cmd->command->command_enum == vgchange_locktype_CMD)) {
-+		if (!deactivate_lv(cmd, vg->sanlock_lv)) {
-+			log_error("Failed to deativate %s.",
-+				  display_lvname(vg->sanlock_lv));
-+			return ECMD_FAILED;
-+		}
-+	}
- 
- 	log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name);
- 
-diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
-index be01861..ee1c28f 100644
---- a/tools/vgimportclone.c
-+++ b/tools/vgimportclone.c
-@@ -315,6 +315,8 @@ retry_name:
- 		goto_out;
- 	log_debug("Using new VG name %s.", vp.new_vgname);
- 
-+	lvmcache_destroy(cmd, 1, 0);
-+
- 	/*
- 	 * Create a device filter so that we are only working with the devices
- 	 * in arg_import.  With the original devs hidden (that arg_import were
-@@ -325,7 +327,7 @@ retry_name:
- 	init_internal_filtering(1);
- 	dm_list_iterate_items(vd, &vp.arg_import)
- 		internal_filter_allow(cmd->mem, vd->dev);
--	lvmcache_destroy(cmd, 1, 0);
-+	refresh_filters(cmd);
- 
- 	log_debug("Changing VG %s to %s.", vp.old_vgname, vp.new_vgname);
- 
-diff --git a/tools/vgmerge.c b/tools/vgmerge.c
-index 903504c..895018a 100644
---- a/tools/vgmerge.c
-+++ b/tools/vgmerge.c
-@@ -21,10 +21,8 @@ static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
- 	struct volume_group *vg;
- 	log_verbose("Checking for volume group \"%s\"", vg_name);
- 	vg = vg_read_for_update(cmd, vg_name, NULL, 0, 0);
--	if (vg_read_error(vg)) {
--		release_vg(vg);
-+	if (!vg)
- 		return NULL;
--	}
- 
- 	if (vg_is_shared(vg)) {
- 		log_error("vgmerge not allowed for lock_type %s", vg->lock_type);
-diff --git a/tools/vgrename.c b/tools/vgrename.c
-index 8b76d0b..f442f73 100644
---- a/tools/vgrename.c
-+++ b/tools/vgrename.c
-@@ -183,7 +183,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
- 	vg_name_new = skip_dev_dir(cmd, argv[1], NULL);
- 
- 	if (!validate_vg_rename_params(cmd, vg_name_old, vg_name_new))
--		return_0;
-+		return_ECMD_FAILED;
- 
- 	if (!(vp.vg_name_old = dm_pool_strdup(cmd->mem, vg_name_old)))
- 		return_ECMD_FAILED;
-diff --git a/tools/vgsplit.c b/tools/vgsplit.c
-index 3dc19ec..1a422e6 100644
---- a/tools/vgsplit.c
-+++ b/tools/vgsplit.c
-@@ -691,7 +691,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
- 
- 		vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0, 0);
- 
--		if (vg_read_error(vg_to)) {
-+		if (!vg_to) {
- 			log_error("Volume group \"%s\" became inconsistent: "
- 				  "please fix manually", vg_name_to);
- 			goto bad;
--- 
-1.8.3.1
-
diff --git a/SOURCES/0002-Merge-master-up-to-commit-be61bd6ff5c6.patch b/SOURCES/0002-Merge-master-up-to-commit-be61bd6ff5c6.patch
deleted file mode 100644
index 0f1b14a..0000000
--- a/SOURCES/0002-Merge-master-up-to-commit-be61bd6ff5c6.patch
+++ /dev/null
@@ -1,210 +0,0 @@
-From f540a18fd7f5f65599a6c85c0bd3ba84e54f1cc8 Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Thu, 28 May 2020 18:02:16 +0200
-Subject: [PATCH] Merge master up to commit be61bd6ff5c6
-
----
- VERSION                           |  2 +-
- VERSION_DM                        |  2 +-
- test/shell/cache-single-usage.sh  | 13 +++++++++++++
- test/shell/integrity-dmeventd.sh  |  8 ++++++++
- test/shell/integrity-large.sh     |  8 ++++++++
- test/shell/integrity-misc.sh      |  8 ++++++++
- test/shell/integrity.sh           |  8 ++++++++
- test/shell/thin-foreign-repair.sh | 14 ++++++++++----
- tools/lvconvert.c                 | 15 +++++++++++++++
- 9 files changed, 72 insertions(+), 6 deletions(-)
-
-diff --git a/VERSION b/VERSION
-index 00618e0..9ad7a70 100644
---- a/VERSION
-+++ b/VERSION
-@@ -1 +1 @@
--2.03.09(2)-RHEL8 (2020-04-21)
-+2.03.09(2)-RHEL8 (2020-05-28)
-diff --git a/VERSION_DM b/VERSION_DM
-index b9ec43e..bcd97de 100644
---- a/VERSION_DM
-+++ b/VERSION_DM
-@@ -1 +1 @@
--1.02.171-RHEL8 (2020-04-21)
-+1.02.171-RHEL8 (2020-05-28)
-diff --git a/test/shell/cache-single-usage.sh b/test/shell/cache-single-usage.sh
-index a885bf7..8936aa3 100644
---- a/test/shell/cache-single-usage.sh
-+++ b/test/shell/cache-single-usage.sh
-@@ -127,4 +127,17 @@ umount "$mount_dir"
- lvchange -an $vg/$lv1
- lvchange -an $vg/$lv2
- 
-+# misc tests
-+
-+lvremove $vg
-+
-+lvcreate -n $lv1 -l 2 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 2 -an $vg "$dev1"
-+lvcreate -n $lv3 -l 2 -an $vg "$dev2"
-+
-+lvconvert -y --type writecache --cachevol $lv3 $vg/$lv1
-+not lvconvert -y --type writecache --cachevol ${lv3}_cvol $vg/$lv2
-+not lvconvert -y --type cache --cachevol ${lv3}_cvol $vg/$lv2
-+not lvconvert -y --type cache --cachepool ${lv3}_cvol $vg/$lv2
-+
- vgremove -ff $vg
-diff --git a/test/shell/integrity-dmeventd.sh b/test/shell/integrity-dmeventd.sh
-index ed2436a..296f556 100644
---- a/test/shell/integrity-dmeventd.sh
-+++ b/test/shell/integrity-dmeventd.sh
-@@ -109,6 +109,14 @@ _wait_recalc() {
- 		sleep 1
- 	done
- 
-+	# TODO: There is some strange bug, first leg of RAID with integrity
-+	# enabled never gets in sync. I saw this in BB, but not when executing
-+	# the commands manually
-+	if test -z "$sync"; then
-+		echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+		exit
-+	fi
- 	echo "timeout waiting for recalc"
- 	return 1
- }
-diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh
-index 7a333c1..5aba80e 100644
---- a/test/shell/integrity-large.sh
-+++ b/test/shell/integrity-large.sh
-@@ -95,6 +95,14 @@ _wait_recalc() {
- 		sleep 1
- 	done
- 
-+	# TODO: There is some strange bug, first leg of RAID with integrity
-+	# enabled never gets in sync. I saw this in BB, but not when executing
-+	# the commands manually
-+	if test -z "$sync"; then
-+		echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+		exit
-+	fi
- 	echo "timeout waiting for recalc"
- 	return 1
- }
-diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh
-index a176f18..0d05689 100644
---- a/test/shell/integrity-misc.sh
-+++ b/test/shell/integrity-misc.sh
-@@ -109,6 +109,14 @@ _wait_recalc() {
- 		sleep 1
- 	done
- 
-+	# TODO: There is some strange bug, first leg of RAID with integrity
-+	# enabled never gets in sync. I saw this in BB, but not when executing
-+	# the commands manually
-+	if test -z "$sync"; then
-+		echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+		exit
-+	fi
- 	echo "timeout waiting for recalc"
- 	return 1
- }
-diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh
-index 6baccf0..77e9430 100644
---- a/test/shell/integrity.sh
-+++ b/test/shell/integrity.sh
-@@ -204,6 +204,14 @@ _wait_recalc() {
- 		sleep 1
- 	done
- 
-+	# TODO: There is some strange bug, first leg of RAID with integrity
-+	# enabled never gets in sync. I saw this in BB, but not when executing
-+	# the commands manually
-+	if test -z "$sync"; then
-+		echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+		exit
-+	fi
- 	echo "timeout waiting for recalc"
- 	return 1
- }
-diff --git a/test/shell/thin-foreign-repair.sh b/test/shell/thin-foreign-repair.sh
-index 8b4018e..55e9f62 100644
---- a/test/shell/thin-foreign-repair.sh
-+++ b/test/shell/thin-foreign-repair.sh
-@@ -17,9 +17,15 @@ SKIP_WITH_LVMPOLLD=1
- 
- . lib/inittest
- 
-+clean_thin_()
-+{
-+	aux udev_wait
-+	dmsetup remove "$THIN" || { sleep .5 ; dmsetup remove "$THIN" ; }
-+}
-+
- cleanup_mounted_and_teardown()
- {
--	dmsetup remove $THIN || true
-+	clean_thin_ || true
- 	vgremove -ff $vg
- 	aux teardown
- }
-@@ -56,9 +62,7 @@ dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
- 
- mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN"
- 
--aux udev_wait
--
--dmsetup remove "$THIN" || { sleep .5 ; dmsetup remove "$THIN" }
-+clean_thin_
- 
- lvchange -an $vg/pool
- 
-@@ -72,3 +76,5 @@ lvchange -ay $vg/pool
- dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
- 
- fsck -n "$DM_DEV_DIR/mapper/$THIN"
-+
-+# exit calls cleanup_mounted_and_teardown
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index cf93538..8652252 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -4264,6 +4264,11 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
- 		goto out;
- 	}
- 
-+	if (lv_is_cache_vol(cachevol_lv)) {
-+		log_error("LV %s is already used as a cachevol.", display_lvname(cachevol_lv));
-+		goto out;
-+	}
-+
- 	/* Ensure the LV is not active elsewhere. */
- 	if (!lockd_lv(cmd, lv, "ex", 0))
- 		goto_out;
-@@ -4347,6 +4352,11 @@ static int _lvconvert_cachepool_attach_single(struct cmd_context *cmd,
- 			goto out;
- 		}
- 
-+		if (lv_is_cache_vol(cachepool_lv)) {
-+			log_error("LV %s is already used as a cachevol.", display_lvname(cachepool_lv));
-+			goto out;
-+		}
-+
- 		if (cachepool_lv == lv) {
- 			log_error("Use a different LV for cache pool LV and cache LV %s.",
- 				  display_lvname(cachepool_lv));
-@@ -5629,6 +5639,11 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
- 		goto bad;
- 	}
- 
-+	if (lv_is_cache_vol(lv_fast)) {
-+		log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
-+		goto bad;
-+	}
-+
- 	/*
- 	 * To permit this we need to check the block size of the fs using lv
- 	 * (recently in libblkid) so that we can use a matching writecache
--- 
-1.8.3.1
-
diff --git a/SOURCES/0003-Merge-master-up-to-commit-c1d136fea3d1.patch b/SOURCES/0003-Merge-master-up-to-commit-c1d136fea3d1.patch
deleted file mode 100644
index 02fe5b1..0000000
--- a/SOURCES/0003-Merge-master-up-to-commit-c1d136fea3d1.patch
+++ /dev/null
@@ -1,6235 +0,0 @@
-From d8f301b9244d93695b344c33e9ff7a116b5f17b7 Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Sun, 9 Aug 2020 16:42:09 +0200
-Subject: [PATCH] Merge master up to commit c1d136fea3d1
-
-(cherry picked from commit 4ef278fcb7c08721e973af7300fd1bff5d142398)
----
- WHATS_NEW                                |  11 +-
- conf/example.conf.in                     |   6 +-
- daemons/lvmdbusd/cmdhandler.py           |   9 +
- daemons/lvmdbusd/lv.py                   |  45 +-
- daemons/lvmdbusd/manager.py              |   2 +-
- device_mapper/all.h                      |   4 +
- device_mapper/libdm-deptree.c            |  12 +
- include/configure.h.in                   |   6 +-
- lib/cache/lvmcache.c                     |   4 +
- lib/config/config_settings.h             |   5 +-
- lib/config/defaults.h                    |   1 +
- lib/device/bcache.c                      |   2 +-
- lib/device/dev-cache.c                   |   1 +
- lib/device/dev-md.c                      | 206 ++++++---
- lib/device/dev-type.c                    |  36 +-
- lib/label/hints.c                        |   4 +-
- lib/metadata/cache_manip.c               |   4 +
- lib/metadata/integrity_manip.c           |  61 ++-
- lib/metadata/lv.c                        |   3 +
- lib/metadata/lv_manip.c                  | 102 +++--
- lib/metadata/merge.c                     |   3 +-
- lib/metadata/metadata-exported.h         |   7 +-
- lib/metadata/metadata.c                  |   4 +-
- lib/metadata/pool_manip.c                |   6 +-
- lib/metadata/raid_manip.c                |   5 +
- lib/metadata/snapshot_manip.c            |   2 -
- lib/metadata/writecache_manip.c          | 365 ++++++++++++++--
- lib/report/report.c                      |  18 +-
- lib/writecache/writecache.c              |  49 +++
- man/lvconvert.8_pregen                   |  58 +++
- man/lvcreate.8_pregen                    | 246 ++++++++++-
- man/lvmcache.7_main                      |  85 +++-
- man/lvs.8_end                            |   4 +
- man/lvs.8_pregen                         |   4 +
- man/vgck.8_pregen                        |   9 +
- scripts/blkdeactivate.sh.in              |   6 +
- test/dbus/lvmdbustest.py                 |  30 ++
- test/lib/aux.sh                          |   1 +
- test/shell/cachevol-cachedevice.sh       | 222 ++++++++++
- test/shell/integrity-blocksize-2.sh      | 128 ++++++
- test/shell/integrity-blocksize-3.sh      | 285 ++++++++++++
- test/shell/integrity-blocksize.sh        | 108 ++++-
- test/shell/integrity-large.sh            |  23 +-
- test/shell/integrity-misc.sh             |  27 +-
- test/shell/integrity.sh                  |  46 +-
- test/shell/lvconvert-m-raid1-degraded.sh |   6 +-
- test/shell/lvcreate-signature-wiping.sh  |   7 +
- test/shell/lvcreate-thin.sh              |  21 +
- test/shell/writecache-blocksize.sh       | 342 +++++++++++++++
- test/shell/writecache-large.sh           | 153 +++++++
- test/shell/writecache-split.sh           |  34 +-
- test/shell/writecache.sh                 | 315 +++++++++-----
- tools/args.h                             |  17 +-
- tools/command-lines.in                   | 145 +++---
- tools/command.c                          |   3 +
- tools/lvchange.c                         |  85 ++++
- tools/lvconvert.c                        | 726 +++++++++++++++++++------------
- tools/lvcreate.c                         | 153 ++++++-
- tools/lvmcmdline.c                       |   8 +
- tools/toollib.c                          | 164 +++++++
- tools/toollib.h                          |   3 +
- tools/tools.h                            |  11 +
- 62 files changed, 3761 insertions(+), 697 deletions(-)
- create mode 100644 test/shell/cachevol-cachedevice.sh
- create mode 100644 test/shell/integrity-blocksize-2.sh
- create mode 100644 test/shell/integrity-blocksize-3.sh
- create mode 100644 test/shell/writecache-blocksize.sh
- create mode 100644 test/shell/writecache-large.sh
-
-diff --git a/WHATS_NEW b/WHATS_NEW
-index c0267b7..ac99e97 100644
---- a/WHATS_NEW
-+++ b/WHATS_NEW
-@@ -1,5 +1,14 @@
- Version 2.03.10 - 
--=================================
-+==================================
-+  Add writecache and integrity support to lvmdbusd.
-+  Generate unique cachevol name when default required from lvcreate.
-+  Converting RAID1 volume to one with same number of legs now succeeds with a
-+  warning.
-+  Fix conversion to raid from striped lagging type.
-+  Fix conversion to 'mirrored' mirror log with larger regionsize.
-+  Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
-+  Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
-+  Fix running out of free buffers for async writing for larger writes.
-   Add integrity with raid capability.
-   Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
- 
-diff --git a/conf/example.conf.in b/conf/example.conf.in
-index 88858fc..d5807e6 100644
---- a/conf/example.conf.in
-+++ b/conf/example.conf.in
-@@ -489,7 +489,7 @@ allocation {
- 	# This configuration option does not have a default value defined.
- 
- 	# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
--	# Thin pool metdata and data will always use different PVs.
-+	# Thin pool metadata and data will always use different PVs.
- 	thin_pool_metadata_require_separate_pvs = 0
- 
- 	# Configuration option allocation/thin_pool_zero.
-@@ -527,6 +527,10 @@ allocation {
- 	# This configuration option has an automatic default value.
- 	# thin_pool_chunk_size_policy = "generic"
- 
-+	# Configuration option allocation/zero_metadata.
-+	# Zero whole metadata area before use with thin or cache pool.
-+	zero_metadata = 1
-+
- 	# Configuration option allocation/thin_pool_chunk_size.
- 	# The minimal chunk size in KiB for thin pool volumes.
- 	# Larger chunk sizes may improve performance for plain thin volumes,
-diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
-index 7d2f4c4..1c15b78 100644
---- a/daemons/lvmdbusd/cmdhandler.py
-+++ b/daemons/lvmdbusd/cmdhandler.py
-@@ -453,6 +453,15 @@ def lv_cache_lv(cache_pool_full_name, lv_full_name, cache_options):
- 	return call(cmd)
- 
- 
-+def lv_writecache_lv(cache_lv_full_name, lv_full_name, cache_options):
-+	# lvconvert --type writecache --cachevol VG/CacheLV VG/OriginLV
-+	cmd = ['lvconvert']
-+	cmd.extend(options_to_cli_args(cache_options))
-+	cmd.extend(['-y', '--type', 'writecache', '--cachevol',
-+				cache_lv_full_name, lv_full_name])
-+	return call(cmd)
-+
-+
- def lv_detach_cache(lv_full_name, detach_options, destroy_cache):
- 	cmd = ['lvconvert']
- 	if destroy_cache:
-diff --git a/daemons/lvmdbusd/lv.py b/daemons/lvmdbusd/lv.py
-index fd46f34..edfdd0d 100644
---- a/daemons/lvmdbusd/lv.py
-+++ b/daemons/lvmdbusd/lv.py
-@@ -388,7 +388,7 @@ class LvCommon(AutomatedProperties):
- 					'l': 'mirror log device', 'c': 'under conversion',
- 					'V': 'thin Volume', 't': 'thin pool', 'T': 'Thin pool data',
- 					'e': 'raid or pool metadata or pool metadata spare',
--					'd': 'vdo pool', 'D': 'vdo pool data',
-+					'd': 'vdo pool', 'D': 'vdo pool data', 'g': 'integrity',
- 					'-': 'Unspecified'}
- 		return self.attr_struct(0, type_map)
- 
-@@ -743,6 +743,49 @@ class Lv(LvCommon):
- 			cb, cbe, return_tuple=False)
- 		cfg.worker_q.put(r)
- 
-+	@staticmethod
-+	def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
-+		# Make sure we have a dbus object representing it
-+		dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
-+
-+		# Make sure we have dbus object representing lv to cache
-+		lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
-+
-+		if lv_to_cache:
-+			fcn = lv_to_cache.lv_full_name()
-+			rc, out, err = cmdhandler.lv_writecache_lv(
-+				dbo.lv_full_name(), fcn, cache_options)
-+			if rc == 0:
-+				# When we cache an LV, the cache pool and the lv that is getting
-+				# cached need to be removed from the object manager and
-+				# re-created as their interfaces have changed!
-+				mt_remove_dbus_objects((dbo, lv_to_cache))
-+				cfg.load()
-+
-+				lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
-+			else:
-+				raise dbus.exceptions.DBusException(
-+					LV_INTERFACE,
-+					'Exit code %s, stderr = %s' % (str(rc), err))
-+		else:
-+			raise dbus.exceptions.DBusException(
-+				LV_INTERFACE, 'LV to cache with object path %s not present!' %
-+				lv_object_path)
-+		return lv_converted
-+
-+	@dbus.service.method(
-+		dbus_interface=LV_INTERFACE,
-+		in_signature='oia{sv}',
-+		out_signature='(oo)',
-+		async_callbacks=('cb', 'cbe'))
-+	def WriteCacheLv(self, lv_object, tmo, cache_options, cb, cbe):
-+		r = RequestEntry(
-+			tmo, Lv._writecache_lv,
-+			(self.Uuid, self.lvm_id, lv_object,
-+			cache_options), cb, cbe)
-+		cfg.worker_q.put(r)
-+
-+
- # noinspection PyPep8Naming
- @utils.dbus_property(VDO_POOL_INTERFACE, 'OperatingMode', 's')
- @utils.dbus_property(VDO_POOL_INTERFACE, 'CompressionState', 's')
-diff --git a/daemons/lvmdbusd/manager.py b/daemons/lvmdbusd/manager.py
-index 2857e9a..573a396 100644
---- a/daemons/lvmdbusd/manager.py
-+++ b/daemons/lvmdbusd/manager.py
-@@ -27,7 +27,7 @@ class Manager(AutomatedProperties):
- 
- 	@property
- 	def Version(self):
--		return dbus.String('1.0.0')
-+		return dbus.String('1.1.0')
- 
- 	@staticmethod
- 	def handle_execute(rc, out, err):
-diff --git a/device_mapper/all.h b/device_mapper/all.h
-index f00b6a5..c3c6219 100644
---- a/device_mapper/all.h
-+++ b/device_mapper/all.h
-@@ -951,6 +951,8 @@ struct writecache_settings {
- 	uint64_t autocommit_time; /* in milliseconds */
- 	uint32_t fua;
- 	uint32_t nofua;
-+	uint32_t cleaner;
-+	uint32_t max_age;
- 
- 	/*
- 	 * Allow an unrecognized key and its val to be passed to the kernel for
-@@ -970,6 +972,8 @@ struct writecache_settings {
- 	unsigned autocommit_time_set:1;
- 	unsigned fua_set:1;
- 	unsigned nofua_set:1;
-+	unsigned cleaner_set:1;
-+	unsigned max_age_set:1;
- };
- 
- int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
-diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
-index 9ba24cb..2722a2c 100644
---- a/device_mapper/libdm-deptree.c
-+++ b/device_mapper/libdm-deptree.c
-@@ -2670,6 +2670,10 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
- 		count += 1;
- 	if (seg->writecache_settings.nofua_set)
- 		count += 1;
-+	if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner)
-+		count += 1;
-+	if (seg->writecache_settings.max_age_set)
-+		count += 2;
- 	if (seg->writecache_settings.new_key)
- 		count += 2;
- 
-@@ -2713,6 +2717,14 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
- 		EMIT_PARAMS(pos, " nofua");
- 	}
- 
-+	if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
-+		EMIT_PARAMS(pos, " cleaner");
-+	}
-+
-+	if (seg->writecache_settings.max_age_set) {
-+		EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
-+	}
-+
- 	if (seg->writecache_settings.new_key) {
- 		EMIT_PARAMS(pos, " %s %s",
- 			seg->writecache_settings.new_key,
-diff --git a/include/configure.h.in b/include/configure.h.in
-index 57736cc..540cee7 100644
---- a/include/configure.h.in
-+++ b/include/configure.h.in
-@@ -531,6 +531,9 @@
- /* Define to 1 if the system has the `__builtin_clzll' built-in function */
- #undef HAVE___BUILTIN_CLZLL
- 
-+/* Define to 1 to include built-in support for integrity. */
-+#undef INTEGRITY_INTERNAL
-+
- /* Internalization package */
- #undef INTL_PACKAGE
- 
-@@ -678,9 +681,6 @@
- /* Define to 1 to include built-in support for writecache. */
- #undef WRITECACHE_INTERNAL
- 
--/* Define to 1 to include built-in support for integrity. */
--#undef INTEGRITY_INTERNAL
--
- /* Define to get access to GNU/Linux extension */
- #undef _GNU_SOURCE
- 
-diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
-index 6cb5ff0..b1d05fb 100644
---- a/lib/cache/lvmcache.c
-+++ b/lib/cache/lvmcache.c
-@@ -84,6 +84,7 @@ static DM_LIST_INIT(_unused_duplicates);
- static DM_LIST_INIT(_prev_unused_duplicate_devs);
- static int _vgs_locked = 0;
- static int _found_duplicate_vgnames = 0;
-+static int _outdated_warning = 0;
- 
- int lvmcache_init(struct cmd_context *cmd)
- {
-@@ -1776,6 +1777,9 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted)
- 		log_warn("WARNING: outdated PV %s seqno %u has been removed in current VG %s seqno %u.",
- 			 dev_name(info->dev), info->summary_seqno, vg->name, vginfo->seqno);
- 
-+		if (!_outdated_warning++)
-+			log_warn("See vgck --updatemetadata to clear outdated metadata.");
-+
- 		_drop_vginfo(info, vginfo); /* remove from vginfo->infos */
- 		dm_list_add(&vginfo->outdated_infos, &info->list);
- 	}
-diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
-index dce9705..b38ca11 100644
---- a/lib/config/config_settings.h
-+++ b/lib/config/config_settings.h
-@@ -626,7 +626,7 @@ cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CF
- 	"Using cache pool with more chunks may degrade cache performance.\n")
- 
- cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
--	"Thin pool metdata and data will always use different PVs.\n")
-+	"Thin pool metadata and data will always use different PVs.\n")
- 
- cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL,
- 	"Thin pool data chunks are zeroed before they are first used.\n"
-@@ -657,6 +657,9 @@ cfg(allocation_thin_pool_chunk_size_policy_CFG, "thin_pool_chunk_size_policy", a
- 	"    512KiB.\n"
- 	"#\n")
- 
-+cfg(allocation_zero_metadata_CFG, "zero_metadata", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ZERO_METADATA, vsn(2, 3, 10), NULL, 0, NULL,
-+	"Zero whole metadata area before use with thin or cache pool.\n")
-+
- cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 99), 0, NULL,
- 	"The minimal chunk size in KiB for thin pool volumes.\n"
- 	"Larger chunk sizes may improve performance for plain thin volumes,\n"
-diff --git a/lib/config/defaults.h b/lib/config/defaults.h
-index be4f5ff..708a575 100644
---- a/lib/config/defaults.h
-+++ b/lib/config/defaults.h
-@@ -129,6 +129,7 @@
- #define DEFAULT_THIN_POOL_DISCARDS "passdown"
- #define DEFAULT_THIN_POOL_ZERO 1
- #define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
-+#define DEFAULT_ZERO_METADATA 1		/* thin + cache */
- 
- #ifdef CACHE_CHECK_NEEDS_CHECK
- #  define DEFAULT_CACHE_CHECK_OPTION1 "-q"
-diff --git a/lib/device/bcache.c b/lib/device/bcache.c
-index a7d8055..7e7e185 100644
---- a/lib/device/bcache.c
-+++ b/lib/device/bcache.c
-@@ -950,7 +950,7 @@ static struct block *_new_block(struct bcache *cache, int fd, block_address i, b
- 	struct block *b;
- 
- 	b = _alloc_block(cache);
--	while (!b && !dm_list_empty(&cache->clean)) {
-+	while (!b) {
- 		b = _find_unused_clean_block(cache);
- 		if (!b) {
- 			if (can_wait) {
-diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
-index 6af559c..c3f7c49 100644
---- a/lib/device/dev-cache.c
-+++ b/lib/device/dev-cache.c
-@@ -65,6 +65,7 @@ static int _insert(const char *path, const struct stat *info,
- static void _dev_init(struct device *dev)
- {
- 	dev->fd = -1;
-+	dev->bcache_fd = -1;
- 	dev->read_ahead = -1;
- 
- 	dev->ext.enabled = 0;
-diff --git a/lib/device/dev-md.c b/lib/device/dev-md.c
-index 9d0a363..23ce41a 100644
---- a/lib/device/dev-md.c
-+++ b/lib/device/dev-md.c
-@@ -16,6 +16,7 @@
- #include "lib/misc/lib.h"
- #include "lib/device/dev-type.h"
- #include "lib/mm/xlate.h"
-+#include "lib/misc/crc.h"
- #ifdef UDEV_SYNC_SUPPORT
- #include <libudev.h> /* for MD detection using udev db records */
- #include "lib/device/dev-ext-udev-constants.h"
-@@ -48,44 +49,89 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
- 	return 0;
- }
- 
--/*
-- * Calculate the position of the superblock.
-- * It is always aligned to a 4K boundary and
-- * depending on minor_version, it can be:
-- * 0: At least 8K, but less than 12K, from end of device
-- * 1: At start of device
-- * 2: 4K from start of device.
-- */
--typedef enum {
--	MD_MINOR_VERSION_MIN,
--	MD_MINOR_V0 = MD_MINOR_VERSION_MIN,
--	MD_MINOR_V1,
--	MD_MINOR_V2,
--	MD_MINOR_VERSION_MAX = MD_MINOR_V2
--} md_minor_version_t;
--
--static uint64_t _v1_sb_offset(uint64_t size, md_minor_version_t minor_version)
-+#define IMSM_SIGNATURE "Intel Raid ISM Cfg Sig. "
-+#define IMSM_SIG_LEN (strlen(IMSM_SIGNATURE))
-+
-+static int _dev_has_imsm_magic(struct device *dev, uint64_t devsize_sectors)
- {
--	uint64_t sb_offset;
-+	char imsm_signature[IMSM_SIG_LEN];
-+	uint64_t off = (devsize_sectors * 512) - 1024;
- 
--	switch(minor_version) {
--	case MD_MINOR_V0:
--		sb_offset = (size - 8 * 2) & ~(4 * 2 - 1ULL);
--		break;
--	case MD_MINOR_V1:
--		sb_offset = 0;
--		break;
--	case MD_MINOR_V2:
--		sb_offset = 4 * 2;
--		break;
--	default:
--		log_warn(INTERNAL_ERROR "WARNING: Unknown minor version %d.",
--			 minor_version);
-+	if (!dev_read_bytes(dev, off, IMSM_SIG_LEN, imsm_signature))
-+		return_0;
-+
-+	if (!memcmp(imsm_signature, IMSM_SIGNATURE, IMSM_SIG_LEN))
-+		return 1;
-+
-+	return 0;
-+}
-+
-+#define DDF_MAGIC 0xDE11DE11
-+struct ddf_header {
-+	uint32_t magic;
-+	uint32_t crc;
-+	char guid[24];
-+	char revision[8];
-+	char padding[472];
-+};
-+
-+static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint64_t *sb_offset)
-+{
-+	struct ddf_header hdr;
-+	uint32_t crc, our_crc;
-+	uint64_t off;
-+	uint64_t devsize_bytes = devsize_sectors * 512;
-+
-+	if (devsize_bytes < 0x30000)
- 		return 0;
-+
-+	/* 512 bytes before the end of device (from libblkid) */
-+	off = ((devsize_bytes / 0x200) - 1) * 0x200;
-+
-+	if (!dev_read_bytes(dev, off, 512, &hdr))
-+		return_0;
-+
-+	if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
-+	    (hdr.magic == cpu_to_le32(DDF_MAGIC))) {
-+		crc = hdr.crc;
-+		hdr.crc = 0xffffffff;
-+		our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
-+
-+		if ((cpu_to_be32(our_crc) == crc) ||
-+		    (cpu_to_le32(our_crc) == crc)) {
-+			*sb_offset = off;
-+			return 1;
-+		} else {
-+			log_debug_devs("Found md ddf magic at %llu wrong crc %x disk %x %s",
-+				       (unsigned long long)off, our_crc, crc, dev_name(dev));
-+			return 0;
-+		}
-+	}
-+
-+	/* 128KB before the end of device (from libblkid) */
-+	off = ((devsize_bytes / 0x200) - 257) * 0x200;
-+
-+	if (!dev_read_bytes(dev, off, 512, &hdr))
-+		return_0;
-+
-+	if ((hdr.magic == cpu_to_be32(DDF_MAGIC)) ||
-+	    (hdr.magic == cpu_to_le32(DDF_MAGIC))) {
-+		crc = hdr.crc;
-+		hdr.crc = 0xffffffff;
-+		our_crc = calc_crc(0, (const uint8_t *)&hdr, 512);
-+
-+		if ((cpu_to_be32(our_crc) == crc) ||
-+		    (cpu_to_le32(our_crc) == crc)) {
-+			*sb_offset = off;
-+			return 1;
-+		} else {
-+			log_debug_devs("Found md ddf magic at %llu wrong crc %x disk %x %s",
-+				       (unsigned long long)off, our_crc, crc, dev_name(dev));
-+			return 0;
-+		}
- 	}
--	sb_offset <<= SECTOR_SHIFT;
- 
--	return sb_offset;
-+	return 0;
- }
- 
- /*
-@@ -130,7 +176,6 @@ static int _udev_dev_is_md_component(struct device *dev)
-  */
- static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
- {
--	md_minor_version_t minor;
- 	uint64_t size, sb_offset;
- 	int ret;
- 
-@@ -146,9 +191,9 @@ static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_foun
- 		return 0;
- 
- 	/*
--	 * Old md versions locate the magic number at the end of the device.
--	 * Those checks can't be satisfied with the initial bcache data, and
--	 * would require an extra read i/o at the end of every device.  Issuing
-+	 * Some md versions locate the magic number at the end of the device.
-+	 * Those checks can't be satisfied with the initial scan data, and
-+	 * require an extra read i/o at the end of every device.  Issuing
- 	 * an extra read to every device in every command, just to check for
- 	 * the old md format is a bad tradeoff.
- 	 *
-@@ -159,42 +204,81 @@ static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_foun
- 	 * and set it for commands that could possibly write to an md dev
- 	 * (pvcreate/vgcreate/vgextend).
- 	 */
--	if (!full) {
--		sb_offset = 0;
--		if (_dev_has_md_magic(dev, sb_offset)) {
--			log_debug_devs("Found md magic number at offset 0 of %s.", dev_name(dev));
--			ret = 1;
--			goto out;
--		}
- 
--		sb_offset = 8 << SECTOR_SHIFT;
--		if (_dev_has_md_magic(dev, sb_offset)) {
--			log_debug_devs("Found md magic number at offset %d of %s.", (int)sb_offset, dev_name(dev));
--			ret = 1;
--			goto out;
--		}
-+	/*
-+	 * md superblock version 1.1 at offset 0 from start
-+	 */
-+
-+	if (_dev_has_md_magic(dev, 0)) {
-+		log_debug_devs("Found md magic number at offset 0 of %s.", dev_name(dev));
-+		ret = 1;
-+		goto out;
-+	}
- 
-+	/*
-+	 * md superblock version 1.2 at offset 4KB from start
-+	 */
-+
-+	if (_dev_has_md_magic(dev, 4096)) {
-+		log_debug_devs("Found md magic number at offset 4096 of %s.", dev_name(dev));
-+		ret = 1;
-+		goto out;
-+	}
-+
-+	if (!full) {
- 		ret = 0;
- 		goto out;
- 	}
- 
--	/* Check if it is an md component device. */
--	/* Version 0.90.0 */
-+	/*
-+	 * Handle superblocks at the end of the device.
-+	 */
-+
-+	/*
-+	 * md superblock version 0 at 64KB from end of device
-+	 * (after end is aligned to 64KB)
-+	 */
-+
- 	sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
-+
- 	if (_dev_has_md_magic(dev, sb_offset)) {
-+		log_debug_devs("Found md magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
- 		ret = 1;
- 		goto out;
- 	}
- 
--	minor = MD_MINOR_VERSION_MIN;
--	/* Version 1, try v1.0 -> v1.2 */
--	do {
--		sb_offset = _v1_sb_offset(size, minor);
--		if (_dev_has_md_magic(dev, sb_offset)) {
--			ret = 1;
--			goto out;
--		}
--	} while (++minor <= MD_MINOR_VERSION_MAX);
-+	/*
-+	 * md superblock version 1.0 at 8KB from end of device
-+	 */
-+
-+	sb_offset = ((size - 8 * 2) & ~(4 * 2 - 1ULL)) << SECTOR_SHIFT;
-+
-+	if (_dev_has_md_magic(dev, sb_offset)) {
-+		log_debug_devs("Found md magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
-+		ret = 1;
-+		goto out;
-+	}
-+
-+	/*
-+	 * md imsm superblock 1K from end of device
-+	 */
-+
-+	if (_dev_has_imsm_magic(dev, size)) {
-+		log_debug_devs("Found md imsm magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
-+		sb_offset = 1024;
-+		ret = 1;
-+		goto out;
-+	}
-+
-+	/*
-+	 * md ddf superblock 512 bytes from end, or 128KB from end
-+	 */
-+
-+	if (_dev_has_ddf_magic(dev, size, &sb_offset)) {
-+		log_debug_devs("Found md ddf magic number at offset %llu of %s.", (unsigned long long)sb_offset, dev_name(dev));
-+		ret = 1;
-+		goto out;
-+	}
- 
- 	ret = 0;
- out:
-diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
-index deb5d6a..896821d 100644
---- a/lib/device/dev-type.c
-+++ b/lib/device/dev-type.c
-@@ -649,37 +649,23 @@ out:
- #ifdef BLKID_WIPING_SUPPORT
- int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
- {
--	blkid_probe probe = NULL;
--	const char *block_size_str = NULL;
--	uint64_t block_size_val;
--	int r = 0;
-+	char *block_size_str = NULL;
- 
--	*fs_block_size = 0;
--
--	if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
--		log_error("Failed to create a new blkid probe for device %s.", dev_name(dev));
--		goto out;
-+	if ((block_size_str = blkid_get_tag_value(NULL, "BLOCK_SIZE", dev_name(dev)))) {
-+		*fs_block_size = (uint32_t)atoi(block_size_str);
-+		free(block_size_str);
-+		log_debug("Found blkid BLOCK_SIZE %u for fs on %s", *fs_block_size, dev_name(dev));
-+		return 1;
-+	} else {
-+		log_debug("No blkid BLOCK_SIZE for fs on %s", dev_name(dev));
-+		*fs_block_size = 0;
-+		return 0;
- 	}
--
--	blkid_probe_enable_partitions(probe, 1);
--
--	(void) blkid_probe_lookup_value(probe, "BLOCK_SIZE", &block_size_str, NULL);
--
--	if (!block_size_str)
--		goto out;
--
--	block_size_val = strtoull(block_size_str, NULL, 10);
--
--	*fs_block_size = (uint32_t)block_size_val;
--	r = 1;
--out:
--	if (probe)
--		blkid_free_probe(probe);
--	return r;
- }
- #else
- int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
- {
-+	log_debug("Disabled blkid BLOCK_SIZE for fs.");
- 	*fs_block_size = 0;
- 	return 0;
- }
-diff --git a/lib/label/hints.c b/lib/label/hints.c
-index 9546f48..efa02f7 100644
---- a/lib/label/hints.c
-+++ b/lib/label/hints.c
-@@ -801,10 +801,8 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
- 	if (fclose(fp))
- 		stack;
- 
--	if (!ret) {
--		free_hints(hints);
-+	if (!ret)
- 		return 0;
--	}
- 
- 	if (!found)
- 		return 1;
-diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
-index 49b3850..a786e8b 100644
---- a/lib/metadata/cache_manip.c
-+++ b/lib/metadata/cache_manip.c
-@@ -1094,6 +1094,10 @@ int cache_vol_set_params(struct cmd_context *cmd,
- 	if (!meta_size) {
- 		meta_size = _cache_min_metadata_size(pool_lv->size, chunk_size);
- 
-+		/* fix bad value from _cache_min_metadata_size */
-+		if (meta_size > (pool_lv->size / 2))
-+			meta_size = pool_lv->size / 2;
-+
- 		if (meta_size < min_meta_size)
- 			meta_size = min_meta_size;
- 
-diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c
-index 7942be0..3322a21 100644
---- a/lib/metadata/integrity_manip.c
-+++ b/lib/metadata/integrity_manip.c
-@@ -21,7 +21,6 @@
- #include "lib/metadata/segtype.h"
- #include "lib/activate/activate.h"
- #include "lib/config/defaults.h"
--#include "lib/activate/dev_manager.h"
- 
- #define DEFAULT_TAG_SIZE 4 /* bytes */
- #define DEFAULT_MODE 'J'
-@@ -29,6 +28,7 @@
- #define DEFAULT_BLOCK_SIZE 512
- 
- #define ONE_MB_IN_BYTES 1048576
-+#define ONE_GB_IN_BYTES 1073741824
- 
- int lv_is_integrity_origin(const struct logical_volume *lv)
- {
-@@ -46,10 +46,35 @@ int lv_is_integrity_origin(const struct logical_volume *lv)
- /*
-  * Every 500M of data needs 4M of metadata.
-  * (From trial and error testing.)
-+ *
-+ * plus some initial space for journals.
-+ * (again from trial and error testing.)
-  */
- static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
- {
--	return ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
-+	uint64_t meta_bytes;
-+	uint64_t initial_bytes;
-+
-+	/* Every 500M of data needs 4M of metadata. */
-+	meta_bytes = ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
-+
-+	/*
-+	 * initial space used for journals
-+	 * lv_size <= 512M -> 4M
-+	 * lv_size <= 1G   -> 8M
-+	 * lv_size <= 4G   -> 32M
-+	 * lv_size > 4G    -> 64M
-+	 */
-+	if (lv_size_bytes <= (512 * ONE_MB_IN_BYTES))
-+		initial_bytes = 4 * ONE_MB_IN_BYTES;
-+	else if (lv_size_bytes <= ONE_GB_IN_BYTES)
-+		initial_bytes = 8 * ONE_MB_IN_BYTES;
-+	else if (lv_size_bytes <= (4ULL * ONE_GB_IN_BYTES))
-+		initial_bytes = 32 * ONE_MB_IN_BYTES;
-+	else if (lv_size_bytes > (4ULL * ONE_GB_IN_BYTES))
-+		initial_bytes = 64 * ONE_MB_IN_BYTES;
-+
-+	return meta_bytes + initial_bytes;
- }
- 
- /*
-@@ -278,7 +303,7 @@ int lv_remove_integrity_from_raid(struct logical_volume *lv)
- 	return 1;
- }
- 
--static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_volume *lv,
-+static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_volume *lv, int is_active,
- 				     struct integrity_settings *settings,
- 				     int lbs_4k, int lbs_512, int pbs_4k, int pbs_512)
- {
-@@ -375,7 +400,13 @@ static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_vol
- 		}
- 
- 		if (!settings->block_size) {
--			if (fs_block_size <= 4096)
-+			if (is_active && lbs_512) {
-+				/* increasing the lbs from 512 to 4k under an active LV could cause problems
-+				   for an application that expects a given io size/alignment is possible. */
-+				settings->block_size = 512;
-+				if (fs_block_size > 512)
-+					log_print("Limiting integrity block size to 512 because the LV is active.");
-+			} else if (fs_block_size <= 4096)
- 				settings->block_size = fs_block_size;
- 			else
- 				settings->block_size = 4096; /* dm-integrity max is 4096 */
-@@ -587,13 +618,33 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
- 		}
- 	}
- 
-+	if (!is_active) {
-+		/* checking block size of fs on the lv requires the lv to be active */
-+		if (!activate_lv(cmd, lv)) {
-+			log_error("Failed to activate LV to check block size %s", display_lvname(lv));
-+			goto bad;
-+		}
-+		if (!sync_local_dev_names(cmd))
-+			stack;
-+	}
-+
- 	/*
- 	 * Set settings->block_size which will be copied to segment settings below.
- 	 * integrity block size chosen based on device logical block size and
- 	 * file system block size.
- 	 */
--	if (!_set_integrity_block_size(cmd, lv, settings, lbs_4k, lbs_512, pbs_4k, pbs_512))
-+	if (!_set_integrity_block_size(cmd, lv, is_active, settings, lbs_4k, lbs_512, pbs_4k, pbs_512)) {
-+		if (!is_active && !deactivate_lv(cmd, lv))
-+			stack;
- 		goto_bad;
-+	}
-+
-+	if (!is_active) {
-+		if (!deactivate_lv(cmd, lv)) {
-+			log_error("Failed to deactivate LV after checking block size %s", display_lvname(lv));
-+			goto bad;
-+		}
-+	}
- 
- 	/*
- 	 * For each rimage, move its segments to a new rimage_iorig and give
-diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
-index 4ee58b4..fac47e5 100644
---- a/lib/metadata/lv.c
-+++ b/lib/metadata/lv.c
-@@ -1412,6 +1412,9 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
- 	} else if (lvdm->seg_status.type == SEG_STATUS_THIN) {
- 		if (lvdm->seg_status.thin->fail)
- 			repstr[8] = 'F';
-+	} else if (lvdm->seg_status.type == SEG_STATUS_WRITECACHE) {
-+		if (lvdm->seg_status.writecache->error)
-+			repstr[8] = 'E';
- 	} else if (lvdm->seg_status.type == SEG_STATUS_UNKNOWN)
- 		repstr[8] = 'X'; /* Unknown */
- 
-diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
-index 1311f70..f0ba3f0 100644
---- a/lib/metadata/lv_manip.c
-+++ b/lib/metadata/lv_manip.c
-@@ -5066,6 +5066,7 @@ static int _lvresize_check(struct logical_volume *lv,
- 			   struct lvresize_params *lp)
- {
- 	struct volume_group *vg = lv->vg;
-+	struct lv_segment *seg = first_seg(lv);
- 
- 	if (lv_is_external_origin(lv)) {
- 		/*
-@@ -5089,6 +5090,12 @@ static int _lvresize_check(struct logical_volume *lv,
- 		return 0;
- 	}
- 
-+	if (seg && (seg_is_raid4(seg) || seg_is_any_raid5(seg)) && seg->area_count < 3) {
-+		log_error("Cannot resize %s LV %s. Convert to more stripes first.",
-+			  lvseg_name(seg), display_lvname(lv));
-+		return 0;
-+	}
-+
- 	if (lv_is_raid(lv) &&
- 	    lp->resize == LV_REDUCE) {
- 		unsigned attrs;
-@@ -6568,7 +6575,20 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
- 		}
- 	}
- 
--	if (lv_is_used_cache_pool(lv) || lv_is_cache_vol(lv)) {
-+	if (lv_is_cache_vol(lv)) {
-+		if ((cache_seg = get_only_segment_using_this_lv(lv))) {
-+			/* When used with cache, lvremove on cachevol also removes the cache! */
-+		       	if (seg_is_cache(cache_seg)) {
-+				if (!lv_cache_remove(cache_seg->lv))
-+					return_0;
-+			} else if (seg_is_writecache(cache_seg)) {
-+				log_error("Detach cachevol before removing.");
-+				return 0;
-+			}
-+		}
-+	}
-+
-+	if (lv_is_used_cache_pool(lv)) {
- 		/* Cache pool removal drops cache layer
- 		 * If the cache pool is not linked, we can simply remove it. */
- 		if (!(cache_seg = get_only_segment_using_this_lv(lv)))
-@@ -6832,7 +6852,7 @@ static int _lv_update_and_reload(struct logical_volume *lv, int origin_only)
- 	}
- 
- 	if (!(origin_only ? suspend_lv_origin(vg->cmd, lock_lv) : suspend_lv(vg->cmd, lock_lv))) {
--		log_error("Failed to lock logical volume %s.",
-+		log_error("Failed to suspend logical volume %s.",
- 			  display_lvname(lock_lv));
- 		vg_revert(vg);
- 	} else if (!(r = vg_commit(vg)))
-@@ -7556,20 +7576,22 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
- 	struct device *dev;
- 	char name[PATH_MAX];
- 	uint64_t zero_sectors;
-+	int zero_metadata = wp.is_metadata ?
-+		find_config_tree_bool(lv->vg->cmd, allocation_zero_metadata_CFG, NULL) : 0;
- 
--	if (!wp.do_zero && !wp.do_wipe_signatures)
-+	if (!wp.do_zero && !wp.do_wipe_signatures && !wp.is_metadata)
- 		/* nothing to do */
- 		return 1;
- 
- 	if (!lv_is_active(lv)) {
--		log_error("Volume \"%s/%s\" is not active locally (volume_list activation filter?).",
--			  lv->vg->name, lv->name);
-+		log_error("Volume %s is not active locally (volume_list activation filter?).",
-+			  display_lvname(lv));
- 		return 0;
- 	}
- 
- 	/* Wait until devices are available */
- 	if (!sync_local_dev_names(lv->vg->cmd)) {
--		log_error("Failed to sync local devices before wiping LV %s.",
-+		log_error("Failed to sync local devices before wiping volume %s.",
- 			  display_lvname(lv));
- 		return 0;
- 	}
-@@ -7593,40 +7615,59 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
- 	}
- 
- 	if (!label_scan_open_rw(dev)) {
--		log_error("Failed to open %s/%s for wiping and zeroing.", lv->vg->name, lv->name);
--		goto out;
-+		log_error("Failed to open %s for wiping and zeroing.", display_lvname(lv));
-+		return 0;
- 	}
- 
- 	if (wp.do_wipe_signatures) {
--		log_verbose("Wiping known signatures on logical volume \"%s/%s\"",
--			    lv->vg->name, lv->name);
-+		log_verbose("Wiping known signatures on logical volume %s.",
-+			    display_lvname(lv));
- 		if (!wipe_known_signatures(lv->vg->cmd, dev, name, 0,
- 					   TYPE_DM_SNAPSHOT_COW,
--					   wp.yes, wp.force, NULL))
--			stack;
-+					   wp.yes, wp.force, NULL)) {
-+			log_error("Filed to wipe signatures of logical volume %s.",
-+				  display_lvname(lv));
-+			return 0;
-+		}
- 	}
- 
--	if (wp.do_zero) {
--		zero_sectors = wp.zero_sectors ? : UINT64_C(4096) >> SECTOR_SHIFT;
--
--		if (zero_sectors > lv->size)
-+	if (wp.do_zero || wp.is_metadata) {
-+		zero_metadata = !wp.is_metadata ? 0 :
-+			find_config_tree_bool(lv->vg->cmd, allocation_zero_metadata_CFG, NULL);
-+		if (zero_metadata) {
-+			log_debug("Metadata logical volume %s will be fully zeroed.",
-+				  display_lvname(lv));
- 			zero_sectors = lv->size;
-+		} else {
-+			if (wp.is_metadata) /* Verbosely notify metadata will not be fully zeroed */
-+				log_verbose("Metadata logical volume %s not fully zeroed and may contain stale data.",
-+					    display_lvname(lv));
-+			zero_sectors = UINT64_C(4096) >> SECTOR_SHIFT;
-+			if (wp.zero_sectors > zero_sectors)
-+				zero_sectors = wp.zero_sectors;
- 
--		log_verbose("Initializing %s of logical volume \"%s/%s\" with value %d.",
--			    display_size(lv->vg->cmd, zero_sectors),
--			    lv->vg->name, lv->name, wp.zero_value);
-+			if (zero_sectors > lv->size)
-+				zero_sectors = lv->size;
-+		}
- 
--		if (!wp.zero_value) {
--			if (!dev_write_zeros(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT))
--				stack;
--		} else {
--			if (!dev_set_bytes(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT, (uint8_t)wp.zero_value))
--				stack;
-+		log_verbose("Initializing %s of logical volume %s with value %d.",
-+			    display_size(lv->vg->cmd, zero_sectors),
-+			    display_lvname(lv), wp.zero_value);
-+
-+		if ((!wp.is_metadata &&
-+		     wp.zero_value && !dev_set_bytes(dev, UINT64_C(0),
-+						     (size_t) zero_sectors << SECTOR_SHIFT,
-+						     (uint8_t)wp.zero_value)) ||
-+		    !dev_write_zeros(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT)) {
-+			log_error("Failed to initialize %s of logical volume %s with value %d.",
-+				  display_size(lv->vg->cmd, zero_sectors),
-+				  display_lvname(lv), wp.zero_value);
-+			return 0;
- 		}
- 	}
- 
- 	label_scan_invalidate(dev);
--out:
-+
- 	lv->status &= ~LV_NOSCAN;
- 
- 	return 1;
-@@ -7690,12 +7731,10 @@ int activate_and_wipe_lvlist(struct dm_list *lv_list, int commit)
- 		}
- 
- 	dm_list_iterate_items(lvl, lv_list) {
--		log_verbose("Wiping metadata area %s.", display_lvname(lvl->lv));
- 		/* Wipe any know signatures */
--		if (!wipe_lv(lvl->lv, (struct wipe_params) { .do_wipe_signatures = 1, .do_zero = 1, .zero_sectors = 1 })) {
--			log_error("Failed to wipe %s.", display_lvname(lvl->lv));
-+		if (!wipe_lv(lvl->lv, (struct wipe_params) { .do_zero = 1 /* TODO: is_metadata = 1 */ })) {
- 			r = 0;
--			goto out;
-+			goto_out;
- 		}
- 	}
- out:
-@@ -8440,7 +8479,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
- 				     .do_zero = lp->zero,
- 				     .do_wipe_signatures = lp->wipe_signatures,
- 				     .yes = lp->yes,
--				     .force = lp->force
-+				     .force = lp->force,
-+				     .is_metadata = lp->is_metadata,
- 			     })) {
- 			log_error("Aborting. Failed to wipe %s.", lp->snapshot
- 				  ? "snapshot exception store" : "start of new LV");
-diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
-index ecd55ef..1d47449 100644
---- a/lib/metadata/merge.c
-+++ b/lib/metadata/merge.c
-@@ -441,7 +441,8 @@ static void _check_lv_segment(struct logical_volume *lv, struct lv_segment *seg,
- 		if (seg_is_mirror(seg)) {
- 			if (!seg->region_size)
- 				seg_error("region size is zero");
--			else if (seg->region_size > seg->lv->size)
-+			/* Avoid regionsize check in case of 'mirrored' mirror log or larger than mlog regionsize will fail */
-+			else if (!strstr(seg->lv->name, "_mlog") && (seg->region_size > seg->lv->size))
- 				seg_error("region size is bigger then LV itself");
- 			else if (!is_power_of_2(seg->region_size))
- 				seg_error("region size is non power of 2");
-diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
-index 083f74a..06ea757 100644
---- a/lib/metadata/metadata-exported.h
-+++ b/lib/metadata/metadata-exported.h
-@@ -89,8 +89,7 @@
- #define PARTIAL_LV		UINT64_C(0x0000000001000000)	/* LV - derived flag, not
- 							   written out in metadata*/
- 
--//#define POSTORDER_FLAG	UINT64_C(0x0000000002000000) /* Not real flags, reserved for
--//#define POSTORDER_OPEN_FLAG	UINT64_C(0x0000000004000000)    temporary use inside vg_read_internal. */
-+#define WRITECACHE_ORIGIN	UINT64_C(0x0000000002000000)
- #define INTEGRITY_METADATA	UINT64_C(0x0000000004000000)    /* LV - Internal use only */
- #define VIRTUAL_ORIGIN		UINT64_C(0x0000000008000000)	/* LV - internal use only */
- 
-@@ -804,6 +803,7 @@ struct wipe_params {
- 	int do_wipe_signatures;	/* should we wipe known signatures found on LV? */
- 	int yes;		/* answer yes automatically to all questions */
- 	force_t force;		/* force mode */
-+	int is_metadata;	/* wipe volume is metadata LV */
- };
- 
- /* Zero out LV and/or wipe signatures */
-@@ -955,6 +955,8 @@ struct lvcreate_params {
- 	int thin_chunk_size_calc_policy;
- 	unsigned suppress_zero_warn : 1;
- 	unsigned needs_lockd_init : 1;
-+	unsigned ignore_type : 1;
-+	unsigned is_metadata : 1; /* created LV will be used as metadata LV (and can be zeroed) */
- 
- 	const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
- 	const char *lv_name; /* all */
-@@ -1097,6 +1099,7 @@ int lv_is_cow(const struct logical_volume *lv);
- int lv_is_cache_origin(const struct logical_volume *lv);
- int lv_is_writecache_origin(const struct logical_volume *lv);
- int lv_is_writecache_cachevol(const struct logical_volume *lv);
-+int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem);
- 
- int lv_is_integrity_origin(const struct logical_volume *lv);
- 
-diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
-index 4b8dce9..c0d4206 100644
---- a/lib/metadata/metadata.c
-+++ b/lib/metadata/metadata.c
-@@ -4875,8 +4875,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
- 		}
- 	}
- 
--	if (found_old_metadata)
-+	if (found_old_metadata) {
- 		log_warn("WARNING: Inconsistent metadata found for VG %s.", vgname);
-+		log_warn("See vgck --updatemetadata to correct inconsistency.");
-+	}
- 
- 	vg = NULL;
- 
-diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
-index bed51f1..23b5b63 100644
---- a/lib/metadata/pool_manip.c
-+++ b/lib/metadata/pool_manip.c
-@@ -545,8 +545,8 @@ int create_pool(struct logical_volume *pool_lv,
- 				  display_lvname(pool_lv));
- 			goto bad;
- 		}
--		/* Clear 4KB of pool metadata device. */
--		if (!(r = wipe_lv(pool_lv, (struct wipe_params) { .do_zero = 1 }))) {
-+		/* Clear pool metadata device. */
-+		if (!(r = wipe_lv(pool_lv, (struct wipe_params) { .is_metadata = 1 }))) {
- 			log_error("Aborting. Failed to wipe pool metadata %s.",
- 				  display_lvname(pool_lv));
- 		}
-@@ -627,6 +627,7 @@ struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv,
- 		.tags = DM_LIST_HEAD_INIT(lvc.tags),
- 		.temporary = 1,
- 		.zero = 1,
-+		.is_metadata = 1,
- 	};
- 
- 	if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
-@@ -663,6 +664,7 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
- 		.tags = DM_LIST_HEAD_INIT(lp.tags),
- 		.temporary = 1,
- 		.zero = 1,
-+		.is_metadata = 1,
- 	};
- 
- 	if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
-diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
-index 3b3e1d3..1ff2a0c 100644
---- a/lib/metadata/raid_manip.c
-+++ b/lib/metadata/raid_manip.c
-@@ -3229,6 +3229,11 @@ int lv_raid_change_image_count(struct logical_volume *lv, int yes, uint32_t new_
- 	const char *level = seg->area_count == 1 ? "raid1 with " : "";
- 	const char *resil = new_count < seg->area_count ? "reducing" : "enhancing";
- 
-+	if (new_count == seg->area_count) {
-+		log_warn("Type %s LV %s already has %u images.", lvseg_name(seg), display_lvname(lv), new_count);
-+		return 1;
-+	}
-+
- 	/* LV must be active to perform raid conversion operations */
- 	if (!lv_is_active(lv)) {
- 		log_error("%s must be active to perform this operation.",
-diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
-index 3faea0e..0f48e62 100644
---- a/lib/metadata/snapshot_manip.c
-+++ b/lib/metadata/snapshot_manip.c
-@@ -389,8 +389,6 @@ int validate_snapshot_origin(const struct logical_volume *origin_lv)
- 		err = "raid subvolumes";
- 	} else if (lv_is_raid(origin_lv) && lv_raid_has_integrity((struct logical_volume *)origin_lv)) {
- 		err = "raid with integrity";
--	} else if (lv_is_writecache(origin_lv)) {
--		err = "writecache";
- 	}
- 
- 	if (err) {
-diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c
-index 31d069e..fade82e 100644
---- a/lib/metadata/writecache_manip.c
-+++ b/lib/metadata/writecache_manip.c
-@@ -21,11 +21,21 @@
- #include "lib/metadata/segtype.h"
- #include "lib/activate/activate.h"
- #include "lib/config/defaults.h"
-+#include "lib/datastruct/str_list.h"
- 
- int lv_is_writecache_origin(const struct logical_volume *lv)
- {
- 	struct lv_segment *seg;
- 
-+	/*
-+	 * This flag is needed when removing writecache from an origin
-+	 * in which case the lv connections have been destroyed and
-+	 * identifying a writecache origin by these connections doesn't
-+	 * work.
-+	 */
-+	if (lv->status & WRITECACHE_ORIGIN)
-+		return 1;
-+
- 	/* Make sure there's exactly one segment in segs_using_this_lv! */
- 	if (dm_list_empty(&lv->segs_using_this_lv) ||
- 	    (dm_list_size(&lv->segs_using_this_lv) > 1))
-@@ -48,46 +58,6 @@ int lv_is_writecache_cachevol(const struct logical_volume *lv)
- 	return 0;
- }
- 
--static int _lv_writecache_detach(struct cmd_context *cmd, struct logical_volume *lv,
--				 struct logical_volume *lv_fast)
--{
--	struct lv_segment *seg = first_seg(lv);
--	struct logical_volume *origin;
--
--	if (!seg_is_writecache(seg)) {
--		log_error("LV %s segment is not writecache.", display_lvname(lv));
--		return 0;
--	}
--
--	if (!seg->writecache) {
--		log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
--		return 0;
--	}
--
--	if (!(origin = seg_lv(seg, 0))) {
--		log_error("LV %s writecache segment has no origin", display_lvname(lv));
--		return 0;
--	}
--
--	if (!remove_seg_from_segs_using_this_lv(seg->writecache, seg))
--		return_0;
--
--	lv_set_visible(seg->writecache);
--
--	lv->status &= ~WRITECACHE;
--	seg->writecache = NULL;
--
--	lv_fast->status &= ~LV_CACHE_VOL;
--
--	if (!remove_layer_from_lv(lv, origin))
--		return_0;
--
--	if (!lv_remove(origin))
--		return_0;
--
--	return 1;
--}
--
- static int _get_writecache_kernel_error(struct cmd_context *cmd,
- 					struct logical_volume *lv,
- 					uint32_t *kernel_error)
-@@ -131,13 +101,64 @@ fail:
- 	return 0;
- }
- 
--int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
-+static void _rename_detached_cvol(struct cmd_context *cmd, struct logical_volume *lv_fast)
-+{
-+	struct volume_group *vg = lv_fast->vg;
-+	char cvol_name[NAME_LEN];
-+	char *suffix, *cvol_name_dup;
-+
-+	/*
-+	 * Rename lv_fast back to its original name, without the _cvol
-+	 * suffix that was added when lv_fast was attached for caching.
-+	 * If the name is in use, generate new lvol%d.
-+	 * Failing to rename is not really a problem, so we intentionally
-+	 * do not consider some things here as errors.
-+	 */
-+	if (!dm_strncpy(cvol_name, lv_fast->name, sizeof(cvol_name)) ||
-+	    !(suffix  = strstr(cvol_name, "_cvol"))) {
-+		log_debug("LV %s has no suffix for cachevol (skipping rename).",
-+			display_lvname(lv_fast));
-+		return;
-+	}
-+
-+	*suffix = 0;
-+	if (lv_name_is_used_in_vg(vg, cvol_name, NULL) &&
-+	    !generate_lv_name(vg, "lvol%d", cvol_name, sizeof(cvol_name))) {
-+		log_warn("Failed to generate new unique name for unused LV %s", lv_fast->name);
-+		return;
-+	}
-+
-+	if (!(cvol_name_dup = dm_pool_strdup(vg->vgmem, cvol_name))) {
-+		stack;
-+		return;
-+	}
-+
-+	lv_fast->name = cvol_name_dup;
-+}
-+
-+static int _lv_detach_writecache_cachevol_inactive(struct logical_volume *lv, int noflush)
- {
- 	struct cmd_context *cmd = lv->vg->cmd;
-+	struct volume_group *vg = lv->vg;
- 	struct logical_volume *lv_fast;
-+	struct logical_volume *lv_wcorig;
-+	struct lv_segment *seg = first_seg(lv);
- 	uint32_t kernel_error = 0;
- 
--	lv_fast = first_seg(lv)->writecache;
-+	if (!seg_is_writecache(seg)) {
-+		log_error("LV %s segment is not writecache.", display_lvname(lv));
-+		return 0;
-+	}
-+
-+	if (!(lv_fast = seg->writecache)) {
-+		log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
-+		return 0;
-+	}
-+
-+	if (!(lv_wcorig = seg_lv(seg, 0))) {
-+		log_error("LV %s writecache segment has no origin", display_lvname(lv));
-+		return 0;
-+	}
- 
- 	if (noflush)
- 		goto detach;
-@@ -157,6 +178,8 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
- 
- 	if (!sync_local_dev_names(cmd)) {
- 		log_error("Failed to sync local devices before detaching writecache.");
-+		if (!deactivate_lv(cmd, lv))
-+			log_error("Failed to deactivate %s.", display_lvname(lv));
- 		return 0;
- 	}
- 
-@@ -176,7 +199,8 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
- 
- 	if (kernel_error) {
- 		log_error("Failed to flush writecache (error %u) for %s.", kernel_error, display_lvname(lv));
--		deactivate_lv(cmd, lv);
-+		if (!deactivate_lv(cmd, lv))
-+			log_error("Failed to deactivate %s.", display_lvname(lv));
- 		return 0;
- 	}
- 
-@@ -188,11 +212,262 @@ int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
- 	lv->status &= ~LV_TEMPORARY;
- 
-  detach:
--	if (!_lv_writecache_detach(cmd, lv, lv_fast)) {
--		log_error("Failed to detach writecache from %s", display_lvname(lv));
-+	if (!remove_seg_from_segs_using_this_lv(lv_fast, seg))
-+		return_0;
-+
-+	lv->status &= ~WRITECACHE;
-+	seg->writecache = NULL;
-+
-+	if (!remove_layer_from_lv(lv, lv_wcorig))
-+		return_0;
-+
-+	if (!lv_remove(lv_wcorig))
-+		return_0;
-+
-+	lv_set_visible(lv_fast);
-+	lv_fast->status &= ~LV_CACHE_VOL;
-+
-+	_rename_detached_cvol(cmd, lv_fast);
-+
-+	if (!vg_write(vg) || !vg_commit(vg))
-+		return_0;
-+
-+	return 1;
-+}
-+
-+static int _lv_detach_writecache_cachevol_active(struct logical_volume *lv, int noflush)
-+{
-+	struct cmd_context *cmd = lv->vg->cmd;
-+	struct volume_group *vg = lv->vg;
-+	struct logical_volume *lv_fast;
-+	struct logical_volume *lv_wcorig;
-+	struct logical_volume *lv_old;
-+	struct lv_segment *seg = first_seg(lv);
-+	uint32_t kernel_error = 0;
-+
-+	if (!seg_is_writecache(seg)) {
-+		log_error("LV %s segment is not writecache.", display_lvname(lv));
-+		return 0;
-+	}
-+
-+	if (!(lv_fast = seg->writecache)) {
-+		log_error("LV %s writecache segment has no writecache.", display_lvname(lv));
- 		return 0;
- 	}
- 
-+	if (!(lv_wcorig = seg_lv(seg, 0))) {
-+		log_error("LV %s writecache segment has no origin", display_lvname(lv));
-+		return 0;
-+	}
-+
-+	if (noflush)
-+		goto detach;
-+
-+	if (!lv_writecache_message(lv, "flush_on_suspend")) {
-+		log_error("Failed to set flush_on_suspend in writecache detach %s.", display_lvname(lv));
-+		return 0;
-+	}
-+
-+ detach:
-+	if (!remove_seg_from_segs_using_this_lv(lv_fast, seg)) {
-+		log_error("Failed to remove seg in writecache detach.");
-+		return 0;
-+	}
-+
-+	lv->status &= ~WRITECACHE;
-+	seg->writecache = NULL;
-+
-+	if (!remove_layer_from_lv(lv, lv_wcorig)) {
-+		log_error("Failed to remove lv layer in writecache detach.");
-+		return 0;
-+	}
-+
-+	/*
-+	 * vg_write(), suspend_lv(), vg_commit(), resume_lv().
-+	 * usually done by lv_update_and_reload for an active lv,
-+	 * but in this case we need to check for writecache errors
-+	 * after suspend.
-+	 */
-+
-+	if (!vg_write(vg)) {
-+		log_error("Failed to write VG in writecache detach.");
-+		return 0;
-+	}
-+
-+	/*
-+	 * The version of LV before removal of writecache.  When need to
-+	 * check for kernel errors based on the old version of LV which
-+	 * is still present in the kernel.
-+	 */
-+	if (!(lv_old = (struct logical_volume *)lv_committed(lv))) {
-+		log_error("Failed to get lv_committed in writecache detach.");
-+		return 0;
-+	}
-+
-+	/*
-+	 * suspend does not use 'lv' as we know it here, but grabs the
-+	 * old (precommitted) version of 'lv' using lv_committed(),
-+	 * which is from vg->vg_comitted.
-+	 */
-+	log_debug("Suspending writecache to detach %s", display_lvname(lv));
-+
-+	if (!suspend_lv(cmd, lv)) {
-+		log_error("Failed to suspend LV in writecache detach.");
-+		vg_revert(vg);
-+		return 0;
-+	}
-+
-+	log_debug("Checking writecache errors to detach.");
-+
-+	if (!_get_writecache_kernel_error(cmd, lv_old, &kernel_error)) {
-+		log_error("Failed to get writecache error status for %s.", display_lvname(lv_old));
-+		return 0;
-+	}
-+
-+	if (kernel_error) {
-+		log_error("Failed to flush writecache (error %u) for %s.", kernel_error, display_lvname(lv));
-+		return 0;
-+	}
-+
-+	if (!vg_commit(vg)) {
-+		log_error("Failed to commit VG in writecache detach.");
-+		return 0;
-+	}
-+
-+	/*
-+	 * Since vg_commit has happened, vg->vg_committed is now the
-+	 * newest copy of lv, so resume uses the 'lv' that we know
-+	 * here.
-+	 */
-+	log_debug("Resuming after writecache detached %s", display_lvname(lv));
-+
-+	if (!resume_lv(cmd, lv)) {
-+		log_error("Failed to resume LV in writecache detach.");
-+		return 0;
-+	}
-+
-+	log_debug("Deactivating previous cachevol %s", display_lvname(lv_fast));
-+
-+	if (!deactivate_lv(cmd, lv_fast))
-+		log_error("Failed to deactivate previous cachevol in writecache detach.");
-+
-+	/*
-+	 * Needed for lv_is_writecache_origin to know lv_wcorig was
-+	 * a writecache origin, which is needed so that the -real
-+	 * dm uuid suffix is applied, which is needed for deactivate to
-+	 * work. This is a hacky roundabout way of setting the -real
-+	 * uuid suffix (it would be nice to have a deactivate command
-+	 * that accepts a dm uuid.)
-+	 */
-+	lv_wcorig->status |= WRITECACHE_ORIGIN;
-+
-+	log_debug("Deactivating previous wcorig %s", display_lvname(lv_wcorig));
-+
-+	if (!lv_deactivate(cmd, NULL, lv_wcorig))
-+		log_error("Failed to deactivate previous wcorig LV in writecache detach.");
-+
-+	log_debug("Removing previous wcorig %s", display_lvname(lv_wcorig));
-+
-+	if (!lv_remove(lv_wcorig)) {
-+		log_error("Failed to remove previous wcorig LV in writecache detach.");
-+		return 0;
-+	}
-+
-+	lv_set_visible(lv_fast);
-+	lv_fast->status &= ~LV_CACHE_VOL;
-+
-+	_rename_detached_cvol(cmd, lv_fast);
-+
-+	if (!vg_write(vg) || !vg_commit(vg)) {
-+		log_error("Failed to write and commit VG in writecache detach.");
-+		return 0;
-+	}
-+
-+	return 1;
-+}
-+
-+int lv_detach_writecache_cachevol(struct logical_volume *lv, int noflush)
-+{
-+	if (lv_is_active(lv))
-+		return _lv_detach_writecache_cachevol_active(lv, noflush);
-+	else
-+		return _lv_detach_writecache_cachevol_inactive(lv, noflush);
-+}
-+
-+static int _writecache_setting_str_list_add(const char *field, uint64_t val, char *val_str, struct dm_list *result, struct dm_pool *mem)
-+{
-+	char buf[128];
-+	char *list_item;
-+	int len;
-+
-+	if (val_str) {
-+		if (dm_snprintf(buf, sizeof(buf), "%s=%s", field, val_str) < 0)
-+			return_0;
-+	} else {
-+		if (dm_snprintf(buf, sizeof(buf), "%s=%llu", field, (unsigned long long)val) < 0)
-+			return_0;
-+	}
-+
-+	len = strlen(buf) + 1;
-+
-+	if (!(list_item = dm_pool_zalloc(mem, len)))
-+		return_0;
-+
-+	memcpy(list_item, buf, len);
-+
-+	if (!str_list_add_no_dup_check(mem, result, list_item))
-+		return_0;
-+
-+	return 1;
-+}
-+
-+int writecache_settings_to_str_list(struct writecache_settings *settings, struct dm_list *result, struct dm_pool *mem)
-+{
-+	int errors = 0;
-+
-+	if (settings->high_watermark_set)
-+		if (!_writecache_setting_str_list_add("high_watermark", settings->high_watermark, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->low_watermark_set)
-+		if (!_writecache_setting_str_list_add("low_watermark", settings->low_watermark, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->writeback_jobs_set)
-+		if (!_writecache_setting_str_list_add("writeback_jobs", settings->writeback_jobs, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->autocommit_blocks_set)
-+		if (!_writecache_setting_str_list_add("autocommit_blocks", settings->autocommit_blocks, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->autocommit_time_set)
-+		if (!_writecache_setting_str_list_add("autocommit_time", settings->autocommit_time, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->fua_set)
-+		if (!_writecache_setting_str_list_add("fua", (uint64_t)settings->fua, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->nofua_set)
-+		if (!_writecache_setting_str_list_add("nofua", (uint64_t)settings->nofua, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->cleaner_set && settings->cleaner)
-+		if (!_writecache_setting_str_list_add("cleaner", (uint64_t)settings->cleaner, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->max_age_set)
-+		if (!_writecache_setting_str_list_add("max_age", (uint64_t)settings->max_age, NULL, result, mem))
-+			errors++;
-+
-+	if (settings->new_key && settings->new_val)
-+		if (!_writecache_setting_str_list_add(settings->new_key, 0, settings->new_val, result, mem))
-+			errors++;
-+
-+	if (errors)
-+		log_warn("Failed to create list of writecache settings.");
-+
- 	return 1;
- }
- 
-diff --git a/lib/report/report.c b/lib/report/report.c
-index 170df69..979cbee 100644
---- a/lib/report/report.c
-+++ b/lib/report/report.c
-@@ -1430,6 +1430,16 @@ static int _cache_settings_disp(struct dm_report *rh, struct dm_pool *mem,
- 	struct _str_list_append_baton baton;
- 	struct dm_list dummy_list; /* dummy list to display "nothing" */
- 
-+	if (seg_is_writecache(seg)) {
-+		if (!(result = str_list_create(mem)))
-+			return_0;
-+
-+		if (!writecache_settings_to_str_list((struct writecache_settings *)&seg->writecache_settings, result, mem))
-+			return_0;
-+
-+		return _field_set_string_list(rh, field, result, private, 0, NULL);
-+	}
-+
- 	if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
- 		setting_seg = seg;
- 
-@@ -3802,6 +3812,12 @@ static int _lvhealthstatus_disp(struct dm_report *rh, struct dm_pool *mem,
- 			health = "failed";
- 		else if (lvdm->seg_status.cache->read_only)
- 			health = "metadata_read_only";
-+	} else if (lv_is_writecache(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) {
-+		if (lvdm->seg_status.type != SEG_STATUS_WRITECACHE)
-+			return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef),
-+						GET_FIELD_RESERVED_VALUE(health_undef));
-+		if (lvdm->seg_status.writecache->error)
-+			health = "error";
- 	} else if (lv_is_thin_pool(lv) && (lvdm->seg_status.type != SEG_STATUS_NONE)) {
- 		if (lvdm->seg_status.type != SEG_STATUS_THIN_POOL)
- 			return _field_set_value(field, GET_FIRST_RESERVED_NAME(health_undef),
-@@ -3945,7 +3961,7 @@ static int _vdo_ ## vdo_field_name ## _disp (struct dm_report *rh, struct dm_poo
- 	if (!seg_is_vdo_pool(seg)) \
- 		return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64)); \
- \
--	size = seg->vdo_params.vdo_field_name ## _mb * (1024 * 1024 >> SECTOR_SHIFT); \
-+	size = seg->vdo_params.vdo_field_name ## _mb * (UINT64_C(1024) * 1024 >> SECTOR_SHIFT); \
- \
- 	return _size64_disp(rh, mem, field, &size, private);\
- }
-diff --git a/lib/writecache/writecache.c b/lib/writecache/writecache.c
-index 130922a..c7aea28 100644
---- a/lib/writecache/writecache.c
-+++ b/lib/writecache/writecache.c
-@@ -26,6 +26,9 @@
- #include "lib/metadata/lv_alloc.h"
- #include "lib/config/defaults.h"
- 
-+static int _writecache_cleaner_supported;
-+static int _writecache_max_age_supported;
-+
- #define SEG_LOG_ERROR(t, p...) \
-         log_error(t " segment %s of logical volume %s.", ## p,	\
-                   dm_config_parent_name(sn), seg->lv->name), 0;
-@@ -120,6 +123,18 @@ static int _writecache_text_import(struct lv_segment *seg,
- 		seg->writecache_settings.nofua_set = 1;
- 	}
- 
-+	if (dm_config_has_node(sn, "cleaner")) {
-+		if (!dm_config_get_uint32(sn, "cleaner", &seg->writecache_settings.cleaner))
-+			return SEG_LOG_ERROR("Unknown writecache_setting in");
-+		seg->writecache_settings.cleaner_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "max_age")) {
-+		if (!dm_config_get_uint32(sn, "max_age", &seg->writecache_settings.max_age))
-+			return SEG_LOG_ERROR("Unknown writecache_setting in");
-+		seg->writecache_settings.max_age_set = 1;
-+	}
-+
- 	if (dm_config_has_node(sn, "writecache_setting_key")) {
- 		const char *key;
- 		const char *val;
-@@ -184,6 +199,14 @@ static int _writecache_text_export(const struct lv_segment *seg,
- 	        outf(f, "nofua = %u", seg->writecache_settings.nofua);
- 	}
- 
-+	if (seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
-+	        outf(f, "cleaner = %u", seg->writecache_settings.cleaner);
-+	}
-+
-+	if (seg->writecache_settings.max_age_set) {
-+	        outf(f, "max_age = %u", seg->writecache_settings.max_age);
-+	}
-+
- 	if (seg->writecache_settings.new_key && seg->writecache_settings.new_val) {
- 	        outf(f, "writecache_setting_key = \"%s\"",
- 	                seg->writecache_settings.new_key);
-@@ -208,6 +231,7 @@ static int _target_present(struct cmd_context *cmd,
- {
- 	static int _writecache_checked = 0;
- 	static int _writecache_present = 0;
-+	uint32_t maj, min, patchlevel;
- 
- 	if (!activation())
- 		return 0;
-@@ -215,6 +239,19 @@ static int _target_present(struct cmd_context *cmd,
- 	if (!_writecache_checked) {
- 		_writecache_checked = 1;
- 		_writecache_present =  target_present(cmd, TARGET_NAME_WRITECACHE, 1);
-+
-+		if (!target_version(TARGET_NAME_WRITECACHE, &maj, &min, &patchlevel))
-+			return_0;
-+
-+		if (maj < 1) {
-+			log_error("writecache target version older than minimum 1.0.0");
-+			return 0;
-+		}
-+
-+		if (min >= 2) {
-+			_writecache_cleaner_supported = 1;
-+			_writecache_max_age_supported = 1;
-+		}
- 	}
- 
- 	return _writecache_present;
-@@ -257,6 +294,18 @@ static int _writecache_add_target_line(struct dev_manager *dm,
- 		return 0;
- 	}
- 
-+	if (!_writecache_cleaner_supported && seg->writecache_settings.cleaner_set && seg->writecache_settings.cleaner) {
-+		log_warn("WARNING: ignoring writecache setting \"cleaner\" which is not supported by kernel for LV %s.", seg->lv->name);
-+		seg->writecache_settings.cleaner = 0;
-+		seg->writecache_settings.cleaner_set = 0;
-+	}
-+
-+	if (!_writecache_max_age_supported && seg->writecache_settings.max_age_set) {
-+		log_warn("WARNING: ignoring writecache setting \"max_age\" which is not supported by kernel for LV %s.", seg->lv->name);
-+		seg->writecache_settings.max_age = 0;
-+		seg->writecache_settings.max_age_set = 0;
-+	}
-+
- 	if ((pmem = lv_on_pmem(seg->writecache)) < 0)
- 		return_0;
- 
-diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen
-index 7440984..b3902a5 100644
---- a/man/lvconvert.8_pregen
-+++ b/man/lvconvert.8_pregen
-@@ -23,6 +23,10 @@ lvconvert - Change logical volume layout
- .ad b
- .br
- .ad l
-+    \fB--cachedevice\fP \fIPV\fP
-+.ad b
-+.br
-+.ad l
-     \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
- .ad b
- .br
-@@ -43,6 +47,10 @@ lvconvert - Change logical volume layout
- .ad b
- .br
- .ad l
-+    \fB--cachesize\fP \fISize\fP[m|UNIT]
-+.ad b
-+.br
-+.ad l
-     \fB--cachevol\fP \fILV\fP
- .ad b
- .br
-@@ -738,6 +746,44 @@ Attach a cache to an LV, converts the LV to type cache.
- .br
- -
- 
-+Add a writecache to an LV, using a specified cache device.
-+.br
-+.P
-+\fBlvconvert\fP \fB--type\fP \fBwritecache\fP \fB--cachedevice\fP \fIPV\fP \fILV\fP\fI_linear_striped_raid\fP
-+.br
-+.RS 4
-+.ad l
-+[    \fB--cachesize\fP \fISize\fP[m|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+-
-+
-+Add a cache to an LV, using a specified cache device.
-+.br
-+.P
-+\fBlvconvert\fP \fB--type\fP \fBcache\fP \fB--cachedevice\fP \fIPV\fP \fILV\fP\fI_linear_striped_thinpool_raid\fP
-+.br
-+.RS 4
-+.ad l
-+[    \fB--cachesize\fP \fISize\fP[m|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+-
-+
- Convert LV to type thin-pool.
- .br
- .P
-@@ -1135,6 +1181,12 @@ See \fBlvmcache\fP(7) for more information about LVM caching.
- .ad b
- .HP
- .ad l
-+\fB--cachedevice\fP \fIPV\fP
-+.br
-+The name of a device to use for a cache.
-+.ad b
-+.HP
-+.ad l
- \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
- .br
- Specifies the cache metadata format used by cache target.
-@@ -1182,6 +1234,12 @@ See \fBlvmcache\fP(7) for more information.
- .ad b
- .HP
- .ad l
-+\fB--cachesize\fP \fISize\fP[m|UNIT]
-+.br
-+The size of cache to use.
-+.ad b
-+.HP
-+.ad l
- \fB--cachevol\fP \fILV\fP
- .br
- The name of a cache volume.
-diff --git a/man/lvcreate.8_pregen b/man/lvcreate.8_pregen
-index be8e783..ee69034 100644
---- a/man/lvcreate.8_pregen
-+++ b/man/lvcreate.8_pregen
-@@ -31,6 +31,10 @@ lvcreate - Create a logical volume
- .ad b
- .br
- .ad l
-+    \fB--cachedevice\fP \fIPV\fP
-+.ad b
-+.br
-+.ad l
-     \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
- .ad b
- .br
-@@ -51,6 +55,14 @@ lvcreate - Create a logical volume
- .ad b
- .br
- .ad l
-+    \fB--cachesize\fP \fISize\fP[m|UNIT]
-+.ad b
-+.br
-+.ad l
-+    \fB--cachevol\fP \fILV\fP
-+.ad b
-+.br
-+.ad l
-  \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT]
- .ad b
- .br
-@@ -816,11 +828,9 @@ where the new thin pool is named by the --thinpool arg.
- .RE
- -
- 
--Create a cache LV, first creating a new origin LV, 
-+Create a new LV, then attach the specified cachepool 
- .br
--then combining it with the existing cache pool named 
--.br
--by the --cachepool arg.
-+which converts the new LV to type cache.
- .br
- .P
- \fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
-@@ -881,6 +891,190 @@ by the --cachepool arg.
- .RE
- -
- 
-+Create a new LV, then attach the specified cachevol 
-+.br
-+which converts the new LV to type cache.
-+.br
-+.P
-+\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
-+.RS 5
-+ \fB--cachevol\fP \fILV\fP \fIVG\fP
-+.RE
-+.br
-+.RS 4
-+.ad l
-+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachemode\fP \fBwritethrough\fP|\fBwriteback\fP|\fBpassthrough\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachepolicy\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+.RS 4
-+[ \fIPV\fP ... ]
-+.RE
-+-
-+
-+Create a new LV, then attach a cachevol created from 
-+.br
-+the specified cache device, which converts the 
-+.br
-+new LV to type cache.
-+.br
-+.P
-+\fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
-+.RS 5
-+ \fB--cachedevice\fP \fIPV\fP \fIVG\fP
-+.RE
-+.br
-+.RS 4
-+.ad l
-+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachemode\fP \fBwritethrough\fP|\fBwriteback\fP|\fBpassthrough\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachepolicy\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesize\fP \fISize\fP[m|UNIT] ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+.RS 4
-+[ \fIPV\fP ... ]
-+.RE
-+-
-+
-+Create a new LV, then attach the specified cachevol 
-+.br
-+which converts the new LV to type writecache.
-+.br
-+.P
-+\fBlvcreate\fP \fB--type\fP \fBwritecache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
-+.RS 5
-+ \fB--cachevol\fP \fILV\fP \fIVG\fP
-+.RE
-+.br
-+.RS 4
-+.ad l
-+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+.RS 4
-+[ \fIPV\fP ... ]
-+.RE
-+-
-+
-+Create a new LV, then attach a cachevol created from 
-+.br
-+the specified cache device, which converts the 
-+.br
-+new LV to type writecache.
-+.br
-+.P
-+\fBlvcreate\fP \fB--type\fP \fBwritecache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT]
-+.RS 5
-+ \fB--cachedevice\fP \fIPV\fP \fIVG\fP
-+.RE
-+.br
-+.RS 4
-+.ad l
-+[ \fB-l\fP|\fB--extents\fP \fINumber\fP[PERCENT] ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-i\fP|\fB--stripes\fP \fINumber\fP ]
-+.ad b
-+.br
-+.ad l
-+[ \fB-I\fP|\fB--stripesize\fP \fISize\fP[k|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesize\fP \fISize\fP[m|UNIT] ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--cachesettings\fP \fIString\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+.RS 4
-+[ \fIPV\fP ... ]
-+.RE
-+-
-+
- Common options for command:
- .
- .RS 4
-@@ -1091,6 +1285,12 @@ See \fBlvmcache\fP(7) for more information about LVM caching.
- .ad b
- .HP
- .ad l
-+\fB--cachedevice\fP \fIPV\fP
-+.br
-+The name of a device to use for a cache.
-+.ad b
-+.HP
-+.ad l
- \fB--cachemetadataformat\fP \fBauto\fP|\fB1\fP|\fB2\fP
- .br
- Specifies the cache metadata format used by cache target.
-@@ -1138,6 +1338,18 @@ See \fBlvmcache\fP(7) for more information.
- .ad b
- .HP
- .ad l
-+\fB--cachesize\fP \fISize\fP[m|UNIT]
-+.br
-+The size of cache to use.
-+.ad b
-+.HP
-+.ad l
-+\fB--cachevol\fP \fILV\fP
-+.br
-+The name of a cache volume.
-+.ad b
-+.HP
-+.ad l
- \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT]
- .br
- The size of chunks in a snapshot, cache pool or thin pool.
-@@ -2659,11 +2871,11 @@ config setting sparse_segtype_default.
- .RE
- -
- 
--Create a cache LV, first creating a new origin LV, 
-+Create a new LV, then attach the specified cachepool 
- .br
--then combining it with the existing cache pool named 
-+which converts the new LV to type cache 
- .br
--by the --cachepool arg (variant, infers --type cache).
-+(variant, infers --type cache.)
- .br
- .P
- \fBlvcreate\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fB--cachepool\fP \fILV\fP\fI_cachepool\fP \fIVG\fP
-@@ -2717,11 +2929,11 @@ by the --cachepool arg (variant, infers --type cache).
- .RE
- -
- 
--Create a cache LV, first creating a new origin LV, 
-+Create a new LV, then attach the specified cachepool 
- .br
--then combining it with the existing cache pool named 
-+which converts the new LV to type cache. 
- .br
--in the first arg (variant, also use --cachepool).
-+(variant, also use --cachepool).
- .br
- .P
- \fBlvcreate\fP \fB--type\fP \fBcache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fILV\fP\fI_cachepool\fP
-@@ -2779,19 +2991,15 @@ in the first arg (variant, also use --cachepool).
- .RE
- -
- 
--When LV is a cache pool, create a cache LV, 
--.br
--first creating a new origin LV, then combining it with 
--.br
--the existing cache pool named in the first arg 
-+When the LV arg is a cachepool, then create a new LV and 
- .br
--(variant, infers --type cache, also use --cachepool). 
-+attach the cachepool arg to it. 
- .br
--When LV is not a cache pool, convert the specified LV 
-+(variant, use --type cache and --cachepool.) 
- .br
--to type cache after creating a new cache pool LV to use 
-+When the LV arg is not a cachepool, then create a new cachepool 
- .br
--(use lvconvert).
-+and attach it to the LV arg (alternative, use lvconvert.)
- .br
- .P
- \fBlvcreate\fP \fB-H\fP|\fB--cache\fP \fB-L\fP|\fB--size\fP \fISize\fP[m|UNIT] \fILV\fP
-diff --git a/man/lvmcache.7_main b/man/lvmcache.7_main
-index 425904e..37d0e33 100644
---- a/man/lvmcache.7_main
-+++ b/man/lvmcache.7_main
-@@ -34,8 +34,6 @@ LVM refers to this using the LV type \fBwritecache\fP.
- 
- .SH USAGE
- 
--Both kinds of caching use similar lvm commands:
--
- .B 1. Identify main LV that needs caching
- 
- The main LV may already exist, and is located on larger, slower devices.
-@@ -131,8 +129,35 @@ attached.
-   LV   VG Attr       Type   Devices    
-   fast vg -wi------- linear /dev/fast_ssd
-   main vg -wi------- linear /dev/slow_hhd
-+
-+To stop caching the main LV and also remove unneeded cache pool,
-+use the --uncache:
-+
-+.nf
-+  $ lvconvert --uncache vg/main
-+
-+  $ lvs -a
-+  LV   VG Attr       Type   Devices
-+  main vg -wi------- linear /dev/slow_hhd
-+
- .fi
- 
-+.SS Create a new LV with caching.
-+
-+A new LV can be created with caching attached at the time of creation
-+using the following command:
-+
-+.nf
-+$ lvcreate --type cache|writecache -n Name -L Size
-+	--cachedevice /dev/fast_ssd vg /dev/slow_hhd
-+.fi
-+
-+The main LV is created with the specified Name and Size from the slow_hhd.
-+A hidden fast LV is created on the fast_ssd and is then attached to the
-+new main LV.  If the fast_ssd is unused, the entire disk will be used as
-+the cache unless the --cachesize option is used to specify a size for the
-+fast LV.  The --cachedevice option can be repeated to use multiple disks
-+for the fast LV.
- 
- .SH OPTIONS
- 
-@@ -156,12 +181,26 @@ same fast LV.  This option can be used with dm-writecache or dm-cache.
- 
- Pass this option a cachepool LV or a standard LV.  When using a cache
- pool, lvm places cache data and cache metadata on different LVs.  The two
--LVs together are called a cache pool.  This permits specific placement of
--data and metadata.  A cache pool is represented as a special type of LV
-+LVs together are called a cache pool.  This has a bit better performance
-+for dm-cache and permits specific placement and segment type selection
-+for data and metadata volumes.
-+A cache pool is represented as a special type of LV
- that cannot be used directly.  If a standard LV is passed with this
- option, lvm will first convert it to a cache pool by combining it with
- another LV to use for metadata.  This option can be used with dm-cache.
- 
-+.B --cachedevice
-+.I PV
-+.br
-+
-+This option can be used in place of --cachevol, in which case a cachevol
-+LV will be created using the specified device.  This option can be
-+repeated to create a cachevol using multiple devices, or a tag name can be
-+specified in which case the cachevol will be created using any of the
-+devices with the given tag.  If a named cache device is unused, the entire
-+device will be used to create the cachevol.  To create a cachevol of a
-+specific size from the cache devices, include the --cachesize option.
-+
- \&
- 
- .SS dm-cache block size
-@@ -335,11 +374,16 @@ $ lvconvert --type cache --cachevol fast \\
- 
- The size of data blocks managed by dm-cache can be specified with the
- --chunksize option when caching is started.  The default unit is KiB.  The
--value must be a multiple of 32KiB between 32KiB and 1GiB.
-+value must be a multiple of 32KiB between 32KiB and 1GiB. Cache chunks
-+bigger then 512KiB shall be only used when necessary.
- 
- Using a chunk size that is too large can result in wasteful use of the
- cache, in which small reads and writes cause large sections of an LV to be
--stored in the cache.  However, choosing a chunk size that is too small
-+stored in the cache. It can also require increasing migration threshold
-+which defaults to 2048 sectors (1 MiB). Lvm2 ensures migration threshold is
-+at least 8 chunks in size. This may in some cases result in very
-+high bandwidth load of transfering data between the cache LV and its
-+cache origin LV. However, choosing a chunk size that is too small
- can result in more overhead trying to manage the numerous chunks that
- become mapped into the cache.  Overhead can include both excessive CPU
- time searching for chunks, and excessive memory tracking chunks.
-@@ -357,6 +401,35 @@ The default value is shown by:
- .br
- .B lvmconfig --type default allocation/cache_pool_chunk_size
- 
-+Checking migration threshold (in sectors) of running cached LV:
-+.br
-+.B lvs -o+kernel_cache_settings VG/LV
-+
-+
-+.SS dm-cache migration threshold
-+
-+\&
-+
-+Migrating data between the origin and cache LV uses bandwidth.
-+The user can set a throttle to prevent more than a certain amount of
-+migration occurring at any one time.  Currently dm-cache is not taking any
-+account of normal io traffic going to the devices.
-+
-+User can set migration threshold via cache policy settings as
-+"migration_threshold=<#sectors>" to set the maximum number
-+of sectors being migrated, the default being 2048 sectors (1MiB).
-+
-+Command to set migration threshold to 2MiB (4096 sectors):
-+.br
-+.B lvcreate --cachepolicy 'migration_threshold=4096' VG/LV
-+
-+
-+Command to display the migration threshold:
-+.br
-+.B lvs -o+kernel_cache_settings,cache_settings VG/LV
-+.br
-+.B lvs -o+chunksize VG/LV
-+
- 
- .SS dm-cache cache policy
- 
-diff --git a/man/lvs.8_end b/man/lvs.8_end
-index 6efc9cb..5a4ecc8 100644
---- a/man/lvs.8_end
-+++ b/man/lvs.8_end
-@@ -74,5 +74,9 @@ Related to Thin Logical Volumes: (F)ailed.
- .br
- (F)ailed is set when related thin pool enters Failed state and no further I/O
- is permitted at all.
-+.IP
-+Related to writecache logical volumes: (E)rror.
-+.br
-+(E)rror is set dm-writecache reports an error.
- .IP 10 3
- s(k)ip activation: this volume is flagged to be skipped during activation.
-diff --git a/man/lvs.8_pregen b/man/lvs.8_pregen
-index 8c3091d..8aea356 100644
---- a/man/lvs.8_pregen
-+++ b/man/lvs.8_pregen
-@@ -577,6 +577,10 @@ Related to Thin Logical Volumes: (F)ailed.
- .br
- (F)ailed is set when related thin pool enters Failed state and no further I/O
- is permitted at all.
-+.IP
-+Related to writecache logical volumes: (E)rror.
-+.br
-+(E)rror is set dm-writecache reports an error.
- .IP 10 3
- s(k)ip activation: this volume is flagged to be skipped during activation.
- .SH SEE ALSO
-diff --git a/man/vgck.8_pregen b/man/vgck.8_pregen
-index a66de5d..2a1ec23 100644
---- a/man/vgck.8_pregen
-+++ b/man/vgck.8_pregen
-@@ -199,6 +199,15 @@ back metadata it believes has changed but hasn't.
- \fB--updatemetadata\fP
- .br
- Update VG metadata to correct problems.
-+If VG metadata was updated while a PV was missing, and the PV
-+reappears with an old version of metadata, then this option
-+(or any other command that writes metadata) will update the
-+metadata on the previously missing PV. If a PV was removed
-+from a VG while it was missing, and the PV reappears, using
-+this option will clear the outdated metadata from the previously
-+missing PV. If metadata text is damaged on one PV, using this
-+option will replace the damaged metadata text. For more severe
-+damage, e.g. with headers, see \fBpvck\fP(8).
- .ad b
- .HP
- .ad l
-diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
-index 57b3e58..7c517b8 100644
---- a/scripts/blkdeactivate.sh.in
-+++ b/scripts/blkdeactivate.sh.in
-@@ -330,6 +330,12 @@ deactivate_vdo() {
-         test -b "$DEV_DIR/mapper/$xname" || return 0
-         test -z "${SKIP_DEVICE_LIST["$kname"]}" || return 1
- 
-+	# Skip VDO device deactivation if VDO tools missing.
-+	test "$VDO_AVAILABLE" -eq 0 && {
-+		add_device_to_skip_list
-+		return 1
-+	}
-+
-         deactivate_holders "$DEV_DIR/mapper/$xname" || return 1
- 
-         echo -n "  [VDO]: deactivating VDO volume $xname... "
-diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
-index b2986bf..473bb94 100755
---- a/test/dbus/lvmdbustest.py
-+++ b/test/dbus/lvmdbustest.py
-@@ -1558,6 +1558,36 @@ class TestDbusService(unittest.TestCase):
- 			cached_lv.Lv.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD))
- 		verify_cache_lv_count()
- 
-+	def test_writecache_lv(self):
-+		vg = self._vg_create().Vg
-+		data_lv = self._create_lv(size=mib(16), vg=vg)
-+		cache_lv = self._create_lv(size=mib(16), vg=vg)
-+
-+		# both LVs need to be inactive
-+		self.handle_return(data_lv.Lv.Deactivate(
-+			dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
-+		data_lv.update()
-+		self.handle_return(cache_lv.Lv.Deactivate(
-+			dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
-+		cache_lv.update()
-+
-+		cached_lv_path = self.handle_return(
-+			cache_lv.Lv.WriteCacheLv(
-+				dbus.ObjectPath(data_lv.object_path),
-+				dbus.Int32(g_tmo),
-+				EOD))
-+
-+		intf = (LV_COMMON_INT, LV_INT, CACHE_LV_INT)
-+		cached_lv = ClientProxy(self.bus, cached_lv_path, interfaces=intf)
-+		self.assertEqual(cached_lv.LvCommon.SegType, ["writecache"])
-+
-+		uncached_lv_path = self.handle_return(
-+				cached_lv.CachedLv.DetachCachePool(
-+					dbus.Boolean(True),
-+					dbus.Int32(g_tmo),
-+					EOD))
-+		self.assertTrue('/com/redhat/lvmdbus1/Lv' in uncached_lv_path)
-+
- 	def test_vg_change(self):
- 		vg_proxy = self._vg_create()
- 
-diff --git a/test/lib/aux.sh b/test/lib/aux.sh
-index e40da95..17e7935 100644
---- a/test/lib/aux.sh
-+++ b/test/lib/aux.sh
-@@ -1234,6 +1234,7 @@ activation/verify_udev_operations = $LVM_VERIFY_UDEV
- activation/raid_region_size = 512
- allocation/wipe_signatures_when_zeroing_new_lvs = 0
- allocation/vdo_slab_size_mb = 128
-+allocation/zero_metadata = 0
- backup/archive = 0
- backup/backup = 0
- devices/cache_dir = "$TESTDIR/etc"
-diff --git a/test/shell/cachevol-cachedevice.sh b/test/shell/cachevol-cachedevice.sh
-new file mode 100644
-index 0000000..3831ee9
---- /dev/null
-+++ b/test/shell/cachevol-cachedevice.sh
-@@ -0,0 +1,222 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_cache 1 10 0 || skip
-+aux have_writecache 1 0 0 || skip
-+
-+aux prepare_devs 4 64
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2"
-+
-+## cache
-+
-+# use existing cachevol
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvcreate --type cache -n $lv2 -L40M --cachevol $lv1 -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype cache
-+check lv_field $vg/${lv1}_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+
-+# use entire cachedevice for cachevol
-+lvcreate --type cache -n $lv2 -L40M --cachedevice "$dev1" -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype cache
-+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+
-+# use part of cachedevice for cachevol
-+lvcreate --type cache -n $lv2 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype cache
-+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
-+lvcreate --type cache -n $lv3 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
-+check lv_field $vg/$lv3 segtype cache
-+check lv_field $vg/${lv3}_cache_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+lvremove -y $vg/$lv3
-+
-+## writecache
-+
-+# use existing cachevol
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvcreate --type writecache -n $lv2 -L40M --cachevol $lv1 -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype writecache
-+check lv_field $vg/${lv1}_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+
-+# use entire cachedevice for cachevol
-+lvcreate --type writecache -n $lv2 -L40M --cachedevice "$dev1" -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype writecache
-+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+
-+# use part of cachedevice for cachevol
-+lvcreate --type writecache -n $lv2 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
-+check lv_field $vg/$lv2 segtype writecache
-+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
-+lvcreate --type writecache -n $lv3 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
-+check lv_field $vg/$lv3 segtype writecache
-+check lv_field $vg/${lv3}_cache_cvol segtype linear -a
-+lvremove -y $vg/$lv2
-+lvremove -y $vg/$lv3
-+
-+## multiple cachedevs
-+
-+vgextend $vg "$dev3" "$dev4"
-+
-+lvcreate --type writecache -n $lv2 -L100M --cachedevice "$dev1" --cachedevice "$dev3" -y $vg "$dev2" "$dev4"
-+check lv_field $vg/${lv2}_cache_cvol lv_size "120.00m"
-+lvremove -y $vg/$lv2
-+
-+lvcreate --type writecache -n $lv2 -L100M --cachedevice "$dev1" --cachedevice "$dev3" --cachesize 80M -y $vg "$dev2" "$dev4"
-+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
-+lvremove -y $vg/$lv2
-+
-+pvchange --addtag slow "$dev2"
-+pvchange --addtag slow "$dev4"
-+pvchange --addtag fast "$dev1"
-+pvchange --addtag fast "$dev3"
-+
-+lvcreate --type writecache -n $lv2 -L100M --cachedevice @fast --cachesize 80M -y $vg @slow
-+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
-+lvremove -y $vg/$lv2
-+
-+lvcreate --type cache -n $lv2 -L100M --cachedevice @fast --cachesize 80M -y $vg @slow
-+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
-+lvremove -y $vg/$lv2
-+
-+## error cases
-+
-+# cachevol doesn't exist
-+not lvcreate --type cache -n $lv2 -l8 --cachevol asdf -y $vg "$dev2"
-+not lvs $vg/$lv1
-+not lvs $vg/$lv2
-+
-+# cachedevice doesn't exist
-+not lvcreate --type cache -n $lv2 -l8 --cachedevice asdf -y $vg "$dev2"
-+not lvs $vg/$lv1
-+not lvs $vg/$lv2
-+
-+# cachevol doesn't exist
-+not lvcreate --type writecache -n $lv2 -l8 --cachevol asdf -y $vg "$dev2"
-+not lvs $vg/$lv1
-+not lvs $vg/$lv2
-+
-+# cachedevice doesn't exist
-+not lvcreate --type writecache -n $lv2 -l8 --cachedevice asdf -y $vg "$dev2"
-+not lvs $vg/$lv1
-+not lvs $vg/$lv2
-+
-+# when cachedevice is already being used, cachesize is required to use a part of it
-+lvcreate -n asdf -l1 $vg "$dev1"
-+not lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" -y $vg "$dev2"
-+not lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" --cachedevice "$dev3" -y $vg "$dev2"
-+not lvs $vg/$lv1
-+not lvs $vg/$lv2
-+lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" --cachesize 8M -y $vg "$dev2"
-+lvs $vg/$lv2
-+check lv_field $vg/${lv2}_cache_cvol lv_size "8.00m"
-+lvremove -y $vg/$lv2
-+
-+vgremove -ff $vg
-+
-+# lvconvert single step cachevol creation and attachment
-+# . cache and writecache
-+# . one or two cachedevices
-+# . with or without --cachesize
-+# . using tags for devices
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type cache --cachedevice "$dev2" $vg/$lv1
-+check lv_field $vg/$lv1 segtype cache
-+check lv_field $vg/${lv1}_cache_cvol segtype linear -a
-+check lv_field $vg/${lv1}_cache_cvol lv_size "60.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type cache --cachedevice "$dev2" --cachedevice "$dev3" $vg/$lv1
-+check lv_field $vg/$lv1 segtype cache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "120.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type cache --cachedevice "$dev2" --cachedevice "$dev3" --cachesize 8M $vg/$lv1
-+check lv_field $vg/$lv1 segtype cache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type writecache --cachedevice "$dev2" $vg/$lv1
-+check lv_field $vg/$lv1 segtype writecache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "60.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type writecache --cachedevice "$dev2" --cachedevice "$dev3" $vg/$lv1
-+check lv_field $vg/$lv1 segtype writecache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "120.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg "$dev1"
-+lvconvert -y --type writecache --cachedevice "$dev2" --cachedevice "$dev3" --cachesize 8M $vg/$lv1
-+check lv_field $vg/$lv1 segtype writecache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+pvchange --addtag slow "$dev1"
-+pvchange --addtag fast "$dev2"
-+pvchange --addtag fast "$dev3"
-+
-+lvcreate -n $lv1 -l8 -an $vg @slow
-+lvconvert -y --type cache --cachedevice @fast --cachesize 8M $vg/$lv1
-+check lv_field $vg/$lv1 segtype cache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+lvcreate -n $lv1 -l8 -an $vg @slow
-+lvconvert -y --type writecache --cachedevice @fast --cachesize 8M $vg/$lv1
-+check lv_field $vg/$lv1 segtype writecache
-+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# if the cache name is used generate a new name
-+lvcreate -n $lv1 -l8 -an $vg @slow
-+lvcreate -n ${lv1}_cache -l1 -an $vg @slow
-+lvconvert -y --type writecache --cachedevice @fast --cachesize 8M $vg/$lv1
-+check lv_field $vg/$lv1 segtype writecache
-+check lv_field $vg/${lv1}_cache0_cvol lv_size "8.00m"
-+lvchange -ay $vg/$lv1
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+vgremove -ff $vg
-+
-diff --git a/test/shell/integrity-blocksize-2.sh b/test/shell/integrity-blocksize-2.sh
-new file mode 100644
-index 0000000..5e0fd9a
---- /dev/null
-+++ b/test/shell/integrity-blocksize-2.sh
-@@ -0,0 +1,128 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+_sync_percent() {
-+        local checklv=$1
-+        get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+        local checklv=$1
-+
-+        for i in $(seq 1 10) ; do
-+                sync=$(_sync_percent "$checklv")
-+                echo "sync_percent is $sync"
-+
-+                if test "$sync" = "100"; then
-+                        return
-+                fi
-+
-+                sleep 1
-+        done
-+
-+        # TODO: There is some strange bug, first leg of RAID with integrity
-+        # enabled never gets in sync. I saw this in BB, but not when executing
-+        # the commands manually
-+        if test -z "$sync"; then
-+                echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+                exit
-+        fi
-+        echo "timeout waiting for recalc"
-+        return 1
-+}
-+
-+# prepare_devs uses ramdisk backing which has 512 LBS and 4K PBS
-+# This should cause mkfs.xfs to use 4K sector size,
-+# and integrity to use 4K block size
-+aux prepare_devs 2 64
-+
-+vgcreate $vg "$dev1" "$dev2"
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# add integrity while LV is inactive
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+lvchange -ay $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs unmounted
-+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvchange -ay $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs mounted
-+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+vgremove -ff $vg
-+
-diff --git a/test/shell/integrity-blocksize-3.sh b/test/shell/integrity-blocksize-3.sh
-new file mode 100644
-index 0000000..4aea972
---- /dev/null
-+++ b/test/shell/integrity-blocksize-3.sh
-@@ -0,0 +1,285 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+_sync_percent() {
-+        local checklv=$1
-+        get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+        local checklv=$1
-+
-+        for i in $(seq 1 10) ; do
-+                sync=$(_sync_percent "$checklv")
-+                echo "sync_percent is $sync"
-+
-+                if test "$sync" = "100"; then
-+                        return
-+                fi
-+
-+                sleep 1
-+        done
-+
-+        # TODO: There is some strange bug, first leg of RAID with integrity
-+        # enabled never gets in sync. I saw this in BB, but not when executing
-+        # the commands manually
-+        if test -z "$sync"; then
-+                echo "TEST WARNING: Resync of dm-integrity device '$checklv' failed"
-+                dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
-+                exit
-+        fi
-+        echo "timeout waiting for recalc"
-+        return 1
-+}
-+
-+# scsi_debug devices with 512 LBS 512 PBS
-+aux prepare_scsi_debug_dev 256
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
-+aux prepare_devs 2 64
-+
-+vgcreate $vg "$dev1" "$dev2"
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# add integrity while LV is inactive
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+lvchange -ay $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs unmounted
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvchange -ay $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs mounted
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+vgremove -ff $vg
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-+# scsi_debug devices with 4K LBS and 4K PBS
-+aux prepare_scsi_debug_dev 256 sector_size=4096
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "4096"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
-+aux prepare_devs 2 64
-+
-+vgcreate $vg "$dev1" "$dev2"
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# add integrity while LV is inactive
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+lvchange -ay $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs unmounted
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvchange -ay $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs mounted
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+vgremove -ff $vg
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-+# scsi_debug devices with 512 LBS and 4K PBS
-+aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
-+aux prepare_devs 2 64
-+
-+vgcreate $vg "$dev1" "$dev2"
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# add integrity while LV is inactive
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+lvchange -ay $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs unmounted
-+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+umount $mnt
-+lvchange -an $vg
-+lvchange -ay $vg
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# add integrity while LV is active, fs mounted
-+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+echo "hello world" > $mnt/hello
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+cat $mnt/hello | grep "hello world"
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+vgremove -ff $vg
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-diff --git a/test/shell/integrity-blocksize.sh b/test/shell/integrity-blocksize.sh
-index 444e3db..eb6a364 100644
---- a/test/shell/integrity-blocksize.sh
-+++ b/test/shell/integrity-blocksize.sh
-@@ -48,9 +48,24 @@ aux extend_filter "a|$LOOP4|"
- 
- aux lvmconf 'devices/scan = "/dev"'
- 
-+mnt="mnt"
-+mkdir -p $mnt
-+
- vgcreate $vg1 $LOOP1 $LOOP2
- vgcreate $vg2 $LOOP3 $LOOP4
- 
-+# LOOP1/LOOP2 have LBS 512 and PBS 512
-+# LOOP3/LOOP4 have LBS 4K and PBS 4K
-+
-+blockdev --getss $LOOP1
-+blockdev --getpbsz $LOOP1
-+blockdev --getss $LOOP2
-+blockdev --getpbsz $LOOP2
-+blockdev --getss $LOOP3
-+blockdev --getpbsz $LOOP3
-+blockdev --getss $LOOP4
-+blockdev --getpbsz $LOOP4
-+
- # lvcreate on dev512, result 512
- lvcreate --type raid1 -m1 --raidintegrity y -l 8 -n $lv1 $vg1
- pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-@@ -105,7 +120,11 @@ lvremove -y $vg2/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
- aux wipefs_a /dev/$vg1/$lv1
- mkfs.xfs -f "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"512\"
- lvconvert --raidintegrity y $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"512\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP1 | grep 'block_size = 512'
- lvremove -y $vg1/$lv1
- 
-@@ -113,15 +132,37 @@ lvremove -y $vg1/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
- aux wipefs_a /dev/$vg2/$lv1
- mkfs.xfs -f "$DM_DEV_DIR/$vg2/$lv1"
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
- lvconvert --raidintegrity y $vg2/$lv1
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
-+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
- lvremove -y $vg2/$lv1
- 
--# lvconvert on dev512, ext4 1024, result 1024 
-+# lvconvert on dev512, ext4 1024, result 1024 (LV active when adding)
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
-+lvconvert --raidintegrity y $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert on dev512, ext4 1024, result 1024 (LV inactive when adding)
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
- aux wipefs_a /dev/$vg1/$lv1
- mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
-+lvchange -an $vg1/$lv1
- lvconvert --raidintegrity y $vg1/$lv1
-+lvchange -ay $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP1 | grep 'block_size = 1024'
- lvremove -y $vg1/$lv1
- 
-@@ -129,7 +170,11 @@ lvremove -y $vg1/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
- aux wipefs_a /dev/$vg2/$lv1
- mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
- lvconvert --raidintegrity y $vg2/$lv1
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
-+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
- lvremove -y $vg2/$lv1
- 
-@@ -137,7 +182,11 @@ lvremove -y $vg2/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
- aux wipefs_a /dev/$vg1/$lv1
- mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
- lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP1 | grep 'block_size = 512'
- lvremove -y $vg1/$lv1
- 
-@@ -145,7 +194,14 @@ lvremove -y $vg1/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
- aux wipefs_a /dev/$vg1/$lv1
- mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
-+lvchange -an $vg1/$lv1
-+# lv needs to be inactive to increase LBS from 512
- lvconvert --raidintegrity y --raidintegrityblocksize 1024 $vg1/$lv1
-+lvchange -ay $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP1 | grep 'block_size = 1024'
- lvremove -y $vg1/$lv1
- 
-@@ -153,7 +209,11 @@ lvremove -y $vg1/$lv1
- lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
- aux wipefs_a /dev/$vg1/$lv1
- mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
- lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+umount $mnt
- pvck --dump metadata $LOOP1 | grep 'block_size = 512'
- lvremove -y $vg1/$lv1
- 
-@@ -164,10 +224,48 @@ mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
- not lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg2/$lv1
- lvremove -y $vg2/$lv1
- 
--# FIXME: need to use scsi_debug to create devs with LBS 512 PBS 4k
--# FIXME: lvconvert, fsunknown, LBS 512, PBS 4k: result 512
--# FIXME: lvconvert --bs 512, fsunknown, LBS 512, PBS 4k: result 512
--# FIXME: lvconvert --bs 4k, fsunknown, LBS 512, PBS 4k: result 4k
-+# TODO: need to use scsi_debug to create devs with LBS 512 PBS 4k
-+# TODO: lvconvert, fsunknown, LBS 512, PBS 4k: result 512
-+# TODO: lvconvert --bs 512, fsunknown, LBS 512, PBS 4k: result 512
-+# TODO: lvconvert --bs 4k, fsunknown, LBS 512, PBS 4k: result 4k
-+
-+# lvconvert on dev512, xfs 512, result 512, (detect fs with LV inactive)
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg1/$lv1"
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+echo "test" > $mnt/test
-+umount $mnt
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"512\"
-+lvchange -an $vg1/$lv1
-+lvconvert --raidintegrity y $vg1/$lv1
-+lvchange -ay $vg1/$lv1
-+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
-+cat $mnt/test
-+umount $mnt
-+blkid "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"512\"
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvchange -an $vg1/$lv1
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert on dev4k, xfs 4096, result 4096 (detect fs with LV inactive)
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+aux wipefs_a /dev/$vg2/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg2/$lv1"
-+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
-+echo "test" > $mnt/test
-+umount $mnt
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
-+lvchange -an $vg2/$lv1
-+lvconvert --raidintegrity y $vg2/$lv1
-+lvchange -ay $vg2/$lv1
-+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
-+cat $mnt/test
-+umount $mnt
-+blkid "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
-+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
-+lvchange -an $vg2/$lv1
-+lvremove -y $vg2/$lv1
- 
- vgremove -ff $vg1
- vgremove -ff $vg2
-diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh
-index 5aba80e..06b0e03 100644
---- a/test/shell/integrity-large.sh
-+++ b/test/shell/integrity-large.sh
-@@ -23,7 +23,7 @@ mnt="mnt"
- mkdir -p $mnt
- 
- # raid1 LV needs to be extended to 512MB to test imeta being exended
--aux prepare_devs 4 600
-+aux prepare_devs 4 632
- 
- printf "%0.sA" {1..16384} >> fileA
- printf "%0.sB" {1..16384} >> fileB
-@@ -115,7 +115,10 @@ lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
- lvchange -an $vg/$lv1
- lvchange -ay $vg/$lv1
- _add_data_to_lv
-+# lv needs to be inactive when adding integrity to increase LBS from 512 and get a ribs of 4k
-+lvchange -an $vg/$lv1
- lvconvert --raidintegrity y $vg/$lv1
-+lvchange -ay $vg/$lv1
- _wait_recalc $vg/${lv1}_rimage_0
- _wait_recalc $vg/${lv1}_rimage_1
- lvs -a -o+devices $vg
-@@ -128,8 +131,8 @@ _verify_data_on_lv
- _wait_recalc $vg/${lv1}_rimage_0
- _wait_recalc $vg/${lv1}_rimage_1
- lvs -a -o+devices $vg
--check lv_field $vg/${lv1}_rimage_0_imeta size "8.00m"
--check lv_field $vg/${lv1}_rimage_1_imeta size "8.00m"
-+check lv_field $vg/${lv1}_rimage_0_imeta size "12.00m"
-+check lv_field $vg/${lv1}_rimage_1_imeta size "12.00m"
- 
- # provide space to extend the images onto new devs
- vgextend $vg "$dev3" "$dev4"
-@@ -150,33 +153,35 @@ lvconvert --raidintegrity y $vg/$lv1
- _wait_recalc $vg/${lv1}_rimage_0
- _wait_recalc $vg/${lv1}_rimage_1
- lvs -a -o+devices $vg
--check lv_field $vg/${lv1}_rimage_0_imeta size "12.00m"
--check lv_field $vg/${lv1}_rimage_1_imeta size "12.00m"
-+check lv_field $vg/${lv1}_rimage_0_imeta size "20.00m"
-+check lv_field $vg/${lv1}_rimage_1_imeta size "20.00m"
- 
- lvchange -an $vg/$lv1
- lvremove $vg/$lv1
- 
- # this succeeds because dev1,dev2 can hold rmeta+rimage
- lvcreate --type raid1 -n $lv1 -L 592M -an $vg "$dev1" "$dev2"
-+lvs -a -o+devices $vg
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
- 
- # this fails because dev1,dev2 can hold rmeta+rimage, but not imeta
- # and we require imeta to be on same devs as rmeta/rimeta
--not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 592M -an $vg "$dev1" "$dev2"
-+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 624M -an $vg "$dev1" "$dev2"
- lvs -a -o+devices $vg
--lvremove $vg/$lv1
- 
- # this can allocate from more devs so there's enough space for imeta to
- # be allocated in the vg, but lvcreate fails because rmeta+rimage are
- # allocated from dev1,dev2, we restrict imeta to being allocated on the
- # same devs as rmeta/rimage, and dev1,dev2 can't fit imeta.
--not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 592M -an $vg
-+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 624M -an $vg
- lvs -a -o+devices $vg
- 
- # counterintuitively, increasing the size will allow lvcreate to succeed
- # because rmeta+rimage are pushed to being allocated on dev1,dev2,dev3,dev4
- # which means imeta is now free to be allocated from dev3,dev4 which have
- # plenty of space
--lvcreate --type raid1 --raidintegrity y -n $lv1 -L 600M -an $vg
-+lvcreate --type raid1 --raidintegrity y -n $lv1 -L 640M -an $vg
- lvs -a -o+devices $vg
- 
- vgremove -ff $vg
-diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh
-index 0d05689..2dae25f 100644
---- a/test/shell/integrity-misc.sh
-+++ b/test/shell/integrity-misc.sh
-@@ -95,7 +95,7 @@ _sync_percent() {
- 	get lv_field "$checklv" sync_percent | cut -d. -f1
- }
- 
--_wait_recalc() {
-+_wait_sync() {
- 	local checklv=$1
- 
- 	for i in $(seq 1 10) ; do
-@@ -124,8 +124,9 @@ _wait_recalc() {
- # lvrename
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
--_wait_recalc $vg/${lv1}_rimage_0
--_wait_recalc $vg/${lv1}_rimage_1
-+_wait_sync $vg/${lv1}_rimage_0
-+_wait_sync $vg/${lv1}_rimage_1
-+_wait_sync $vg/$lv1
- _add_new_data_to_mnt
- umount $mnt
- lvrename $vg/$lv1 $vg/$lv2
-@@ -141,8 +142,9 @@ vgremove -ff $vg
- # lv must be active
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
--_wait_recalc $vg/${lv1}_rimage_0
--_wait_recalc $vg/${lv1}_rimage_1
-+_wait_sync $vg/${lv1}_rimage_0
-+_wait_sync $vg/${lv1}_rimage_1
-+_wait_sync $vg/$lv1
- _add_new_data_to_mnt
- lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
- lvs -a -o+devices $vg > out
-@@ -162,8 +164,9 @@ vgremove -ff $vg
- # same as prev but with bitmap mode
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
--_wait_recalc $vg/${lv1}_rimage_0
--_wait_recalc $vg/${lv1}_rimage_1
-+_wait_sync $vg/${lv1}_rimage_0
-+_wait_sync $vg/${lv1}_rimage_1
-+_wait_sync $vg/$lv1
- _add_new_data_to_mnt
- lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
- lvs -a -o+devices $vg > out
-@@ -185,8 +188,9 @@ vgremove -ff $vg
- # (like lvconvert --replace does for a dev that's not missing).
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
--_wait_recalc $vg/${lv1}_rimage_0
--_wait_recalc $vg/${lv1}_rimage_1
-+_wait_sync $vg/${lv1}_rimage_0
-+_wait_sync $vg/${lv1}_rimage_1
-+_wait_sync $vg/$lv1
- _add_new_data_to_mnt
- aux disable_dev "$dev2"
- lvs -a -o+devices $vg > out
-@@ -213,8 +217,9 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
--_wait_recalc $vg/${lv1}_rimage_0
--_wait_recalc $vg/${lv1}_rimage_1
-+_wait_sync $vg/${lv1}_rimage_0
-+_wait_sync $vg/${lv1}_rimage_1
-+_wait_sync $vg/$lv1
- _add_new_data_to_mnt
- umount $mnt
- lvchange -an $vg/$lv1
-diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh
-index 77e9430..0143129 100644
---- a/test/shell/integrity.sh
-+++ b/test/shell/integrity.sh
-@@ -78,14 +78,14 @@ _test_fs_with_error() {
- 	dd if=$mnt/fileA of=tmp bs=1k
- 	ls -l tmp
- 	stat -c %s tmp
--	diff fileA tmp
-+	cmp -b fileA tmp
- 	rm tmp
- 
- 	# read partial fileB which was corrupted
- 	not dd if=$mnt/fileB of=tmp bs=1k
- 	ls -l tmp
- 	stat -c %s tmp | grep 12288
--	not diff fileB tmp
-+	not cmp -b fileB tmp
- 	rm tmp
- 
- 	umount $mnt
-@@ -118,14 +118,14 @@ _test_fs_with_raid() {
- 	dd if=$mnt/fileA of=tmp bs=1k
- 	ls -l tmp
- 	stat -c %s tmp | grep 16384
--	diff fileA tmp
-+	cmp -b fileA tmp
- 	rm tmp
- 
- 	# read complete fileB, corruption is corrected by raid
- 	dd if=$mnt/fileB of=tmp bs=1k
- 	ls -l tmp
- 	stat -c %s tmp | grep 16384
--	diff fileB tmp
-+	cmp -b fileB tmp
- 	rm tmp
- 
- 	umount $mnt
-@@ -161,15 +161,15 @@ _add_more_data_to_mnt() {
- }
- 
- _verify_data_on_mnt() {
--	diff randA $mnt/randA
--	diff randB $mnt/randB
--	diff randC $mnt/randC
--	diff fileA $mnt/1/fileA
--	diff fileB $mnt/1/fileB
--	diff fileC $mnt/1/fileC
--	diff fileA $mnt/2/fileA
--	diff fileB $mnt/2/fileB
--	diff fileC $mnt/2/fileC
-+	cmp -b randA $mnt/randA
-+	cmp -b randB $mnt/randB
-+	cmp -b randC $mnt/randC
-+	cmp -b fileA $mnt/1/fileA
-+	cmp -b fileB $mnt/1/fileB
-+	cmp -b fileC $mnt/1/fileC
-+	cmp -b fileA $mnt/2/fileA
-+	cmp -b fileB $mnt/2/fileB
-+	cmp -b fileC $mnt/2/fileC
- }
- 
- _verify_data_on_lv() {
-@@ -221,6 +221,8 @@ _wait_recalc() {
- 
- _prepare_vg
- lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-@@ -229,6 +231,9 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-@@ -237,6 +242,9 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid4 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-@@ -245,6 +253,9 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-@@ -253,6 +264,11 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+_wait_recalc $vg/${lv1}_rimage_3
-+_wait_recalc $vg/${lv1}_rimage_4
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-@@ -261,6 +277,10 @@ vgremove -ff $vg
- 
- _prepare_vg
- lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+_wait_recalc $vg/${lv1}_rimage_3
- _test_fs_with_raid
- lvchange -an $vg/$lv1
- lvconvert --raidintegrity n $vg/$lv1
-diff --git a/test/shell/lvconvert-m-raid1-degraded.sh b/test/shell/lvconvert-m-raid1-degraded.sh
-index 05c3e89..c3f7085 100644
---- a/test/shell/lvconvert-m-raid1-degraded.sh
-+++ b/test/shell/lvconvert-m-raid1-degraded.sh
-@@ -33,8 +33,10 @@ aux disable_dev "$dev1"
- vgreduce --force --removemissing $vg
- check raid_leg_status $vg $lv "DA"
- 
--# Conversion to 2 legs must fail on degraded 2-legged raid1 LV
--not lvconvert -y -m1 $vg/$lv
-+# Conversion to 2 legs does nothing on degraded 2-legged raid1 LV
-+lvconvert -y -m1 $vg/$lv 2>&1 | tee out
-+grep "already has 2 images" out
-+# Check it remains degraded after the successful "conversion"
- check raid_leg_status $vg $lv "DA"
- 
- # Repair has to succeed
-diff --git a/test/shell/lvcreate-signature-wiping.sh b/test/shell/lvcreate-signature-wiping.sh
-index 73fea54..18d7a2f 100644
---- a/test/shell/lvcreate-signature-wiping.sh
-+++ b/test/shell/lvcreate-signature-wiping.sh
-@@ -42,6 +42,13 @@ init_lv_
- test_blkid_ || skip
- lvremove -f $vg/$lv1
- 
-+# Zeroing stops the command when there is a failure (write error in this case)
-+aux error_dev "$dev1" "$(get first_extent_sector "$dev1"):2"
-+not lvcreate -l1 -n $lv1 $vg 2>&1 | tee out
-+grep "Failed to initialize" out
-+aux enable_dev "$dev1"
-+
-+
- aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 0"
- 
- lvcreate -y -Zn -l1 -n $lv1 $vg 2>&1 | tee out
-diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh
-index 9ca7f11..c073eaf 100644
---- a/test/shell/lvcreate-thin.sh
-+++ b/test/shell/lvcreate-thin.sh
-@@ -248,4 +248,25 @@ not lvcreate -s $vg/lv1 -L4M -V2G --name $vg/lv4
- not lvcreate -T mirpool -L4M --alloc anywhere -m1 $vg
- not lvcreate --thinpool mirpool -L4M --alloc anywhere -m1 $vg
- 
-+
-+# Check pool metadata volume is zeroed, when zero_metadata is enabled.
-+# 1st. ensure 8megs of both PVs will have some non-0 data
-+lvcreate -L8m -n $lv1 $vg "$dev1"
-+lvextend -L+8m $vg/$lv1 "$dev2"
-+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=16 oflag=direct conv=fdatasync
-+lvremove -ff $vg/$lv1
-+
-+lvcreate -l1 --poolmetadatasize 4m --conf 'allocation/zero_metadata=1' -vvvv -T $vg/pool
-+lvchange -an $vg
-+# component activation to check device was zeroed
-+lvchange -y -ay $vg/pool_tmeta
-+dd if="$DM_DEV_DIR/$vg/pool_tmeta" of=file bs=1M count=3 skip=1 iflag=direct conv=fdatasync
-+
-+md5sum -b file | tee out
-+# md5sum of 3M of zeros
-+grep d1dd210d6b1312cb342b56d02bd5e651 out
-+lvchange -an $vg
-+lvremove -ff $vg
-+
-+
- vgremove -ff $vg
-diff --git a/test/shell/writecache-blocksize.sh b/test/shell/writecache-blocksize.sh
-new file mode 100644
-index 0000000..1300176
---- /dev/null
-+++ b/test/shell/writecache-blocksize.sh
-@@ -0,0 +1,342 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+# Test writecache usage
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_writecache 1 0 0 || skip
-+which mkfs.xfs || skip
-+
-+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
-+aux prepare_devs 1
-+vgcreate $vg "$dev1"
-+lvcreate -n $lv1 -l8 $vg
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+blkid "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
-+lvchange -an $vg
-+vgremove -ff $vg
-+aux cleanup_scsi_debug_dev
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_add_new_data_to_mnt() {
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp randA $mnt
-+	cp randB $mnt
-+	cp randC $mnt
-+	mkdir $mnt/1
-+	cp fileA $mnt/1
-+	cp fileB $mnt/1
-+	cp fileC $mnt/1
-+	mkdir $mnt/2
-+	cp fileA $mnt/2
-+	cp fileB $mnt/2
-+	cp fileC $mnt/2
-+	sync
-+}
-+
-+_add_more_data_to_mnt() {
-+	mkdir $mnt/more
-+	cp fileA $mnt/more
-+	cp fileB $mnt/more
-+	cp fileC $mnt/more
-+	cp randA $mnt/more
-+	cp randB $mnt/more
-+	cp randC $mnt/more
-+	sync
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_more_data_on_mnt() {
-+	diff randA $mnt/more/randA
-+	diff randB $mnt/more/randB
-+	diff randC $mnt/more/randC
-+	diff fileA $mnt/more/fileA
-+	diff fileB $mnt/more/fileB
-+	diff fileC $mnt/more/fileC
-+}
-+
-+_verify_data_on_lv() {
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+	_verify_data_on_mnt
-+	rm $mnt/randA
-+	rm $mnt/randB
-+	rm $mnt/randC
-+	rm -rf $mnt/1
-+	rm -rf $mnt/2
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+}
-+
-+# the default is brd ram devs with 512 LBS 4K PBS
-+aux prepare_devs 2 64
-+
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# lbs 512, pbs 4k, xfs 4k, wc 4k
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=4096 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 4096 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+# lbs 512, pbs 4k, xfs -s 512, wc 512
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f -s size=512 "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=512 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 512 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-+
-+# scsi_debug devices with 512 LBS 512 PBS
-+aux prepare_scsi_debug_dev 256
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
-+aux prepare_devs 2 64
-+
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# lbs 512, pbs 512, xfs 512, wc 512
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=512 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 512 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+# lbs 512, pbs 512, xfs -s 4096, wc 4096
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -s size=4096 -f "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=4096 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 4096 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-+
-+# scsi_debug devices with 512 LBS and 4K PBS
-+aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
-+aux prepare_devs 2 64
-+
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# lbs 512, pbs 4k, xfs 4k, wc 4k
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=4096 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 4096 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+aux cleanup_scsi_debug_dev
-+sleep 1
-+
-+
-+# scsi_debug devices with 4K LBS and 4K PBS
-+aux prepare_scsi_debug_dev 256 sector_size=4096
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "4096"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
-+aux prepare_devs 2 64
-+
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+# lbs 4k, pbs 4k, xfs 4k, wc 4k
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+lvchange -ay $vg/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep sectsz=4096 out
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
-+grep 4096 out
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+vgremove $vg
-+
-+aux cleanup_scsi_debug_dev
-+
-+
-diff --git a/test/shell/writecache-large.sh b/test/shell/writecache-large.sh
-new file mode 100644
-index 0000000..b52eaf6
---- /dev/null
-+++ b/test/shell/writecache-large.sh
-@@ -0,0 +1,153 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+# Test writecache usage
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_writecache 1 0 0 || skip
-+which mkfs.xfs || skip
-+
-+# scsi_debug devices with 512 LBS 512 PBS
-+aux prepare_scsi_debug_dev 1200
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
-+
-+aux prepare_devs 2 600
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_add_new_data_to_mnt() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp randA $mnt
-+	cp randB $mnt
-+	cp randC $mnt
-+	mkdir $mnt/1
-+	cp fileA $mnt/1
-+	cp fileB $mnt/1
-+	cp fileC $mnt/1
-+	mkdir $mnt/2
-+	cp fileA $mnt/2
-+	cp fileB $mnt/2
-+	cp fileC $mnt/2
-+	sync
-+}
-+
-+_add_more_data_to_mnt() {
-+	mkdir $mnt/more
-+	cp fileA $mnt/more
-+	cp fileB $mnt/more
-+	cp fileC $mnt/more
-+	cp randA $mnt/more
-+	cp randB $mnt/more
-+	cp randC $mnt/more
-+	sync
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_more_data_on_mnt() {
-+	diff randA $mnt/more/randA
-+	diff randB $mnt/more/randB
-+	diff randC $mnt/more/randC
-+	diff fileA $mnt/more/fileA
-+	diff fileB $mnt/more/fileB
-+	diff fileC $mnt/more/fileC
-+}
-+
-+_verify_data_on_lv() {
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+	_verify_data_on_mnt
-+	rm $mnt/randA
-+	rm $mnt/randB
-+	rm $mnt/randC
-+	rm -rf $mnt/1
-+	rm -rf $mnt/2
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+}
-+
-+vgcreate $SHARED $vg "$dev1"
-+vgextend $vg "$dev2"
-+
-+# Use a large enough size so that the cleaner will not
-+# finish immediately when detaching, and will require
-+# a secondary check from command top level.
-+
-+lvcreate -n $lv1 -L 560M -an $vg "$dev1"
-+lvcreate -n $lv2 -L 500M -an $vg "$dev2"
-+
-+lvchange -ay $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" 
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1" 
-+
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+dmsetup table $vg-$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" 
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1" 
-+
-+_add_new_data_to_mnt
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+
-+dd if=/dev/zero of=$mnt/big1 bs=1M count=100 oflag=sync
-+dd if=/dev/zero of=$mnt/big2 bs=1M count=100 oflag=sync
-+dd if=/dev/zero of=$mnt/big3 bs=1M count=100 oflag=sync
-+dd if=/dev/zero of=$mnt/big4 bs=1M count=100 oflag=sync
-+
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+dmsetup table $vg-$lv1
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+dd if=$mnt/big4 of=/dev/null bs=1M count=100
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvchange -an $vg/$lv2
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
-+
-+vgremove -ff $vg
-+
-diff --git a/test/shell/writecache-split.sh b/test/shell/writecache-split.sh
-index 0f2dc47..e615e2a 100644
---- a/test/shell/writecache-split.sh
-+++ b/test/shell/writecache-split.sh
-@@ -20,29 +20,21 @@ mkfs_mount_umount()
- {
-         lvt=$1
- 
--        lvchange -ay $vg/$lvt
--
-         mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
-         mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
-         cp pattern1 "$mount_dir/pattern1"
-         dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=32 conv=fdatasync
-         umount "$mount_dir"
--
--        lvchange -an $vg/$lvt
- }
- 
- mount_umount()
- {
-         lvt=$1
- 
--        lvchange -ay $vg/$lvt
--
-         mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
-         diff pattern1 "$mount_dir/pattern1"
-         dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=32
-         umount "$mount_dir"
--
--        lvchange -an $vg/$lvt
- }
- 
- aux have_writecache 1 0 0 || skip
-@@ -62,18 +54,38 @@ lvcreate -n $lv1 -l 16 -an $vg "$dev1" "$dev4"
- lvcreate -n $lv2 -l 4 -an $vg "$dev2"
- 
- #
--# split when no devs are missing
-+# split while inactive
- #
- 
- lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
- 
-+lvchange -ay $vg/$lv1
- mkfs_mount_umount $lv1
-+lvchange -an $vg/$lv1
- 
- lvconvert --splitcache $vg/$lv1
- lvs -o segtype $vg/$lv1 | grep linear
- lvs -o segtype $vg/$lv2 | grep linear
- 
-+lvchange -ay $vg/$lv1
- mount_umount $lv1
-+lvchange -an $vg/$lv1
-+
-+#
-+# split while active
-+#
-+
-+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
-+
-+lvchange -ay $vg/$lv1
-+mkfs_mount_umount $lv1
-+
-+lvconvert --splitcache $vg/$lv1
-+lvs -o segtype $vg/$lv1 | grep linear
-+lvs -o segtype $vg/$lv2 | grep linear
-+
-+mount_umount $lv1
-+lvchange -an $vg/$lv1
- 
- #
- # split while cachevol is missing
-@@ -81,7 +93,9 @@ mount_umount $lv1
- 
- lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
- 
-+lvchange -ay $vg/$lv1
- mkfs_mount_umount $lv1
-+lvchange -an $vg/$lv1
- 
- aux disable_dev "$dev2"
- 
-@@ -108,7 +122,9 @@ lvcreate -n $lv2 -l 14 -an $vg "$dev2" "$dev3"
- 
- lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
- 
-+lvchange -ay $vg/$lv1
- mkfs_mount_umount $lv1
-+lvchange -an $vg/$lv1
- 
- aux disable_dev "$dev3"
- 
-diff --git a/test/shell/writecache.sh b/test/shell/writecache.sh
-index 8852e93..39ef319 100644
---- a/test/shell/writecache.sh
-+++ b/test/shell/writecache.sh
-@@ -19,152 +19,251 @@ SKIP_WITH_LVMPOLLD=1
- aux have_writecache 1 0 0 || skip
- which mkfs.xfs || skip
- 
--mount_dir="mnt"
--mkdir -p $mount_dir
-+# scsi_debug devices with 512 LBS 512 PBS
-+aux prepare_scsi_debug_dev 256
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
-+aux prepare_devs 2 64
-+
-+# scsi_debug devices with 512 LBS and 4K PBS
-+#aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
-+#check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
-+#check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
-+#aux prepare_devs 2 64
-+
-+# loop devs with 512 LBS and 512 PBS
-+#dd if=/dev/zero of=loopa bs=$((1024*1024)) count=64 2> /dev/null
-+#dd if=/dev/zero of=loopb bs=$((1024*1024)) count=64 2> /dev/null
-+#LOOP1=$(losetup -f loopa --show)
-+#LOOP2=$(losetup -f loopb --show)
-+#aux extend_filter "a|$LOOP1|"
-+#aux extend_filter "a|$LOOP2|"
-+#aux lvmconf 'devices/scan = "/dev"'
-+#dev1=$LOOP1
-+#dev2=$LOOP2
-+
-+# loop devs with 4096 LBS and 4096 PBS
-+#dd if=/dev/zero of=loopa bs=$((1024*1024)) count=64 2> /dev/null
-+#dd if=/dev/zero of=loopb bs=$((1024*1024)) count=64 2> /dev/null
-+#LOOP1=$(losetup -f loopa --sector-size 4096 --show)
-+#LOOP2=$(losetup -f loopb --sector-size 4096 --show)
-+#aux extend_filter "a|$LOOP1|"
-+#aux extend_filter "a|$LOOP2|"
-+#aux lvmconf 'devices/scan = "/dev"'
-+#dev1=$LOOP1
-+#dev2=$LOOP2
-+
-+# the default is brd ram devs with 512 LBS 4K PBS
-+# aux prepare_devs 2 64
-+
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
-+
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
- 
- # generate random data
--dd if=/dev/urandom of=pattern1 bs=512K count=1
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_add_new_data_to_mnt() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp randA $mnt
-+	cp randB $mnt
-+	cp randC $mnt
-+	mkdir $mnt/1
-+	cp fileA $mnt/1
-+	cp fileB $mnt/1
-+	cp fileC $mnt/1
-+	mkdir $mnt/2
-+	cp fileA $mnt/2
-+	cp fileB $mnt/2
-+	cp fileC $mnt/2
-+	sync
-+}
-+
-+_add_more_data_to_mnt() {
-+	mkdir $mnt/more
-+	cp fileA $mnt/more
-+	cp fileB $mnt/more
-+	cp fileC $mnt/more
-+	cp randA $mnt/more
-+	cp randB $mnt/more
-+	cp randC $mnt/more
-+	sync
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_more_data_on_mnt() {
-+	diff randA $mnt/more/randA
-+	diff randB $mnt/more/randB
-+	diff randC $mnt/more/randC
-+	diff fileA $mnt/more/fileA
-+	diff fileB $mnt/more/fileB
-+	diff fileC $mnt/more/fileC
-+}
-+
-+_verify_data_on_lv() {
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+	_verify_data_on_mnt
-+	rm $mnt/randA
-+	rm $mnt/randB
-+	rm $mnt/randC
-+	rm -rf $mnt/1
-+	rm -rf $mnt/2
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+}
- 
--aux prepare_devs 2 64
- 
- vgcreate $SHARED $vg "$dev1"
--
- vgextend $vg "$dev2"
- 
--lvcreate -n $lv1 -l 8 -an $vg "$dev1"
--
--lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+blockdev --getss "$dev1"
-+blockdev --getpbsz "$dev1"
-+blockdev --getss "$dev2"
-+blockdev --getpbsz "$dev2"
- 
--# test1: create fs on LV before writecache is attached
-+# Test attach while inactive, detach while inactive
-+# create fs on LV before writecache is attached
- 
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
- lvchange -ay $vg/$lv1
--
--mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--cp pattern1 $mount_dir/pattern1
--
--umount $mount_dir
-+_add_new_data_to_mnt
-+umount $mnt
- lvchange -an $vg/$lv1
--
- lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
--
- check lv_field $vg/$lv1 segtype writecache
--
- lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
- grep linear out
--
- lvchange -ay $vg/$lv1
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--diff pattern1 $mount_dir/pattern1
--
--cp pattern1 $mount_dir/pattern1b
--
--ls -l $mount_dir
--
--umount $mount_dir
--
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
- lvchange -an $vg/$lv1
--
- lvconvert --splitcache $vg/$lv1
--
- check lv_field $vg/$lv1 segtype linear
- check lv_field $vg/$lv2 segtype linear
--
- lvchange -ay $vg/$lv1
--lvchange -ay $vg/$lv2
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--ls -l $mount_dir
--
--diff pattern1 $mount_dir/pattern1
--diff pattern1 $mount_dir/pattern1b
--
--umount $mount_dir
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
- lvchange -an $vg/$lv1
-+_verify_data_on_lv
- lvchange -an $vg/$lv2
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
- 
--# test2: create fs on LV after writecache is attached
-+# Test attach while inactive, detach while inactive
-+# create fs on LV after writecache is attached
- 
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
- lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
--
- check lv_field $vg/$lv1 segtype writecache
--
- lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
- grep linear out
--
- lvchange -ay $vg/$lv1
--
--mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--cp pattern1 $mount_dir/pattern1
--ls -l $mount_dir
--
--umount $mount_dir
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_new_data_to_mnt
-+umount $mnt
- lvchange -an $vg/$lv1
--
- lvconvert --splitcache $vg/$lv1
--
--check lv_field $vg/$lv1 segtype linear
--check lv_field $vg/$lv2 segtype linear
--
- lvchange -ay $vg/$lv1
--lvchange -ay $vg/$lv2
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--ls -l $mount_dir
--
--diff pattern1 $mount_dir/pattern1
--
--umount $mount_dir
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
- lvchange -an $vg/$lv1
--lvchange -an $vg/$lv2
--
--
--# test3: attach writecache to an active LV
--
--lvchange -ay $vg/$lv1
--
--mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
--
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--cp pattern1 $mount_dir/pattern1
--ls -l $mount_dir
--
--# TODO BZ 1808012 - can not convert active volume to writecache:
--not lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
--
--if false; then
--check lv_field $vg/$lv1 segtype writecache
--
--lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
--grep linear out
--
--cp pattern1 $mount_dir/pattern1.after
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+lvremove $vg/$lv2
- 
--diff pattern1 $mount_dir/pattern1
--diff pattern1 $mount_dir/pattern1.after
-+# Test attach while active, detach while active
- 
--umount $mount_dir
--lvchange -an $vg/$lv1
-+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
- lvchange -ay $vg/$lv1
--mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
--
--diff pattern1 $mount_dir/pattern1
--diff pattern1 $mount_dir/pattern1.after
--fi
--
--umount $mount_dir
-+_add_new_data_to_mnt
-+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+lvconvert --splitcache $vg/$lv1
-+check lv_field $vg/$lv1 segtype linear
-+check lv_field $vg/$lv2 segtype linear
-+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+_verify_data_on_mnt
-+_verify_more_data_on_mnt
-+umount $mnt
- lvchange -an $vg/$lv1
-+lvchange -an $vg/$lv2
-+_verify_data_on_lv
- lvremove $vg/$lv1
-+lvremove $vg/$lv2
- 
-+# FIXME: test depends on unpushed commit
-+# that enables two stage flush using cleaner
-+#
-+# Test attach while active, detach while active,
-+# skip cleaner so flush message is used instead
-+# 
-+# lvcreate -n $lv1 -l 8 -an $vg "$dev1"
-+# lvcreate -n $lv2 -l 4 -an $vg "$dev2"
-+# lvchange -ay $vg/$lv1
-+# _add_new_data_to_mnt
-+# lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
-+# blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+# blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+# _add_more_data_to_mnt
-+# _verify_data_on_mnt
-+# lvconvert --splitcache --cachesettings cleaner=0 $vg/$lv1
-+# check lv_field $vg/$lv1 segtype linear
-+# check lv_field $vg/$lv2 segtype linear
-+# blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
-+# blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
-+# _verify_data_on_mnt
-+# _verify_more_data_on_mnt
-+# umount $mnt
-+# lvchange -an $vg/$lv1
-+# lvchange -an $vg/$lv2
-+# _verify_data_on_lv
-+# lvremove $vg/$lv1
-+# lvremove $vg/$lv2
-+ 
- vgremove -ff $vg
--
-+ 
-diff --git a/tools/args.h b/tools/args.h
-index d1f604b..3a7e5d4 100644
---- a/tools/args.h
-+++ b/tools/args.h
-@@ -126,6 +126,12 @@ arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0,
- arg(cachevol_ARG, '\0', "cachevol", lv_VAL, 0, 0,
-     "The name of a cache volume.\n")
- 
-+arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, ARG_GROUPABLE, 0,
-+    "The name of a device to use for a cache.\n")
-+
-+arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
-+    "The size of cache to use.\n")
-+
- arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0,
-     "The command profile to use for command configuration.\n"
-     "See \\fBlvm.conf\\fP(5) for more information about profiles.\n")
-@@ -1428,7 +1434,16 @@ arg(thin_ARG, 'T', "thin", 0, 0, 0,
-     "See \\fBlvmthin\\fP(7) for more information about LVM thin provisioning.\n")
- 
- arg(updatemetadata_ARG, '\0', "updatemetadata", 0, 0, 0,
--    "Update VG metadata to correct problems.\n")
-+    "Update VG metadata to correct problems.\n"
-+    "If VG metadata was updated while a PV was missing, and the PV\n"
-+    "reappears with an old version of metadata, then this option\n"
-+    "(or any other command that writes metadata) will update the\n"
-+    "metadata on the previously missing PV. If a PV was removed\n"
-+    "from a VG while it was missing, and the PV reappears, using\n"
-+    "this option will clear the outdated metadata from the previously\n"
-+    "missing PV. If metadata text is damaged on one PV, using this\n"
-+    "option will replace the damaged metadata text. For more severe\n"
-+    "damage, e.g. with headers, see \\fBpvck\\fP(8).\n")
- 
- arg(uuid_ARG, 'u', "uuid", 0, 0, 0,
-     "#pvchange\n"
-diff --git a/tools/command-lines.in b/tools/command-lines.in
-index ed3d041..1b0ca22 100644
---- a/tools/command-lines.in
-+++ b/tools/command-lines.in
-@@ -247,7 +247,7 @@ RULE: --profile not --detachprofile
- RULE: --metadataprofile not --detachprofile
- RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
- RULE: --writebehind --writemostly and LV_raid1
--RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
-+RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool LV_writecache
- RULE: --errorwhenfull --discards --zero and LV_thinpool
- RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
- RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
-@@ -359,7 +359,8 @@ OP: PV ...
- ID: lvconvert_raid_types
- DESC: Convert LV to raid or change raid layout
- DESC: (a specific raid level must be used, e.g. raid1).
--RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
-+RULE: all not lv_is_locked lv_is_pvmove
-+RULE: lv_is_raid_with_integrity not --stripes_long --stripesize --regionsize --interval
- 
- lvconvert --mirrors SNumber LV
- OO: --regionsize RegionSize, --interval Number, --mirrorlog MirrorLog, OO_LVCONVERT
-@@ -497,6 +498,20 @@ FLAGS: SECONDARY_SYNTAX
- 
- ---
- 
-+lvconvert --type writecache --cachedevice PV LV_linear_striped_raid
-+OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String
-+ID: lvconvert_to_writecache_with_device
-+DESC: Add a writecache to an LV, using a specified cache device.
-+RULE: all and lv_is_visible
-+
-+lvconvert --type cache --cachedevice PV LV_linear_striped_raid_thinpool
-+OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String
-+ID: lvconvert_to_cache_with_device
-+DESC: Add a cache to an LV, using a specified cache device.
-+RULE: all and lv_is_visible
-+
-+---
-+
- lvconvert --type thin-pool LV_linear_striped_raid_cache
- OO: --stripes_long Number, --stripesize SizeKB,
- --discards Discards, OO_LVCONVERT_POOL, OO_LVCONVERT
-@@ -1205,87 +1220,107 @@ lvcreate --type cache --size SizeMB --cachepool LV_cachepool VG
- OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
- --stripes Number, --stripesize SizeKB
- OP: PV ...
--ID: lvcreate_cache_vol_with_new_origin
--DESC: Create a cache LV, first creating a new origin LV,
--DESC: then combining it with the existing cache pool named
--DESC: by the --cachepool arg.
-+ID: lvcreate_and_attach_cachepool
-+DESC: Create a new LV, then attach the specified cachepool
-+DESC: which converts the new LV to type cache.
- 
- # alternate form of lvcreate --type cache
-+# (omits the --type cache option which is inferred)
- lvcreate --size SizeMB --cachepool LV_cachepool VG
- OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE,
- --stripes Number, --stripesize SizeKB
- OP: PV ...
--ID: lvcreate_cache_vol_with_new_origin
--DESC: Create a cache LV, first creating a new origin LV,
--DESC: then combining it with the existing cache pool named
--DESC: by the --cachepool arg (variant, infers --type cache).
-+ID: lvcreate_and_attach_cachepool_v2
-+DESC: Create a new LV, then attach the specified cachepool
-+DESC: which converts the new LV to type cache
-+DESC: (variant, infers --type cache.)
- FLAGS: SECONDARY_SYNTAX
- 
- # alternate form of lvcreate --type cache
-+# (moves cachepool from option arg to position arg,
-+# dropping the normal VG position arg)
- lvcreate --type cache --size SizeMB LV_cachepool
- OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
- --stripes Number, --stripesize SizeKB
- OP: PV ...
--ID: lvcreate_cache_vol_with_new_origin
--DESC: Create a cache LV, first creating a new origin LV,
--DESC: then combining it with the existing cache pool named
--DESC: in the first arg (variant, also use --cachepool).
-+ID: lvcreate_and_attach_cachepool_v3
-+DESC: Create a new LV, then attach the specified cachepool
-+DESC: which converts the new LV to type cache.
-+DESC: (variant, also use --cachepool).
- FLAGS: SECONDARY_SYNTAX
- 
--# This is a ridiculously crazy command which nobody could
--# understand.  It should be be eliminated.  It does two different
--# things depending on whether LV in pos 1 is a cachepool LV
--# or not.  Both variations are unnecessary.
--#
--# 1. If LV is a cachepool, then it's an alternate form of
--#    an already complicated command above.
--#
--# # alternate form for lvcreate_cache_vol_with_new_origin
--# lvcreate --cache --size SizeMB LV_cachepool
--# OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE, --stripes Number, --stripesize SizeKB
--# OP: PV ...
--# ID: lvcreate_cache_vol_with_new_origin
--# DESC: Create a cache LV, first creating a new origin LV,
--# DESC: then combining it with the existing cache pool named
--# DESC: in the first arg (variant, infers --type cache,
--# DESC: also use --cachepool).
--#
--# 2. If LV is not a cachepool, then it's a disguised lvconvert.
--#
--# # FIXME: this should be done by lvconvert, and this command removed
--# lvcreate --type cache --size SizeMB LV
--# OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
--# OP: PV ...
--# ID: lvcreate_convert_to_cache_vol_with_cachepool
--# DESC: Convert the specified LV to type cache after creating a new
--# DESC: cache pool LV to use (use lvconvert).
-+# This command has two different meanings which ought to
-+# have separate command defs, but since the syntax is the
-+# same for both they have to share one command def with
-+# an ambiguous meaning.  Which command is performed depends
-+# on whether the LV in the first arg position is a
-+# cachepool or not (we can't have two different command
-+# defs that differ only in the type of LV in the arg position
-+# because when parsing commands we don't know the LV type.)
-+#
-+# 1. An alternate form of lvcreate_and_attach_cachepool_v3
-+#    this syntax:         lvcreate --cache --size SizeMB LV_cachepool
-+#    is alternative for:  lvcreate --type cache --size SizeMB LV_cachepool
-+#
-+# 2. An alternative to using lvconvert to convert LV to type cache,
-+#    but in this case the cachepool is created internally and
-+#    then attached to the LV arg.
- #
- # Note that stripes are accepted by the first and not by the
- # second, but it's not possible to validate this until after
- # the LV type is known.
--#
--# So, to define this syntax we have to combine both of
--# those variants, each crazy on it's own, into one
--# ridiculous command.
- 
--# def1: alternate form of lvcreate --type cache, or
--# def2: it should be done by lvconvert.
- lvcreate --cache --size SizeMB LV
- OO: OO_LVCREATE_CACHE, OO_LVCREATE_POOL, OO_LVCREATE,
- --stripes Number, --stripesize SizeKB
- OP: PV ...
--ID: lvcreate_cache_vol_with_new_origin_or_convert_to_cache_vol_with_cachepool
--DESC: When LV is a cache pool, create a cache LV,
--DESC: first creating a new origin LV, then combining it with
--DESC: the existing cache pool named in the first arg
--DESC: (variant, infers --type cache, also use --cachepool).
--DESC: When LV is not a cache pool, convert the specified LV
--DESC: to type cache after creating a new cache pool LV to use
--DESC: (use lvconvert).
-+ID: lvcreate_new_plus_old_cachepool_or_lvconvert_old_plus_new_cachepool
-+DESC: When the LV arg is a cachepool, then create a new LV and
-+DESC: attach the cachepool arg to it.
-+DESC: (variant, use --type cache and --cachepool.)
-+DESC: When the LV arg is not a cachepool, then create a new cachepool
-+DESC: and attach it to the LV arg (alternative, use lvconvert.)
- FLAGS: SECONDARY_SYNTAX
- 
- ---
- 
-+# These all create a new origin LV, then forwards to lvconvert
-+# which combines it with a cachevol (which already exists or
-+# which needs to be created from cachedevice), converting
-+# the new LV to type cache or writecache.
-+
-+lvcreate --type cache --size SizeMB --cachevol LV VG
-+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --stripes Number, --stripesize SizeKB
-+OP: PV ...
-+ID: lvcreate_and_attach_cachevol_for_cache
-+DESC: Create a new LV, then attach the specified cachevol
-+DESC: which converts the new LV to type cache.
-+
-+lvcreate --type cache --size SizeMB --cachedevice PV VG
-+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --cachesize SizeMB, --stripes Number, --stripesize SizeKB
-+OP: PV ...
-+ID: lvcreate_and_attach_cachedevice_for_cache
-+DESC: Create a new LV, then attach a cachevol created from
-+DESC: the specified cache device, which converts the
-+DESC: new LV to type cache.
-+
-+lvcreate --type writecache --size SizeMB --cachevol LV VG
-+OO: OO_LVCREATE, --cachesettings String, --stripes Number, --stripesize SizeKB
-+OP: PV ...
-+ID: lvcreate_and_attach_cachevol_for_writecache
-+DESC: Create a new LV, then attach the specified cachevol
-+DESC: which converts the new LV to type writecache.
-+
-+lvcreate --type writecache --size SizeMB --cachedevice PV VG
-+OO: OO_LVCREATE, --cachesize SizeMB, --cachesettings String, --stripes Number, --stripesize SizeKB
-+OP: PV ...
-+ID: lvcreate_and_attach_cachedevice_for_writecache
-+DESC: Create a new LV, then attach a cachevol created from
-+DESC: the specified cache device, which converts the
-+DESC: new LV to type writecache.
-+
-+---
-+
- lvdisplay
- OO: --aligned, --all, --binary, --colon, --columns,
- --configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
-diff --git a/tools/command.c b/tools/command.c
-index 511dda1..2d01849 100644
---- a/tools/command.c
-+++ b/tools/command.c
-@@ -1420,6 +1420,9 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
- 		if (line[0] == '\n')
- 			break;
- 
-+		if (!strcmp(line, "---") || !strcmp(line, "--"))
-+			continue;
-+
- 		if ((n = strchr(line, '\n')))
- 			*n = '\0';
- 
-diff --git a/tools/lvchange.c b/tools/lvchange.c
-index 2d5bb32..c0adadf 100644
---- a/tools/lvchange.c
-+++ b/tools/lvchange.c
-@@ -606,6 +606,88 @@ static int _lvchange_persistent(struct cmd_context *cmd,
- 	return 1;
- }
- 
-+static int _lvchange_writecache(struct cmd_context *cmd,
-+			   struct logical_volume *lv,
-+			   uint32_t *mr)
-+{
-+	struct writecache_settings settings = { 0 };
-+	uint32_t block_size_sectors = 0;
-+	struct lv_segment *seg = first_seg(lv);
-+	int set_count = 0;
-+
-+	if (!get_writecache_settings(cmd, &settings, &block_size_sectors))
-+		return_0;
-+
-+	if (block_size_sectors && (seg->writecache_block_size != (block_size_sectors * 512))) {
-+		log_error("Cannot change existing block size %u bytes.", seg->writecache_block_size);
-+		return 0;
-+	}
-+
-+	if (settings.high_watermark_set) {
-+		seg->writecache_settings.high_watermark_set = settings.high_watermark_set;
-+		seg->writecache_settings.high_watermark = settings.high_watermark;
-+		set_count++;
-+	}
-+	if (settings.low_watermark_set) {
-+		seg->writecache_settings.low_watermark_set = settings.low_watermark_set;
-+		seg->writecache_settings.low_watermark = settings.low_watermark;
-+		set_count++;
-+	}
-+	if (settings.writeback_jobs_set) {
-+		seg->writecache_settings.writeback_jobs_set = settings.writeback_jobs_set;
-+		seg->writecache_settings.writeback_jobs = settings.writeback_jobs;
-+		set_count++;
-+	}
-+	if (settings.autocommit_blocks_set) {
-+		seg->writecache_settings.autocommit_blocks_set = settings.autocommit_blocks_set;
-+		seg->writecache_settings.autocommit_blocks = settings.autocommit_blocks;
-+		set_count++;
-+	}
-+	if (settings.autocommit_time_set) {
-+		seg->writecache_settings.autocommit_time_set = settings.autocommit_time_set;
-+		seg->writecache_settings.autocommit_time = settings.autocommit_time;
-+		set_count++;
-+	}
-+	if (settings.fua_set) {
-+		seg->writecache_settings.fua_set = settings.fua_set;
-+		seg->writecache_settings.fua = settings.fua;
-+		set_count++;
-+	}
-+	if (settings.nofua_set) {
-+		seg->writecache_settings.nofua_set = settings.nofua_set;
-+		seg->writecache_settings.nofua = settings.nofua;
-+		set_count++;
-+	}
-+	if (settings.cleaner_set) {
-+		seg->writecache_settings.cleaner_set = settings.cleaner_set;
-+		seg->writecache_settings.cleaner = settings.cleaner;
-+		set_count++;
-+	}
-+	if (settings.max_age_set) {
-+		seg->writecache_settings.max_age_set = settings.max_age_set;
-+		seg->writecache_settings.max_age = settings.max_age;
-+		set_count++;
-+	}
-+
-+	if (!set_count) {
-+		/*
-+		 * Empty settings can be used to clear all current settings,
-+		 * lvchange --cachesettings "" vg/lv
-+		 */
-+		if (!arg_count(cmd, yes_ARG) &&
-+		    yes_no_prompt("Clear all writecache settings? ") == 'n') {
-+			log_print("No settings changed.");
-+			return 1;
-+		}
-+		memset(&seg->writecache_settings, 0, sizeof(struct writecache_settings));
-+	}
-+
-+	/* Request caller to commit and reload metadata */
-+	*mr |= MR_RELOAD;
-+
-+	return 1;
-+}
-+
- static int _lvchange_cache(struct cmd_context *cmd,
- 			   struct logical_volume *lv,
- 			   uint32_t *mr)
-@@ -619,6 +701,9 @@ static int _lvchange_cache(struct cmd_context *cmd,
- 	int r = 0, is_clean;
- 	uint32_t chunk_size = 0; /* FYI: lvchange does NOT support its change */
- 
-+	if (lv_is_writecache(lv))
-+		return _lvchange_writecache(cmd, lv, mr);
-+
- 	seg = first_seg(lv);
- 
- 	if (seg_is_cache(seg) && lv_is_cache_vol(seg->pool_lv))
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index 8652252..524ed5a 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -1319,6 +1319,8 @@ static int _raid4_conversion_supported(struct logical_volume *lv, struct lvconve
- static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
- {
- 	int image_count = 0;
-+	int images_reduced = 0;
-+	int type_enforced = 0;
- 	struct cmd_context *cmd = lv->vg->cmd;
- 	struct lv_segment *seg = first_seg(lv);
- 
-@@ -1357,6 +1359,8 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 		else
- 			image_count = lp->mirrors + 1;
- 
-+		images_reduced = (image_count < lv_raid_image_count(lv));
-+
- 		if (image_count < 1) {
- 			log_error("Unable to %s images by specified amount.",
- 				  lp->keep_mimages ? "split" : "reduce");
-@@ -1369,6 +1373,12 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 				  display_lvname(lv));
- 			return 0;
- 		}
-+
-+		if (!*lp->type_str) {
-+			lp->type_str = SEG_TYPE_NAME_RAID1;
-+			lp->segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_RAID1);
-+			type_enforced = 1;
-+		}
- 	}
- 
- 	if ((lp->corelog || lp->mirrorlog) && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
-@@ -1383,7 +1393,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 		return lv_raid_split(lv, lp->yes, lp->lv_split_name, image_count, lp->pvh);
- 
- 	if (lp->mirrors_supplied) {
--		if ((seg_is_striped(seg) && seg->area_count == 1) || seg_is_raid1(seg)) { /* ??? */
-+		if (seg_is_linear(seg) || seg_is_raid1(seg)) { /* ??? */
- 		if (!*lp->type_str || !strcmp(lp->type_str, SEG_TYPE_NAME_RAID1) || !strcmp(lp->type_str, SEG_TYPE_NAME_LINEAR) ||
- 		    (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED) && image_count == 1)) {
- 			if (image_count > DEFAULT_RAID1_MAX_IMAGES) {
-@@ -1400,7 +1410,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 							lp->region_size : seg->region_size , lp->pvh))
- 				return_0;
- 
--			if (lv_raid_has_integrity(lv)) {
-+			if (lv_raid_has_integrity(lv) && !images_reduced) {
- 				struct integrity_settings *isettings = NULL;
- 				if (!lv_get_raid_integrity_settings(lv, &isettings))
- 					return_0;
-@@ -1446,7 +1456,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 		/* FIXME This needs changing globally. */
- 		if (!arg_is_set(cmd, stripes_long_ARG))
- 			lp->stripes = 0;
--		if (!arg_is_set(cmd, type_ARG))
-+		if (!type_enforced && !arg_is_set(cmd, type_ARG))
- 		       lp->segtype = NULL;
- 		if (!arg_is_set(cmd, regionsize_ARG))
- 		       lp->region_size = 0;
-@@ -1474,7 +1484,7 @@ try_new_takeover_or_reshape:
- 	/* FIXME This needs changing globally. */
- 	if (!arg_is_set(cmd, stripes_long_ARG))
- 		lp->stripes = 0;
--	if (!arg_is_set(cmd, type_ARG))
-+	if (!type_enforced && !arg_is_set(cmd, type_ARG))
- 	       lp->segtype = NULL;
- 
- 	if (!lv_raid_convert(lv, lp->segtype,
-@@ -3276,7 +3286,11 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
- 			}
- 			metadata_lv->status &= ~LV_ACTIVATION_SKIP;
- 
--			if (!wipe_lv(metadata_lv, (struct wipe_params) { .do_zero = 1 })) {
-+			if (!wipe_lv(metadata_lv, (struct wipe_params) {
-+						  .do_wipe_signatures = 1,
-+						  .is_metadata = 1,
-+						  .yes = arg_count(cmd, yes_ARG),
-+						  .force = arg_count(cmd, force_ARG) } )) {
- 				log_error("Aborting. Failed to wipe metadata lv.");
- 				goto bad;
- 			}
-@@ -4245,51 +4259,205 @@ int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv)
- 			       NULL, NULL, &_lvconvert_to_pool_single);
- }
- 
--static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
--					  struct logical_volume *lv,
--					  struct processing_handle *handle)
-+#define MAX_CACHEDEVS 8
-+
-+static int _lv_create_cachevol(struct cmd_context *cmd,
-+			       struct volume_group *vg,
-+			       struct logical_volume *lv,
-+			       struct logical_volume **cachevol_lv)
- {
--	struct volume_group *vg = lv->vg;
--	struct logical_volume *cachevol_lv;
--	const char *cachevol_name;
-+	char cvname[NAME_LEN];
-+	char format[NAME_LEN];
-+	struct dm_list *use_pvh;
-+	struct pv_list *pvl;
-+	char *dev_name;
-+	struct device *dev_fast;
-+	char *dev_argv[MAX_CACHEDEVS];
-+	int dev_argc = 0;
-+	uint64_t cache_size_sectors = 0;
-+	uint64_t full_size_sectors = 0;
-+	uint64_t pv_size_sectors;
-+	struct logical_volume *cachevol;
-+	struct arg_value_group_list *group;
-+	struct lvcreate_params lp = {
-+		.activate = CHANGE_AN,
-+		.alloc = ALLOC_INHERIT,
-+		.major = -1,
-+		.minor = -1,
-+		.permission = LVM_READ | LVM_WRITE,
-+		.pvh = &vg->pvs,
-+		.read_ahead = DM_READ_AHEAD_NONE,
-+		.stripes = 1,
-+		.vg_name = vg->name,
-+		.zero = 0,
-+		.wipe_signatures = 0,
-+		.suppress_zero_warn = 1,
-+	};
- 
--	if (!(cachevol_name = arg_str_value(cmd, cachevol_ARG, NULL)))
--		goto_out;
-+	/*
-+	 * If cache size is not set, and all cachedevice's are unused,
-+	 * then the cache size is the sum of all cachedevice sizes.
-+	 */
-+	cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0);
- 
--	if (!validate_lvname_param(cmd, &vg->name, &cachevol_name))
--		goto_out;
-+	dm_list_iterate_items(group, &cmd->arg_value_groups) {
-+		if (!grouped_arg_is_set(group->arg_values, cachedevice_ARG))
-+			continue;
- 
--	if (!(cachevol_lv = find_lv(vg, cachevol_name))) {
--		log_error("Cache single %s not found.", cachevol_name);
--		goto out;
-+		if (!(dev_name = (char *)grouped_arg_str_value(group->arg_values, cachedevice_ARG, NULL)))
-+			break;
-+
-+		if (dev_name[0] == '@') {
-+			if (!cache_size_sectors) {
-+				log_error("With tag as cachedevice, --cachesize is required.");
-+				return 0;
-+			}
-+			goto add_dev_arg;
-+		}
-+
-+		if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) {
-+			log_error("Device %s not found.", dev_name);
-+			return 0;
-+		}
-+
-+		if (!(pvl = find_pv_in_vg(vg, dev_name))) {
-+			log_error("PV %s not found in VG.", dev_name);
-+			return 0;
-+		}
-+
-+		/*
-+		 * If the dev is used in the VG, then require a cachesize to allocate
-+		 * from it.  If it is not used in the VG, then prompt asking if the
-+		 * entire dev should be used.
-+		 */
-+		if (!cache_size_sectors && pvl->pv->pe_alloc_count) {
-+			log_error("PV %s is in use, --cachesize is required.", dev_name);
-+			return 0;
-+		}
-+
-+		if (!cache_size_sectors) {
-+			pv_size_sectors = (pvl->pv->pe_count * vg->extent_size);
-+
-+			if (!arg_is_set(cmd, yes_ARG) &&
-+			    yes_no_prompt("Use all %s from %s for cache? [y/n]: ",
-+					  display_size(cmd, pv_size_sectors), dev_name) == 'n') {
-+				log_print("Use --cachesize SizeMB to use a part of the cachedevice.");
-+				log_error("Conversion aborted.");
-+				return 0;
-+			}
-+			full_size_sectors += pv_size_sectors;
-+		}
-+ add_dev_arg:
-+		if (dev_argc >= MAX_CACHEDEVS) {
-+			log_error("Cannot allocate from more than %u cache devices.", MAX_CACHEDEVS);
-+			return 0;
-+		}
-+
-+		dev_argv[dev_argc++] = dev_name;
- 	}
- 
--	if (lv_is_cache_vol(cachevol_lv)) {
--		log_error("LV %s is already used as a cachevol.", display_lvname(cachevol_lv));
--		goto out;
-+	if (!cache_size_sectors)
-+		cache_size_sectors = full_size_sectors;
-+
-+	if (!dev_argc) {
-+		log_error("No cachedevice specified to create a cachevol.");
-+		return 0;
- 	}
- 
--	/* Ensure the LV is not active elsewhere. */
--	if (!lockd_lv(cmd, lv, "ex", 0))
--		goto_out;
-+	if (!(use_pvh = create_pv_list(cmd->mem, vg, dev_argc, dev_argv, 1))) {
-+		log_error("cachedevice not found in VG %s.", dev_name);
-+		return 0;
-+	}
- 
--	if (!dm_list_empty(&cachevol_lv->segs_using_this_lv)) {
--		log_error("LV %s is already in use.", display_lvname(cachevol_lv));
--		goto out;
-+	if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) {
-+		log_error("Failed to create cachevol LV name.");
-+		return 0;
- 	}
- 
--	if (!arg_is_set(cmd, yes_ARG) &&
--	    yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(cachevol_lv)) == 'n') {
--		log_error("Conversion aborted.");
--		goto out;
-+	if (find_lv(vg, cvname)) {
-+		memset(format, 0, sizeof(cvname));
-+		memset(cvname, 0, sizeof(cvname));
-+		if (dm_snprintf(format, sizeof(format), "%s_cache%%d", lv->name) < 0) {
-+			log_error("Failed to generate cachevol LV format.");
-+			return 0;
-+		}
-+		if (!generate_lv_name(vg, format, cvname, sizeof(cvname))) {
-+			log_error("Failed to generate cachevol LV name.");
-+			return 0;
-+		}
-+	}
-+
-+	lp.lv_name = cvname;
-+	lp.pvh = use_pvh;
-+	lp.extents = cache_size_sectors / vg->extent_size;
-+
-+	log_print("Creating cachevol LV %s with size %s.",
-+		  cvname, display_size(cmd, cache_size_sectors));
-+
-+	dm_list_init(&lp.tags);
-+
-+	if (!(lp.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
-+		return_0;
-+
-+	if (!(cachevol = lv_create_single(vg, &lp))) {
-+		log_error("Failed to create cachevol LV");
-+		return 0;
-+	}
-+
-+	*cachevol_lv = cachevol;
-+	return 1;
-+}
-+
-+int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
-+				     struct logical_volume *lv,
-+				     struct processing_handle *handle)
-+{
-+	struct volume_group *vg = lv->vg;
-+	struct logical_volume *lv_fast;
-+	const char *fast_name;
-+
-+	/*
-+	 * User specifies an existing cachevol to use or a cachedevice
-+	 * to create a cachevol from.
-+	 */
-+	if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
-+		if (!validate_lvname_param(cmd, &vg->name, &fast_name))
-+			goto_bad;
-+
-+		if (!(lv_fast = find_lv(vg, fast_name))) {
-+			log_error("LV %s not found.", fast_name);
-+			goto bad;
-+		}
-+
-+		if (lv_is_cache_vol(lv_fast)) {
-+			log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
-+			goto bad;
-+		}
-+
-+		if (!dm_list_empty(&lv_fast->segs_using_this_lv)) {
-+			log_error("LV %s is already in use.", display_lvname(lv_fast));
-+			goto bad;
-+		}
-+
-+		if (!arg_is_set(cmd, yes_ARG) &&
-+		    yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
-+			log_error("Conversion aborted.");
-+			goto bad;
-+		}
-+
-+		if (!lockd_lv(cmd, lv_fast, "ex", 0))
-+			goto_bad;
-+	} else {
-+		if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
-+			goto_bad;
- 	}
- 
- 	/* Ensure the LV is not active elsewhere. */
--	if (!lockd_lv(cmd, cachevol_lv, "ex", LDLV_PERSISTENT))
--		goto_out;
-+	if (!lockd_lv(cmd, lv, "ex", 0))
-+		goto_bad;
- 
--	if (!wipe_cache_pool(cachevol_lv))
--		goto_out;
-+	if (!wipe_cache_pool(lv_fast))
-+		goto_bad;
- 
- 	/* When the lv arg is a thinpool, redirect command to data sub lv. */
- 
-@@ -4299,17 +4467,17 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
- 	}
- 
- 	if (_raid_split_image_conversion(lv))
--		goto_out;
-+		goto_bad;
- 
- 	/* Attach the cache to the main LV. */
- 
--	if (!_cache_vol_attach(cmd, lv, cachevol_lv))
--		goto_out;
-+	if (!_cache_vol_attach(cmd, lv, lv_fast))
-+		goto_bad;
- 
- 	log_print_unless_silent("Logical volume %s is now cached.", display_lvname(lv));
- 
- 	return ECMD_PROCESSED;
-- out:
-+ bad:
- 	return ECMD_FAILED;
- }
- 
-@@ -5308,19 +5476,8 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
- 					struct logical_volume *lv,
- 					struct logical_volume *lv_fast)
- {
--	char cvol_name[NAME_LEN];
--	char *c;
- 	int noflush = 0;
- 
--	/*
--	 * LV must be inactive externally before detaching cache.
--	 */
--
--	if (lv_info(cmd, lv, 1, NULL, 0, 0)) {
--		log_error("LV %s must be inactive to detach writecache.", display_lvname(lv));
--		return 0;
--	}
--
- 	if (!archive(lv->vg))
- 		return_0;
- 
-@@ -5344,36 +5501,23 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
- 		noflush = 1;
- 	}
- 
--	if (!lv_detach_writecache_cachevol(lv, noflush))
--		return_0;
--
- 	/*
--	 * Rename lv_fast back to its original name, without the _cvol
--	 * suffix that was added when lv_fast was attached for caching.
-+	 * TODO: send a message to writecache in the kernel to start writing
-+	 * back cache data to the origin.  Then release the vg lock and monitor
-+	 * the progress of that writeback.  When it's complete we can reacquire
-+	 * the vg lock, rescan the vg (ensure it hasn't changed), and do the
-+	 * detach which should be quick since the writeback is complete.  If
-+	 * this command is canceled while monitoring writeback, it should just
-+	 * be rerun.  The LV will continue to have the writecache until this
-+	 * command is run to completion.
- 	 */
--	if (!dm_strncpy(cvol_name, lv_fast->name, sizeof(cvol_name)) ||
--	    !(c = strstr(cvol_name, "_cvol"))) {
--		log_debug("LV %s has no suffix for cachevol (skipping rename).",
--			display_lvname(lv_fast));
--	} else {
--		*c = 0;
--		/* If the name is in use, generate new lvol%d */
--		if (lv_name_is_used_in_vg(lv->vg, cvol_name, NULL) &&
--		    !generate_lv_name(lv->vg, "lvol%d", cvol_name, sizeof(cvol_name))) {
--			log_error("Failed to generate unique name for unused logical volume.");
--			return 0;
--		}
- 
--		if (!lv_rename_update(cmd, lv_fast, cvol_name, 0))
--			return_0;
--	}
--
--	if (!vg_write(lv->vg) || !vg_commit(lv->vg))
-+	if (!lv_detach_writecache_cachevol(lv, noflush))
- 		return_0;
- 
- 	backup(lv->vg);
- 
--	log_print_unless_silent("Logical volume %s write cache has been detached.",
-+	log_print_unless_silent("Logical volume %s writecache has been detached.",
- 				display_lvname(lv));
- 	return 1;
- }
-@@ -5383,7 +5527,8 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
- 	struct wipe_params wp = {
- 		.do_wipe_signatures = 1, /* optional, to print warning if clobbering something */
- 		.do_zero = 1,            /* required for dm-writecache to work */
--		.zero_sectors = 1
-+		.yes = arg_count(cmd, yes_ARG),
-+		.force = arg_count(cmd, force_ARG)
- 	};
- 	int ret;
- 
-@@ -5400,7 +5545,8 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
- 		return 0;
- 	}
- 
--	ret = wipe_lv(lv, wp);
-+	if (!(ret = wipe_lv(lv, wp)))
-+		stack;
- 
- 	if (!deactivate_lv(cmd, lv)) {
- 		log_error("Failed to deactivate LV %s for zeroing.", display_lvname(lv));
-@@ -5410,157 +5556,6 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
- 	return ret;
- }
- 
--static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
--				       char *key, char *val, uint32_t *block_size_sectors)
--{
--	/* special case: block_size is not a setting but is set with the --cachesettings option */
--	if (!strncmp(key, "block_size", strlen("block_size"))) {
--		uint32_t block_size = 0;
--		if (sscanf(val, "%u", &block_size) != 1)
--			goto_bad;
--		if (block_size == 512)
--			*block_size_sectors = 1;
--		else if (block_size == 4096)
--			*block_size_sectors = 8;
--		else
--			goto_bad;
--		return 1;
--	}
--
--	if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
--		if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
--			goto_bad;
--		if (settings->high_watermark > 100)
--			goto_bad;
--		settings->high_watermark_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
--		if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
--			goto_bad;
--		if (settings->low_watermark > 100)
--			goto_bad;
--		settings->low_watermark_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
--		if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
--			goto_bad;
--		settings->writeback_jobs_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
--		if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
--			goto_bad;
--		settings->autocommit_blocks_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
--		if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
--			goto_bad;
--		settings->autocommit_time_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "fua", strlen("fua"))) {
--		if (settings->nofua_set) {
--			log_error("Setting fua and nofua cannot both be set.");
--			return 0;
--		}
--		if (sscanf(val, "%u", &settings->fua) != 1)
--			goto_bad;
--		settings->fua_set = 1;
--		return 1;
--	}
--
--	if (!strncmp(key, "nofua", strlen("nofua"))) {
--		if (settings->fua_set) {
--			log_error("Setting fua and nofua cannot both be set.");
--			return 0;
--		}
--		if (sscanf(val, "%u", &settings->nofua) != 1)
--			goto_bad;
--		settings->nofua_set = 1;
--		return 1;
--	}
--
--	if (settings->new_key) {
--		log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
--		return 0;
--	}
--
--	log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
--	if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
--		log_error("Aborting writecache conversion.");
--		return 0;
--	}
--
--	log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
--
--	settings->new_key = dm_pool_strdup(cmd->mem, key);
--	settings->new_val = dm_pool_strdup(cmd->mem, val);
--	return 1;
--
-- bad:
--	log_error("Invalid setting: %s", key);
--	return 0;
--}
--
--static int _get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
--				    uint32_t *block_size_sectors)
--{
--	struct arg_value_group_list *group;
--	const char *str;
--	char key[64];
--	char val[64];
--	int num;
--	int pos;
--
--	/*
--	 * "grouped" means that multiple --cachesettings options can be used.
--	 * Each option is also allowed to contain multiple key = val pairs.
--	 */
--
--	dm_list_iterate_items(group, &cmd->arg_value_groups) {
--		if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
--			continue;
--
--		if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
--			break;
--
--		pos = 0;
--
--		while (pos < strlen(str)) {
--			/* scan for "key1=val1 key2 = val2  key3= val3" */
--
--			memset(key, 0, sizeof(key));
--			memset(val, 0, sizeof(val));
--
--			if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
--				log_error("Invalid setting at: %s", str+pos);
--				return 0;
--			}
--
--			pos += num;
--
--			if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
--				return_0;
--		}
--	}
--
--	if (settings->high_watermark_set && settings->low_watermark_set &&
--	    (settings->high_watermark <= settings->low_watermark)) {
--		log_error("High watermark must be greater than low watermark.");
--		return 0;
--	}
--
--	return 1;
--}
--
- static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
- 					    struct logical_volume *lv,
- 					    struct logical_volume *lv_fast,
-@@ -5605,9 +5600,177 @@ static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd,
- 	return lv_wcorig;
- }
- 
--#define DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS 8 /* 4K */
-+/*
-+ * Currently only supports writecache block sizes 512 and 4096.
-+ * This could be expanded later.
-+ */
-+static int _set_writecache_block_size(struct cmd_context *cmd,
-+				      struct logical_volume *lv,
-+				      uint32_t *block_size_sectors)
-+{
-+	char pathname[PATH_MAX];
-+	struct device *fs_dev;
-+	struct dm_list pvs;
-+	struct pv_list *pvl;
-+	uint32_t fs_block_size = 0;
-+	uint32_t block_size_setting = 0;
-+	uint32_t block_size = 0;
-+	int lbs_unknown = 0, lbs_4k = 0, lbs_512 = 0;
-+	int pbs_unknown = 0, pbs_4k = 0, pbs_512 = 0;
-+	int rv;
-+
-+	/* This is set if the user specified a writecache block size on the command line. */
-+	if (*block_size_sectors)
-+		block_size_setting = *block_size_sectors * 512;
-+
-+	dm_list_init(&pvs);
-+
-+	if (!get_pv_list_for_lv(cmd->mem, lv, &pvs)) {
-+		log_error("Failed to build list of PVs for %s.", display_lvname(lv));
-+		goto_bad;
-+	}
-+
-+	dm_list_iterate_items(pvl, &pvs) {
-+		unsigned int pbs = 0;
-+		unsigned int lbs = 0;
- 
--static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
-+		if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) {
-+			lbs_unknown++;
-+			pbs_unknown++;
-+			continue;
-+		}
-+
-+		if (lbs == 4096)
-+			lbs_4k++;
-+		else if (lbs == 512)
-+			lbs_512++;
-+		else
-+			lbs_unknown++;
-+
-+		if (pbs == 4096)
-+			pbs_4k++;
-+		else if (pbs == 512)
-+			pbs_512++;
-+		else
-+			pbs_unknown++;
-+	}
-+
-+	if (lbs_4k && lbs_512) {
-+		log_error("Writecache requires consistent logical block size for LV devices.");
-+		goto_bad;
-+	}
-+
-+	if (lbs_4k && block_size_setting && (block_size_setting < 4096)) {
-+		log_error("Writecache block size %u not allowed with device logical block size 4096.",
-+			  block_size_setting);
-+		goto_bad;
-+	}
-+
-+	if (dm_snprintf(pathname, sizeof(pathname), "%s/%s/%s", cmd->dev_dir,
-+			lv->vg->name, lv->name) < 0) {
-+		log_error("Path name too long to get LV block size %s", display_lvname(lv));
-+		goto_bad;
-+	}
-+
-+	if (!sync_local_dev_names(cmd))
-+		stack;
-+
-+	if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) {
-+		if (test_mode()) {
-+			log_print("Test mode skips checking fs block size.");
-+			fs_block_size = 0;
-+			goto skip_fs;
-+		}
-+		log_error("Device for LV not found to check block size %s", pathname);
-+		goto_bad;
-+	}
-+
-+	/*
-+	 * get_fs_block_size() returns the libblkid BLOCK_SIZE value,
-+	 * where libblkid has fs-specific code to set BLOCK_SIZE to the
-+	 * value we need here.
-+	 *
-+	 * The term "block size" here may not equate directly to what the fs
-+	 * calls the block size, e.g. xfs calls this the sector size (and
-+	 * something different the block size); while ext4 does call this
-+	 * value the block size, but it's possible values are not the same
-+	 * as xfs's, and do not seem to relate directly to the device LBS.
-+	 *
-+	 * With 512 LBS and 4K PBS, mkfs.xfs will use xfs sector size 4K.
-+	 */
-+	rv = get_fs_block_size(fs_dev, &fs_block_size);
-+skip_fs:
-+	if (!rv || !fs_block_size) {
-+		if (lbs_4k && pbs_4k && !pbs_512) {
-+			block_size = 4096;
-+		} else if (lbs_512 && pbs_512 && !pbs_4k) {
-+			block_size = 512;
-+		} else if (lbs_512 && pbs_4k) {
-+			if (block_size_setting == 4096)
-+				block_size = 4096;
-+			else
-+				block_size = 512;
-+		} else {
-+			block_size = 512;
-+		}
-+
-+		if (block_size_setting && (block_size_setting != block_size)) {
-+			log_error("Cannot use writecache block size %u with unknown file system block size, logical block size %u, physical block size %u.",
-+				  block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
-+			goto bad;
-+		}
-+
-+		if (block_size != 512) {
-+			log_warn("WARNING: unable to detect a file system block size on %s", display_lvname(lv));
-+			log_warn("WARNING: using a writecache block size larger than the file system block size may corrupt the file system.");
-+			if (!arg_is_set(cmd, yes_ARG) &&
-+			    yes_no_prompt("Use writecache block size %u? [y/n]: ", block_size) == 'n')  {
-+				log_error("Conversion aborted.");
-+				goto bad;
-+			}
-+		}
-+
-+		log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
-+			 block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
-+		goto out;
-+	}
-+
-+	if (!block_size_setting) {
-+		/* User did not specify a block size, so choose according to fs block size. */
-+		if (fs_block_size == 4096)
-+			block_size = 4096;
-+		else if (fs_block_size == 512)
-+			block_size = 512;
-+		else if (fs_block_size > 4096)
-+			block_size = 4096;
-+		else if (fs_block_size < 4096)
-+			block_size = 512;
-+		else
-+			goto_bad;
-+	} else {
-+		if (block_size_setting <= fs_block_size)
-+			block_size = block_size_setting;
-+		else {
-+			log_error("Writecache block size %u cannot be larger than file system block size %u.",
-+				  block_size_setting, fs_block_size);
-+			goto_bad;
-+		}
-+	}
-+
-+out:
-+	if (block_size == 512)
-+		*block_size_sectors = 1;
-+	else if (block_size == 4096)
-+		*block_size_sectors = 8;
-+	else
-+		goto_bad;
-+
-+	return 1;
-+bad:
-+	return 0;
-+}
-+
-+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
- 					struct logical_volume *lv,
- 					struct processing_handle *handle)
- {
-@@ -5616,68 +5779,91 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
- 	struct logical_volume *lv_fast;
- 	struct writecache_settings settings;
- 	const char *fast_name;
--	uint32_t block_size_sectors;
-+	uint32_t block_size_sectors = 0;
- 	char *lockd_fast_args = NULL;
- 	char *lockd_fast_name = NULL;
- 	struct id lockd_fast_id;
- 	char cvol_name[NAME_LEN];
-+	int is_active;
- 
--	fast_name = arg_str_value(cmd, cachevol_ARG, "");
-+	/*
-+	 * User specifies an existing cachevol to use or a cachedevice
-+	 * to create a cachevol from.
-+	 */
-+	if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
-+		if (!validate_lvname_param(cmd, &vg->name, &fast_name))
-+			goto_bad;
- 
--	if (!(lv_fast = find_lv(vg, fast_name))) {
--		log_error("LV %s not found.", fast_name);
--		goto bad;
--	}
-+		if (!(lv_fast = find_lv(vg, fast_name))) {
-+			log_error("LV %s not found.", fast_name);
-+			goto bad;
-+		}
- 
--	if (lv_fast == lv) {
--		log_error("Invalid cachevol LV.");
--		goto bad;
--	}
-+		if (lv_fast == lv) {
-+			log_error("Invalid cachevol LV.");
-+			goto bad;
-+		}
- 
--	if (!seg_is_linear(first_seg(lv_fast))) {
--		log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast));
--		goto bad;
--	}
-+		if (lv_is_cache_vol(lv_fast)) {
-+			log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
-+			goto bad;
-+		}
- 
--	if (lv_is_cache_vol(lv_fast)) {
--		log_error("LV %s is already used as a cachevol.", display_lvname(lv_fast));
--		goto bad;
--	}
-+		if (!seg_is_linear(first_seg(lv_fast))) {
-+			log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast));
-+			goto bad;
-+		}
- 
--	/*
--	 * To permit this we need to check the block size of the fs using lv
--	 * (recently in libblkid) so that we can use a matching writecache
--	 * block size.  We also want to do that if the lv is inactive.
--	 */
--	if (lv_is_active(lv)) {
--		log_error("LV %s must be inactive to attach writecache.", display_lvname(lv));
--		goto bad;
--	}
-+		/* fast LV shouldn't generally be active by itself, but just in case. */
-+		if (lv_is_active(lv_fast)) {
-+			log_error("LV %s must be inactive to attach.", display_lvname(lv_fast));
-+			goto bad;
-+		}
- 
--	/* fast LV shouldn't generally be active by itself, but just in case. */
--	if (lv_info(cmd, lv_fast, 1, NULL, 0, 0)) {
--		log_error("LV %s must be inactive to attach.", display_lvname(lv_fast));
--		goto bad;
-+		if (!arg_is_set(cmd, yes_ARG) &&
-+		     yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
-+			log_error("Conversion aborted.");
-+			goto bad;
-+		}
-+	} else {
-+		if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
-+			goto_bad;
- 	}
- 
-+	is_active = lv_is_active(lv);
-+
- 	memset(&settings, 0, sizeof(settings));
--	block_size_sectors = DEFAULT_WRITECACHE_BLOCK_SIZE_SECTORS;
- 
--	if (!_get_writecache_settings(cmd, &settings, &block_size_sectors)) {
-+	if (!get_writecache_settings(cmd, &settings, &block_size_sectors)) {
- 		log_error("Invalid writecache settings.");
- 		goto bad;
- 	}
- 
--	if (!arg_is_set(cmd, yes_ARG) &&
--	    yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') {
--		log_error("Conversion aborted.");
--		goto bad;
-+	if (!is_active) {
-+		/* checking block size of fs on the lv requires the lv to be active */
-+		if (!activate_lv(cmd, lv)) {
-+			log_error("Failed to activate LV to check block size %s", display_lvname(lv));
-+			goto bad;
-+		}
-+	}
-+
-+	if (!_set_writecache_block_size(cmd, lv, &block_size_sectors)) {
-+		if (!is_active && !deactivate_lv(cmd, lv))
-+			stack;
-+		goto_bad;
- 	}
- 
--	/* Ensure the two LVs are not active elsewhere. */
-+	if (!is_active) {
-+		if (!deactivate_lv(cmd, lv)) {
-+			log_error("Failed to deactivate LV after checking block size %s", display_lvname(lv));
-+			goto bad;
-+		}
-+	}
-+
-+	/* Ensure the LV is not active elsewhere. */
- 	if (!lockd_lv(cmd, lv, "ex", 0))
- 		goto_bad;
--	if (!lockd_lv(cmd, lv_fast, "ex", 0))
-+	if (fast_name && !lockd_lv(cmd, lv_fast, "ex", 0))
- 		goto_bad;
- 
- 	if (!archive(vg))
-@@ -5744,7 +5930,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
- 			log_error("Failed to unlock fast LV %s/%s", vg->name, lockd_fast_name);
- 	}
- 
--	log_print_unless_silent("Logical volume %s now has write cache.",
-+	log_print_unless_silent("Logical volume %s now has writecache.",
- 				display_lvname(lv));
- 	return ECMD_PROCESSED;
- bad:
-@@ -5768,7 +5954,7 @@ int lvconvert_to_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
- 	cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
- 
- 	ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
--			      &_lvconvert_writecache_attach_single);
-+			      &lvconvert_writecache_attach_single);
- 
- 	destroy_processing_handle(cmd, handle);
- 
-@@ -5791,7 +5977,7 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
- 	cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
- 
- 	ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
--			      &_lvconvert_cachevol_attach_single);
-+			      &lvconvert_cachevol_attach_single);
- 
- 	destroy_processing_handle(cmd, handle);
- 
-diff --git a/tools/lvcreate.c b/tools/lvcreate.c
-index 5c978b3..3357a08 100644
---- a/tools/lvcreate.c
-+++ b/tools/lvcreate.c
-@@ -766,7 +766,9 @@ static int _lvcreate_params(struct cmd_context *cmd,
- 	 *
- 	 * Ordering of following type tests is IMPORTANT
- 	 */
--	if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
-+	if (lp->ignore_type) {
-+		segtype_str = SEG_TYPE_NAME_STRIPED;
-+	} else if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
- 		lp->type = 1;
- 		if (!strcmp(segtype_str, "linear")) {
- 			segtype_str = "striped";
-@@ -1799,3 +1801,152 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
- 	destroy_processing_handle(cmd, handle);
- 	return ret;
- }
-+
-+static int _lvcreate_and_attach_writecache_single(struct cmd_context *cmd,
-+		const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
-+{
-+	struct processing_params *pp = (struct processing_params *) handle->custom_handle;
-+	struct lvcreate_params *lp = pp->lp;
-+	struct logical_volume *lv;
-+	int ret;
-+
-+	ret = _lvcreate_single(cmd, vg_name, vg, handle);
-+
-+	if (ret == ECMD_FAILED)
-+		return ret;
-+
-+	if (!(lv = find_lv(vg, lp->lv_name))) {
-+		log_error("Failed to find LV %s to add writecache.", lp->lv_name);
-+		return ECMD_FAILED;
-+	}
-+
-+	ret = lvconvert_writecache_attach_single(cmd, lv, handle);
-+
-+	if (ret == ECMD_FAILED) {
-+		log_error("Removing new LV after failing to add writecache.");
-+		if (!deactivate_lv(cmd, lv))
-+			log_error("Failed to deactivate new LV %s.", display_lvname(lv));
-+		if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
-+			log_error("Failed to remove new LV %s.", display_lvname(lv));
-+		return ECMD_FAILED;
-+	}
-+
-+	return ECMD_PROCESSED;
-+}
-+
-+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
-+{
-+	struct processing_handle *handle = NULL;
-+	struct processing_params pp;
-+	struct lvcreate_params lp = {
-+		.major = -1,
-+		.minor = -1,
-+	};
-+	struct lvcreate_cmdline_params lcp = { 0 };
-+	int ret;
-+
-+	/*
-+	 * Tell lvcreate to ignore --type since we are using lvcreate
-+	 * to create a linear LV and using lvconvert to add cache.
-+	 * (Would be better if lvcreate code was split up so we could
-+	 * call a specific function that just created a linear/striped LV.)
-+	 */
-+	lp.ignore_type = 1;
-+
-+	if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
-+		stack;
-+		return EINVALID_CMD_LINE;
-+	}
-+
-+	pp.lp = &lp;
-+	pp.lcp = &lcp;
-+
-+        if (!(handle = init_processing_handle(cmd, NULL))) {
-+		log_error("Failed to initialize processing handle.");
-+		return ECMD_FAILED;
-+	}
-+
-+	handle->custom_handle = &pp;
-+
-+	ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
-+			      &_lvcreate_and_attach_writecache_single);
-+
-+	_destroy_lvcreate_params(&lp);
-+	destroy_processing_handle(cmd, handle);
-+	return ret;
-+}
-+
-+static int _lvcreate_and_attach_cache_single(struct cmd_context *cmd,
-+		const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
-+{
-+	struct processing_params *pp = (struct processing_params *) handle->custom_handle;
-+	struct lvcreate_params *lp = pp->lp;
-+	struct logical_volume *lv;
-+	int ret;
-+
-+	ret = _lvcreate_single(cmd, vg_name, vg, handle);
-+
-+	if (ret == ECMD_FAILED)
-+		return ret;
-+
-+	if (!(lv = find_lv(vg, lp->lv_name))) {
-+		log_error("Failed to find LV %s to add cache.", lp->lv_name);
-+		return ECMD_FAILED;
-+	}
-+
-+	ret = lvconvert_cachevol_attach_single(cmd, lv, handle);
-+
-+	if (ret == ECMD_FAILED) {
-+		log_error("Removing new LV after failing to add cache.");
-+		if (!deactivate_lv(cmd, lv))
-+			log_error("Failed to deactivate new LV %s.", display_lvname(lv));
-+		if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
-+			log_error("Failed to remove new LV %s.", display_lvname(lv));
-+		return ECMD_FAILED;
-+	}
-+
-+	return ECMD_PROCESSED;
-+}
-+
-+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
-+{
-+	struct processing_handle *handle = NULL;
-+	struct processing_params pp;
-+	struct lvcreate_params lp = {
-+		.major = -1,
-+		.minor = -1,
-+	};
-+	struct lvcreate_cmdline_params lcp = { 0 };
-+	int ret;
-+
-+	/*
-+	 * Tell lvcreate to ignore --type since we are using lvcreate
-+	 * to create a linear LV and using lvconvert to add cache.
-+	 * (Would be better if lvcreate code was split up so we could
-+	 * call a specific function that just created a linear/striped LV.)
-+	 */
-+	lp.ignore_type = 1;
-+
-+	if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
-+		stack;
-+		return EINVALID_CMD_LINE;
-+	}
-+
-+	pp.lp = &lp;
-+	pp.lcp = &lcp;
-+
-+	if (!(handle = init_processing_handle(cmd, NULL))) {
-+		log_error("Failed to initialize processing handle.");
-+		return ECMD_FAILED;
-+	}
-+
-+	handle->custom_handle = &pp;
-+
-+	ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
-+			      &_lvcreate_and_attach_cache_single);
-+
-+	_destroy_lvcreate_params(&lp);
-+	destroy_processing_handle(cmd, handle);
-+	return ret;
-+}
-+
-diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
-index d87a8f0..7cf4e3f 100644
---- a/tools/lvmcmdline.c
-+++ b/tools/lvmcmdline.c
-@@ -124,8 +124,10 @@ static const struct command_function _command_functions[CMD_COUNT] = {
- 	{ lvconvert_to_cachepool_CMD,			lvconvert_to_pool_cmd },
- 	{ lvconvert_to_thin_with_external_CMD,		lvconvert_to_thin_with_external_cmd },
- 	{ lvconvert_to_cache_with_cachevol_CMD,		lvconvert_to_cache_with_cachevol_cmd },
-+	{ lvconvert_to_cache_with_device_CMD,		lvconvert_to_cache_with_cachevol_cmd },
- 	{ lvconvert_to_cache_with_cachepool_CMD,	lvconvert_to_cache_with_cachepool_cmd },
- 	{ lvconvert_to_writecache_CMD,			lvconvert_to_writecache_cmd },
-+	{ lvconvert_to_writecache_with_device_CMD,	lvconvert_to_writecache_cmd },
- 	{ lvconvert_swap_pool_metadata_CMD,		lvconvert_swap_pool_metadata_cmd },
- 	{ lvconvert_to_thinpool_or_swap_metadata_CMD,   lvconvert_to_pool_or_swap_metadata_cmd },
- 	{ lvconvert_to_cachepool_or_swap_metadata_CMD,  lvconvert_to_pool_or_swap_metadata_cmd },
-@@ -152,6 +154,12 @@ static const struct command_function _command_functions[CMD_COUNT] = {
- 	/* lvconvert for integrity */
- 	{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
- 
-+	/* lvcreate */
-+	{ lvcreate_and_attach_cachevol_for_cache_CMD,		lvcreate_and_attach_cache_cmd },
-+	{ lvcreate_and_attach_cachedevice_for_cache_CMD,	lvcreate_and_attach_cache_cmd },
-+	{ lvcreate_and_attach_cachevol_for_writecache_CMD,	lvcreate_and_attach_writecache_cmd },
-+	{ lvcreate_and_attach_cachedevice_for_writecache_CMD,	lvcreate_and_attach_writecache_cmd },
-+
- 	{ pvscan_display_CMD, pvscan_display_cmd },
- 	{ pvscan_cache_CMD, pvscan_cache_cmd },
- };
-diff --git a/tools/toollib.c b/tools/toollib.c
-index 89b6374..eb0de55 100644
---- a/tools/toollib.c
-+++ b/tools/toollib.c
-@@ -1184,6 +1184,170 @@ out:
- 	return ok;
- }
- 
-+static int _get_one_writecache_setting(struct cmd_context *cmd, struct writecache_settings *settings,
-+				       char *key, char *val, uint32_t *block_size_sectors)
-+{
-+	/* special case: block_size is not a setting but is set with the --cachesettings option */
-+	if (!strncmp(key, "block_size", strlen("block_size"))) {
-+		uint32_t block_size = 0;
-+		if (sscanf(val, "%u", &block_size) != 1)
-+			goto_bad;
-+		if (block_size == 512)
-+			*block_size_sectors = 1;
-+		else if (block_size == 4096)
-+			*block_size_sectors = 8;
-+		else
-+			goto_bad;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "high_watermark", strlen("high_watermark"))) {
-+		if (sscanf(val, "%llu", (unsigned long long *)&settings->high_watermark) != 1)
-+			goto_bad;
-+		if (settings->high_watermark > 100)
-+			goto_bad;
-+		settings->high_watermark_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "low_watermark", strlen("low_watermark"))) {
-+		if (sscanf(val, "%llu", (unsigned long long *)&settings->low_watermark) != 1)
-+			goto_bad;
-+		if (settings->low_watermark > 100)
-+			goto_bad;
-+		settings->low_watermark_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "writeback_jobs", strlen("writeback_jobs"))) {
-+		if (sscanf(val, "%llu", (unsigned long long *)&settings->writeback_jobs) != 1)
-+			goto_bad;
-+		settings->writeback_jobs_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "autocommit_blocks", strlen("autocommit_blocks"))) {
-+		if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_blocks) != 1)
-+			goto_bad;
-+		settings->autocommit_blocks_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "autocommit_time", strlen("autocommit_time"))) {
-+		if (sscanf(val, "%llu", (unsigned long long *)&settings->autocommit_time) != 1)
-+			goto_bad;
-+		settings->autocommit_time_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "fua", strlen("fua"))) {
-+		if (settings->nofua_set) {
-+			log_error("Setting fua and nofua cannot both be set.");
-+			return 0;
-+		}
-+		if (sscanf(val, "%u", &settings->fua) != 1)
-+			goto_bad;
-+		settings->fua_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "nofua", strlen("nofua"))) {
-+		if (settings->fua_set) {
-+			log_error("Setting fua and nofua cannot both be set.");
-+			return 0;
-+		}
-+		if (sscanf(val, "%u", &settings->nofua) != 1)
-+			goto_bad;
-+		settings->nofua_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "cleaner", strlen("cleaner"))) {
-+		if (sscanf(val, "%u", &settings->cleaner) != 1)
-+			goto_bad;
-+		settings->cleaner_set = 1;
-+		return 1;
-+	}
-+
-+	if (!strncmp(key, "max_age", strlen("max_age"))) {
-+		if (sscanf(val, "%u", &settings->max_age) != 1)
-+			goto_bad;
-+		settings->max_age_set = 1;
-+		return 1;
-+	}
-+
-+	if (settings->new_key) {
-+		log_error("Setting %s is not recognized. Only one unrecognized setting is allowed.", key);
-+		return 0;
-+	}
-+
-+	log_warn("Unrecognized writecache setting \"%s\" may cause activation failure.", key);
-+	if (yes_no_prompt("Use unrecognized writecache setting? [y/n]: ") == 'n') {
-+		log_error("Aborting writecache conversion.");
-+		return 0;
-+	}
-+
-+	log_warn("Using unrecognized writecache setting: %s = %s.", key, val);
-+
-+	settings->new_key = dm_pool_strdup(cmd->mem, key);
-+	settings->new_val = dm_pool_strdup(cmd->mem, val);
-+	return 1;
-+
-+ bad:
-+	log_error("Invalid setting: %s", key);
-+	return 0;
-+}
-+
-+int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
-+			    uint32_t *block_size_sectors)
-+{
-+	struct arg_value_group_list *group;
-+	const char *str;
-+	char key[64];
-+	char val[64];
-+	int num;
-+	int pos;
-+
-+	/*
-+	 * "grouped" means that multiple --cachesettings options can be used.
-+	 * Each option is also allowed to contain multiple key = val pairs.
-+	 */
-+
-+	dm_list_iterate_items(group, &cmd->arg_value_groups) {
-+		if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
-+			continue;
-+
-+		if (!(str = grouped_arg_str_value(group->arg_values, cachesettings_ARG, NULL)))
-+			break;
-+
-+		pos = 0;
-+
-+		while (pos < strlen(str)) {
-+			/* scan for "key1=val1 key2 = val2  key3= val3" */
-+
-+			memset(key, 0, sizeof(key));
-+			memset(val, 0, sizeof(val));
-+
-+			if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
-+				log_error("Invalid setting at: %s", str+pos);
-+				return 0;
-+			}
-+
-+			pos += num;
-+
-+			if (!_get_one_writecache_setting(cmd, settings, key, val, block_size_sectors))
-+				return_0;
-+		}
-+	}
-+
-+	if (settings->high_watermark_set && settings->low_watermark_set &&
-+	    (settings->high_watermark <= settings->low_watermark)) {
-+		log_error("High watermark must be greater than low watermark.");
-+		return 0;
-+	}
-+
-+	return 1;
-+}
- 
- /* FIXME move to lib */
- static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
-diff --git a/tools/toollib.h b/tools/toollib.h
-index 53a5e5b..f3a60fb 100644
---- a/tools/toollib.h
-+++ b/tools/toollib.h
-@@ -217,6 +217,9 @@ int get_cache_params(struct cmd_context *cmd,
- 		     const char **name,
- 		     struct dm_config_tree **settings);
- 
-+int get_writecache_settings(struct cmd_context *cmd, struct writecache_settings *settings,
-+                            uint32_t *block_size_sectors);
-+
- int change_tag(struct cmd_context *cmd, struct volume_group *vg,
- 	       struct logical_volume *lv, struct physical_volume *pv, int arg);
- 
-diff --git a/tools/tools.h b/tools/tools.h
-index 7f2434d..c3d780d 100644
---- a/tools/tools.h
-+++ b/tools/tools.h
-@@ -278,7 +278,18 @@ int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **arg
- 
- int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
- 
-+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv);
-+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
-+
- int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
- int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
- 
-+
-+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
-+                                        struct logical_volume *lv,
-+                                        struct processing_handle *handle);
-+int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
-+                                     struct logical_volume *lv,
-+                                     struct processing_handle *handle);
-+
- #endif
--- 
-1.8.3.1
-
diff --git a/SOURCES/0004-Revert-wipe_lv-changes.patch b/SOURCES/0004-Revert-wipe_lv-changes.patch
deleted file mode 100644
index 0dce48f..0000000
--- a/SOURCES/0004-Revert-wipe_lv-changes.patch
+++ /dev/null
@@ -1,422 +0,0 @@
-From 99b646d87469b5ca0e93fad6b77f51a00fbbd2b7 Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Wed, 12 Aug 2020 18:47:15 +0200
-Subject: [PATCH] Revert "debug: missing stacktrace"
-
-This reverts commit d0faad0db38fe733cae42d7df136d7ed4f7bcba6.
-
-Revert "raid: no wiping when zeroing raid metadata device"
-
-This reverts commit 9b9bf8786fb423a4430cc676301edadf2310098d.
-
-Revert "lvconvert: more support for yes conversion"
-
-This reverts commit b7f3667ce20b731bbda9b1d61df49abbcd1bd20e.
-
-Revert "wipe_lv: always zero at least 4K"
-
-This reverts commit fe78cd4082cb9af10580180d61898fcef93dc624.
-
-Revert "tests: check pool metadata are zeroed"
-
-This reverts commit 3f32f9811e01c8953d201c7c9b563561ad856130.
-
-Revert "tests: failure of zeroing fails command"
-
-This reverts commit 094d6f80ddb6d8a1c64977dfaae4073827063fe3.
-
-Revert "make: make generate"
-
-This reverts commit 88b92d4225b90db82047f3bac55d8059918e9c1b.
-
-Conflicts:
-	man/lvconvert.8_pregen
-
-Revert "pool: zero metadata"
-
-This reverts commit bc39d5bec6fea787a8d8d16fa484084b7d2a7c29.
-
-Conflicts:
-	WHATS_NEW
-
-Revert "wipe_lv: make error a fatal event"
-
-This reverts commit edbc5a62b26806e5c4de59b5292609e955303576.
-
-Conflicts:
-	WHATS_NEW
-
-build: make generate
----
- WHATS_NEW                               |  2 -
- conf/example.conf.in                    |  6 +--
- lib/config/config_settings.h            |  5 +--
- lib/config/defaults.h                   |  1 -
- lib/metadata/lv_manip.c                 | 78 ++++++++++++---------------------
- lib/metadata/metadata-exported.h        |  2 -
- lib/metadata/pool_manip.c               |  6 +--
- test/lib/aux.sh                         |  1 -
- test/shell/lvcreate-signature-wiping.sh |  7 ---
- test/shell/lvcreate-thin.sh             | 21 ---------
- tools/lvconvert.c                       | 12 ++---
- 11 files changed, 36 insertions(+), 105 deletions(-)
-
-diff --git a/WHATS_NEW b/WHATS_NEW
-index ac99e97..6a098b5 100644
---- a/WHATS_NEW
-+++ b/WHATS_NEW
-@@ -6,8 +6,6 @@ Version 2.03.10 -
-   warning.
-   Fix conversion to raid from striped lagging type.
-   Fix conversion to 'mirrored' mirror log with larger regionsize.
--  Zero pool metadata on allocation (disable with allocation/zero_metadata=0).
--  Failure in zeroing or wiping will fail command (bypass with -Zn, -Wn).
-   Fix running out of free buffers for async writing for larger writes.
-   Add integrity with raid capability.
-   Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
-diff --git a/conf/example.conf.in b/conf/example.conf.in
-index d5807e6..88858fc 100644
---- a/conf/example.conf.in
-+++ b/conf/example.conf.in
-@@ -489,7 +489,7 @@ allocation {
- 	# This configuration option does not have a default value defined.
- 
- 	# Configuration option allocation/thin_pool_metadata_require_separate_pvs.
--	# Thin pool metadata and data will always use different PVs.
-+	# Thin pool metdata and data will always use different PVs.
- 	thin_pool_metadata_require_separate_pvs = 0
- 
- 	# Configuration option allocation/thin_pool_zero.
-@@ -527,10 +527,6 @@ allocation {
- 	# This configuration option has an automatic default value.
- 	# thin_pool_chunk_size_policy = "generic"
- 
--	# Configuration option allocation/zero_metadata.
--	# Zero whole metadata area before use with thin or cache pool.
--	zero_metadata = 1
--
- 	# Configuration option allocation/thin_pool_chunk_size.
- 	# The minimal chunk size in KiB for thin pool volumes.
- 	# Larger chunk sizes may improve performance for plain thin volumes,
-diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
-index b38ca11..dce9705 100644
---- a/lib/config/config_settings.h
-+++ b/lib/config/config_settings.h
-@@ -626,7 +626,7 @@ cfg(allocation_cache_pool_max_chunks_CFG, "cache_pool_max_chunks", allocation_CF
- 	"Using cache pool with more chunks may degrade cache performance.\n")
- 
- cfg(allocation_thin_pool_metadata_require_separate_pvs_CFG, "thin_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 89), NULL, 0, NULL,
--	"Thin pool metadata and data will always use different PVs.\n")
-+	"Thin pool metdata and data will always use different PVs.\n")
- 
- cfg(allocation_thin_pool_zero_CFG, "thin_pool_zero", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_THIN_POOL_ZERO, vsn(2, 2, 99), NULL, 0, NULL,
- 	"Thin pool data chunks are zeroed before they are first used.\n"
-@@ -657,9 +657,6 @@ cfg(allocation_thin_pool_chunk_size_policy_CFG, "thin_pool_chunk_size_policy", a
- 	"    512KiB.\n"
- 	"#\n")
- 
--cfg(allocation_zero_metadata_CFG, "zero_metadata", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ZERO_METADATA, vsn(2, 3, 10), NULL, 0, NULL,
--	"Zero whole metadata area before use with thin or cache pool.\n")
--
- cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, vsn(2, 2, 99), 0, NULL,
- 	"The minimal chunk size in KiB for thin pool volumes.\n"
- 	"Larger chunk sizes may improve performance for plain thin volumes,\n"
-diff --git a/lib/config/defaults.h b/lib/config/defaults.h
-index 708a575..be4f5ff 100644
---- a/lib/config/defaults.h
-+++ b/lib/config/defaults.h
-@@ -129,7 +129,6 @@
- #define DEFAULT_THIN_POOL_DISCARDS "passdown"
- #define DEFAULT_THIN_POOL_ZERO 1
- #define DEFAULT_POOL_METADATA_SPARE 1 /* thin + cache */
--#define DEFAULT_ZERO_METADATA 1		/* thin + cache */
- 
- #ifdef CACHE_CHECK_NEEDS_CHECK
- #  define DEFAULT_CACHE_CHECK_OPTION1 "-q"
-diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
-index f0ba3f0..1642b90 100644
---- a/lib/metadata/lv_manip.c
-+++ b/lib/metadata/lv_manip.c
-@@ -7576,22 +7576,20 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
- 	struct device *dev;
- 	char name[PATH_MAX];
- 	uint64_t zero_sectors;
--	int zero_metadata = wp.is_metadata ?
--		find_config_tree_bool(lv->vg->cmd, allocation_zero_metadata_CFG, NULL) : 0;
- 
--	if (!wp.do_zero && !wp.do_wipe_signatures && !wp.is_metadata)
-+	if (!wp.do_zero && !wp.do_wipe_signatures)
- 		/* nothing to do */
- 		return 1;
- 
- 	if (!lv_is_active(lv)) {
--		log_error("Volume %s is not active locally (volume_list activation filter?).",
--			  display_lvname(lv));
-+		log_error("Volume \"%s/%s\" is not active locally (volume_list activation filter?).",
-+			  lv->vg->name, lv->name);
- 		return 0;
- 	}
- 
- 	/* Wait until devices are available */
- 	if (!sync_local_dev_names(lv->vg->cmd)) {
--		log_error("Failed to sync local devices before wiping volume %s.",
-+		log_error("Failed to sync local devices before wiping LV %s.",
- 			  display_lvname(lv));
- 		return 0;
- 	}
-@@ -7615,59 +7613,40 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
- 	}
- 
- 	if (!label_scan_open_rw(dev)) {
--		log_error("Failed to open %s for wiping and zeroing.", display_lvname(lv));
--		return 0;
-+		log_error("Failed to open %s/%s for wiping and zeroing.", lv->vg->name, lv->name);
-+		goto out;
- 	}
- 
- 	if (wp.do_wipe_signatures) {
--		log_verbose("Wiping known signatures on logical volume %s.",
--			    display_lvname(lv));
-+		log_verbose("Wiping known signatures on logical volume \"%s/%s\"",
-+			    lv->vg->name, lv->name);
- 		if (!wipe_known_signatures(lv->vg->cmd, dev, name, 0,
- 					   TYPE_DM_SNAPSHOT_COW,
--					   wp.yes, wp.force, NULL)) {
--			log_error("Filed to wipe signatures of logical volume %s.",
--				  display_lvname(lv));
--			return 0;
--		}
-+					   wp.yes, wp.force, NULL))
-+			stack;
- 	}
- 
--	if (wp.do_zero || wp.is_metadata) {
--		zero_metadata = !wp.is_metadata ? 0 :
--			find_config_tree_bool(lv->vg->cmd, allocation_zero_metadata_CFG, NULL);
--		if (zero_metadata) {
--			log_debug("Metadata logical volume %s will be fully zeroed.",
--				  display_lvname(lv));
--			zero_sectors = lv->size;
--		} else {
--			if (wp.is_metadata) /* Verbosely notify metadata will not be fully zeroed */
--				log_verbose("Metadata logical volume %s not fully zeroed and may contain stale data.",
--					    display_lvname(lv));
--			zero_sectors = UINT64_C(4096) >> SECTOR_SHIFT;
--			if (wp.zero_sectors > zero_sectors)
--				zero_sectors = wp.zero_sectors;
-+	if (wp.do_zero) {
-+		zero_sectors = wp.zero_sectors ? : UINT64_C(4096) >> SECTOR_SHIFT;
- 
--			if (zero_sectors > lv->size)
--				zero_sectors = lv->size;
--		}
-+		if (zero_sectors > lv->size)
-+			zero_sectors = lv->size;
- 
--		log_verbose("Initializing %s of logical volume %s with value %d.",
-+		log_verbose("Initializing %s of logical volume \"%s/%s\" with value %d.",
- 			    display_size(lv->vg->cmd, zero_sectors),
--			    display_lvname(lv), wp.zero_value);
--
--		if ((!wp.is_metadata &&
--		     wp.zero_value && !dev_set_bytes(dev, UINT64_C(0),
--						     (size_t) zero_sectors << SECTOR_SHIFT,
--						     (uint8_t)wp.zero_value)) ||
--		    !dev_write_zeros(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT)) {
--			log_error("Failed to initialize %s of logical volume %s with value %d.",
--				  display_size(lv->vg->cmd, zero_sectors),
--				  display_lvname(lv), wp.zero_value);
--			return 0;
-+			    lv->vg->name, lv->name, wp.zero_value);
-+
-+		if (!wp.zero_value) {
-+			if (!dev_write_zeros(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT))
-+				stack;
-+		} else {
-+			if (!dev_set_bytes(dev, UINT64_C(0), (size_t) zero_sectors << SECTOR_SHIFT, (uint8_t)wp.zero_value))
-+				stack;
- 		}
- 	}
- 
- 	label_scan_invalidate(dev);
--
-+out:
- 	lv->status &= ~LV_NOSCAN;
- 
- 	return 1;
-@@ -7731,10 +7710,12 @@ int activate_and_wipe_lvlist(struct dm_list *lv_list, int commit)
- 		}
- 
- 	dm_list_iterate_items(lvl, lv_list) {
-+		log_verbose("Wiping metadata area %s.", display_lvname(lvl->lv));
- 		/* Wipe any know signatures */
--		if (!wipe_lv(lvl->lv, (struct wipe_params) { .do_zero = 1 /* TODO: is_metadata = 1 */ })) {
-+		if (!wipe_lv(lvl->lv, (struct wipe_params) { .do_wipe_signatures = 1, .do_zero = 1, .zero_sectors = 1 })) {
-+			log_error("Failed to wipe %s.", display_lvname(lvl->lv));
- 			r = 0;
--			goto_out;
-+			goto out;
- 		}
- 	}
- out:
-@@ -8479,8 +8460,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
- 				     .do_zero = lp->zero,
- 				     .do_wipe_signatures = lp->wipe_signatures,
- 				     .yes = lp->yes,
--				     .force = lp->force,
--				     .is_metadata = lp->is_metadata,
-+				     .force = lp->force
- 			     })) {
- 			log_error("Aborting. Failed to wipe %s.", lp->snapshot
- 				  ? "snapshot exception store" : "start of new LV");
-diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
-index 06ea757..0cc5f37 100644
---- a/lib/metadata/metadata-exported.h
-+++ b/lib/metadata/metadata-exported.h
-@@ -803,7 +803,6 @@ struct wipe_params {
- 	int do_wipe_signatures;	/* should we wipe known signatures found on LV? */
- 	int yes;		/* answer yes automatically to all questions */
- 	force_t force;		/* force mode */
--	int is_metadata;	/* wipe volume is metadata LV */
- };
- 
- /* Zero out LV and/or wipe signatures */
-@@ -956,7 +955,6 @@ struct lvcreate_params {
- 	unsigned suppress_zero_warn : 1;
- 	unsigned needs_lockd_init : 1;
- 	unsigned ignore_type : 1;
--	unsigned is_metadata : 1; /* created LV will be used as metadata LV (and can be zeroed) */
- 
- 	const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
- 	const char *lv_name; /* all */
-diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
-index 23b5b63..bed51f1 100644
---- a/lib/metadata/pool_manip.c
-+++ b/lib/metadata/pool_manip.c
-@@ -545,8 +545,8 @@ int create_pool(struct logical_volume *pool_lv,
- 				  display_lvname(pool_lv));
- 			goto bad;
- 		}
--		/* Clear pool metadata device. */
--		if (!(r = wipe_lv(pool_lv, (struct wipe_params) { .is_metadata = 1 }))) {
-+		/* Clear 4KB of pool metadata device. */
-+		if (!(r = wipe_lv(pool_lv, (struct wipe_params) { .do_zero = 1 }))) {
- 			log_error("Aborting. Failed to wipe pool metadata %s.",
- 				  display_lvname(pool_lv));
- 		}
-@@ -627,7 +627,6 @@ struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv,
- 		.tags = DM_LIST_HEAD_INIT(lvc.tags),
- 		.temporary = 1,
- 		.zero = 1,
--		.is_metadata = 1,
- 	};
- 
- 	if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
-@@ -664,7 +663,6 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
- 		.tags = DM_LIST_HEAD_INIT(lp.tags),
- 		.temporary = 1,
- 		.zero = 1,
--		.is_metadata = 1,
- 	};
- 
- 	if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
-diff --git a/test/lib/aux.sh b/test/lib/aux.sh
-index 17e7935..e40da95 100644
---- a/test/lib/aux.sh
-+++ b/test/lib/aux.sh
-@@ -1234,7 +1234,6 @@ activation/verify_udev_operations = $LVM_VERIFY_UDEV
- activation/raid_region_size = 512
- allocation/wipe_signatures_when_zeroing_new_lvs = 0
- allocation/vdo_slab_size_mb = 128
--allocation/zero_metadata = 0
- backup/archive = 0
- backup/backup = 0
- devices/cache_dir = "$TESTDIR/etc"
-diff --git a/test/shell/lvcreate-signature-wiping.sh b/test/shell/lvcreate-signature-wiping.sh
-index 18d7a2f..73fea54 100644
---- a/test/shell/lvcreate-signature-wiping.sh
-+++ b/test/shell/lvcreate-signature-wiping.sh
-@@ -42,13 +42,6 @@ init_lv_
- test_blkid_ || skip
- lvremove -f $vg/$lv1
- 
--# Zeroing stops the command when there is a failure (write error in this case)
--aux error_dev "$dev1" "$(get first_extent_sector "$dev1"):2"
--not lvcreate -l1 -n $lv1 $vg 2>&1 | tee out
--grep "Failed to initialize" out
--aux enable_dev "$dev1"
--
--
- aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 0"
- 
- lvcreate -y -Zn -l1 -n $lv1 $vg 2>&1 | tee out
-diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh
-index c073eaf..9ca7f11 100644
---- a/test/shell/lvcreate-thin.sh
-+++ b/test/shell/lvcreate-thin.sh
-@@ -248,25 +248,4 @@ not lvcreate -s $vg/lv1 -L4M -V2G --name $vg/lv4
- not lvcreate -T mirpool -L4M --alloc anywhere -m1 $vg
- not lvcreate --thinpool mirpool -L4M --alloc anywhere -m1 $vg
- 
--
--# Check pool metadata volume is zeroed, when zero_metadata is enabled.
--# 1st. ensure 8megs of both PVs will have some non-0 data
--lvcreate -L8m -n $lv1 $vg "$dev1"
--lvextend -L+8m $vg/$lv1 "$dev2"
--dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=16 oflag=direct conv=fdatasync
--lvremove -ff $vg/$lv1
--
--lvcreate -l1 --poolmetadatasize 4m --conf 'allocation/zero_metadata=1' -vvvv -T $vg/pool
--lvchange -an $vg
--# component activation to check device was zeroed
--lvchange -y -ay $vg/pool_tmeta
--dd if="$DM_DEV_DIR/$vg/pool_tmeta" of=file bs=1M count=3 skip=1 iflag=direct conv=fdatasync
--
--md5sum -b file | tee out
--# md5sum of 3M of zeros
--grep d1dd210d6b1312cb342b56d02bd5e651 out
--lvchange -an $vg
--lvremove -ff $vg
--
--
- vgremove -ff $vg
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index 524ed5a..6324ed7 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -3286,11 +3286,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
- 			}
- 			metadata_lv->status &= ~LV_ACTIVATION_SKIP;
- 
--			if (!wipe_lv(metadata_lv, (struct wipe_params) {
--						  .do_wipe_signatures = 1,
--						  .is_metadata = 1,
--						  .yes = arg_count(cmd, yes_ARG),
--						  .force = arg_count(cmd, force_ARG) } )) {
-+			if (!wipe_lv(metadata_lv, (struct wipe_params) { .do_zero = 1 })) {
- 				log_error("Aborting. Failed to wipe metadata lv.");
- 				goto bad;
- 			}
-@@ -5527,8 +5523,7 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
- 	struct wipe_params wp = {
- 		.do_wipe_signatures = 1, /* optional, to print warning if clobbering something */
- 		.do_zero = 1,            /* required for dm-writecache to work */
--		.yes = arg_count(cmd, yes_ARG),
--		.force = arg_count(cmd, force_ARG)
-+		.zero_sectors = 1
- 	};
- 	int ret;
- 
-@@ -5545,8 +5540,7 @@ static int _writecache_zero(struct cmd_context *cmd, struct logical_volume *lv)
- 		return 0;
- 	}
- 
--	if (!(ret = wipe_lv(lv, wp)))
--		stack;
-+	ret = wipe_lv(lv, wp);
- 
- 	if (!deactivate_lv(cmd, lv)) {
- 		log_error("Failed to deactivate LV %s for zeroing.", display_lvname(lv));
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-Allow-dm-integrity-to-be-used-for-raid-images.patch b/SOURCES/lvm2-2_03_10-Allow-dm-integrity-to-be-used-for-raid-images.patch
deleted file mode 100644
index d8dcd03..0000000
--- a/SOURCES/lvm2-2_03_10-Allow-dm-integrity-to-be-used-for-raid-images.patch
+++ /dev/null
@@ -1,5052 +0,0 @@
-From d51fc23f967acdf8534cdda63aa9aea0f44f9d0c Mon Sep 17 00:00:00 2001
-From: David Teigland <teigland@redhat.com>
-Date: Wed, 20 Nov 2019 16:07:27 -0600
-Subject: [PATCH 2/3] Allow dm-integrity to be used for raid images
-
-dm-integrity stores checksums of the data written to an
-LV, and returns an error if data read from the LV does
-not match the previously saved checksum.  When used on
-raid images, dm-raid will correct the error by reading
-the block from another image, and the device user sees
-no error.  The integrity metadata (checksums) are stored
-on an internal LV allocated by lvm for each linear image.
-The internal LV is allocated on the same PV as the image.
-
-Create a raid LV with an integrity layer over each
-raid image (for raid levels 1,4,5,6,10):
-
-lvcreate --type raidN --raidintegrity y [options]
-
-Add an integrity layer to images of an existing raid LV:
-
-lvconvert --raidintegrity y LV
-
-Remove the integrity layer from images of a raid LV:
-
-lvconvert --raidintegrity n LV
-
-Settings
-
-Use --raidintegritymode journal|bitmap (journal is default)
-to configure the method used by dm-integrity to ensure
-crash consistency.
-
-Initialization
-
-When integrity is added to an LV, the kernel needs to
-initialize the integrity metadata/checksums for all blocks
-in the LV.  The data corruption checking performed by
-dm-integrity will only operate on areas of the LV that
-are already initialized.  The progress of integrity
-initialization is reported by the "syncpercent" LV
-reporting field (and under the Cpy%Sync lvs column.)
-
-Example: create a raid1 LV with integrity:
-
-$ lvcreate --type raid1 -m1 --raidintegrity y -n rr -L1G foo
-  Creating integrity metadata LV rr_rimage_0_imeta with size 12.00 MiB.
-  Logical volume "rr_rimage_0_imeta" created.
-  Creating integrity metadata LV rr_rimage_1_imeta with size 12.00 MiB.
-  Logical volume "rr_rimage_1_imeta" created.
-  Logical volume "rr" created.
-$ lvs -a foo
-  LV                  VG  Attr       LSize  Origin              Cpy%Sync
-  rr                  foo rwi-a-r---  1.00g                     4.93
-  [rr_rimage_0]       foo gwi-aor---  1.00g [rr_rimage_0_iorig] 41.02
-  [rr_rimage_0_imeta] foo ewi-ao---- 12.00m
-  [rr_rimage_0_iorig] foo -wi-ao----  1.00g
-  [rr_rimage_1]       foo gwi-aor---  1.00g [rr_rimage_1_iorig] 39.45
-  [rr_rimage_1_imeta] foo ewi-ao---- 12.00m
-  [rr_rimage_1_iorig] foo -wi-ao----  1.00g
-  [rr_rmeta_0]        foo ewi-aor---  4.00m
-  [rr_rmeta_1]        foo ewi-aor---  4.00m
-
-(cherry picked from commit d9e8895a96539d75166c0f74e58f5ed4e729e551)
----
- configure                           |  27 ++
- configure.ac                        |  18 +
- device_mapper/all.h                 |  39 ++
- device_mapper/ioctl/libdm-iface.c   |  31 +-
- device_mapper/ioctl/libdm-targets.h |   1 +
- device_mapper/libdm-deptree.c       | 154 ++++++-
- device_mapper/libdm-targets.c       |  27 ++
- include/configure.h.in              |   3 +
- lib/Makefile.in                     |   2 +
- lib/activate/activate.c             |   7 +
- lib/activate/activate.h             |   4 +
- lib/activate/dev_manager.c          |  18 +-
- lib/commands/toolcontext.c          |   5 +
- lib/device/dev-type.c               |  39 ++
- lib/device/dev-type.h               |   2 +
- lib/format_text/flags.c             |   2 +
- lib/integrity/integrity.c           | 343 +++++++++++++++
- lib/metadata/integrity_manip.c      | 821 ++++++++++++++++++++++++++++++++++++
- lib/metadata/lv.c                   |  18 +-
- lib/metadata/lv_manip.c             | 150 ++++++-
- lib/metadata/merge.c                |   2 +
- lib/metadata/metadata-exported.h    |  26 ++
- lib/metadata/raid_manip.c           |  85 +++-
- lib/metadata/segtype.h              |   6 +
- lib/metadata/snapshot_manip.c       |   2 +
- lib/misc/lvm-string.c               |   4 +-
- lib/report/report.c                 |   2 +-
- man/lvmraid.7_main                  |  83 ++++
- test/lib/aux.sh                     |   8 +
- test/shell/integrity-blocksize.sh   | 183 ++++++++
- test/shell/integrity-dmeventd.sh    | 289 +++++++++++++
- test/shell/integrity-large.sh       | 175 ++++++++
- test/shell/integrity-misc.sh        | 228 ++++++++++
- test/shell/integrity.sh             | 735 ++++++++++++++++++++++++++++++++
- tools/args.h                        |  20 +
- tools/command-lines.in              |  45 +-
- tools/lv_props.h                    |   1 +
- tools/lv_types.h                    |   1 +
- tools/lvchange.c                    |   5 +
- tools/lvconvert.c                   | 137 ++++++
- tools/lvcreate.c                    |  15 +-
- tools/lvmcmdline.c                  |   3 +
- tools/pvmove.c                      |  10 +
- tools/toollib.c                     |  47 +++
- tools/tools.h                       |   4 +
- 45 files changed, 3790 insertions(+), 37 deletions(-)
- create mode 100644 lib/integrity/integrity.c
- create mode 100644 lib/metadata/integrity_manip.c
- create mode 100644 test/shell/integrity-blocksize.sh
- create mode 100644 test/shell/integrity-dmeventd.sh
- create mode 100644 test/shell/integrity-large.sh
- create mode 100644 test/shell/integrity-misc.sh
- create mode 100644 test/shell/integrity.sh
-
-diff --git a/configure b/configure
-index 6dd7eda..716ee9c 100755
---- a/configure
-+++ b/configure
-@@ -918,6 +918,7 @@ enable_cache_check_needs_check
- with_vdo
- with_vdo_format
- with_writecache
-+with_integrity
- enable_readline
- enable_realtime
- enable_ocf
-@@ -1716,6 +1717,7 @@ Optional Packages:
-   --with-vdo=TYPE         vdo support: internal/none [internal]
-   --with-vdo-format=PATH  vdoformat tool: [autodetect]
-   --with-writecache=TYPE  writecache support: internal/none [none]
-+  --with-integrity=TYPE   integrity support: internal/none [none]
-   --with-ocfdir=DIR       install OCF files in
-                           [PREFIX/lib/ocf/resource.d/lvm2]
-   --with-default-pid-dir=PID_DIR
-@@ -9762,6 +9764,31 @@ $as_echo "#define WRITECACHE_INTERNAL 1" >>confdefs.h
- esac
- 
- ################################################################################
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include integrity" >&5
-+$as_echo_n "checking whether to include integrity... " >&6; }
-+
-+# Check whether --with-integrity was given.
-+if test "${with_integrity+set}" = set; then :
-+  withval=$with_integrity; INTEGRITY=$withval
-+else
-+  INTEGRITY="none"
-+fi
-+
-+
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INTEGRITY" >&5
-+$as_echo "$INTEGRITY" >&6; }
-+
-+case "$INTEGRITY" in
-+ none) ;;
-+ internal)
-+
-+$as_echo "#define INTEGRITY_INTERNAL 1" >>confdefs.h
-+
-+	;;
-+ *) as_fn_error $? "--with-integrity parameter invalid" "$LINENO" 5 ;;
-+esac
-+
-+################################################################################
- # Check whether --enable-readline was given.
- if test "${enable_readline+set}" = set; then :
-   enableval=$enable_readline; READLINE=$enableval
-diff --git a/configure.ac b/configure.ac
-index 74ca201..9a0e41a 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -668,6 +668,24 @@ case "$WRITECACHE" in
- esac
- 
- ################################################################################
-+dnl -- integrity inclusion type
-+AC_MSG_CHECKING(whether to include integrity)
-+AC_ARG_WITH(integrity,
-+	    AC_HELP_STRING([--with-integrity=TYPE],
-+			   [integrity support: internal/none [none]]),
-+			   INTEGRITY=$withval, INTEGRITY="none")
-+
-+AC_MSG_RESULT($INTEGRITY)
-+
-+case "$INTEGRITY" in
-+ none) ;;
-+ internal)
-+	AC_DEFINE([INTEGRITY_INTERNAL], 1, [Define to 1 to include built-in support for integrity.])
-+	;;
-+ *) AC_MSG_ERROR([--with-integrity parameter invalid]) ;;
-+esac
-+
-+################################################################################
- dnl -- Disable readline
- AC_ARG_ENABLE([readline],
- 	      AC_HELP_STRING([--disable-readline], [disable readline support]),
-diff --git a/device_mapper/all.h b/device_mapper/all.h
-index b23485f..f00b6a5 100644
---- a/device_mapper/all.h
-+++ b/device_mapper/all.h
-@@ -234,6 +234,7 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt);
- int dm_task_secure_data(struct dm_task *dmt);
- int dm_task_retry_remove(struct dm_task *dmt);
- int dm_task_deferred_remove(struct dm_task *dmt);
-+void dm_task_skip_reload_params_compare(struct dm_task *dmt);
- 
- /*
-  * Record timestamp immediately after the ioctl returns.
-@@ -392,6 +393,15 @@ struct dm_status_writecache {
- int dm_get_status_writecache(struct dm_pool *mem, const char *params,
-                              struct dm_status_writecache **status);
- 
-+struct dm_status_integrity {
-+	uint64_t number_of_mismatches;
-+	uint64_t provided_data_sectors;
-+	uint64_t recalc_sector;
-+};
-+
-+int dm_get_status_integrity(struct dm_pool *mem, const char *params,
-+                            struct dm_status_integrity **status);
-+
- /*
-  * Parse params from STATUS call for snapshot target
-  *
-@@ -970,6 +980,35 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
- 				uint32_t writecache_block_size,
- 				struct writecache_settings *settings);
- 
-+struct integrity_settings {
-+	char mode[8];
-+	uint32_t tag_size;
-+	uint32_t block_size;       /* optional table param always set by lvm */
-+	const char *internal_hash; /* optional table param always set by lvm */
-+
-+	uint32_t journal_sectors;
-+	uint32_t interleave_sectors;
-+	uint32_t buffer_sectors;
-+	uint32_t journal_watermark;
-+	uint32_t commit_time;
-+	uint32_t bitmap_flush_interval;
-+	uint64_t sectors_per_bit;
-+
-+	unsigned journal_sectors_set:1;
-+	unsigned interleave_sectors_set:1;
-+	unsigned buffer_sectors_set:1;
-+	unsigned journal_watermark_set:1;
-+	unsigned commit_time_set:1;
-+	unsigned bitmap_flush_interval_set:1;
-+	unsigned sectors_per_bit_set:1;
-+};
-+
-+int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
-+				uint64_t size,
-+				const char *origin_uuid,
-+				const char *meta_uuid,
-+				struct integrity_settings *settings,
-+				int recalculate);
- 
- /*
-  * VDO target
-diff --git a/device_mapper/ioctl/libdm-iface.c b/device_mapper/ioctl/libdm-iface.c
-index fe04af8..25e7d1a 100644
---- a/device_mapper/ioctl/libdm-iface.c
-+++ b/device_mapper/ioctl/libdm-iface.c
-@@ -805,6 +805,11 @@ int dm_task_suppress_identical_reload(struct dm_task *dmt)
- 	return 1;
- }
- 
-+void dm_task_skip_reload_params_compare(struct dm_task *dmt)
-+{
-+	dmt->skip_reload_params_compare = 1;
-+}
-+
- int dm_task_set_add_node(struct dm_task *dmt, dm_add_node_t add_node)
- {
- 	switch (add_node) {
-@@ -1575,11 +1580,29 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
- 		len = strlen(t2->params);
- 		while (len-- > 0 && t2->params[len] == ' ')
- 			t2->params[len] = '\0';
--		if ((t1->start != t2->start) ||
--		    (t1->length != t2->length) ||
--		    (strcmp(t1->type, t2->type)) ||
--		    (strcmp(t1->params, t2->params)))
-+
-+		if (t1->start != t2->start) {
-+			log_debug("reload %u:%u start diff", task->major, task->minor);
-+			goto no_match;
-+		}
-+		if (t1->length != t2->length) {
-+			log_debug("reload %u:%u length diff", task->major, task->minor);
- 			goto no_match;
-+		}
-+		if (strcmp(t1->type, t2->type)) {
-+			log_debug("reload %u:%u type diff %s %s", task->major, task->minor, t1->type, t2->type);
-+			goto no_match;
-+		}
-+		if (strcmp(t1->params, t2->params)) {
-+			if (dmt->skip_reload_params_compare)
-+				log_debug("reload %u:%u skip params ignore %s %s",
-+					  task->major, task->minor, t1->params, t2->params);
-+			else {
-+				log_debug("reload %u:%u params diff", task->major, task->minor);
-+				goto no_match;
-+			}
-+		}
-+
- 		t1 = t1->next;
- 		t2 = t2->next;
- 	}
-diff --git a/device_mapper/ioctl/libdm-targets.h b/device_mapper/ioctl/libdm-targets.h
-index b5b20d5..9786a7e 100644
---- a/device_mapper/ioctl/libdm-targets.h
-+++ b/device_mapper/ioctl/libdm-targets.h
-@@ -59,6 +59,7 @@ struct dm_task {
- 	int skip_lockfs;
- 	int query_inactive_table;
- 	int suppress_identical_reload;
-+	int skip_reload_params_compare;
- 	dm_add_node_t add_node;
- 	uint64_t existing_table_size;
- 	int cookie_set;
-diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
-index 7fac6ab..9ba24cb 100644
---- a/device_mapper/libdm-deptree.c
-+++ b/device_mapper/libdm-deptree.c
-@@ -38,6 +38,7 @@ enum {
- 	SEG_STRIPED,
- 	SEG_ZERO,
- 	SEG_WRITECACHE,
-+	SEG_INTEGRITY,
- 	SEG_THIN_POOL,
- 	SEG_THIN,
- 	SEG_VDO,
-@@ -78,6 +79,7 @@ static const struct {
- 	{ SEG_STRIPED, "striped" },
- 	{ SEG_ZERO, "zero"},
- 	{ SEG_WRITECACHE, "writecache"},
-+	{ SEG_INTEGRITY, "integrity"},
- 	{ SEG_THIN_POOL, "thin-pool"},
- 	{ SEG_THIN, "thin"},
- 	{ SEG_VDO, "vdo" },
-@@ -221,6 +223,11 @@ struct load_segment {
- 	int writecache_pmem;				/* writecache, 1 if pmem, 0 if ssd */
- 	uint32_t writecache_block_size;			/* writecache, in bytes */
- 	struct writecache_settings writecache_settings;	/* writecache */
-+
-+	uint64_t integrity_data_sectors;		/* integrity (provided_data_sectors) */
-+	struct dm_tree_node *integrity_meta_node;	/* integrity */
-+	struct integrity_settings integrity_settings;	/* integrity */
-+	int integrity_recalculate;			/* integrity */
- };
- 
- /* Per-device properties */
-@@ -268,6 +275,16 @@ struct load_properties {
- 	unsigned delay_resume_if_extended;
- 
- 	/*
-+	 * When comparing table lines to decide if a reload is
-+	 * needed, ignore any differences betwen the lvm device
-+	 * params and the kernel-reported device params.
-+	 * dm-integrity reports many internal parameters on the
-+	 * table line when lvm does not explicitly set them,
-+	 * causing lvm and the kernel to have differing params.
-+	 */
-+	unsigned skip_reload_params_compare;
-+
-+	/*
- 	 * Call node_send_messages(), set to 2 if there are messages
- 	 * When != 0, it validates matching transaction id, thus thin-pools
- 	 * where transation_id is passed as 0 are never validated, this
-@@ -2705,6 +2722,84 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
- 	return 1;
- }
- 
-+static int _integrity_emit_segment_line(struct dm_task *dmt,
-+				    struct load_segment *seg,
-+				    char *params, size_t paramsize)
-+{
-+	struct integrity_settings *set = &seg->integrity_settings;
-+	int pos = 0;
-+	int count;
-+	char origin_dev[DM_FORMAT_DEV_BUFSIZE];
-+	char meta_dev[DM_FORMAT_DEV_BUFSIZE];
-+
-+	if (!_build_dev_string(origin_dev, sizeof(origin_dev), seg->origin))
-+		return_0;
-+
-+	if (seg->integrity_meta_node &&
-+	    !_build_dev_string(meta_dev, sizeof(meta_dev), seg->integrity_meta_node))
-+		return_0;
-+
-+	count = 3; /* block_size, internal_hash, fix_padding options are always passed */
-+
-+	if (seg->integrity_meta_node)
-+		count++;
-+
-+	if (seg->integrity_recalculate)
-+		count++;
-+
-+	if (set->journal_sectors_set)
-+		count++;
-+	if (set->interleave_sectors_set)
-+		count++;
-+	if (set->buffer_sectors_set)
-+		count++;
-+	if (set->journal_watermark_set)
-+		count++;
-+	if (set->commit_time_set)
-+		count++;
-+	if (set->bitmap_flush_interval_set)
-+		count++;
-+	if (set->sectors_per_bit_set)
-+		count++;
-+
-+	EMIT_PARAMS(pos, "%s 0 %u %s %d fix_padding block_size:%u internal_hash:%s",
-+		    origin_dev,
-+		    set->tag_size,
-+		    set->mode,
-+		    count,
-+		    set->block_size,
-+		    set->internal_hash);
-+
-+	if (seg->integrity_meta_node)
-+		EMIT_PARAMS(pos, " meta_device:%s", meta_dev);
-+
-+	if (seg->integrity_recalculate)
-+		EMIT_PARAMS(pos, " recalculate");
-+
-+	if (set->journal_sectors_set)
-+		EMIT_PARAMS(pos, " journal_sectors:%u", set->journal_sectors);
-+
-+	if (set->interleave_sectors_set)
-+		EMIT_PARAMS(pos, " ineterleave_sectors:%u", set->interleave_sectors);
-+
-+	if (set->buffer_sectors_set)
-+		EMIT_PARAMS(pos, " buffer_sectors:%u", set->buffer_sectors);
-+
-+	if (set->journal_watermark_set)
-+		EMIT_PARAMS(pos, " journal_watermark:%u", set->journal_watermark);
-+
-+	if (set->commit_time_set)
-+		EMIT_PARAMS(pos, " commit_time:%u", set->commit_time);
-+
-+	if (set->bitmap_flush_interval_set)
-+		EMIT_PARAMS(pos, " bitmap_flush_interval:%u", set->bitmap_flush_interval);
-+
-+	if (set->sectors_per_bit_set)
-+		EMIT_PARAMS(pos, " sectors_per_bit:%llu", (unsigned long long)set->sectors_per_bit);
-+
-+	return 1;
-+}
-+
- static int _thin_pool_emit_segment_line(struct dm_task *dmt,
- 					struct load_segment *seg,
- 					char *params, size_t paramsize)
-@@ -2889,6 +2984,10 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
- 		if (!_writecache_emit_segment_line(dmt, seg, params, paramsize))
- 			return_0;
- 		break;
-+	case SEG_INTEGRITY:
-+		if (!_integrity_emit_segment_line(dmt, seg, params, paramsize))
-+			return_0;
-+		break;
- 	}
- 
- 	switch(seg->type) {
-@@ -2901,6 +3000,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
- 	case SEG_THIN:
- 	case SEG_CACHE:
- 	case SEG_WRITECACHE:
-+	case SEG_INTEGRITY:
- 		break;
- 	case SEG_CRYPT:
- 	case SEG_LINEAR:
-@@ -3005,6 +3105,9 @@ static int _load_node(struct dm_tree_node *dnode)
- 	if (!dm_task_suppress_identical_reload(dmt))
- 		log_warn("WARNING: Failed to suppress reload of identical tables.");
- 
-+	if (dnode->props.skip_reload_params_compare)
-+		dm_task_skip_reload_params_compare(dmt);
-+
- 	if ((r = dm_task_run(dmt))) {
- 		r = dm_task_get_info(dmt, &dnode->info);
- 		if (r && !dnode->info.inactive_table)
-@@ -3023,8 +3126,8 @@ static int _load_node(struct dm_tree_node *dnode)
- 			if (!existing_table_size && dnode->props.delay_resume_if_new)
- 				dnode->props.size_changed = 0;
- 
--			log_debug_activation("Table size changed from %" PRIu64 " to %"
--					     PRIu64 " for %s.%s", existing_table_size,
-+			log_debug_activation("Table size changed from %" PRIu64 " to %" PRIu64 " for %s.%s",
-+					     existing_table_size,
- 					     seg_start, _node_name(dnode),
- 					     dnode->props.size_changed ? "" : " (Ignoring.)");
- 
-@@ -3136,7 +3239,10 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
- 		}
- 
- 		/* No resume for a device without parents or with unchanged or smaller size */
--		if (!dm_tree_node_num_children(child, 1) || (child->props.size_changed <= 0))
-+		if (!dm_tree_node_num_children(child, 1))
-+			continue;
-+
-+		if (child->props.size_changed <= 0)
- 			continue;
- 
- 		if (!child->info.inactive_table && !child->info.suspended)
-@@ -3738,6 +3844,48 @@ int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
- 	return 1;
- }
- 
-+int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
-+				  uint64_t size,
-+				  const char *origin_uuid,
-+				  const char *meta_uuid,
-+				  struct integrity_settings *settings,
-+				  int recalculate)
-+{
-+	struct load_segment *seg;
-+
-+	if (!(seg = _add_segment(node, SEG_INTEGRITY, size)))
-+		return_0;
-+
-+	if (!meta_uuid) {
-+		log_error("No integrity meta uuid.");
-+		return 0;
-+	}
-+
-+	if (!(seg->integrity_meta_node = dm_tree_find_node_by_uuid(node->dtree, meta_uuid))) {
-+		log_error("Missing integrity's meta uuid %s.", meta_uuid);
-+		return 0;
-+	}
-+
-+	if (!_link_tree_nodes(node, seg->integrity_meta_node))
-+		return_0;
-+
-+	if (!(seg->origin = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
-+		log_error("Missing integrity's origin uuid %s.", origin_uuid);
-+		return 0;
-+	}
-+
-+	if (!_link_tree_nodes(node, seg->origin))
-+		return_0;
-+
-+	memcpy(&seg->integrity_settings, settings, sizeof(struct integrity_settings));
-+
-+	seg->integrity_recalculate = recalculate;
-+
-+	node->props.skip_reload_params_compare = 1;
-+
-+	return 1;
-+}
-+
- int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
- 				       uint64_t size,
- 				       const char *rlog_uuid,
-diff --git a/device_mapper/libdm-targets.c b/device_mapper/libdm-targets.c
-index 86cb847..bfe76c5 100644
---- a/device_mapper/libdm-targets.c
-+++ b/device_mapper/libdm-targets.c
-@@ -380,6 +380,33 @@ int dm_get_status_writecache(struct dm_pool *mem, const char *params,
- 	return 1;
- }
- 
-+int dm_get_status_integrity(struct dm_pool *mem, const char *params,
-+			     struct dm_status_integrity **status)
-+{
-+	struct dm_status_integrity *s;
-+	char recalc_str[16] = "\0";
-+
-+	if (!(s = dm_pool_zalloc(mem, sizeof(*s))))
-+		return_0;
-+
-+	if (sscanf(params, "%llu %llu %s",
-+		   (unsigned long long *)&s->number_of_mismatches,
-+		   (unsigned long long *)&s->provided_data_sectors,
-+		   recalc_str) != 3) {
-+		log_error("Failed to parse integrity params: %s.", params);
-+		dm_pool_free(mem, s);
-+		return 0;
-+	}
-+
-+	if (recalc_str[0] == '-')
-+		s->recalc_sector = 0;
-+	else
-+		s->recalc_sector = strtoull(recalc_str, NULL, 0);
-+
-+	*status = s;
-+	return 1;
-+}
-+
- int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
- {
- 	int pos;
-diff --git a/include/configure.h.in b/include/configure.h.in
-index 91a3a7d..57736cc 100644
---- a/include/configure.h.in
-+++ b/include/configure.h.in
-@@ -678,6 +678,9 @@
- /* Define to 1 to include built-in support for writecache. */
- #undef WRITECACHE_INTERNAL
- 
-+/* Define to 1 to include built-in support for integrity. */
-+#undef INTEGRITY_INTERNAL
-+
- /* Define to get access to GNU/Linux extension */
- #undef _GNU_SOURCE
- 
-diff --git a/lib/Makefile.in b/lib/Makefile.in
-index 2a064f3..8e50ec4 100644
---- a/lib/Makefile.in
-+++ b/lib/Makefile.in
-@@ -20,6 +20,7 @@ SOURCES =\
- 	activate/activate.c \
- 	cache/lvmcache.c \
- 	writecache/writecache.c \
-+	integrity/integrity.c \
- 	cache_segtype/cache.c \
- 	commands/toolcontext.c \
- 	config/config.c \
-@@ -67,6 +68,7 @@ SOURCES =\
- 	log/log.c \
- 	metadata/cache_manip.c \
- 	metadata/writecache_manip.c \
-+	metadata/integrity_manip.c \
- 	metadata/lv.c \
- 	metadata/lv_manip.c \
- 	metadata/merge.c \
-diff --git a/lib/activate/activate.c b/lib/activate/activate.c
-index a82a5cb..22c4e63 100644
---- a/lib/activate/activate.c
-+++ b/lib/activate/activate.c
-@@ -2535,6 +2535,13 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
- 		goto out;
- 	}
- 
-+	if ((cmd->partial_activation || cmd->degraded_activation) &&
-+	    lv_is_partial(lv) && lv_is_raid(lv) && lv_raid_has_integrity((struct logical_volume *)lv)) {
-+		cmd->partial_activation = 0;
-+		cmd->degraded_activation = 0;
-+		log_print("No degraded or partial activation for raid with integrity.");
-+	}
-+
- 	if ((!lv->vg->cmd->partial_activation) && lv_is_partial(lv)) {
- 		if (!lv_is_raid_type(lv) || !partial_raid_lv_supports_degraded_activation(lv)) {
- 			log_error("Refusing activation of partial LV %s.  "
-diff --git a/lib/activate/activate.h b/lib/activate/activate.h
-index a5ee438..e3c1bb3 100644
---- a/lib/activate/activate.h
-+++ b/lib/activate/activate.h
-@@ -39,6 +39,7 @@ typedef enum {
- 	SEG_STATUS_THIN_POOL,
- 	SEG_STATUS_VDO_POOL,
- 	SEG_STATUS_WRITECACHE,
-+	SEG_STATUS_INTEGRITY,
- 	SEG_STATUS_UNKNOWN
- } lv_seg_status_type_t;
- 
-@@ -53,6 +54,7 @@ struct lv_seg_status {
- 		struct dm_status_thin *thin;
- 		struct dm_status_thin_pool *thin_pool;
- 		struct dm_status_writecache *writecache;
-+		struct dm_status_integrity *integrity;
- 		struct lv_status_vdo vdo_pool;
- 	};
- };
-@@ -260,6 +262,7 @@ void fs_unlock(void);
- 
- #define TARGET_NAME_CACHE "cache"
- #define TARGET_NAME_WRITECACHE "writecache"
-+#define TARGET_NAME_INTEGRITY "integrity"
- #define TARGET_NAME_ERROR "error"
- #define TARGET_NAME_ERROR_OLD "erro"	/* Truncated in older kernels */
- #define TARGET_NAME_LINEAR "linear"
-@@ -277,6 +280,7 @@ void fs_unlock(void);
- #define MODULE_NAME_CLUSTERED_MIRROR "clog"
- #define MODULE_NAME_CACHE TARGET_NAME_CACHE
- #define MODULE_NAME_WRITECACHE TARGET_NAME_WRITECACHE
-+#define MODULE_NAME_INTEGRITY TARGET_NAME_INTEGRITY
- #define MODULE_NAME_ERROR TARGET_NAME_ERROR
- #define MODULE_NAME_LOG_CLUSTERED "log-clustered"
- #define MODULE_NAME_LOG_USERSPACE "log-userspace"
-diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
-index 75d4df0..a626b00 100644
---- a/lib/activate/dev_manager.c
-+++ b/lib/activate/dev_manager.c
-@@ -46,7 +46,7 @@ typedef enum {
- } action_t;
- 
- /* This list must match lib/misc/lvm-string.c:build_dm_uuid(). */
--const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", NULL};
-+const char *uuid_suffix_list[] = { "pool", "cdata", "cmeta", "cvol", "tdata", "tmeta", "vdata", "vpool", "imeta", NULL};
- 
- struct dlid_list {
- 	struct dm_list list;
-@@ -222,6 +222,10 @@ static int _get_segment_status_from_target_params(const char *target_name,
- 		if (!dm_get_status_writecache(seg_status->mem, params, &(seg_status->writecache)))
- 			return_0;
- 		seg_status->type = SEG_STATUS_WRITECACHE;
-+	} else if (segtype_is_integrity(segtype)) {
-+		if (!dm_get_status_integrity(seg_status->mem, params, &(seg_status->integrity)))
-+			return_0;
-+		seg_status->type = SEG_STATUS_INTEGRITY;
- 	} else
- 		/*
- 		 * TODO: Add support for other segment types too!
-@@ -299,6 +303,9 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
- 		if (lv_is_vdo_pool(seg_status->seg->lv))
- 			length = get_vdo_pool_virtual_size(seg_status->seg);
- 
-+		if (lv_is_integrity(seg_status->seg->lv))
-+			length = seg_status->seg->integrity_data_sectors;
-+
- 		do {
- 			target = dm_get_next_target(dmt, target, &target_start,
- 						    &target_length, &target_name, &target_params);
-@@ -2620,6 +2627,10 @@ static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
- 			if (!_add_lv_to_dtree(dm, dtree, seg->writecache, dm->activation ? origin_only : 1))
- 				return_0;
- 		}
-+		if (seg->integrity_meta_dev && seg_is_integrity(seg)) {
-+			if (!_add_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, dm->activation ? origin_only : 1))
-+				return_0;
-+		}
- 		if (seg->pool_lv &&
- 		    (lv_is_cache_pool(seg->pool_lv) || lv_is_cache_vol(seg->pool_lv) || dm->track_external_lv_deps) &&
- 		    /* When activating and not origin_only detect linear 'overlay' over pool */
-@@ -3076,6 +3087,11 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
- 				  lv_layer(seg->writecache)))
- 		return_0;
- 
-+	if (seg->integrity_meta_dev && !laopts->origin_only &&
-+	    !_add_new_lv_to_dtree(dm, dtree, seg->integrity_meta_dev, laopts,
-+				  lv_layer(seg->integrity_meta_dev)))
-+		return_0;
-+
- 	/* Add any LVs used by this segment */
- 	for (s = 0; s < seg->area_count; ++s) {
- 		if ((seg_type(seg, s) == AREA_LV) &&
-diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
-index 479d499..88d5b3e 100644
---- a/lib/commands/toolcontext.c
-+++ b/lib/commands/toolcontext.c
-@@ -1362,6 +1362,11 @@ static int _init_segtypes(struct cmd_context *cmd)
- 		return 0;
- #endif
- 
-+#ifdef INTEGRITY_INTERNAL
-+	if (!init_integrity_segtypes(cmd, &seglib))
-+		return 0;
-+#endif
-+
- 	return 1;
- }
- 
-diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
-index d225d4d..deb5d6a 100644
---- a/lib/device/dev-type.c
-+++ b/lib/device/dev-type.c
-@@ -647,6 +647,45 @@ out:
- }
- 
- #ifdef BLKID_WIPING_SUPPORT
-+int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
-+{
-+	blkid_probe probe = NULL;
-+	const char *block_size_str = NULL;
-+	uint64_t block_size_val;
-+	int r = 0;
-+
-+	*fs_block_size = 0;
-+
-+	if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
-+		log_error("Failed to create a new blkid probe for device %s.", dev_name(dev));
-+		goto out;
-+	}
-+
-+	blkid_probe_enable_partitions(probe, 1);
-+
-+	(void) blkid_probe_lookup_value(probe, "BLOCK_SIZE", &block_size_str, NULL);
-+
-+	if (!block_size_str)
-+		goto out;
-+
-+	block_size_val = strtoull(block_size_str, NULL, 10);
-+
-+	*fs_block_size = (uint32_t)block_size_val;
-+	r = 1;
-+out:
-+	if (probe)
-+		blkid_free_probe(probe);
-+	return r;
-+}
-+#else
-+int get_fs_block_size(struct device *dev, uint32_t *fs_block_size)
-+{
-+	*fs_block_size = 0;
-+	return 0;
-+}
-+#endif
-+
-+#ifdef BLKID_WIPING_SUPPORT
- 
- static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
- {
-diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
-index e090050..fdf7791 100644
---- a/lib/device/dev-type.h
-+++ b/lib/device/dev-type.h
-@@ -97,4 +97,6 @@ int dev_is_pmem(struct device *dev);
- 
- int dev_is_lv(struct device *dev);
- 
-+int get_fs_block_size(struct device *dev, uint32_t *fs_block_size);
-+
- #endif
-diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
-index 2873ba6..bc93a5d 100644
---- a/lib/format_text/flags.c
-+++ b/lib/format_text/flags.c
-@@ -104,6 +104,8 @@ static const struct flag _lv_flags[] = {
- 	{LV_VDO_POOL, NULL, 0},
- 	{LV_VDO_POOL_DATA, NULL, 0},
- 	{WRITECACHE, NULL, 0},
-+	{INTEGRITY, NULL, 0},
-+	{INTEGRITY_METADATA, NULL, 0},
- 	{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
- 	{LV_REMOVED, NULL, 0},
- 	{0, NULL, 0}
-diff --git a/lib/integrity/integrity.c b/lib/integrity/integrity.c
-new file mode 100644
-index 0000000..d5ad86b
---- /dev/null
-+++ b/lib/integrity/integrity.c
-@@ -0,0 +1,343 @@
-+/*
-+ * Copyright (C) 2013-2016 Red Hat, Inc. All rights reserved.
-+ *
-+ * This file is part of LVM2.
-+ *
-+ * This copyrighted material is made available to anyone wishing to use,
-+ * modify, copy, or redistribute it subject to the terms and conditions
-+ * of the GNU Lesser General Public License v.2.1.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "base/memory/zalloc.h"
-+#include "lib/misc/lib.h"
-+#include "lib/commands/toolcontext.h"
-+#include "lib/metadata/segtype.h"
-+#include "lib/display/display.h"
-+#include "lib/format_text/text_export.h"
-+#include "lib/config/config.h"
-+#include "lib/datastruct/str_list.h"
-+#include "lib/misc/lvm-string.h"
-+#include "lib/activate/activate.h"
-+#include "lib/metadata/metadata.h"
-+#include "lib/metadata/lv_alloc.h"
-+#include "lib/config/defaults.h"
-+
-+#define SEG_LOG_ERROR(t, p...) \
-+        log_error(t " segment %s of logical volume %s.", ## p,	\
-+                  dm_config_parent_name(sn), seg->lv->name), 0;
-+
-+static void _integrity_display(const struct lv_segment *seg)
-+{
-+	/* TODO: lvdisplay segments */
-+}
-+
-+static int _integrity_text_import(struct lv_segment *seg,
-+				   const struct dm_config_node *sn,
-+				   struct dm_hash_table *pv_hash __attribute__((unused)))
-+{
-+	struct integrity_settings *set;
-+	struct logical_volume *origin_lv = NULL;
-+	struct logical_volume *meta_lv = NULL;
-+	const char *origin_name = NULL;
-+	const char *meta_dev = NULL;
-+	const char *mode = NULL;
-+	const char *hash = NULL;
-+
-+	memset(&seg->integrity_settings, 0, sizeof(struct integrity_settings));
-+	set = &seg->integrity_settings;
-+
-+	/* origin always set */
-+
-+	if (!dm_config_has_node(sn, "origin"))
-+		return SEG_LOG_ERROR("origin not specified in");
-+
-+	if (!dm_config_get_str(sn, "origin", &origin_name))
-+		return SEG_LOG_ERROR("origin must be a string in");
-+
-+	if (!(origin_lv = find_lv(seg->lv->vg, origin_name)))
-+		return SEG_LOG_ERROR("Unknown LV specified for integrity origin %s in", origin_name);
-+
-+	if (!set_lv_segment_area_lv(seg, 0, origin_lv, 0, 0))
-+		return_0;
-+
-+	/* data_sectors always set */
-+
-+	if (!dm_config_get_uint64(sn, "data_sectors", &seg->integrity_data_sectors))
-+		return SEG_LOG_ERROR("integrity data_sectors must be set in");
-+
-+	/* mode always set */
-+
-+	if (!dm_config_get_str(sn, "mode", &mode))
-+		return SEG_LOG_ERROR("integrity mode must be set in");
-+
-+	if (strlen(mode) > 7)
-+		return SEG_LOG_ERROR("integrity mode invalid in");
-+
-+	strncpy(set->mode, mode, 7);
-+
-+	/* tag_size always set */
-+
-+	if (!dm_config_get_uint32(sn, "tag_size", &set->tag_size))
-+		return SEG_LOG_ERROR("integrity tag_size must be set in");
-+
-+	/* block_size always set */
-+
-+	if (!dm_config_get_uint32(sn, "block_size", &set->block_size))
-+		return SEG_LOG_ERROR("integrity block_size invalid in");
-+
-+	/* internal_hash always set */
-+
-+	if (!dm_config_get_str(sn, "internal_hash", &hash))
-+		return SEG_LOG_ERROR("integrity internal_hash must be set in");
-+
-+	if (!(set->internal_hash = dm_pool_strdup(seg->lv->vg->vgmem, hash)))
-+		return SEG_LOG_ERROR("integrity internal_hash failed to be set in");
-+
-+	/* meta_dev optional */
-+
-+	if (dm_config_has_node(sn, "meta_dev")) {
-+		if (!dm_config_get_str(sn, "meta_dev", &meta_dev))
-+			return SEG_LOG_ERROR("meta_dev must be a string in");
-+
-+		if (!(meta_lv = find_lv(seg->lv->vg, meta_dev)))
-+			return SEG_LOG_ERROR("Unknown logical volume %s specified for integrity in", meta_dev);
-+	}
-+
-+	if (dm_config_has_node(sn, "recalculate")) {
-+		if (!dm_config_get_uint32(sn, "recalculate", &seg->integrity_recalculate))
-+			return SEG_LOG_ERROR("integrity recalculate error in");
-+	}
-+
-+	/* the rest are optional */
-+
-+	if (dm_config_has_node(sn, "journal_sectors")) {
-+		if (!dm_config_get_uint32(sn, "journal_sectors", &set->journal_sectors))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->journal_sectors_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "interleave_sectors")) {
-+		if (!dm_config_get_uint32(sn, "interleave_sectors", &set->interleave_sectors))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->interleave_sectors_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "buffer_sectors")) {
-+		if (!dm_config_get_uint32(sn, "buffer_sectors", &set->buffer_sectors))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->buffer_sectors_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "journal_watermark")) {
-+		if (!dm_config_get_uint32(sn, "journal_watermark", &set->journal_watermark))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->journal_watermark_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "commit_time")) {
-+		if (!dm_config_get_uint32(sn, "commit_time", &set->commit_time))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->commit_time_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "bitmap_flush_interval")) {
-+		if (!dm_config_get_uint32(sn, "bitmap_flush_interval", &set->bitmap_flush_interval))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->bitmap_flush_interval_set = 1;
-+	}
-+
-+	if (dm_config_has_node(sn, "sectors_per_bit")) {
-+		if (!dm_config_get_uint64(sn, "sectors_per_bit", &set->sectors_per_bit))
-+			return SEG_LOG_ERROR("Unknown integrity_setting in");
-+		set->sectors_per_bit_set = 1;
-+	}
-+
-+	seg->origin = origin_lv;
-+	seg->integrity_meta_dev = meta_lv;
-+	seg->lv->status |= INTEGRITY;
-+
-+	if (meta_lv)
-+		meta_lv->status |= INTEGRITY_METADATA;
-+
-+	if (meta_lv && !add_seg_to_segs_using_this_lv(meta_lv, seg))
-+		return_0;
-+
-+	return 1;
-+}
-+
-+static int _integrity_text_import_area_count(const struct dm_config_node *sn,
-+					      uint32_t *area_count)
-+{
-+	*area_count = 1;
-+
-+	return 1;
-+}
-+
-+static int _integrity_text_export(const struct lv_segment *seg,
-+				   struct formatter *f)
-+{
-+	const struct integrity_settings *set = &seg->integrity_settings;
-+
-+	outf(f, "origin = \"%s\"", seg_lv(seg, 0)->name);
-+	outf(f, "data_sectors = %llu", (unsigned long long)seg->integrity_data_sectors);
-+
-+	outf(f, "mode = \"%s\"", set->mode);
-+	outf(f, "tag_size = %u", set->tag_size);
-+	outf(f, "block_size = %u", set->block_size);
-+	outf(f, "internal_hash = \"%s\"", set->internal_hash);
-+
-+	if (seg->integrity_meta_dev)
-+		outf(f, "meta_dev = \"%s\"", seg->integrity_meta_dev->name);
-+
-+	if (seg->integrity_recalculate)
-+		outf(f, "recalculate = %u", seg->integrity_recalculate);
-+
-+	if (set->journal_sectors_set)
-+		outf(f, "journal_sectors = %u", set->journal_sectors);
-+
-+	if (set->interleave_sectors_set)
-+		outf(f, "interleave_sectors = %u", set->interleave_sectors);
-+
-+	if (set->buffer_sectors_set)
-+		outf(f, "buffer_sectors = %u", set->buffer_sectors);
-+
-+	if (set->journal_watermark_set)
-+		outf(f, "journal_watermark = %u", set->journal_watermark);
-+
-+	if (set->commit_time_set)
-+		outf(f, "commit_time = %u", set->commit_time);
-+
-+	if (set->bitmap_flush_interval)
-+		outf(f, "bitmap_flush_interval = %u", set->bitmap_flush_interval);
-+
-+	if (set->sectors_per_bit)
-+		outf(f, "sectors_per_bit = %llu", (unsigned long long)set->sectors_per_bit);
-+
-+	return 1;
-+}
-+
-+static void _destroy(struct segment_type *segtype)
-+{
-+	free((void *) segtype);
-+}
-+
-+#ifdef DEVMAPPER_SUPPORT
-+
-+static int _target_present(struct cmd_context *cmd,
-+			   const struct lv_segment *seg __attribute__((unused)),
-+			   unsigned *attributes __attribute__((unused)))
-+{
-+	static int _integrity_checked = 0;
-+	static int _integrity_present = 0;
-+	uint32_t maj, min, patchlevel;
-+
-+	if (!activation())
-+		return 0;
-+
-+	if (!_integrity_checked) {
-+		_integrity_checked = 1;
-+		_integrity_present =  target_present(cmd, TARGET_NAME_INTEGRITY, 1);
-+
-+		if (!target_version(TARGET_NAME_INTEGRITY, &maj, &min, &patchlevel))
-+			return 0;
-+
-+		if (maj < 1 || min < 6) {
-+			log_error("Integrity target version older than minimum 1.6.0");
-+			return 0;
-+		}
-+	}
-+
-+	return _integrity_present;
-+}
-+
-+static int _modules_needed(struct dm_pool *mem,
-+			   const struct lv_segment *seg __attribute__((unused)),
-+			   struct dm_list *modules)
-+{
-+	if (!str_list_add(mem, modules, MODULE_NAME_INTEGRITY)) {
-+		log_error("String list allocation failed for integrity module.");
-+		return 0;
-+	}
-+
-+	return 1;
-+}
-+#endif /* DEVMAPPER_SUPPORT */
-+
-+#ifdef DEVMAPPER_SUPPORT
-+static int _integrity_add_target_line(struct dev_manager *dm,
-+				 struct dm_pool *mem,
-+				 struct cmd_context *cmd __attribute__((unused)),
-+				 void **target_state __attribute__((unused)),
-+				 struct lv_segment *seg,
-+				 const struct lv_activate_opts *laopts,
-+				 struct dm_tree_node *node, uint64_t len,
-+				 uint32_t *pvmove_mirror_count __attribute__((unused)))
-+{
-+	char *origin_uuid;
-+	char *meta_uuid = NULL;
-+
-+	if (!seg_is_integrity(seg)) {
-+		log_error(INTERNAL_ERROR "Passed segment is not integrity.");
-+		return 0;
-+	}
-+
-+	if (!(origin_uuid = build_dm_uuid(mem, seg_lv(seg, 0), NULL)))
-+		return_0;
-+
-+	if (seg->integrity_meta_dev) {
-+		if (!(meta_uuid = build_dm_uuid(mem, seg->integrity_meta_dev, NULL)))
-+			return_0;
-+	}
-+
-+	if (!seg->integrity_data_sectors) {
-+		log_error("_integrity_add_target_line zero size");
-+		return_0;
-+	}
-+
-+	if (!dm_tree_node_add_integrity_target(node, seg->integrity_data_sectors,
-+					       origin_uuid, meta_uuid,
-+					       &seg->integrity_settings,
-+					       seg->integrity_recalculate))
-+		return_0;
-+
-+	return 1;
-+}
-+#endif /* DEVMAPPER_SUPPORT */
-+
-+static struct segtype_handler _integrity_ops = {
-+	.display = _integrity_display,
-+	.text_import = _integrity_text_import,
-+	.text_import_area_count = _integrity_text_import_area_count,
-+	.text_export = _integrity_text_export,
-+#ifdef DEVMAPPER_SUPPORT
-+	.add_target_line = _integrity_add_target_line,
-+	.target_present = _target_present,
-+	.modules_needed = _modules_needed,
-+#endif
-+	.destroy = _destroy,
-+};
-+
-+int init_integrity_segtypes(struct cmd_context *cmd,
-+			struct segtype_library *seglib)
-+{
-+	struct segment_type *segtype = zalloc(sizeof(*segtype));
-+
-+	if (!segtype) {
-+		log_error("Failed to allocate memory for integrity segtype");
-+		return 0;
-+	}
-+
-+	segtype->name = SEG_TYPE_NAME_INTEGRITY;
-+	segtype->flags = SEG_INTEGRITY;
-+	segtype->ops = &_integrity_ops;
-+
-+	if (!lvm_register_segtype(seglib, segtype))
-+		return_0;
-+	log_very_verbose("Initialised segtype: %s", segtype->name);
-+
-+	return 1;
-+}
-diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c
-new file mode 100644
-index 0000000..7942be0
---- /dev/null
-+++ b/lib/metadata/integrity_manip.c
-@@ -0,0 +1,821 @@
-+/*
-+ * Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
-+ *
-+ * This file is part of LVM2.
-+ *
-+ * This copyrighted material is made available to anyone wishing to use,
-+ * modify, copy, or redistribute it subject to the terms and conditions
-+ * of the GNU Lesser General Public License v.2.1.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "lib/misc/lib.h"
-+#include "lib/metadata/metadata.h"
-+#include "lib/locking/locking.h"
-+#include "lib/misc/lvm-string.h"
-+#include "lib/commands/toolcontext.h"
-+#include "lib/display/display.h"
-+#include "lib/metadata/segtype.h"
-+#include "lib/activate/activate.h"
-+#include "lib/config/defaults.h"
-+#include "lib/activate/dev_manager.h"
-+
-+#define DEFAULT_TAG_SIZE 4 /* bytes */
-+#define DEFAULT_MODE 'J'
-+#define DEFAULT_INTERNAL_HASH "crc32c"
-+#define DEFAULT_BLOCK_SIZE 512
-+
-+#define ONE_MB_IN_BYTES 1048576
-+
-+int lv_is_integrity_origin(const struct logical_volume *lv)
-+{
-+	struct seg_list *sl;
-+
-+	dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
-+		if (!sl->seg || !sl->seg->lv || !sl->seg->origin)
-+			continue;
-+		if (lv_is_integrity(sl->seg->lv) && (sl->seg->origin == lv))
-+			return 1;
-+	}
-+	return 0;
-+}
-+
-+/*
-+ * Every 500M of data needs 4M of metadata.
-+ * (From trial and error testing.)
-+ */
-+static uint64_t _lv_size_bytes_to_integrity_meta_bytes(uint64_t lv_size_bytes)
-+{
-+	return ((lv_size_bytes / (500 * ONE_MB_IN_BYTES)) + 1) * (4 * ONE_MB_IN_BYTES);
-+}
-+
-+/*
-+ * The user wants external metadata, but did not specify an existing
-+ * LV to hold metadata, so create an LV for metadata.
-+ */
-+static int _lv_create_integrity_metadata(struct cmd_context *cmd,
-+				struct volume_group *vg,
-+				struct lvcreate_params *lp,
-+				struct logical_volume **meta_lv)
-+{
-+	char metaname[NAME_LEN];
-+	uint64_t lv_size_bytes, meta_bytes, meta_sectors;
-+	struct logical_volume *lv;
-+	struct lvcreate_params lp_meta = {
-+		.activate = CHANGE_AN,
-+		.alloc = ALLOC_INHERIT,
-+		.major = -1,
-+		.minor = -1,
-+		.permission = LVM_READ | LVM_WRITE,
-+		.pvh = &vg->pvs,
-+		.read_ahead = DM_READ_AHEAD_NONE,
-+		.stripes = 1,
-+		.vg_name = vg->name,
-+		.zero = 0,
-+		.wipe_signatures = 0,
-+		.suppress_zero_warn = 1,
-+	};
-+
-+	if (lp->lv_name &&
-+	    dm_snprintf(metaname, NAME_LEN, "%s_imeta", lp->lv_name) < 0) {
-+		log_error("Failed to create metadata LV name.");
-+		return 0;
-+	}
-+
-+	lp_meta.lv_name = metaname;
-+	lp_meta.pvh = lp->pvh;
-+
-+	lv_size_bytes = (uint64_t)lp->extents * (uint64_t)vg->extent_size * 512;
-+	meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
-+	meta_sectors = meta_bytes / 512;
-+	lp_meta.extents = meta_sectors / vg->extent_size;
-+
-+	log_print_unless_silent("Creating integrity metadata LV %s with size %s.",
-+		  metaname, display_size(cmd, meta_sectors));
-+
-+	dm_list_init(&lp_meta.tags);
-+
-+	if (!(lp_meta.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
-+		return_0;
-+
-+	if (!(lv = lv_create_single(vg, &lp_meta))) {
-+		log_error("Failed to create integrity metadata LV");
-+		return 0;
-+	}
-+
-+	if (dm_list_size(&lv->segments) > 1) {
-+		log_error("Integrity metadata uses more than one segment.");
-+		return 0;
-+	}
-+
-+	*meta_lv = lv;
-+	return 1;
-+}
-+
-+int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh)
-+{
-+	struct cmd_context *cmd = lv->vg->cmd;
-+	struct volume_group *vg = lv->vg;
-+	const struct segment_type *segtype;
-+	struct lv_segment *seg_top, *seg_image;
-+	struct logical_volume *lv_image;
-+	struct logical_volume *lv_iorig;
-+	struct logical_volume *lv_imeta;
-+	struct dm_list allocatable_pvs;
-+	struct dm_list *use_pvh;
-+	uint64_t lv_size_bytes, meta_bytes, meta_sectors, prev_meta_sectors;
-+	uint32_t meta_extents, prev_meta_extents;
-+	uint32_t area_count, s;
-+
-+	seg_top = first_seg(lv);
-+		                
-+	if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
-+		return_0;
-+
-+	area_count = seg_top->area_count;
-+
-+	for (s = 0; s < area_count; s++) {
-+		lv_image = seg_lv(seg_top, s);
-+		seg_image = first_seg(lv_image);
-+
-+		if (!(lv_imeta = seg_image->integrity_meta_dev)) {
-+			log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
-+			return 0;
-+		}
-+
-+		if (!(lv_iorig = seg_lv(seg_image, 0))) {
-+			log_error("LV %s integrity segment has no origin", display_lvname(lv));
-+			return 0;
-+		}
-+
-+		lv_size_bytes = lv_iorig->size * 512;
-+		meta_bytes = _lv_size_bytes_to_integrity_meta_bytes(lv_size_bytes);
-+		meta_sectors = meta_bytes / 512;
-+		meta_extents = meta_sectors / vg->extent_size;
-+
-+		prev_meta_sectors = lv_imeta->size;
-+		prev_meta_extents = prev_meta_sectors / vg->extent_size;
-+
-+		if (meta_extents <= prev_meta_extents) {
-+			log_debug("extend not needed for imeta LV %s", lv_imeta->name);
-+			continue;
-+		}
-+
-+		/*
-+		 * We only allow lv_imeta to exist on a single PV (for now),
-+		 * so the allocatable_pvs is the one PV currently used by
-+		 * lv_imeta.
-+		 */
-+		dm_list_init(&allocatable_pvs);
-+
-+		if (!get_pv_list_for_lv(cmd->mem, lv_imeta, &allocatable_pvs)) {
-+			log_error("Failed to build list of PVs for extending %s.", display_lvname(lv_imeta));
-+			return 0;
-+		}
-+
-+		use_pvh = &allocatable_pvs;
-+
-+		if (!lv_extend(lv_imeta, segtype, 1, 0, 0, 0,
-+			       meta_extents - prev_meta_extents,
-+			       use_pvh, lv_imeta->alloc, 0)) {
-+			log_error("Failed to extend integrity metadata LV %s", lv_imeta->name);
-+			return 0;
-+		}
-+	}
-+
-+	return 1;
-+}
-+
-+int lv_remove_integrity_from_raid(struct logical_volume *lv)
-+{
-+	struct logical_volume *iorig_lvs[DEFAULT_RAID_MAX_IMAGES];
-+	struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
-+	struct cmd_context *cmd = lv->vg->cmd;
-+	struct volume_group *vg = lv->vg;
-+	struct lv_segment *seg_top, *seg_image;
-+	struct logical_volume *lv_image;
-+	struct logical_volume *lv_iorig;
-+	struct logical_volume *lv_imeta;
-+	uint32_t area_count, s;
-+	int is_active = lv_is_active(lv);
-+
-+	seg_top = first_seg(lv);
-+
-+	if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) &&
-+	    !seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) &&
-+	    !seg_is_any_raid10(seg_top)) {
-+		log_error("LV %s segment is unsupported raid for integrity.", display_lvname(lv));
-+		return 0;
-+	}
-+
-+	area_count = seg_top->area_count;
-+
-+	for (s = 0; s < area_count; s++) {
-+		lv_image = seg_lv(seg_top, s);
-+		seg_image = first_seg(lv_image);
-+
-+		if (!(lv_imeta = seg_image->integrity_meta_dev)) {
-+			log_error("LV %s segment has no integrity metadata device.", display_lvname(lv));
-+			return 0;
-+		}
-+
-+		if (!(lv_iorig = seg_lv(seg_image, 0))) {
-+			log_error("LV %s integrity segment has no origin", display_lvname(lv));
-+			return 0;
-+		}
-+
-+		if (!remove_seg_from_segs_using_this_lv(seg_image->integrity_meta_dev, seg_image))
-+			return_0;
-+
-+		iorig_lvs[s] = lv_iorig;
-+		imeta_lvs[s] = lv_imeta;
-+
-+		lv_image->status &= ~INTEGRITY;
-+		seg_image->integrity_meta_dev = NULL;
-+		seg_image->integrity_data_sectors = 0;
-+		memset(&seg_image->integrity_settings, 0, sizeof(seg_image->integrity_settings));
-+
-+		if (!remove_layer_from_lv(lv_image, lv_iorig))
-+			return_0;
-+	}
-+
-+	if (is_active) {
-+		/* vg_write(), suspend_lv(), vg_commit(), resume_lv() */
-+		if (!lv_update_and_reload(lv)) {
-+			log_error("Failed to update and reload LV after integrity remove.");
-+			return 0;
-+                }
-+	}
-+
-+	for (s = 0; s < area_count; s++) {
-+		lv_iorig = iorig_lvs[s];
-+		lv_imeta = imeta_lvs[s];
-+
-+		if (is_active) {
-+			if (!deactivate_lv(cmd, lv_iorig))
-+				log_error("Failed to deactivate unused iorig LV %s.", lv_iorig->name);
-+
-+			if (!deactivate_lv(cmd, lv_imeta))
-+				log_error("Failed to deactivate unused imeta LV %s.", lv_imeta->name);
-+		}
-+
-+		lv_imeta->status &= ~INTEGRITY_METADATA;
-+		lv_set_visible(lv_imeta);
-+
-+		if (!lv_remove(lv_iorig))
-+			log_error("Failed to remove unused iorig LV %s.", lv_iorig->name);
-+
-+		if (!lv_remove(lv_imeta))
-+			log_error("Failed to remove unused imeta LV %s.", lv_imeta->name);
-+	}
-+
-+	if (!vg_write(vg) || !vg_commit(vg))
-+		return_0;
-+
-+	return 1;
-+}
-+
-+static int _set_integrity_block_size(struct cmd_context *cmd, struct logical_volume *lv,
-+				     struct integrity_settings *settings,
-+				     int lbs_4k, int lbs_512, int pbs_4k, int pbs_512)
-+{
-+	char pathname[PATH_MAX];
-+	struct device *fs_dev;
-+	uint32_t fs_block_size = 0;
-+	int rv;
-+
-+	if (lbs_4k && lbs_512) {
-+		log_error("Integrity requires consistent logical block size for LV devices.");
-+		goto_bad;
-+	}
-+
-+	if (settings->block_size &&
-+	    (settings->block_size != 512 && settings->block_size != 1024 &&
-+	     settings->block_size != 2048 && settings->block_size != 4096)) {
-+		log_error("Invalid integrity block size, possible values are 512, 1024, 2048, 4096");
-+		goto_bad;
-+	}
-+
-+	if (lbs_4k && settings->block_size && (settings->block_size < 4096)) {
-+		log_error("Integrity block size %u not allowed with device logical block size 4096.",
-+			  settings->block_size);
-+		goto_bad;
-+	}
-+
-+	if (!strcmp(cmd->name, "lvcreate")) {
-+		if (lbs_4k) {
-+			settings->block_size = 4096;
-+		} else if (lbs_512 && pbs_4k && !pbs_512) {
-+			settings->block_size = 4096;
-+		} else if (lbs_512) {
-+			if (!settings->block_size)
-+				settings->block_size = 512;
-+		} else if (!lbs_4k && !lbs_512) {
-+			if (!settings->block_size)
-+				settings->block_size = 512;
-+			log_print("Using integrity block size %u with unknown device logical block size.",
-+				  settings->block_size);
-+		} else {
-+			goto_bad;
-+		}
-+
-+	} else if (!strcmp(cmd->name, "lvconvert")) {
-+		if (dm_snprintf(pathname, sizeof(pathname), "%s%s/%s", cmd->dev_dir,
-+				lv->vg->name, lv->name) < 0) {
-+			log_error("Path name too long to get LV block size %s", display_lvname(lv));
-+			goto_bad;
-+		}
-+		if (!(fs_dev = dev_cache_get(cmd, pathname, NULL))) {
-+			log_error("Device for LV not found to check block size %s", display_lvname(lv));
-+			goto_bad;
-+		}
-+
-+		/*
-+		 * get_fs_block_size() returns the libblkid BLOCK_SIZE value,
-+		 * where libblkid has fs-specific code to set BLOCK_SIZE to the
-+		 * value we need here.
-+		 *
-+		 * The term "block size" here may not equate directly to what the fs
-+		 * calls the block size, e.g. xfs calls this the sector size (and
-+		 * something different the block size); while ext4 does call this
-+		 * value the block size, but it's possible values are not the same
-+		 * as xfs's, and do not seem to relate directly to the device LBS.
-+		 */
-+		rv = get_fs_block_size(fs_dev, &fs_block_size);
-+		if (!rv || !fs_block_size) {
-+			int use_bs;
-+
-+			if (lbs_4k && pbs_4k) {
-+				use_bs = 4096;
-+			} else if (lbs_512 && pbs_512) {
-+				use_bs = 512;
-+			} else if (lbs_512 && pbs_4k) {
-+				if (settings->block_size == 4096)
-+					use_bs = 4096;
-+				else
-+					use_bs = 512;
-+			} else {
-+				use_bs = 512;
-+			}
-+
-+			if (settings->block_size && (settings->block_size != use_bs)) {
-+				log_error("Cannot use integrity block size %u with unknown file system block size, logical block size %u, physical block size %u.",
-+					   settings->block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
-+				goto bad;
-+			}
-+
-+			settings->block_size = use_bs;
-+
-+			log_print("Using integrity block size %u for unknown file system block size, logical block size %u, physical block size %u.",
-+				  settings->block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
-+			goto out;
-+		}
-+
-+		if (!settings->block_size) {
-+			if (fs_block_size <= 4096)
-+				settings->block_size = fs_block_size;
-+			else
-+				settings->block_size = 4096; /* dm-integrity max is 4096 */
-+			log_print("Using integrity block size %u for file system block size %u.",
-+				  settings->block_size, fs_block_size);
-+		} else {
-+			/* let user specify integrity block size that is less than fs block size */
-+			if (settings->block_size > fs_block_size) {
-+				log_error("Integrity block size %u cannot be larger than file system block size %u.",
-+					  settings->block_size, fs_block_size);
-+				goto_bad;
-+			}
-+			log_print("Using integrity block size %u for file system block size %u.",
-+				  settings->block_size, fs_block_size);
-+		}
-+	}
-+out:
-+	return 1;
-+bad:
-+	return 0;
-+}
-+
-+/*
-+ * Add integrity to each raid image.
-+ *
-+ * for each rimage_N:
-+ * . create and allocate a new linear LV rimage_N_imeta
-+ * . move the segments from rimage_N to a new rimage_N_iorig
-+ * . add an integrity segment to rimage_N with
-+ *   origin=rimage_N_iorig, meta_dev=rimage_N_imeta
-+ *
-+ * Before:
-+ * rimage_0
-+ *   segment1: striped: pv0:A
-+ * rimage_1
-+ *   segment1: striped: pv1:B
-+ *
-+ * After:
-+ * rimage_0
-+ *   segment1: integrity: rimage_0_iorig, rimage_0_imeta
-+ * rimage_1
-+ *   segment1: integrity: rimage_1_iorig, rimage_1_imeta
-+ * rimage_0_iorig
-+ *   segment1: striped: pv0:A
-+ * rimage_1_iorig
-+ *   segment1: striped: pv1:B
-+ * rimage_0_imeta
-+ *   segment1: striped: pv2:A
-+ * rimage_1_imeta
-+ *   segment1: striped: pv2:B
-+ *    
-+ */
-+
-+int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_settings *settings,
-+			     struct dm_list *pvh, struct logical_volume *lv_imeta_0)
-+{
-+	char imeta_name[NAME_LEN];
-+	char *imeta_name_dup;
-+	struct lvcreate_params lp;
-+	struct dm_list allocatable_pvs;
-+	struct logical_volume *imeta_lvs[DEFAULT_RAID_MAX_IMAGES];
-+	struct cmd_context *cmd = lv->vg->cmd;
-+	struct volume_group *vg = lv->vg;
-+	struct logical_volume *lv_image, *lv_imeta, *lv_iorig;
-+	struct lv_segment *seg_top, *seg_image;
-+	struct pv_list *pvl;
-+	const struct segment_type *segtype;
-+	struct integrity_settings *set = NULL;
-+	struct dm_list *use_pvh = NULL;
-+	uint32_t area_count, s;
-+	uint32_t revert_meta_lvs = 0;
-+	int lbs_4k = 0, lbs_512 = 0, lbs_unknown = 0;
-+	int pbs_4k = 0, pbs_512 = 0, pbs_unknown = 0;
-+	int is_active;
-+
-+	memset(imeta_lvs, 0, sizeof(imeta_lvs));
-+
-+	is_active = lv_is_active(lv);
-+
-+	if (dm_list_size(&lv->segments) != 1)
-+		return_0;
-+
-+	if (!dm_list_empty(&lv->segs_using_this_lv)) {
-+		log_error("Integrity can only be added to top level raid LV.");
-+		return 0;
-+	}
-+
-+	if (lv_is_origin(lv)) {
-+		log_error("Integrity cannot be added to snapshot origins.");
-+		return 0;
-+	}
-+
-+	seg_top = first_seg(lv);
-+	area_count = seg_top->area_count;
-+
-+	if (!seg_is_raid1(seg_top) && !seg_is_raid4(seg_top) &&
-+	    !seg_is_any_raid5(seg_top) && !seg_is_any_raid6(seg_top) &&
-+	    !seg_is_any_raid10(seg_top)) {
-+		log_error("Integrity can only be added to raid1,4,5,6,10.");
-+		return 0;
-+	}
-+
-+	/*
-+	 * For each rimage, create an _imeta LV for integrity metadata.
-+	 * Each needs to be zeroed.
-+	 */
-+	for (s = 0; s < area_count; s++) {
-+		struct logical_volume *meta_lv;
-+		struct wipe_params wipe = { .do_zero = 1, .zero_sectors = 8 };
-+
-+		if (s >= DEFAULT_RAID_MAX_IMAGES)
-+			goto_bad;
-+
-+		lv_image = seg_lv(seg_top, s);
-+
-+		/*
-+		 * This function is used to add integrity to new images added
-+		 * to the raid, in which case old images will already be
-+		 * integrity.
-+		 */
-+		if (seg_is_integrity(first_seg(lv_image)))
-+			continue;
-+
-+		if (!seg_is_striped(first_seg(lv_image))) {
-+			log_error("raid image must be linear to add integrity");
-+			goto_bad;
-+		}
-+
-+		/*
-+		 * Use an existing lv_imeta from previous linear+integrity LV.
-+		 * FIXME: is it guaranteed that lv_image_0 is the existing?
-+		 */
-+		if (!s && lv_imeta_0) {
-+			if (dm_snprintf(imeta_name, sizeof(imeta_name), "%s_imeta", lv_image->name) > 0) {
-+				if ((imeta_name_dup = dm_pool_strdup(vg->vgmem, imeta_name)))
-+					lv_imeta_0->name = imeta_name_dup;
-+			}
-+			imeta_lvs[0] = lv_imeta_0;
-+			continue;
-+		}
-+
-+		dm_list_init(&allocatable_pvs);
-+
-+		if (!get_pv_list_for_lv(cmd->mem, lv_image, &allocatable_pvs)) {
-+			log_error("Failed to build list of PVs for %s.", display_lvname(lv_image));
-+			goto_bad;
-+		}
-+
-+		dm_list_iterate_items(pvl, &allocatable_pvs) {
-+			unsigned int pbs = 0;
-+			unsigned int lbs = 0;
-+
-+			if (!dev_get_direct_block_sizes(pvl->pv->dev, &pbs, &lbs)) {
-+				lbs_unknown++;
-+				pbs_unknown++;
-+				continue;
-+			}
-+			if (lbs == 4096)
-+				lbs_4k++;
-+			else if (lbs == 512)
-+				lbs_512++;
-+			else
-+				lbs_unknown++;
-+			if (pbs == 4096)
-+				pbs_4k++;
-+			else if (pbs == 512)
-+				pbs_512++;
-+			else
-+				pbs_unknown++;
-+		}
-+
-+		use_pvh = &allocatable_pvs;
-+
-+		/*
-+		 * allocate a new linear LV NAME_rimage_N_imeta
-+		 */
-+		memset(&lp, 0, sizeof(lp));
-+		lp.lv_name = lv_image->name;
-+		lp.pvh = use_pvh;
-+		lp.extents = lv_image->size / vg->extent_size;
-+
-+		if (!_lv_create_integrity_metadata(cmd, vg, &lp, &meta_lv))
-+			goto_bad;
-+
-+		revert_meta_lvs++;
-+
-+		/* Used below to set up the new integrity segment. */
-+		imeta_lvs[s] = meta_lv;
-+
-+		/*
-+		 * dm-integrity requires the metadata LV header to be zeroed.
-+		 */
-+
-+		if (!activate_lv(cmd, meta_lv)) {
-+			log_error("Failed to activate LV %s to zero", display_lvname(meta_lv));
-+			goto_bad;
-+		}
-+
-+		if (!wipe_lv(meta_lv, wipe)) {
-+			log_error("Failed to zero LV for integrity metadata %s", display_lvname(meta_lv));
-+			if (deactivate_lv(cmd, meta_lv))
-+				log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
-+			goto_bad;
-+		}
-+
-+		if (!deactivate_lv(cmd, meta_lv)) {
-+			log_error("Failed to deactivate LV %s after zero", display_lvname(meta_lv));
-+			goto_bad;
-+		}
-+	}
-+
-+	/*
-+	 * Set settings->block_size which will be copied to segment settings below.
-+	 * integrity block size chosen based on device logical block size and
-+	 * file system block size.
-+	 */
-+	if (!_set_integrity_block_size(cmd, lv, settings, lbs_4k, lbs_512, pbs_4k, pbs_512))
-+		goto_bad;
-+
-+	/*
-+	 * For each rimage, move its segments to a new rimage_iorig and give
-+	 * the rimage a new integrity segment.
-+	 */
-+	for (s = 0; s < area_count; s++) {
-+		lv_image = seg_lv(seg_top, s);
-+
-+		/* Not adding integrity to this image. */
-+		if (!imeta_lvs[s])
-+			continue;
-+
-+		if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_INTEGRITY)))
-+			goto_bad;
-+
-+		log_debug("Adding integrity to raid image %s", lv_image->name);
-+
-+		/*
-+		 * "lv_iorig" is a new LV with new id, but with the segments
-+		 * from "lv_image". "lv_image" keeps the existing name and id,
-+		 * but gets a new integrity segment, in place of the segments
-+		 * that were moved to lv_iorig.
-+		 */
-+		if (!(lv_iorig = insert_layer_for_lv(cmd, lv_image, INTEGRITY, "_iorig")))
-+			goto_bad;
-+
-+		lv_image->status |= INTEGRITY;
-+
-+		/*
-+		 * Set up the new first segment of lv_image as integrity.
-+		 */
-+		seg_image = first_seg(lv_image);
-+		seg_image->segtype = segtype;
-+
-+		lv_imeta = imeta_lvs[s];
-+		lv_imeta->status |= INTEGRITY_METADATA;
-+		lv_set_hidden(lv_imeta);
-+		seg_image->integrity_data_sectors = lv_image->size;
-+		seg_image->integrity_meta_dev = lv_imeta;
-+		seg_image->integrity_recalculate = 1;
-+
-+		memcpy(&seg_image->integrity_settings, settings, sizeof(struct integrity_settings));
-+		set = &seg_image->integrity_settings;
-+
-+		if (!set->mode[0])
-+			set->mode[0] = DEFAULT_MODE;
-+
-+		if (!set->tag_size)
-+			set->tag_size = DEFAULT_TAG_SIZE;
-+
-+		if (!set->block_size)
-+			set->block_size = DEFAULT_BLOCK_SIZE;
-+
-+		if (!set->internal_hash)
-+			set->internal_hash = DEFAULT_INTERNAL_HASH;
-+	}
-+
-+	if (is_active) {
-+		log_debug("Writing VG and updating LV with new integrity LV %s", lv->name);
-+
-+		/* vg_write(), suspend_lv(), vg_commit(), resume_lv() */
-+		if (!lv_update_and_reload(lv)) {
-+			log_error("LV update and reload failed");
-+			goto_bad;
-+		}
-+		revert_meta_lvs = 0;
-+
-+	} else {
-+		log_debug("Writing VG with new integrity LV %s", lv->name);
-+
-+		if (!vg_write(vg) || !vg_commit(vg))
-+			goto_bad;
-+
-+		revert_meta_lvs = 0;
-+
-+		/*
-+		 * This first activation includes "recalculate" which starts the
-+		 * kernel's recalculating (initialization) process.
-+		 */
-+
-+		log_debug("Activating to start integrity initialization for LV %s", lv->name);
-+
-+		if (!activate_lv(cmd, lv)) {
-+			log_error("Failed to activate integrity LV to initialize.");
-+			goto_bad;
-+		}
-+	}
-+
-+	/*
-+	 * Now that the device is being initialized, update the VG to clear
-+	 * integrity_recalculate so that subsequent activations will not
-+	 * include "recalculate" and restart initialization.
-+	 */
-+
-+	log_debug("Writing VG with initialized integrity LV %s", lv->name);
-+
-+	for (s = 0; s < area_count; s++) {
-+		lv_image = seg_lv(seg_top, s);
-+		seg_image = first_seg(lv_image);
-+		seg_image->integrity_recalculate = 0;
-+	}
-+
-+	if (!vg_write(vg) || !vg_commit(vg))
-+		goto_bad;
-+
-+	return 1;
-+
-+bad:
-+	log_error("Failed to add integrity.");
-+
-+	for (s = 0; s < revert_meta_lvs; s++) {
-+		if (!lv_remove(imeta_lvs[s]))
-+			log_error("New integrity metadata LV may require manual removal.");
-+	}
-+			       
-+	if (!vg_write(vg) || !vg_commit(vg))
-+		log_error("New integrity metadata LV may require manual removal.");
-+
-+	return 0;
-+}
-+
-+/*
-+ * This should rarely if ever be used.  A command that adds integrity
-+ * to an LV will activate and then clear the flag.  If it fails before
-+ * clearing the flag, then this function will be used by a subsequent
-+ * activation to clear the flag.
-+ */
-+void lv_clear_integrity_recalculate_metadata(struct logical_volume *lv)
-+{
-+	struct volume_group *vg = lv->vg;
-+	struct logical_volume *lv_image;
-+	struct lv_segment *seg, *seg_image;
-+	uint32_t s;
-+
-+	seg = first_seg(lv);
-+
-+	if (seg_is_raid(seg)) {
-+		for (s = 0; s < seg->area_count; s++) {
-+			lv_image = seg_lv(seg, s);
-+			seg_image = first_seg(lv_image);
-+			seg_image->integrity_recalculate = 0;
-+		}
-+	} else if (seg_is_integrity(seg)) {
-+		seg->integrity_recalculate = 0;
-+	} else {
-+		log_error("Invalid LV type for clearing integrity");
-+		return;
-+	}
-+
-+	if (!vg_write(vg) || !vg_commit(vg)) {
-+		log_warn("WARNING: failed to clear integrity recalculate flag for %s",
-+			 display_lvname(lv));
-+	}
-+}
-+
-+int lv_has_integrity_recalculate_metadata(struct logical_volume *lv)
-+{
-+	struct logical_volume *lv_image;
-+	struct lv_segment *seg, *seg_image;
-+	uint32_t s;
-+	int ret = 0;
-+
-+	seg = first_seg(lv);
-+
-+	if (seg_is_raid(seg)) {
-+		for (s = 0; s < seg->area_count; s++) {
-+			lv_image = seg_lv(seg, s);
-+			seg_image = first_seg(lv_image);
-+
-+			if (!seg_is_integrity(seg_image))
-+				continue;
-+			if (seg_image->integrity_recalculate)
-+				ret = 1;
-+		}
-+	} else if (seg_is_integrity(seg)) {
-+		ret = seg->integrity_recalculate;
-+	}
-+
-+	return ret;
-+}
-+
-+int lv_raid_has_integrity(struct logical_volume *lv)
-+{
-+	struct logical_volume *lv_image;
-+	struct lv_segment *seg, *seg_image;
-+	uint32_t s;
-+
-+	seg = first_seg(lv);
-+
-+	if (seg_is_raid(seg)) {
-+		for (s = 0; s < seg->area_count; s++) {
-+			lv_image = seg_lv(seg, s);
-+			seg_image = first_seg(lv_image);
-+
-+			if (seg_is_integrity(seg_image))
-+				return 1;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+int lv_get_raid_integrity_settings(struct logical_volume *lv, struct integrity_settings **isettings)
-+{
-+	struct logical_volume *lv_image;
-+	struct lv_segment *seg, *seg_image;
-+	uint32_t s;
-+
-+	seg = first_seg(lv);
-+
-+	if (seg_is_raid(seg)) {
-+		for (s = 0; s < seg->area_count; s++) {
-+			lv_image = seg_lv(seg, s);
-+			seg_image = first_seg(lv_image);
-+
-+			if (seg_is_integrity(seg_image)) {
-+				*isettings = &seg_image->integrity_settings;
-+				return 1;
-+			}
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
-index 17d4907..4ee58b4 100644
---- a/lib/metadata/lv.c
-+++ b/lib/metadata/lv.c
-@@ -385,6 +385,17 @@ dm_percent_t lvseg_percent_with_info_and_seg_status(const struct lv_with_info_an
- 	 *   Esentially rework  _target_percent API for segtype.
- 	 */
- 	switch (s->type) {
-+	case SEG_STATUS_INTEGRITY:
-+		if (type != PERCENT_GET_DIRTY)
-+			p = DM_PERCENT_INVALID;
-+		else if (!s->integrity->recalc_sector)
-+			p = DM_PERCENT_INVALID;
-+		else if (s->integrity->recalc_sector == s->integrity->provided_data_sectors)
-+			p = DM_PERCENT_100;
-+		else
-+			p = dm_make_percent(s->integrity->recalc_sector,
-+					    s->integrity->provided_data_sectors);
-+		break;
- 	case SEG_STATUS_CACHE:
- 		if (s->cache->fail || s->cache->error)
- 			p = DM_PERCENT_INVALID;
-@@ -593,6 +604,8 @@ struct logical_volume *lv_origin_lv(const struct logical_volume *lv)
- 		origin = first_seg(lv)->external_lv;
- 	else if (lv_is_writecache(lv) && first_seg(lv)->origin)
- 		origin = first_seg(lv)->origin;
-+	else if (lv_is_integrity(lv) && first_seg(lv)->origin)
-+		origin = first_seg(lv)->origin;
- 
- 	return origin;
- }
-@@ -1208,10 +1221,13 @@ char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_
- 		repstr[0] = (lv_is_merging_origin(lv)) ? 'O' : 'o';
- 	else if (lv_is_pool_metadata(lv) ||
- 		 lv_is_pool_metadata_spare(lv) ||
--		 lv_is_raid_metadata(lv))
-+		 lv_is_raid_metadata(lv) ||
-+		 lv_is_integrity_metadata(lv))
- 		repstr[0] = 'e';
- 	else if (lv_is_cache_type(lv) || lv_is_writecache(lv))
- 		repstr[0] = 'C';
-+	else if (lv_is_integrity(lv))
-+		repstr[0] = 'g';
- 	else if (lv_is_raid(lv))
- 		repstr[0] = (lv_is_not_synced(lv)) ? 'R' : 'r';
- 	else if (lv_is_mirror(lv))
-diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
-index 3090a93..1311f70 100644
---- a/lib/metadata/lv_manip.c
-+++ b/lib/metadata/lv_manip.c
-@@ -134,7 +134,9 @@ enum {
- 	LV_TYPE_SANLOCK,
- 	LV_TYPE_CACHEVOL,
- 	LV_TYPE_WRITECACHE,
--	LV_TYPE_WRITECACHEORIGIN
-+	LV_TYPE_WRITECACHEORIGIN,
-+	LV_TYPE_INTEGRITY,
-+	LV_TYPE_INTEGRITYORIGIN
- };
- 
- static const char *_lv_type_names[] = {
-@@ -190,6 +192,8 @@ static const char *_lv_type_names[] = {
- 	[LV_TYPE_CACHEVOL] =				"cachevol",
- 	[LV_TYPE_WRITECACHE] =				"writecache",
- 	[LV_TYPE_WRITECACHEORIGIN] =			"writecacheorigin",
-+	[LV_TYPE_INTEGRITY] =				"integrity",
-+	[LV_TYPE_INTEGRITYORIGIN] =			"integrityorigin",
- };
- 
- static int _lv_layout_and_role_mirror(struct dm_pool *mem,
-@@ -461,6 +465,43 @@ bad:
- 	return 0;
- }
- 
-+static int _lv_layout_and_role_integrity(struct dm_pool *mem,
-+				     const struct logical_volume *lv,
-+				     struct dm_list *layout,
-+				     struct dm_list *role,
-+				     int *public_lv)
-+{
-+	int top_level = 0;
-+
-+	/* non-top-level LVs */
-+	if (lv_is_integrity_metadata(lv)) {
-+		if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
-+		    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_METADATA]))
-+			goto_bad;
-+	} else if (lv_is_integrity_origin(lv)) {
-+		if (!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITY]) ||
-+		    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_ORIGIN]) ||
-+		    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_INTEGRITYORIGIN]))
-+			goto_bad;
-+	} else
-+		top_level = 1;
-+
-+	if (!top_level) {
-+		*public_lv = 0;
-+		return 1;
-+	}
-+
-+	/* top-level LVs */
-+	if (lv_is_integrity(lv)) {
-+		if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_INTEGRITY]))
-+			goto_bad;
-+	}
-+
-+	return 1;
-+bad:
-+	return 0;
-+}
-+
- static int _lv_layout_and_role_thick_origin_snapshot(struct dm_pool *mem,
- 						     const struct logical_volume *lv,
- 						     struct dm_list *layout,
-@@ -577,6 +618,11 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
- 	    !_lv_layout_and_role_cache(mem, lv, *layout, *role, &public_lv))
- 		goto_bad;
- 
-+	/* Integrity related */
-+	if ((lv_is_integrity(lv) || lv_is_integrity_origin(lv) || lv_is_integrity_metadata(lv)) &&
-+	    !_lv_layout_and_role_integrity(mem, lv, *layout, *role, &public_lv))
-+		goto_bad;
-+
- 	/* VDO and related */
- 	if (lv_is_vdo_type(lv) &&
- 	    !_lv_layout_and_role_vdo(mem, lv, *layout, *role, &public_lv))
-@@ -1457,6 +1503,15 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
- 					return_0;
- 			}
- 
-+			if (delete && seg_is_integrity(seg)) {
-+				/* Remove integrity origin in addition to integrity layer. */
-+				if (!lv_remove(seg_lv(seg, 0)))
-+					return_0;
-+				/* Remove integrity metadata. */
-+				if (seg->integrity_meta_dev && !lv_remove(seg->integrity_meta_dev))
-+					return_0;
-+			}
-+
- 			if ((pool_lv = seg->pool_lv)) {
- 				if (!detach_pool_lv(seg))
- 					return_0;
-@@ -4111,11 +4166,14 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
- 				 uint32_t extents, uint32_t first_area,
- 				 uint32_t mirrors, uint32_t stripes, uint32_t stripe_size)
- {
-+	struct logical_volume *sub_lvs[DEFAULT_RAID_MAX_IMAGES];
- 	const struct segment_type *segtype;
--	struct logical_volume *sub_lv, *meta_lv;
-+	struct logical_volume *meta_lv, *sub_lv;
- 	struct lv_segment *seg = first_seg(lv);
-+	struct lv_segment *sub_lv_seg;
- 	uint32_t fa, s;
- 	int clear_metadata = 0;
-+	int integrity_sub_lvs = 0;
- 	uint32_t area_multiple = 1;
- 
- 	if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
-@@ -4133,16 +4191,28 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
- 			area_multiple = seg->area_count;
- 	}
- 
-+	for (s = 0; s < seg->area_count; s++) {
-+		sub_lv = seg_lv(seg, s);
-+		sub_lv_seg = sub_lv ? first_seg(sub_lv) : NULL;
-+
-+		if (sub_lv_seg && seg_is_integrity(sub_lv_seg)) {
-+			sub_lvs[s] = seg_lv(sub_lv_seg, 0);
-+			integrity_sub_lvs = 1;
-+		} else
-+			sub_lvs[s] = sub_lv;
-+	}
-+
- 	for (fa = first_area, s = 0; s < seg->area_count; s++) {
--		if (is_temporary_mirror_layer(seg_lv(seg, s))) {
--			if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents / area_multiple,
-+		sub_lv = sub_lvs[s];
-+
-+		if (is_temporary_mirror_layer(sub_lv)) {
-+			if (!_lv_extend_layered_lv(ah, sub_lv, extents / area_multiple,
- 						   fa, mirrors, stripes, stripe_size))
- 				return_0;
--			fa += lv_mirror_count(seg_lv(seg, s));
-+			fa += lv_mirror_count(sub_lv);
- 			continue;
- 		}
- 
--		sub_lv = seg_lv(seg, s);
- 		if (!lv_add_segment(ah, fa, stripes, sub_lv, segtype,
- 				    stripe_size, sub_lv->status, 0)) {
- 			log_error("Aborting. Failed to extend %s in %s.",
-@@ -4184,6 +4254,41 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
- 		fa += stripes;
- 	}
- 
-+	/*
-+	 * In raid+integrity, the lv_iorig raid images have been extended above.
-+	 * Now propagate the new lv_iorig sizes up to the integrity LV layers
-+	 * that are referencing the lv_iorig.
-+	 */
-+	if (integrity_sub_lvs) {
-+		for (s = 0; s < seg->area_count; s++) {
-+			struct logical_volume *lv_image;
-+			struct logical_volume *lv_iorig;
-+			struct logical_volume *lv_imeta;
-+			struct lv_segment *seg_image;
-+
-+			lv_image = seg_lv(seg, s);
-+			seg_image = first_seg(lv_image);
-+
-+			if (!(lv_imeta = seg_image->integrity_meta_dev)) {
-+				log_error("1");
-+				return_0;
-+			}
-+
-+			if (!(lv_iorig = seg_lv(seg_image, 0))) {
-+				log_error("2");
-+				return_0;
-+			}
-+
-+			/* new size in sectors */
-+			lv_image->size = lv_iorig->size;
-+			seg_image->integrity_data_sectors = lv_iorig->size;
-+			/* new size in extents */
-+			lv_image->le_count = lv_iorig->le_count;
-+			seg_image->len = lv_iorig->le_count;
-+			seg_image->area_len = lv_iorig->le_count;
-+		}
-+	}
-+
- 	seg->len += extents;
- 	if (seg_is_raid(seg))
- 		seg->area_len = seg->len;
-@@ -4345,6 +4450,13 @@ int lv_extend(struct logical_volume *lv,
- 						mirrors, stripes, stripe_size)))
- 			goto_out;
- 
-+		if (lv_raid_has_integrity(lv)) {
-+			if (!lv_extend_integrity_in_raid(lv, allocatable_pvs)) {
-+				r = 0;
-+				goto_out;
-+			}
-+		}
-+
- 		/*
- 		 * If we are expanding an existing mirror, we can skip the
- 		 * resync of the extension if the LV is currently in-sync
-@@ -4538,6 +4650,9 @@ static int _for_each_sub_lv(struct logical_volume *lv, int level,
- 		if (!_for_each_sub_lv(seg->writecache, level, fn, data))
- 			return_0;
- 
-+		if (!_for_each_sub_lv(seg->integrity_meta_dev, level, fn, data))
-+			return_0;
-+
- 		for (s = 0; s < seg->area_count; s++) {
- 			if (seg_type(seg, s) != AREA_LV)
- 				continue;
-@@ -5064,6 +5179,12 @@ static int _lvresize_check(struct logical_volume *lv,
- 		return 0;
- 	}
- 
-+	if (lv_is_integrity(lv) || lv_raid_has_integrity(lv)) {
-+		if (lp->resize == LV_REDUCE) {
-+			log_error("Cannot reduce LV with integrity.");
-+			return 0;
-+		}
-+	}
- 	return 1;
- }
- 
-@@ -5613,6 +5734,9 @@ static int _lvresize_prepare(struct logical_volume **lv,
- 	if (lv_is_thin_pool(*lv) || lv_is_vdo_pool(*lv))
- 		*lv = seg_lv(first_seg(*lv), 0); /* switch to data LV */
- 
-+	if (lv_is_integrity(*lv))
-+		*lv = seg_lv(first_seg(*lv), 0);
-+
- 	/* Resolve extents from size */
- 	if (lp->size && !_lvresize_adjust_size(vg, lp->size, lp->sign, &lp->extents))
- 		return_0;
-@@ -7948,6 +8072,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
- 		/* FIXME Eventually support raid/mirrors with -m */
- 		if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
- 			return_0;
-+
-+	} else if (seg_is_integrity(lp)) {
-+		if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
-+			return_0;
-+
- 	} else if (seg_is_mirrored(lp) || (seg_is_raid(lp) && !seg_is_any_raid0(lp))) {
- 		if (!(lp->region_size = adjusted_mirror_region_size(vg->cmd,
- 								    vg->extent_size,
-@@ -8198,6 +8327,15 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
- 		goto out;
- 	}
- 
-+	if (seg_is_raid(lp) && lp->raidintegrity) {
-+		log_debug("Adding integrity to new LV");
-+
-+		if (!lv_add_integrity_to_raid(lv, &lp->integrity_settings, lp->pvh, NULL))
-+			goto revert_new_lv;
-+
-+		backup(vg);
-+	}
-+
- 	/* Do not scan this LV until properly zeroed/wiped. */
- 	if (_should_wipe_lv(lp, lv, 0))
- 		lv->status |= LV_NOSCAN;
-diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
-index 11b26b4..ecd55ef 100644
---- a/lib/metadata/merge.c
-+++ b/lib/metadata/merge.c
-@@ -742,6 +742,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
- 			seg_found++;
- 		if (seg->metadata_lv == lv || seg->pool_lv == lv || seg->writecache == lv)
- 			seg_found++;
-+		if (seg->integrity_meta_dev == lv)
-+			seg_found++;
- 		if (seg_is_thin_volume(seg) && (seg->origin == lv || seg->external_lv == lv))
- 			seg_found++;
- 
-diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
-index 35c1231..52bc776 100644
---- a/lib/metadata/metadata-exported.h
-+++ b/lib/metadata/metadata-exported.h
-@@ -84,12 +84,14 @@
- #define CONVERTING		UINT64_C(0x0000000000400000)	/* LV */
- 
- #define MISSING_PV		UINT64_C(0x0000000000800000)	/* PV */
-+#define INTEGRITY		UINT64_C(0x0000000000800000)	/* LV - Internal use only */
- #define PV_MOVED_VG		UINT64_C(0x4000000000000000)	/* PV - Moved to a new VG */
- #define PARTIAL_LV		UINT64_C(0x0000000001000000)	/* LV - derived flag, not
- 							   written out in metadata*/
- 
- //#define POSTORDER_FLAG	UINT64_C(0x0000000002000000) /* Not real flags, reserved for
- //#define POSTORDER_OPEN_FLAG	UINT64_C(0x0000000004000000)    temporary use inside vg_read_internal. */
-+#define INTEGRITY_METADATA	UINT64_C(0x0000000004000000)    /* LV - Internal use only */
- #define VIRTUAL_ORIGIN		UINT64_C(0x0000000008000000)	/* LV - internal use only */
- 
- #define MERGING			UINT64_C(0x0000000010000000)	/* LV SEG */
-@@ -261,6 +263,8 @@
- #define lv_is_pool_metadata_spare(lv)	(((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
- #define lv_is_lockd_sanlock_lv(lv)	(((lv)->status & LOCKD_SANLOCK_LV) ? 1 : 0)
- #define lv_is_writecache(lv)   (((lv)->status & WRITECACHE) ? 1 : 0)
-+#define lv_is_integrity(lv)            (((lv)->status & INTEGRITY) ? 1 : 0)
-+#define lv_is_integrity_metadata(lv)   (((lv)->status & INTEGRITY_METADATA) ? 1 : 0)
- 
- #define lv_is_vdo(lv)		(((lv)->status & LV_VDO) ? 1 : 0)
- #define lv_is_vdo_pool(lv)	(((lv)->status & LV_VDO_POOL) ? 1 : 0)
-@@ -272,9 +276,11 @@
- /* Recognize component LV (matching lib/misc/lvm-string.c _lvname_has_reserved_component_string()) */
- #define lv_is_component(lv) (lv_is_cache_origin(lv) || \
- 			     lv_is_writecache_origin(lv) || \
-+			     lv_is_integrity_origin(lv) || \
- 			     ((lv)->status & (\
- 					      CACHE_POOL_DATA |\
- 					      CACHE_POOL_METADATA |\
-+					      INTEGRITY_METADATA |\
- 					      LV_CACHE_VOL |\
- 					      LV_VDO_POOL_DATA |\
- 					      MIRROR_IMAGE |\
-@@ -519,6 +525,11 @@ struct lv_segment {
- 	uint32_t writecache_block_size;		/* For writecache */
- 	struct writecache_settings writecache_settings; /* For writecache */
- 
-+	uint64_t integrity_data_sectors;
-+	struct logical_volume *integrity_meta_dev;
-+	struct integrity_settings integrity_settings;
-+	uint32_t integrity_recalculate;
-+
- 	struct dm_vdo_target_params vdo_params;	/* For VDO-pool */
- 	uint32_t vdo_pool_header_size;		/* For VDO-pool */
- 	uint32_t vdo_pool_virtual_extents;	/* For VDO-pool */
-@@ -992,6 +1003,10 @@ struct lvcreate_params {
- 	alloc_policy_t alloc; /* all */
- 	struct dm_vdo_target_params vdo_params; /* vdo */
- 
-+	int raidintegrity;
-+	const char *raidintegritymode;
-+	struct integrity_settings integrity_settings;
-+
- 	struct dm_list tags;	/* all */
- 
- 	int yes;
-@@ -1086,6 +1101,8 @@ int lv_is_cache_origin(const struct logical_volume *lv);
- int lv_is_writecache_origin(const struct logical_volume *lv);
- int lv_is_writecache_cachevol(const struct logical_volume *lv);
- 
-+int lv_is_integrity_origin(const struct logical_volume *lv);
-+
- int lv_is_merging_cow(const struct logical_volume *cow);
- uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
- int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
-@@ -1389,4 +1406,13 @@ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int
- 		                                            char **argv, int allocatable_only);
- struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl);
- 
-+int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_settings *settings, struct dm_list *pvh,
-+			     struct logical_volume *lv_imeta_0);
-+int lv_remove_integrity_from_raid(struct logical_volume *lv);
-+void lv_clear_integrity_recalculate_metadata(struct logical_volume *lv);
-+int lv_has_integrity_recalculate_metadata(struct logical_volume *lv);
-+int lv_raid_has_integrity(struct logical_volume *lv);
-+int lv_extend_integrity_in_raid(struct logical_volume *lv, struct dm_list *pvh);
-+int lv_get_raid_integrity_settings(struct logical_volume *lv, struct integrity_settings **isettings);
-+
- #endif
-diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
-index fa1b91a..3b3e1d3 100644
---- a/lib/metadata/raid_manip.c
-+++ b/lib/metadata/raid_manip.c
-@@ -3119,6 +3119,11 @@ static int _raid_remove_images(struct logical_volume *lv, int yes,
- 
- 	/* Convert to linear? */
- 	if (new_count == 1) {
-+		if (lv_raid_has_integrity(lv)) {
-+			log_error("Integrity must be removed before converting raid to linear.");
-+			return 0;
-+		}
-+
- 		if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s to type %s losing all resilience? [y/n]: ",
- 					  lvseg_name(first_seg(lv)), display_lvname(lv), SEG_TYPE_NAME_LINEAR) == 'n') {
- 			log_error("Logical volume %s NOT converted to \"%s\".",
-@@ -3265,6 +3270,11 @@ int lv_raid_split(struct logical_volume *lv, int yes, const char *split_name,
- 		return 0;
- 	}
- 
-+	if (lv_raid_has_integrity(lv)) {
-+		log_error("Integrity must be removed before splitting.");
-+		return 0;
-+	}
-+
- 	if ((old_count - new_count) != 1) {
- 		log_error("Unable to split more than one image from %s.",
- 			  display_lvname(lv));
-@@ -3328,9 +3338,11 @@ int lv_raid_split(struct logical_volume *lv, int yes, const char *split_name,
- 	}
- 
- 	/* Convert to linear? */
--	if ((new_count == 1) && !_raid_remove_top_layer(lv, &removal_lvs)) {
--		log_error("Failed to remove RAID layer after linear conversion.");
--		return 0;
-+	if (new_count == 1) {
-+		if (!_raid_remove_top_layer(lv, &removal_lvs)) {
-+			log_error("Failed to remove RAID layer after linear conversion.");
-+			return 0;
-+		}
- 	}
- 
- 	/* Get first item */
-@@ -3432,6 +3444,11 @@ int lv_raid_split_and_track(struct logical_volume *lv,
- 		return 0;
- 	}
- 
-+	if (lv_raid_has_integrity(lv)) {
-+		log_error("Integrity must be removed before splitting.");
-+		return 0;
-+	}
-+
- 	if (!seg_is_mirrored(seg)) {
- 		log_error("Unable to split images from non-mirrored RAID.");
- 		return 0;
-@@ -6727,7 +6744,17 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
- 	struct lv_segment *raid_seg = first_seg(lv);
- 	struct lv_list *lvl;
- 	char *tmp_names[raid_seg->area_count * 2];
-+	char tmp_name_buf[NAME_LEN];
-+	char *tmp_name_dup;
- 	const char *action_str = rebuild ? "rebuild" : "replace";
-+	int has_integrity;
-+
-+	if ((has_integrity = lv_raid_has_integrity(lv))) {
-+		if (rebuild) {
-+			log_error("Can't rebuild raid with integrity.");
-+			return 0;
-+		}
-+	}
- 
- 	if (seg_is_any_raid0(raid_seg)) {
- 		log_error("Can't replace any devices in %s LV %s.",
-@@ -6992,6 +7019,15 @@ try_again:
- 			tmp_names[s] = tmp_names[sd] = NULL;
- 	}
- 
-+	/* Add integrity layer to any new images. */
-+	if (has_integrity) {
-+		struct integrity_settings *isettings = NULL;
-+		if (!lv_get_raid_integrity_settings(lv, &isettings))
-+			return_0;
-+		if (!lv_add_integrity_to_raid(lv, isettings, NULL, NULL))
-+			return_0;
-+	}
-+
- skip_alloc:
- 	if (!lv_update_and_reload_origin(lv))
- 		return_0;
-@@ -7014,9 +7050,43 @@ skip_alloc:
- 	if (!rebuild)
- 		for (s = 0; s < raid_seg->area_count; s++) {
- 			sd = s + raid_seg->area_count;
-+
- 			if (tmp_names[s] && tmp_names[sd]) {
--				seg_metalv(raid_seg, s)->name = tmp_names[s];
--				seg_lv(raid_seg, s)->name = tmp_names[sd];
-+				struct logical_volume *lv_image = seg_lv(raid_seg, s);
-+				struct logical_volume *lv_rmeta = seg_metalv(raid_seg, s);
-+
-+				lv_rmeta->name = tmp_names[s];
-+				lv_image->name = tmp_names[sd];
-+
-+				if (lv_is_integrity(lv_image)) {
-+					struct logical_volume *lv_imeta;
-+					struct logical_volume *lv_iorig;
-+					struct lv_segment *seg_image;
-+
-+					seg_image = first_seg(lv_image);
-+					lv_imeta = seg_image->integrity_meta_dev;
-+					lv_iorig = seg_lv(seg_image, 0);
-+
-+					if (dm_snprintf(tmp_name_buf, NAME_LEN, "%s_imeta", lv_image->name) < 0) {
-+						stack;
-+						continue;
-+					}
-+					if (!(tmp_name_dup = dm_pool_strdup(lv->vg->vgmem, tmp_name_buf))) {
-+						stack;
-+						continue;
-+					}
-+					lv_imeta->name = tmp_name_dup;
-+
-+					if (dm_snprintf(tmp_name_buf, NAME_LEN, "%s_iorig", lv_image->name) < 0) {
-+						stack;
-+						continue;
-+					}
-+					if (!(tmp_name_dup = dm_pool_strdup(lv->vg->vgmem, tmp_name_buf))) {
-+						stack;
-+						continue;
-+					}
-+					lv_iorig->name = tmp_name_dup;
-+				}
- 			}
- 		}
- 
-@@ -7192,6 +7262,11 @@ int partial_raid_lv_supports_degraded_activation(const struct logical_volume *cl
- {
- 	int not_capable = 0;
- 	struct logical_volume * lv = (struct logical_volume *)clv; /* drop const */
-+	
-+	if (lv_raid_has_integrity(lv)) {
-+		log_error("Integrity must be removed before degraded or partial activation of raid.");
-+		return 0;
-+	}
- 
- 	if (!_lv_may_be_activated_in_degraded_mode(lv, &not_capable) || not_capable)
- 		return_0;
-diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
-index 22a511e..08ddc35 100644
---- a/lib/metadata/segtype.h
-+++ b/lib/metadata/segtype.h
-@@ -67,6 +67,7 @@ struct dev_manager;
- #define SEG_RAID6_N_6		(1ULL << 35)
- #define SEG_RAID6		SEG_RAID6_ZR
- #define SEG_WRITECACHE		(1ULL << 36)
-+#define SEG_INTEGRITY		(1ULL << 37)
- 
- #define SEG_STRIPED_TARGET	(1ULL << 39)
- #define SEG_LINEAR_TARGET	(1ULL << 40)
-@@ -84,6 +85,7 @@ struct dev_manager;
- #define SEG_TYPE_NAME_CACHE		"cache"
- #define SEG_TYPE_NAME_CACHE_POOL	"cache-pool"
- #define SEG_TYPE_NAME_WRITECACHE	"writecache"
-+#define SEG_TYPE_NAME_INTEGRITY		"integrity"
- #define SEG_TYPE_NAME_ERROR		"error"
- #define SEG_TYPE_NAME_FREE		"free"
- #define SEG_TYPE_NAME_ZERO		"zero"
-@@ -117,6 +119,7 @@ struct dev_manager;
- #define segtype_is_cache(segtype)	((segtype)->flags & SEG_CACHE ? 1 : 0)
- #define segtype_is_cache_pool(segtype)	((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
- #define segtype_is_writecache(segtype)	((segtype)->flags & SEG_WRITECACHE ? 1 : 0)
-+#define segtype_is_integrity(segtype)	((segtype)->flags & SEG_INTEGRITY ? 1 : 0)
- #define segtype_is_mirrored(segtype)	((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
- #define segtype_is_mirror(segtype)	((segtype)->flags & SEG_MIRROR ? 1 : 0)
- #define segtype_is_pool(segtype)	((segtype)->flags & (SEG_CACHE_POOL | SEG_THIN_POOL)  ? 1 : 0)
-@@ -179,6 +182,7 @@ struct dev_manager;
- #define seg_is_cache(seg)	segtype_is_cache((seg)->segtype)
- #define seg_is_cache_pool(seg)	segtype_is_cache_pool((seg)->segtype)
- #define seg_is_writecache(seg)	segtype_is_writecache((seg)->segtype)
-+#define seg_is_integrity(seg)	segtype_is_integrity((seg)->segtype)
- #define seg_is_used_cache_pool(seg) (seg_is_cache_pool(seg) && (!dm_list_empty(&(seg->lv)->segs_using_this_lv)))
- #define seg_is_linear(seg)	(seg_is_striped(seg) && ((seg)->area_count == 1))
- #define seg_is_mirror(seg)	segtype_is_mirror((seg)->segtype)
-@@ -347,6 +351,8 @@ int init_vdo_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
- 
- int init_writecache_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
- 
-+int init_integrity_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
-+
- #define CACHE_FEATURE_POLICY_MQ			(1U << 0)
- #define CACHE_FEATURE_POLICY_SMQ		(1U << 1)
- #define CACHE_FEATURE_METADATA2			(1U << 2)
-diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
-index 64e27ae..3faea0e 100644
---- a/lib/metadata/snapshot_manip.c
-+++ b/lib/metadata/snapshot_manip.c
-@@ -387,6 +387,8 @@ int validate_snapshot_origin(const struct logical_volume *origin_lv)
- 		}
- 	} else if (lv_is_raid_type(origin_lv) && !lv_is_raid(origin_lv)) {
- 		err = "raid subvolumes";
-+	} else if (lv_is_raid(origin_lv) && lv_raid_has_integrity((struct logical_volume *)origin_lv)) {
-+		err = "raid with integrity";
- 	} else if (lv_is_writecache(origin_lv)) {
- 		err = "writecache";
- 	}
-diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
-index 0ee3403..959a6a1 100644
---- a/lib/misc/lvm-string.c
-+++ b/lib/misc/lvm-string.c
-@@ -166,7 +166,9 @@ static const char *_lvname_has_reserved_component_string(const char *lvname)
- 		"_rmeta",
- 		"_tdata",
- 		"_tmeta",
--		"_vdata"
-+		"_vdata",
-+		"_imeta",
-+		"_iorig"
- 	};
- 	unsigned i;
- 
-diff --git a/lib/report/report.c b/lib/report/report.c
-index d379e2a..170df69 100644
---- a/lib/report/report.c
-+++ b/lib/report/report.c
-@@ -3173,7 +3173,7 @@ static int _copypercent_disp(struct dm_report *rh,
- 	dm_percent_t percent = DM_PERCENT_INVALID;
- 
- 	/* TODO: just cache passes through lvseg_percent... */
--	if (lv_is_cache(lv) || lv_is_used_cache_pool(lv) ||
-+	if (lv_is_integrity(lv) || lv_is_cache(lv) || lv_is_used_cache_pool(lv) ||
- 	    (!lv_is_merging_origin(lv) && lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv))))
- 		percent = lvseg_percent_with_info_and_seg_status(lvdm, PERCENT_GET_DIRTY);
- 	else if (lv_is_raid(lv) && !seg_is_any_raid0(first_seg(lv)))
-diff --git a/man/lvmraid.7_main b/man/lvmraid.7_main
-index 498de90..aedd16a 100644
---- a/man/lvmraid.7_main
-+++ b/man/lvmraid.7_main
-@@ -785,6 +785,89 @@ configuration file itself.
-         activation_mode
- 
- 
-+.SH Data Integrity
-+
-+The device mapper integrity target can be used in combination with RAID
-+levels 1,4,5,6,10 to detect and correct data corruption in RAID images. A
-+dm-integrity layer is placed above each RAID image, and an extra sub LV is
-+created to hold integrity metadata (data checksums) for each RAID image.
-+When data is read from an image, integrity checksums are used to detect
-+corruption. If detected, dm-raid reads the data from another (good) image
-+to return to the caller.  dm-raid will also automatically write the good
-+data back to the image with bad data to correct the corruption.
-+
-+When creating a RAID LV with integrity, or adding integrity, space is
-+required for integrity metadata.  Every 500MB of LV data requires an
-+additional 4MB to be allocated for integrity metadata, for each RAID
-+image.
-+
-+Create a RAID LV with integrity:
-+
-+.B lvcreate \-\-type raidN \-\-raidintegrity y
-+
-+Add integrity to an existing RAID LV:
-+
-+.B lvconvert --raidintegrity y
-+.I LV
-+
-+Remove integrity from a RAID LV:
-+
-+.B lvconvert --raidintegrity n
-+.I LV
-+
-+.SS Integrity options
-+
-+.B --raidintegritymode journal|bitmap
-+
-+Use a journal (default) or bitmap for keeping integrity checksums
-+consistent in case of a crash. The bitmap areas are recalculated after a
-+crash, so corruption in those areas would not be detected. A journal does
-+not have this problem.  The journal mode doubles writes to storage, but
-+can improve performance for scattered writes packed into a single journal
-+write.  bitmap mode can in theory achieve full write throughput of the
-+device, but would not benefit from the potential scattered write
-+optimization.
-+
-+.B --raidintegrityblocksize 512|1024|2048|4096
-+
-+The block size to use for dm-integrity on raid images.  The integrity
-+block size should usually match the device logical block size, or the file
-+system sector/block sizes.  It may be less than the file system
-+sector/block size, but not less than the device logical block size.
-+Possible values: 512, 1024, 2048, 4096.
-+
-+.SS Integrity initialization
-+
-+When integrity is added to an LV, the kernel needs to initialize the
-+integrity metadata (checksums) for all blocks in the LV.  The data
-+corruption checking performed by dm-integrity will only operate on areas
-+of the LV that are already initialized.  The progress of integrity
-+initialization is reported by the "syncpercent" LV reporting field (and
-+under the Cpy%Sync lvs column.)
-+
-+.SS Integrity limitations
-+
-+To work around some limitations, it is possible to remove integrity from
-+the LV, make the change, then add integrity again.  (Integrity metadata
-+would need to initialized when added again.)
-+
-+LVM must be able to allocate the integrity metadata sub LV on a single PV
-+that is already in use by the associated RAID image. This can potentially
-+cause a problem during lvextend if the original PV holding the image and
-+integrity metadata is full.  To work around this limitation, remove
-+integrity, extend the LV, and add integrity again.
-+
-+Additional RAID images can be added to raid1 LVs, but not to other raid
-+levels.
-+
-+A raid1 LV with integrity cannot be converted to linear (remove integrity
-+to do this.)
-+
-+RAID LVs with integrity cannot yet be used as sub LVs with other LV types.
-+
-+The following are not yet permitted on RAID LVs with integrity: lvreduce,
-+pvmove, snapshots, splitmirror, raid syncaction commands, raid rebuild.
-+
- .SH RAID1 Tuning
- 
- A RAID1 LV can be tuned so that certain devices are avoided for reading
-diff --git a/test/lib/aux.sh b/test/lib/aux.sh
-index 83a88a6..e40da95 100644
---- a/test/lib/aux.sh
-+++ b/test/lib/aux.sh
-@@ -1563,6 +1563,14 @@ have_writecache() {
- 	target_at_least dm-writecache "$@"
- }
- 
-+have_integrity() {
-+	lvm segtypes 2>/dev/null | grep -q integrity$ || {
-+		echo "integrity is not built-in." >&2
-+		return 1
-+	}
-+	target_at_least dm-integrity "$@"
-+}
-+
- have_raid() {
- 	target_at_least dm-raid "$@"
- 
-diff --git a/test/shell/integrity-blocksize.sh b/test/shell/integrity-blocksize.sh
-new file mode 100644
-index 0000000..444e3db
---- /dev/null
-+++ b/test/shell/integrity-blocksize.sh
-@@ -0,0 +1,183 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+
-+losetup -h | grep sector-size || skip
-+
-+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
-+aux prepare_devs 1
-+vgcreate $vg "$dev1"
-+lvcreate -n $lv1 -l8 $vg
-+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+blkid "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
-+lvchange -an $vg
-+vgremove -ff $vg
-+
-+dd if=/dev/zero of=loopa bs=$((1024*1024)) count=64 2> /dev/null
-+dd if=/dev/zero of=loopb bs=$((1024*1024)) count=64 2> /dev/null
-+dd if=/dev/zero of=loopc bs=$((1024*1024)) count=64 2> /dev/null
-+dd if=/dev/zero of=loopd bs=$((1024*1024)) count=64 2> /dev/null
-+LOOP1=$(losetup -f loopa --show)
-+LOOP2=$(losetup -f loopb --show)
-+LOOP3=$(losetup -f loopc --sector-size 4096 --show)
-+LOOP4=$(losetup -f loopd --sector-size 4096 --show)
-+
-+echo $LOOP1
-+echo $LOOP2
-+echo $LOOP3
-+echo $LOOP4
-+
-+aux extend_filter "a|$LOOP1|"
-+aux extend_filter "a|$LOOP2|"
-+aux extend_filter "a|$LOOP3|"
-+aux extend_filter "a|$LOOP4|"
-+
-+aux lvmconf 'devices/scan = "/dev"'
-+
-+vgcreate $vg1 $LOOP1 $LOOP2
-+vgcreate $vg2 $LOOP3 $LOOP4
-+
-+# lvcreate on dev512, result 512
-+lvcreate --type raid1 -m1 --raidintegrity y -l 8 -n $lv1 $vg1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvcreate on dev4k, result 4k
-+lvcreate --type raid1 -m1 --raidintegrity y -l 8 -n $lv1 $vg2
-+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
-+lvremove -y $vg2/$lv1
-+
-+# lvcreate --bs 512 on dev4k, result fail
-+not lvcreate --type raid1 -m1 --raidintegrity y --raidintegrityblocksize 512 -l 8 -n $lv1 $vg2
-+
-+# lvcreate --bs 4096 on dev512, result 4k
-+lvcreate --type raid1 -m1 --raidintegrity y --raidintegrityblocksize 4096 -l 8 -n $lv1 $vg1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 4096'
-+lvremove -y $vg1/$lv1
-+
-+# Test an unknown fs block size by simply not creating a fs on the lv.
-+
-+# lvconvert on dev512, fsunknown, result 512
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+# clear any residual fs so that libblkid cannot find an fs block size
-+aux wipefs_a /dev/$vg1/$lv1
-+lvconvert --raidintegrity y $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert on dev4k, fsunknown, result 4k
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+# clear any residual fs so that libblkid cannot find an fs block size
-+aux wipefs_a /dev/$vg2/$lv1
-+lvconvert --raidintegrity y $vg2/$lv1
-+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
-+lvremove -y $vg2/$lv1
-+
-+# lvconvert --bs 4k on dev512, fsunknown, result fail
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+# clear any residual fs so that libblkid cannot find an fs block size
-+aux wipefs_a /dev/$vg1/$lv1
-+not lvconvert --raidintegrity y --raidintegrityblocksize 4096 $vg1/$lv1
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert --bs 512 on dev4k, fsunknown, result fail
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+# clear any residual fs so that libblkid cannot find an fs block size
-+aux wipefs_a /dev/$vg2/$lv1
-+not lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg2/$lv1
-+lvremove -y $vg2/$lv1
-+
-+# lvconvert on dev512, xfs 512, result 512
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg1/$lv1"
-+lvconvert --raidintegrity y $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert on dev4k, xfs 4096, result 4096
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+aux wipefs_a /dev/$vg2/$lv1
-+mkfs.xfs -f "$DM_DEV_DIR/$vg2/$lv1"
-+lvconvert --raidintegrity y $vg2/$lv1
-+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
-+lvremove -y $vg2/$lv1
-+
-+# lvconvert on dev512, ext4 1024, result 1024 
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
-+lvconvert --raidintegrity y $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 1024'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert on dev4k, ext4 4096, result 4096
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+aux wipefs_a /dev/$vg2/$lv1
-+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
-+lvconvert --raidintegrity y $vg2/$lv1
-+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
-+lvremove -y $vg2/$lv1
-+
-+# lvconvert --bs 512 on dev512, xfs 4096, result 512
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg1/$lv1"
-+lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert --bs 1024 on dev512, xfs 4096, result 1024
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg1/$lv1"
-+lvconvert --raidintegrity y --raidintegrityblocksize 1024 $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 1024'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert --bs 512 on dev512, ext4 1024, result 512
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
-+aux wipefs_a /dev/$vg1/$lv1
-+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
-+lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
-+pvck --dump metadata $LOOP1 | grep 'block_size = 512'
-+lvremove -y $vg1/$lv1
-+
-+# lvconvert --bs 512 on dev4k, ext4 4096, result fail
-+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
-+aux wipefs_a /dev/$vg2/$lv1
-+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
-+not lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg2/$lv1
-+lvremove -y $vg2/$lv1
-+
-+# FIXME: need to use scsi_debug to create devs with LBS 512 PBS 4k
-+# FIXME: lvconvert, fsunknown, LBS 512, PBS 4k: result 512
-+# FIXME: lvconvert --bs 512, fsunknown, LBS 512, PBS 4k: result 512
-+# FIXME: lvconvert --bs 4k, fsunknown, LBS 512, PBS 4k: result 4k
-+
-+vgremove -ff $vg1
-+vgremove -ff $vg2
-+
-+losetup -d $LOOP1
-+losetup -d $LOOP2
-+losetup -d $LOOP3
-+losetup -d $LOOP4
-+rm loopa
-+rm loopb
-+rm loopc
-+rm loopd
-+
-diff --git a/test/shell/integrity-dmeventd.sh b/test/shell/integrity-dmeventd.sh
-new file mode 100644
-index 0000000..58899ca
---- /dev/null
-+++ b/test/shell/integrity-dmeventd.sh
-@@ -0,0 +1,289 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+which mkfs.xfs || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+aux prepare_devs 6 64
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_prepare_vg() {
-+	vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
-+	pvs
-+}
-+
-+_add_new_data_to_mnt() {
-+        mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+        mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+        # add original data
-+        cp randA $mnt
-+        cp randB $mnt
-+        cp randC $mnt
-+        mkdir $mnt/1
-+        cp fileA $mnt/1
-+        cp fileB $mnt/1
-+        cp fileC $mnt/1
-+        mkdir $mnt/2
-+        cp fileA $mnt/2
-+        cp fileB $mnt/2
-+        cp fileC $mnt/2
-+}
-+
-+_add_more_data_to_mnt() {
-+        mkdir $mnt/more
-+        cp fileA $mnt/more
-+        cp fileB $mnt/more
-+        cp fileC $mnt/more
-+        cp randA $mnt/more
-+        cp randB $mnt/more
-+        cp randC $mnt/more
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_data_on_lv() {
-+        lvchange -ay $vg/$lv1
-+        mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+        _verify_data_on_mnt
-+        rm $mnt/randA
-+        rm $mnt/randB
-+        rm $mnt/randC
-+        rm -rf $mnt/1
-+        rm -rf $mnt/2
-+        umount $mnt
-+        lvchange -an $vg/$lv1
-+}
-+
-+_sync_percent() {
-+	local checklv=$1
-+	get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+	local checklv=$1
-+
-+	for i in $(seq 1 10) ; do
-+		sync=$(_sync_percent "$checklv")
-+		echo "sync_percent is $sync"
-+
-+		if test "$sync" = "100"; then
-+			return
-+		fi
-+
-+		sleep 1
-+	done
-+
-+	echo "timeout waiting for recalc"
-+	return 1
-+}
-+
-+aux lvmconf \
-+        'activation/raid_fault_policy = "allocate"'
-+
-+aux prepare_dmeventd
-+
-+# raid1, one device fails, dmeventd calls repair
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
-+lvcreate --type raid1 -m 2 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
-+lvchange --monitor y $vg/$lv1
-+lvs -a -o+devices $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+aux wait_for_sync $vg $lv1
-+_add_new_data_to_mnt
-+
-+aux disable_dev "$dev2"
-+
-+# wait for dmeventd to call lvconvert --repair which should
-+# replace dev2 with dev4
-+sleep 5
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev2" out
-+grep "$dev4" out
-+
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+
-+aux enable_dev "$dev2"
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev2" out
-+grep "$dev4" out
-+grep "$dev1" out
-+grep "$dev3" out
-+
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# raid1, two devices fail, dmeventd calls repair
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-+lvcreate --type raid1 -m 2 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
-+lvchange --monitor y $vg/$lv1
-+lvs -a -o+devices $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+aux wait_for_sync $vg $lv1
-+_add_new_data_to_mnt
-+
-+aux disable_dev "$dev2"
-+aux disable_dev "$dev1"
-+
-+# wait for dmeventd to call lvconvert --repair which should
-+# replace dev1 and dev2 with dev4 and dev5
-+sleep 5
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev1" out
-+not grep "$dev2" out
-+grep "$dev4" out
-+grep "$dev5" out
-+grep "$dev3" out
-+
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+
-+aux enable_dev "$dev1"
-+aux enable_dev "$dev2"
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev1" out
-+not grep "$dev2" out
-+grep "$dev4" out
-+grep "$dev5" out
-+grep "$dev3" out
-+
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# raid6, one device fails, dmeventd calls repair
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
-+lvcreate --type raid6 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-+lvchange --monitor y $vg/$lv1
-+lvs -a -o+devices $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+_wait_recalc $vg/${lv1}_rimage_3
-+_wait_recalc $vg/${lv1}_rimage_4
-+aux wait_for_sync $vg $lv1
-+_add_new_data_to_mnt
-+
-+aux disable_dev "$dev2"
-+
-+# wait for dmeventd to call lvconvert --repair which should
-+# replace dev2 with dev6
-+sleep 5
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev2" out
-+grep "$dev6" out
-+
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+
-+aux enable_dev "$dev2"
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev2" out
-+grep "$dev6" out
-+
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# raid10, one device fails, dmeventd calls repair
-+
-+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-+lvcreate --type raid10 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4"
-+lvchange --monitor y $vg/$lv1
-+lvs -a -o+devices $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+_wait_recalc $vg/${lv1}_rimage_3
-+aux wait_for_sync $vg $lv1
-+_add_new_data_to_mnt
-+
-+aux disable_dev "$dev1"
-+
-+# wait for dmeventd to call lvconvert --repair which should
-+# replace dev1 with dev5
-+sleep 5
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev1" out
-+grep "$dev5" out
-+
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+
-+aux enable_dev "$dev1"
-+
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev1" out
-+grep "$dev5" out
-+
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh
-new file mode 100644
-index 0000000..0c36e4d
---- /dev/null
-+++ b/test/shell/integrity-large.sh
-@@ -0,0 +1,175 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+# Test writecache usage
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+which mkfs.xfs || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+# raid1 LV needs to be extended to 512MB to test imeta being exended
-+aux prepare_devs 4 600
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_prepare_vg() {
-+	vgcreate $SHARED $vg "$dev1" "$dev2"
-+	pvs
-+}
-+
-+_add_data_to_lv() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp randA $mnt
-+	cp randB $mnt
-+	cp randC $mnt
-+	mkdir $mnt/1
-+	cp fileA $mnt/1
-+	cp fileB $mnt/1
-+	cp fileC $mnt/1
-+	mkdir $mnt/2
-+	cp fileA $mnt/2
-+	cp fileB $mnt/2
-+	cp fileC $mnt/2
-+
-+	umount $mnt
-+}
-+
-+_verify_data_on_lv() {
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+
-+	umount $mnt
-+}
-+
-+_sync_percent() {
-+	local checklv=$1
-+	get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+	local checklv=$1
-+
-+	for i in $(seq 1 10) ; do
-+		sync=$(_sync_percent "$checklv")
-+		echo "sync_percent is $sync"
-+
-+		if test "$sync" = "100"; then
-+			return
-+		fi
-+
-+		sleep 1
-+	done
-+
-+	echo "timeout waiting for recalc"
-+	return 1
-+}
-+
-+# lvextend to 512MB is needed for the imeta LV to
-+# be extended from 4MB to 8MB.
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvchange -an $vg/$lv1
-+lvchange -ay $vg/$lv1
-+_add_data_to_lv
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_verify_data_on_lv
-+lvchange -an $vg/$lv1
-+lvextend -L 512M $vg/$lv1
-+lvs -a -o+devices $vg
-+lvchange -ay $vg/$lv1
-+_verify_data_on_lv
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+check lv_field $vg/${lv1}_rimage_0_imeta size "8.00m"
-+check lv_field $vg/${lv1}_rimage_1_imeta size "8.00m"
-+
-+# provide space to extend the images onto new devs
-+vgextend $vg "$dev3" "$dev4"
-+
-+# extending the images is possible using dev3,dev4
-+# but extending imeta on the existing dev1,dev2 fails
-+not lvextend -L +512M $vg/$lv1
-+
-+# removing integrity will permit extending the images
-+# using dev3,dev4 since imeta limitation is gone
-+lvconvert --raidintegrity n $vg/$lv1
-+lvextend -L +512M $vg/$lv1
-+lvs -a -o+devices $vg
-+
-+# adding integrity again will allocate new 12MB imeta LVs
-+# on dev3,dev4
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+check lv_field $vg/${lv1}_rimage_0_imeta size "12.00m"
-+check lv_field $vg/${lv1}_rimage_1_imeta size "12.00m"
-+
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+
-+# this succeeds because dev1,dev2 can hold rmeta+rimage
-+lvcreate --type raid1 -n $lv1 -L 592M -an $vg "$dev1" "$dev2"
-+
-+# this fails because dev1,dev2 can hold rmeta+rimage, but not imeta
-+# and we require imeta to be on same devs as rmeta/rimeta
-+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 592M -an $vg "$dev1" "$dev2"
-+lvs -a -o+devices $vg
-+lvremove $vg/$lv1
-+
-+# this can allocate from more devs so there's enough space for imeta to
-+# be allocated in the vg, but lvcreate fails because rmeta+rimage are
-+# allocated from dev1,dev2, we restrict imeta to being allocated on the
-+# same devs as rmeta/rimage, and dev1,dev2 can't fit imeta.
-+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 592M -an $vg
-+lvs -a -o+devices $vg
-+
-+# counterintuitively, increasing the size will allow lvcreate to succeed
-+# because rmeta+rimage are pushed to being allocated on dev1,dev2,dev3,dev4
-+# which means imeta is now free to be allocated from dev3,dev4 which have
-+# plenty of space
-+lvcreate --type raid1 --raidintegrity y -n $lv1 -L 600M -an $vg
-+lvs -a -o+devices $vg
-+
-+vgremove -ff $vg
-+
-diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh
-new file mode 100644
-index 0000000..73b0a67
---- /dev/null
-+++ b/test/shell/integrity-misc.sh
-@@ -0,0 +1,228 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+which mkfs.xfs || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+aux prepare_devs 5 64
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_prepare_vg() {
-+	vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-+	pvs
-+}
-+
-+_add_new_data_to_mnt() {
-+        mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+        mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+        # add original data
-+        cp randA $mnt
-+        cp randB $mnt
-+        cp randC $mnt
-+        mkdir $mnt/1
-+        cp fileA $mnt/1
-+        cp fileB $mnt/1
-+        cp fileC $mnt/1
-+        mkdir $mnt/2
-+        cp fileA $mnt/2
-+        cp fileB $mnt/2
-+        cp fileC $mnt/2
-+}
-+
-+_add_more_data_to_mnt() {
-+        mkdir $mnt/more
-+        cp fileA $mnt/more
-+        cp fileB $mnt/more
-+        cp fileC $mnt/more
-+        cp randA $mnt/more
-+        cp randB $mnt/more
-+        cp randC $mnt/more
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_data_on_lv() {
-+        lvchange -ay $vg/$lv1
-+        mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+        _verify_data_on_mnt
-+        rm $mnt/randA
-+        rm $mnt/randB
-+        rm $mnt/randC
-+        rm -rf $mnt/1
-+        rm -rf $mnt/2
-+        umount $mnt
-+        lvchange -an $vg/$lv1
-+}
-+
-+_sync_percent() {
-+	local checklv=$1
-+	get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+	local checklv=$1
-+
-+	for i in $(seq 1 10) ; do
-+		sync=$(_sync_percent "$checklv")
-+		echo "sync_percent is $sync"
-+
-+		if test "$sync" = "100"; then
-+			return
-+		fi
-+
-+		sleep 1
-+	done
-+
-+	echo "timeout waiting for recalc"
-+	return 1
-+}
-+
-+# lvrename
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+umount $mnt
-+lvrename $vg/$lv1 $vg/$lv2
-+mount "$DM_DEV_DIR/$vg/$lv2" $mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv2
-+lvremove $vg/$lv2
-+vgremove -ff $vg
-+
-+# lvconvert --replace
-+# an existing dev is replaced with another dev
-+# lv must be active
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
-+lvs -a -o+devices $vg > out
-+cat out
-+grep "$dev2" out
-+grep "$dev3" out
-+not grep "$dev1" out
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# lvconvert --replace
-+# same as prev but with bitmap mode
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
-+lvs -a -o+devices $vg > out
-+cat out
-+grep "$dev2" out
-+grep "$dev3" out
-+not grep "$dev1" out
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# lvconvert --repair
-+# while lv is active a device goes missing (with rimage,rmeta,imeta,orig).
-+# lvconvert --repair should replace the missing dev with another,
-+# (like lvconvert --replace does for a dev that's not missing).
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+aux disable_dev "$dev2"
-+lvs -a -o+devices $vg > out
-+cat out
-+grep unknown out
-+lvconvert -vvvv -y --repair $vg/$lv1
-+lvs -a -o+devices $vg > out
-+cat out
-+not grep "$dev2" out
-+not grep unknown out
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+aux enable_dev "$dev2"
-+vgremove -ff $vg
-+
-+# lvchange activationmode
-+# a device is missing (with rimage,rmeta,imeta,iorig), the lv
-+# is already inactive, and it cannot be activated, with
-+# activationmode degraded or partial, or in any way,
-+# until integrity is removed.
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+aux disable_dev "$dev2"
-+lvs -a -o+devices $vg
-+not lvchange -ay $vg/$lv1
-+not lvchange -ay --activationmode degraded $vg/$lv1
-+not lvchange -ay --activationmode partial $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvchange -ay --activationmode degraded $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvremove $vg/$lv1
-+aux enable_dev "$dev2"
-+vgremove -ff $vg
-+
-diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh
-new file mode 100644
-index 0000000..7e4f2cb
---- /dev/null
-+++ b/test/shell/integrity.sh
-@@ -0,0 +1,735 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+aux have_integrity 1 5 0 || skip
-+which mkfs.xfs || skip
-+which xfs_growfs || skip
-+
-+mnt="mnt"
-+mkdir -p $mnt
-+
-+aux prepare_devs 5 64
-+
-+for i in `seq 1 16384`; do echo -n "A" >> fileA; done
-+for i in `seq 1 16384`; do echo -n "B" >> fileB; done
-+for i in `seq 1 16384`; do echo -n "C" >> fileC; done
-+
-+# generate random data
-+dd if=/dev/urandom of=randA bs=512K count=2
-+dd if=/dev/urandom of=randB bs=512K count=3
-+dd if=/dev/urandom of=randC bs=512K count=4
-+
-+_prepare_vg() {
-+	# zero devs so we are sure to find the correct file data
-+	# on the underlying devs when corrupting it
-+	dd if=/dev/zero of="$dev1" || true
-+	dd if=/dev/zero of="$dev2" || true
-+	dd if=/dev/zero of="$dev3" || true
-+	dd if=/dev/zero of="$dev4" || true
-+	dd if=/dev/zero of="$dev5" || true
-+	vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-+	pvs
-+}
-+
-+_test_fs_with_error() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp fileA $mnt
-+	cp fileB $mnt
-+	cp fileC $mnt
-+
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+
-+	# corrupt the original data on the underying dev
-+	# flip one bit in fileB, changing a 0x42 to 0x43
-+	# the bit is changed in the last 4096 byte block
-+	# of the file, so when reading back the file we
-+	# will get the first three 4096 byte blocks, for
-+	# a total of 12288 bytes before getting an error
-+	# on the last 4096 byte block.
-+	xxd "$dev1" > dev1.txt
-+	tac dev1.txt > dev1.rev
-+	sed -e '0,/4242 4242 4242 4242 4242 4242 4242 4242/ s/4242 4242 4242 4242 4242 4242 4242 4242/4242 4242 4242 4242 4242 4242 4242 4243/' dev1.rev > dev1.rev.bad
-+	tac dev1.rev.bad > dev1.bad
-+	xxd -r dev1.bad > "$dev1"
-+	rm dev1.txt dev1.rev dev1.rev.bad dev1.bad
-+
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# read complete fileA which was not corrupted
-+	dd if=$mnt/fileA of=tmp bs=1k
-+	ls -l tmp
-+	stat -c %s tmp
-+	diff fileA tmp
-+	rm tmp
-+
-+	# read partial fileB which was corrupted
-+	not dd if=$mnt/fileB of=tmp bs=1k
-+	ls -l tmp
-+	stat -c %s tmp | grep 12288
-+	not diff fileB tmp
-+	rm tmp
-+
-+	umount $mnt
-+}
-+
-+_test_fs_with_raid() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp fileA $mnt
-+	cp fileB $mnt
-+	cp fileC $mnt
-+
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+
-+	xxd "$dev1" > dev1.txt
-+	tac dev1.txt > dev1.rev
-+	sed -e '0,/4242 4242 4242 4242 4242 4242 4242 4242/ s/4242 4242 4242 4242 4242 4242 4242 4242/4242 4242 4242 4242 4242 4242 4242 4243/' dev1.rev > dev1.rev.bad
-+	tac dev1.rev.bad > dev1.bad
-+	xxd -r dev1.bad > "$dev1"
-+	rm dev1.txt dev1.rev dev1.rev.bad dev1.bad
-+
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# read complete fileA which was not corrupted
-+	dd if=$mnt/fileA of=tmp bs=1k
-+	ls -l tmp
-+	stat -c %s tmp | grep 16384
-+	diff fileA tmp
-+	rm tmp
-+
-+	# read complete fileB, corruption is corrected by raid
-+	dd if=$mnt/fileB of=tmp bs=1k
-+	ls -l tmp
-+	stat -c %s tmp | grep 16384
-+	diff fileB tmp
-+	rm tmp
-+
-+	umount $mnt
-+}
-+
-+_add_new_data_to_mnt() {
-+	mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
-+
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+
-+	# add original data
-+	cp randA $mnt
-+	cp randB $mnt
-+	cp randC $mnt
-+	mkdir $mnt/1
-+	cp fileA $mnt/1
-+	cp fileB $mnt/1
-+	cp fileC $mnt/1
-+	mkdir $mnt/2
-+	cp fileA $mnt/2
-+	cp fileB $mnt/2
-+	cp fileC $mnt/2
-+}
-+
-+_add_more_data_to_mnt() {
-+	mkdir $mnt/more
-+	cp fileA $mnt/more
-+	cp fileB $mnt/more
-+	cp fileC $mnt/more
-+	cp randA $mnt/more
-+	cp randB $mnt/more
-+	cp randC $mnt/more
-+}
-+
-+_verify_data_on_mnt() {
-+	diff randA $mnt/randA
-+	diff randB $mnt/randB
-+	diff randC $mnt/randC
-+	diff fileA $mnt/1/fileA
-+	diff fileB $mnt/1/fileB
-+	diff fileC $mnt/1/fileC
-+	diff fileA $mnt/2/fileA
-+	diff fileB $mnt/2/fileB
-+	diff fileC $mnt/2/fileC
-+}
-+
-+_verify_data_on_lv() {
-+	lvchange -ay $vg/$lv1
-+	mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+	_verify_data_on_mnt
-+	rm $mnt/randA
-+	rm $mnt/randB
-+	rm $mnt/randC
-+	rm -rf $mnt/1
-+	rm -rf $mnt/2
-+	umount $mnt
-+	lvchange -an $vg/$lv1
-+}
-+
-+_sync_percent() {
-+	local checklv=$1
-+	get lv_field "$checklv" sync_percent | cut -d. -f1
-+}
-+
-+_wait_recalc() {
-+	local checklv=$1
-+
-+	for i in $(seq 1 10) ; do
-+		sync=$(_sync_percent "$checklv")
-+		echo "sync_percent is $sync"
-+
-+		if test "$sync" = "100"; then
-+			return
-+		fi
-+
-+		sleep 1
-+	done
-+
-+	echo "timeout waiting for recalc"
-+	return 1
-+}
-+
-+# Test corrupting data on an image and verifying that
-+# it is detected by integrity and corrected by raid.
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid4 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test removing integrity from an active LV
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid4 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test adding integrity to an active LV
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid4 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid5 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid6 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid10 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test lvextend while inactive
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvextend -l 16 $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+xfs_growfs $mnt
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+lvextend -l 16 $vg/$lv1
-+lvchange -ay $vg/$lv1
-+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
-+xfs_growfs $mnt
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test lvextend while active
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvextend -l 16 $vg/$lv1
-+xfs_growfs $mnt
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvextend -l 16 $vg/$lv1
-+xfs_growfs $mnt
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvextend -l 16 $vg/$lv1
-+xfs_growfs $mnt
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test adding image to raid1
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvconvert -y -m+1 $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test removing image from raid1
-+
-+_prepare_vg
-+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvconvert -y -m-1 $vg/$lv1
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test disallowed operations on raid+integrity
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+not lvconvert -y -m-1 $vg/$lv1
-+not lvconvert --splitmirrors 1 -n tmp -y $vg/$lv1
-+not lvconvert --splitmirrors 1 --trackchanges -y $vg/$lv1
-+not lvchange --syncaction check $vg/$lv1
-+not lvchange --syncaction repair $vg/$lv1
-+not lvreduce -L4M $vg/$lv1
-+not lvcreate -s -n snap -L4M $vg/$lv1
-+not pvmove -n $vg/$lv1 "$dev1"
-+not pvmove "$dev1"
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Repeat many of the tests above using bitmap mode
-+
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+_prepare_vg
-+lvcreate --type raid6 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg
-+_test_fs_with_raid
-+lvchange -an $vg/$lv1
-+lvconvert --raidintegrity n $vg/$lv1
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# remove from active lv
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity n $vg/$lv1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# add to active lv
-+_prepare_vg
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+_add_new_data_to_mnt
-+lvconvert --raidintegrity y --raidintegritymode bitmap $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# lvextend active
-+_prepare_vg
-+lvcreate --type raid1 --raidintegrity y --raidintegritymode bitmap -m1 -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvextend -l 16 $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+xfs_growfs $mnt
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# add image to raid1
-+_prepare_vg
-+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+lvs -a -o+devices $vg
-+_add_new_data_to_mnt
-+lvconvert -y -m+1 $vg/$lv1
-+_wait_recalc $vg/${lv1}_rimage_0
-+_wait_recalc $vg/${lv1}_rimage_1
-+_wait_recalc $vg/${lv1}_rimage_2
-+lvs -a -o+devices $vg
-+_add_more_data_to_mnt
-+_verify_data_on_mnt
-+umount $mnt
-+lvchange -an $vg/$lv1
-+_verify_data_on_lv
-+lvremove $vg/$lv1
-+vgremove -ff $vg
-+
-+# Test that raid+integrity cannot be a sublv
-+# part1: cannot add integrity to a raid LV that is already a sublv
-+
-+_prepare_vg
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvconvert -y --type thin-pool $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_tdata
-+not lvconvert --raidintegrity y $vg/${lv1}_tmeta
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvconvert -y --type cache-pool $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_cdata
-+not lvconvert --raidintegrity y $vg/${lv1}_cmeta
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate --type cache-pool -n cpool -l 8 $vg
-+lvconvert -y --type cache --cachepool cpool $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_corig
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate --type raid1 -m1 -n cvol -l 8 $vg
-+lvconvert -y --type cache --cachevol cvol $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_corig
-+not lvconvert --raidintegrity y $vg/cvol
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate -n cvol -l 8 $vg
-+lvchange -an $vg
-+lvconvert -y --type writecache --cachevol cvol $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_wcorig
-+lvremove -y $vg/$lv1
-+
-+# Test that raid+integrity cannot be a sublv
-+# part2: cannot convert an existing raid+integrity LV into a sublv
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvconvert -y --type thin-pool $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_tdata
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate --type raid1 -m1 -n $lv2 -l 8 $vg
-+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_corig
-+not lvconvert --raidintegrity y $vg/${lv2}_vol
-+lvremove -y $vg/$lv1
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate --type raid1 -m1 -n $lv2 -l 8 $vg
-+lvconvert -y --type cache --cachepool $lv2 $vg/$lv1
-+not lvconvert --raidintegrity y $vg/${lv1}_corig
-+not lvconvert --raidintegrity y $vg/${lv2}_cpool_cdata
-+lvremove -y $vg/$lv1
-+
-+# cannot add integrity to raid that has a snapshot
-+
-+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
-+lvcreate -s -n $lv2 -l 8 $vg/$lv1
-+not lvconvert --raidintegrity y $vg/$lv1
-+lvremove -y $vg/$lv1
-+
-+vgremove -ff $vg
-diff --git a/tools/args.h b/tools/args.h
-index 999d891..d1f604b 100644
---- a/tools/args.h
-+++ b/tools/args.h
-@@ -512,6 +512,26 @@ arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0,
-     "This may be useful in VGs containing many PVs (this places limitations\n"
-     "on the ability to use vgsplit later.)\n")
- 
-+arg(raidintegrity_ARG, '\0', "raidintegrity", bool_VAL, 0, 0,
-+    "Enable or disable data integrity checksums for raid images.\n")
-+
-+arg(raidintegrityblocksize_ARG, '\0', "raidintegrityblocksize", number_VAL, 0, 0,
-+    "The block size to use for dm-integrity on raid images.\n"
-+    "The integrity block size should usually match the device\n"
-+    "logical block size, or the file system block size.\n"
-+    "It may be less than the file system block size, but not\n"
-+    "less than the device logical block size.\n"
-+    "Possible values: 512, 1024, 2048, 4096.\n")
-+
-+arg(raidintegritymode_ARG, '\0', "raidintegritymode", string_VAL, 0, 0,
-+    "Use a journal (default) or bitmap for keeping integrity checksums consistent\n"
-+    "in case of a crash. The bitmap areas are recalculated after a crash, so corruption\n"
-+    "in those areas would not be detected. A journal does not have this problem.\n"
-+    "The journal mode doubles writes to storage, but can improve performance for\n"
-+    "scattered writes packed into a single journal write.\n"
-+    "bitmap mode can in theory achieve full write throughput of the device,\n"
-+    "but would not benefit from the potential scattered write optimization.\n")
-+
- arg(readonly_ARG, '\0', "readonly", 0, 0, 0,
-     "Run the command in a special read-only mode which will read on-disk\n"
-     "metadata without needing to take any locks. This can be used to peek\n"
-diff --git a/tools/command-lines.in b/tools/command-lines.in
-index 37a01cb..ed3d041 100644
---- a/tools/command-lines.in
-+++ b/tools/command-lines.in
-@@ -262,7 +262,7 @@ IO: --ignoreskippedcluster
- ID: lvchange_resync
- DESC: Resyncronize a mirror or raid LV.
- DESC: Use to reset 'R' attribute on a not initially synchronized LV.
--RULE: all not lv_is_pvmove lv_is_locked
-+RULE: all not lv_is_pvmove lv_is_locked lv_is_raid_with_integrity
- RULE: all not LV_raid0
- 
- lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
-@@ -359,7 +359,7 @@ OP: PV ...
- ID: lvconvert_raid_types
- DESC: Convert LV to raid or change raid layout
- DESC: (a specific raid level must be used, e.g. raid1).
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- 
- lvconvert --mirrors SNumber LV
- OO: --regionsize RegionSize, --interval Number, --mirrorlog MirrorLog, OO_LVCONVERT
-@@ -373,21 +373,21 @@ OO: OO_LVCONVERT, --interval Number, --regionsize RegionSize, --stripesize SizeK
- OP: PV ...
- ID: lvconvert_raid_types
- DESC: Convert raid LV to change number of stripe images.
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- RULE: all not LV_raid0 LV_raid1
- 
- lvconvert --stripesize SizeKB LV_raid
- OO: OO_LVCONVERT, --interval Number, --regionsize RegionSize
- ID: lvconvert_raid_types
- DESC: Convert raid LV to change the stripe size.
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- RULE: all not LV_raid0 LV_raid1
- 
- lvconvert --regionsize RegionSize LV_raid
- OO: OO_LVCONVERT
- ID: lvconvert_change_region_size
- DESC: Change the region size of an LV.
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- RULE: all not LV_raid0
- FLAGS: SECONDARY_SYNTAX
- 
-@@ -401,20 +401,20 @@ OO: OO_LVCONVERT
- OP: PV ...
- ID: lvconvert_split_mirror_images
- DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- 
- lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
- OO: OO_LVCONVERT
- OP: PV ...
- ID: lvconvert_split_mirror_images
- DESC: Split images from a raid1 LV and track changes to origin for later merge.
--RULE: all not lv_is_locked lv_is_pvmove
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_raid_with_integrity
- 
- lvconvert --mergemirrors LV_linear_raid|VG|Tag ...
- OO: OO_LVCONVERT
- ID: lvconvert_merge_mirror_images
- DESC: Merge LV images that were split from a raid1 LV.
--RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
-+RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow lv_is_raid_with_integrity
- 
- lvconvert --mirrorlog MirrorLog LV_mirror
- OO: OO_LVCONVERT
-@@ -434,7 +434,7 @@ OO: --thin, --originname LV_new, OO_LVCONVERT_POOL, OO_LVCONVERT
- ID: lvconvert_to_thin_with_external
- DESC: Convert LV to a thin LV, using the original LV as an external origin.
- RULE: all and lv_is_visible
--RULE: all not lv_is_locked
-+RULE: all not lv_is_locked lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- # alternate form of lvconvert --type thin
-@@ -445,7 +445,7 @@ DESC: Convert LV to a thin LV, using the original LV as an external origin
- DESC: (infers --type thin).
- FLAGS: SECONDARY_SYNTAX
- RULE: all and lv_is_visible
--RULE: all not lv_is_locked
-+RULE: all not lv_is_locked lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- ---
-@@ -455,6 +455,7 @@ OO: --cache, OO_LVCONVERT_CACHE, OO_LVCONVERT_POOL, OO_LVCONVERT
- ID: lvconvert_to_cache_with_cachepool
- DESC: Attach a cache pool to an LV, converts the LV to type cache.
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- # alternate form of lvconvert --type cache
-@@ -463,6 +464,7 @@ OO: --type cache, OO_LVCONVERT_CACHE, OO_LVCONVERT_POOL, OO_LVCONVERT
- ID: lvconvert_to_cache_with_cachepool
- DESC: Attach a cache pool to an LV (infers --type cache).
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- FLAGS: SECONDARY_SYNTAX
- 
-@@ -473,6 +475,7 @@ OO: OO_LVCONVERT, --cachesettings String
- ID: lvconvert_to_writecache
- DESC: Attach a writecache to an LV, converts the LV to type writecache.
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- 
- ---
- 
-@@ -481,6 +484,7 @@ OO: --cache, OO_LVCONVERT_CACHE, OO_LVCONVERT, --poolmetadatasize SizeMB, --chun
- ID: lvconvert_to_cache_with_cachevol
- DESC: Attach a cache to an LV, converts the LV to type cache.
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- 
- # alternate form of lvconvert --type cache
- lvconvert --cache --cachevol LV LV_linear_striped_raid_thinpool
-@@ -488,6 +492,7 @@ OO: OO_LVCONVERT_CACHE, OO_LVCONVERT, --poolmetadatasize SizeMB, --chunksize Siz
- ID: lvconvert_to_cache_with_cachevol
- DESC: Attach a cache to an LV, converts the LV to type cache.
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- FLAGS: SECONDARY_SYNTAX
- 
- ---
-@@ -499,7 +504,7 @@ OP: PV ...
- ID: lvconvert_to_thinpool
- DESC: Convert LV to type thin-pool.
- RULE: all and lv_is_visible
--RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual
-+RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- # This command syntax has two different meanings depending on
-@@ -533,6 +538,7 @@ DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
- DESC: Swap metadata LV in a thin pool (variant, use --swapmetadata).
- FLAGS: PREVIOUS_SYNTAX
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- ---
-@@ -543,6 +549,7 @@ OP: PV ...
- ID: lvconvert_to_cachepool
- DESC: Convert LV to type cache-pool.
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
-+RULE: all not lv_is_raid_with_integrity
- 
- # This command syntax has two different meanings depending on
- # whether the LV pos arg is already a cache pool or not.
-@@ -574,6 +581,7 @@ DESC: Convert LV to type cache-pool (variant, use --type cache-pool).
- DESC: Swap metadata LV in a cache pool (variant, use --swapmetadata).
- FLAGS: PREVIOUS_SYNTAX
- RULE: all and lv_is_visible
-+RULE: all not lv_is_raid_with_integrity
- RULE: --poolmetadata not --readahead --stripesize --stripes_long
- 
- ---
-@@ -583,7 +591,7 @@ OO: --name LV_new, --virtualsize SizeMB, --compression Bool, --deduplication Boo
- ID: lvconvert_to_vdopool
- DESC: Convert LV to type vdopool.
- RULE: all and lv_is_visible
--RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual
-+RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual lv_is_raid_with_integrity
- 
- lvconvert --vdopool LV_linear_striped_raid_cache
- OO: --type vdo-pool, OO_LVCONVERT,
-@@ -591,7 +599,7 @@ OO: --type vdo-pool, OO_LVCONVERT,
- ID: lvconvert_to_vdopool_param
- DESC: Convert LV to type vdopool.
- RULE: all and lv_is_visible
--RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual
-+RULE: all not lv_is_locked lv_is_origin lv_is_merging_origin lv_is_external_origin lv_is_virtual lv_is_raid_with_integrity
- FLAGS: SECONDARY_SYNTAX
- 
- ---
-@@ -757,6 +765,14 @@ FLAGS: SECONDARY_SYNTAX
- 
- ---
- 
-+lvconvert --raidintegrity Bool LV_raid
-+OO: --raidintegritymode String, --raidintegrityblocksize Number, OO_LVCONVERT
-+OP: PV ...
-+ID: lvconvert_integrity
-+DESC: Add or remove data integrity checksums to raid images.
-+
-+---
-+
- # --extents is not specified; it's an automatic alternative for --size
- 
- OO_LVCREATE: --addtag Tag, --alloc Alloc, --autobackup Bool, --activate Active,
-@@ -870,7 +886,8 @@ DESC: Create a raid1 or mirror LV (infers --type raid1|mirror).
- # R9,R10,R11,R12 (--type raid with any use of --stripes/--mirrors)
- lvcreate --type raid --size SizeMB VG
- OO: --mirrors PNumber, --stripes Number, --stripesize SizeKB,
----regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB, OO_LVCREATE
-+--regionsize RegionSize, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
-+--raidintegrity Bool, --raidintegritymode String, --raidintegrityblocksize Number, OO_LVCREATE
- OP: PV ...
- ID: lvcreate_raid_any
- DESC: Create a raid LV (a specific raid level must be used, e.g. raid1).
-diff --git a/tools/lv_props.h b/tools/lv_props.h
-index 2925028..60c8c73 100644
---- a/tools/lv_props.h
-+++ b/tools/lv_props.h
-@@ -52,5 +52,6 @@ lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
- lvp(is_visible_LVP, "lv_is_visible", NULL)
- lvp(is_historical_LVP, "lv_is_historical", NULL)
- lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
-+lvp(is_raid_with_integrity_LVP, "lv_is_raid_with_integrity", NULL)
- lvp(LVP_COUNT, "", NULL)
- 
-diff --git a/tools/lv_types.h b/tools/lv_types.h
-index 778cd54..d1c94cc 100644
---- a/tools/lv_types.h
-+++ b/tools/lv_types.h
-@@ -34,5 +34,6 @@ lvt(raid10_LVT, "raid10", NULL)
- lvt(error_LVT, "error", NULL)
- lvt(zero_LVT, "zero", NULL)
- lvt(writecache_LVT, "writecache", NULL)
-+lvt(integrity_LVT, "integrity", NULL)
- lvt(LVT_COUNT, "", NULL)
- 
-diff --git a/tools/lvchange.c b/tools/lvchange.c
-index 5f0fcab..2d5bb32 100644
---- a/tools/lvchange.c
-+++ b/tools/lvchange.c
-@@ -1573,6 +1573,11 @@ static int _lvchange_syncaction_single(struct cmd_context *cmd,
- 				       struct logical_volume *lv,
- 				       struct processing_handle *handle)
- {
-+	if (lv_raid_has_integrity(lv)) {
-+		log_error("Integrity must be removed to use syncaction commands.");
-+		return_ECMD_FAILED;
-+	}
-+
- 	/* If LV is inactive here, ensure it's not active elsewhere. */
- 	if (!lockd_lv(cmd, lv, "ex", 0))
- 		return_ECMD_FAILED;
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index bb40930..e969b44 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -1391,11 +1391,23 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 					  DEFAULT_RAID1_MAX_IMAGES, lp->segtype->name, display_lvname(lv));
- 				return 0;
- 			}
-+			if (!seg_is_raid1(seg) && lv_raid_has_integrity(lv)) {
-+				log_error("Cannot add raid images with integrity for this raid level.");
-+				return 0;
-+			}
- 			if (!lv_raid_change_image_count(lv, lp->yes, image_count,
- 							(lp->region_size_supplied || !seg->region_size) ?
- 							lp->region_size : seg->region_size , lp->pvh))
- 				return_0;
- 
-+			if (lv_raid_has_integrity(lv)) {
-+				struct integrity_settings *isettings = NULL;
-+				if (!lv_get_raid_integrity_settings(lv, &isettings))
-+					return_0;
-+				if (!lv_add_integrity_to_raid(lv, isettings, lp->pvh, NULL))
-+					return_0;
-+			}
-+
- 			log_print_unless_silent("Logical volume %s successfully converted.",
- 						display_lvname(lv));
- 
-@@ -1425,6 +1437,12 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 			return 0;
- 		}
- 
-+		if (lv_raid_has_integrity(lv)) {
-+			/* FIXME: which conversions are happening here? */
-+			log_error("This conversion is not supported for raid with integrity.");
-+			return 0;
-+		}
-+
- 		/* FIXME This needs changing globally. */
- 		if (!arg_is_set(cmd, stripes_long_ARG))
- 			lp->stripes = 0;
-@@ -1444,6 +1462,12 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
- 	}
- 
- try_new_takeover_or_reshape:
-+	if (lv_raid_has_integrity(lv)) {
-+		/* FIXME: which conversions are happening here? */
-+		log_error("This conversion is not supported for raid with integrity.");
-+		return 0;
-+	}
-+
- 	if (!_raid4_conversion_supported(lv, lp))
- 		return 0;
- 
-@@ -5758,6 +5782,119 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
- 	return ret;
- }
- 
-+static int _lvconvert_integrity_remove(struct cmd_context *cmd, struct logical_volume *lv)
-+{
-+	struct volume_group *vg = lv->vg;
-+	int ret = 0;
-+
-+	if (!lv_is_integrity(lv) && !lv_is_raid(lv)) {
-+		log_error("LV does not have integrity.");
-+		return 0;
-+	}
-+
-+	/* ensure it's not active elsewhere. */
-+	if (!lockd_lv(cmd, lv, "ex", 0))
-+		return_0;
-+
-+	if (!archive(vg))
-+		return_0;
-+
-+	if (lv_is_raid(lv))
-+		ret = lv_remove_integrity_from_raid(lv);
-+	if (!ret)
-+		return_0;
-+
-+	backup(vg);
-+
-+	log_print_unless_silent("Logical volume %s has removed integrity.", display_lvname(lv));
-+	return 1;
-+}
-+
-+static int _lvconvert_integrity_add(struct cmd_context *cmd, struct logical_volume *lv,
-+				    struct integrity_settings *set)
-+{
-+	struct volume_group *vg = lv->vg;
-+	struct dm_list *use_pvh;
-+	int ret = 0;
-+
-+	/* ensure it's not active elsewhere. */
-+	if (!lockd_lv(cmd, lv, "ex", 0))
-+		return_0;
-+
-+	if (cmd->position_argc > 1) {
-+		/* First pos arg is required LV, remaining are optional PVs. */
-+		if (!(use_pvh = create_pv_list(cmd->mem, vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
-+			return_0;
-+	} else
-+		use_pvh = &vg->pvs;
-+
-+	if (!archive(vg))
-+		return_0;
-+
-+	if (lv_is_partial(lv)) {
-+		log_error("Cannot add integrity while LV is missing PVs.");
-+		return 0;
-+	}
-+
-+	if (lv_is_raid(lv))
-+		ret = lv_add_integrity_to_raid(lv, set, use_pvh, NULL);
-+	if (!ret)
-+		return_0;
-+
-+	backup(vg);
-+
-+	log_print_unless_silent("Logical volume %s has added integrity.", display_lvname(lv));
-+	return 1;
-+}
-+
-+static int _lvconvert_integrity_single(struct cmd_context *cmd,
-+					struct logical_volume *lv,
-+					struct processing_handle *handle)
-+{
-+	struct integrity_settings settings;
-+	int ret = 0;
-+
-+	memset(&settings, 0, sizeof(settings));
-+
-+	if (!integrity_mode_set(arg_str_value(cmd, raidintegritymode_ARG, NULL), &settings))
-+		return_ECMD_FAILED;
-+
-+	if (arg_is_set(cmd, raidintegrityblocksize_ARG))
-+		settings.block_size = arg_int_value(cmd, raidintegrityblocksize_ARG, 0);
-+
-+	if (arg_int_value(cmd, raidintegrity_ARG, 0))
-+		ret = _lvconvert_integrity_add(cmd, lv, &settings);
-+	else
-+		ret = _lvconvert_integrity_remove(cmd, lv);
-+
-+	if (!ret)
-+		return ECMD_FAILED;
-+	return ECMD_PROCESSED;
-+}
-+
-+int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv)
-+{
-+	struct processing_handle *handle;
-+	int ret;
-+
-+	if (!(handle = init_processing_handle(cmd, NULL))) {
-+		log_error("Failed to initialize processing handle.");
-+		return ECMD_FAILED;
-+	}
-+
-+	/* Want to be able to remove integrity from partial LV */
-+	cmd->handles_missing_pvs = 1;
-+
-+	cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
-+
-+	ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
-+			      &_lvconvert_integrity_single);
-+
-+	destroy_processing_handle(cmd, handle);
-+
-+	return ret;
-+}
-+
- /*
-  * All lvconvert command defs have their own function,
-  * so the generic function name is unused.
-diff --git a/tools/lvcreate.c b/tools/lvcreate.c
-index 448f125..5c978b3 100644
---- a/tools/lvcreate.c
-+++ b/tools/lvcreate.c
-@@ -858,7 +858,10 @@ static int _lvcreate_params(struct cmd_context *cmd,
- 	maxrecoveryrate_ARG,\
- 	minrecoveryrate_ARG,\
- 	raidmaxrecoveryrate_ARG,\
--	raidminrecoveryrate_ARG
-+	raidminrecoveryrate_ARG, \
-+	raidintegrity_ARG, \
-+	raidintegritymode_ARG, \
-+	raidintegrityblocksize_ARG
- 
- #define SIZE_ARGS \
- 	extents_ARG,\
-@@ -1227,6 +1230,16 @@ static int _lvcreate_params(struct cmd_context *cmd,
- 		}
- 	}
- 
-+	if (seg_is_raid(lp) && arg_int_value(cmd, raidintegrity_ARG, 0)) {
-+		lp->raidintegrity = 1;
-+		if (arg_is_set(cmd, raidintegrityblocksize_ARG))
-+			lp->integrity_settings.block_size = arg_int_value(cmd, raidintegrityblocksize_ARG, 0);
-+		if (arg_is_set(cmd, raidintegritymode_ARG)) {
-+			if (!integrity_mode_set(arg_str_value(cmd, raidintegritymode_ARG, NULL), &lp->integrity_settings))
-+				return_0;
-+		}
-+	}
-+
- 	lcp->pv_count = argc;
- 	lcp->pvs = argv;
- 
-diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
-index f147be3..d87a8f0 100644
---- a/tools/lvmcmdline.c
-+++ b/tools/lvmcmdline.c
-@@ -149,6 +149,9 @@ static const struct command_function _command_functions[CMD_COUNT] = {
- 	{ lvconvert_to_vdopool_CMD, lvconvert_to_vdopool_cmd },
- 	{ lvconvert_to_vdopool_param_CMD, lvconvert_to_vdopool_param_cmd },
- 
-+	/* lvconvert for integrity */
-+	{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
-+
- 	{ pvscan_display_CMD, pvscan_display_cmd },
- 	{ pvscan_cache_CMD, pvscan_cache_cmd },
- };
-diff --git a/tools/pvmove.c b/tools/pvmove.c
-index 0419a3d..a346b53 100644
---- a/tools/pvmove.c
-+++ b/tools/pvmove.c
-@@ -381,6 +381,11 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
- 			return NULL;
- 		}
- 
-+		if (lv_is_raid(lv) && lv_raid_has_integrity(lv)) {
-+			log_error("Unable to pvmove device used for raid with integrity.");
-+			return NULL;
-+		}
-+
- 		seg = first_seg(lv);
- 		if (!needs_exclusive) {
- 			/* Presence of exclusive LV decides whether pvmove must be also exclusive */
-@@ -625,6 +630,11 @@ static int _pvmove_setup_single(struct cmd_context *cmd,
- 			log_error("pvmove not allowed on LV using writecache.");
- 			return ECMD_FAILED;
- 		}
-+
-+		if (lv_is_raid(lv) && lv_raid_has_integrity(lv)) {
-+			log_error("pvmove not allowed on raid LV with integrity.");
-+			return ECMD_FAILED;
-+		}
- 	}
- 
- 	/*
-diff --git a/tools/toollib.c b/tools/toollib.c
-index 6386a69..96d0d6d 100644
---- a/tools/toollib.c
-+++ b/tools/toollib.c
-@@ -718,11 +718,26 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
- 	return 1;
- }
- 
-+int integrity_mode_set(const char *mode, struct integrity_settings *settings)
-+{
-+	if (!mode || !strcmp(mode, "bitmap") || !strcmp(mode, "B"))
-+		settings->mode[0] = 'B';
-+	else if (!strcmp(mode, "journal") || !strcmp(mode, "J"))
-+		settings->mode[0] = 'J';
-+	else {
-+		/* FIXME: the kernel has other modes, should we allow any of those? */
-+		log_error("Invalid raid integrity mode (use \"bitmap\" or \"journal\")");
-+		return 0;
-+	}
-+	return 1;
-+}
-+
- /* Shared code for changing activation state for vgchange/lvchange */
- int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv,
- 		       activation_change_t activate)
- {
- 	int r = 1;
-+	int integrity_recalculate;
- 	struct logical_volume *snapshot_lv;
- 
- 	if (lv_is_cache_pool(lv)) {
-@@ -780,9 +795,34 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv,
- 		return 0;
- 	}
- 
-+	if ((integrity_recalculate = lv_has_integrity_recalculate_metadata(lv))) {
-+		/* Don't want pvscan to write VG while running from systemd service. */
-+		if (!strcmp(cmd->name, "pvscan")) {
-+			log_error("Cannot activate uninitialized integrity LV %s from pvscan.",
-+				  display_lvname(lv));
-+			return 0;
-+		}
-+
-+		if (vg_is_shared(lv->vg)) {
-+			uint32_t lockd_state = 0;
-+			if (!lockd_vg(cmd, lv->vg->name, "ex", 0, &lockd_state)) {
-+				log_error("Cannot activate uninitialized integrity LV %s without lock.",
-+					  display_lvname(lv));
-+				return 0;
-+			}
-+		}
-+	}
-+
- 	if (!lv_active_change(cmd, lv, activate))
- 		return_0;
- 
-+	/* Write VG metadata to clear the integrity recalculate flag. */
-+	if (integrity_recalculate && lv_is_active(lv)) {
-+		log_print_unless_silent("Updating VG to complete initialization of integrity LV %s.",
-+			  display_lvname(lv));
-+		lv_clear_integrity_recalculate_metadata(lv);
-+	}
-+
- 	set_lv_notify(lv->vg->cmd);
- 
- 	return r;
-@@ -1144,6 +1184,7 @@ out:
- 	return ok;
- }
- 
-+
- /* FIXME move to lib */
- static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
- {
-@@ -2255,6 +2296,8 @@ static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int l
- 		return lv_is_historical(lv);
- 	case is_raid_with_tracking_LVP:
- 		return lv_is_raid_with_tracking(lv);
-+	case is_raid_with_integrity_LVP:
-+		return lv_raid_has_integrity(lv);
- 	default:
- 		log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
- 	}
-@@ -2309,6 +2352,8 @@ static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int l
- 		return seg_is_raid10(seg);
- 	case writecache_LVT:
- 		return seg_is_writecache(seg);
-+	case integrity_LVT:
-+		return seg_is_integrity(seg);
- 	case error_LVT:
- 		return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR);
- 	case zero_LVT:
-@@ -2367,6 +2412,8 @@ int get_lvt_enum(struct logical_volume *lv)
- 		return raid10_LVT;
- 	if (seg_is_writecache(seg))
- 		return writecache_LVT;
-+	if (seg_is_integrity(seg))
-+		return integrity_LVT;
- 
- 	if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR))
- 		return error_LVT;
-diff --git a/tools/tools.h b/tools/tools.h
-index 3cf4293..7f2434d 100644
---- a/tools/tools.h
-+++ b/tools/tools.h
-@@ -212,6 +212,8 @@ unsigned grouped_arg_is_set(const struct arg_values *av, int a);
- const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def);
- int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def); 
- 
-+int integrity_mode_set(const char *mode, struct integrity_settings *settings);
-+
- const char *command_name(struct cmd_context *cmd);
- 
- int pvmove_poll(struct cmd_context *cmd, const char *pv_name, const char *uuid,
-@@ -274,6 +276,8 @@ int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);
- int lvconvert_to_vdopool_cmd(struct cmd_context *cmd, int argc, char **argv);
- int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **argv);
- 
-+int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
-+
- int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
- int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
- 
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-Fix-scripts-lvmlocks.service.in-using-nonexistent-lock-opt-autowait.patch b/SOURCES/lvm2-2_03_10-Fix-scripts-lvmlocks.service.in-using-nonexistent-lock-opt-autowait.patch
deleted file mode 100644
index 2eec67f..0000000
--- a/SOURCES/lvm2-2_03_10-Fix-scripts-lvmlocks.service.in-using-nonexistent-lock-opt-autowait.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 48105f492f7f8c157ba714217ae55c6fb50e76c0 Mon Sep 17 00:00:00 2001
-From: Maxim Plotnikov <wgh@torlan.ru>
-Date: Wed, 22 Apr 2020 00:16:29 +0300
-Subject: [PATCH] Fix scripts/lvmlocks.service.in using nonexistent --lock-opt
- autowait
-
-The --lock-opt autowait was dropped back in 9ab6bdce01,
-and attempting to specify it has quite an opposite effect:
-no waiting is done, which makes the unit almost useless.
-
-(cherry picked from commit a509776588a5c0c0bfc2394e4d1ed717531b0257)
----
- scripts/lvmlocks.service.in | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/scripts/lvmlocks.service.in b/scripts/lvmlocks.service.in
-index f6a951f..a3d0bd4 100644
---- a/scripts/lvmlocks.service.in
-+++ b/scripts/lvmlocks.service.in
-@@ -8,7 +8,7 @@ Type=oneshot
- RemainAfterExit=yes
- 
- # start lockspaces and wait for them to finish starting
--ExecStart=@SBINDIR@/lvm vgchange --lock-start --lock-opt autowait
-+ExecStart=@SBINDIR@/lvm vgchange --lock-start --lock-opt auto
- 
- # stop lockspaces and wait for them to finish stopping
- ExecStop=@SBINDIR@/lvmlockctl --stop-lockspaces --wait 1
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-WHATS_NEW-integrity-with-raid.patch b/SOURCES/lvm2-2_03_10-WHATS_NEW-integrity-with-raid.patch
deleted file mode 100644
index a0d68f4..0000000
--- a/SOURCES/lvm2-2_03_10-WHATS_NEW-integrity-with-raid.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From a08afc8d0d18b2547176e731852b816df76c63eb Mon Sep 17 00:00:00 2001
-From: David Teigland <teigland@redhat.com>
-Date: Wed, 15 Apr 2020 11:04:12 -0500
-Subject: [PATCH 3/3] WHATS_NEW: integrity with raid
-
-(cherry picked from commit 211eaa284c4df992916e0a523d0ff932aa790a98)
----
- WHATS_NEW | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/WHATS_NEW b/WHATS_NEW
-index 89583f7..c0267b7 100644
---- a/WHATS_NEW
-+++ b/WHATS_NEW
-@@ -1,5 +1,6 @@
- Version 2.03.10 - 
- =================================
-+  Add integrity with raid capability.
-   Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
- 
- Version 2.03.09 - 26th March 2020
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-WHATS_NEWS-update.patch b/SOURCES/lvm2-2_03_10-WHATS_NEWS-update.patch
deleted file mode 100644
index 82eb395..0000000
--- a/SOURCES/lvm2-2_03_10-WHATS_NEWS-update.patch
+++ /dev/null
@@ -1,15 +0,0 @@
- WHATS_NEW | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/WHATS_NEW b/WHATS_NEW
-index db914c0..89583f7 100644
---- a/WHATS_NEW
-+++ b/WHATS_NEW
-@@ -1,3 +1,7 @@
-+Version 2.03.10 - 
-+=================================
-+  Fix support for lvconvert --repair used by foreign apps (i.e. Docker).
-+
- Version 2.03.09 - 26th March 2020
- =================================
-   Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
diff --git a/SOURCES/lvm2-2_03_10-blkdeactivate-add-support-for-VDO-in-blkdeactivate-script.patch b/SOURCES/lvm2-2_03_10-blkdeactivate-add-support-for-VDO-in-blkdeactivate-script.patch
deleted file mode 100644
index 6abd26b..0000000
--- a/SOURCES/lvm2-2_03_10-blkdeactivate-add-support-for-VDO-in-blkdeactivate-script.patch
+++ /dev/null
@@ -1,179 +0,0 @@
- WHATS_NEW_DM                |  4 ++++
- man/blkdeactivate.8_main    | 11 +++++++++++
- scripts/blkdeactivate.sh.in | 48 ++++++++++++++++++++++++++++++++++++++++++++-
- 3 files changed, 62 insertions(+), 1 deletion(-)
-
-diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
-index 12bdcea..3ec9c3c 100644
---- a/WHATS_NEW_DM
-+++ b/WHATS_NEW_DM
-@@ -1,3 +1,7 @@
-+Version 1.02.173 - 
-+==================================
-+  Add support for VDO in blkdeactivate script.
-+
- Version 1.02.171 - 26th March 2020
- ==================================
-   Fix dm_list interators with gcc 10 optimization (-ftree-pta).
-diff --git a/man/blkdeactivate.8_main b/man/blkdeactivate.8_main
-index f3c19a8..06af52e 100644
---- a/man/blkdeactivate.8_main
-+++ b/man/blkdeactivate.8_main
-@@ -9,6 +9,7 @@ blkdeactivate \(em utility to deactivate block devices
- .RB [ -l \  \fIlvm_options\fP ]
- .RB [ -m \  \fImpath_options\fP ]
- .RB [ -r \  \fImdraid_options\fP ]
-+.RB [ -o \  \fIvdo_options\fP ]
- .RB [ -u ]
- .RB [ -v ]
- .RI [ device ]
-@@ -70,6 +71,15 @@ Comma-separated list of MD RAID specific options:
- Wait MD device's resync, recovery or reshape action to complete
- before deactivation.
- .RE
-+
-+.TP
-+.BR -o ", " --vdooptions \ \fIvdo_options\fP
-+Comma-separated list of VDO specific options:
-+.RS
-+.IP \fIconfigfile=file\fP
-+Use specified VDO configuration file.
-+.RE
-+
- .TP
- .BR -u ", " --umount
- Unmount a mounted device before trying to deactivate it.
-@@ -120,4 +130,5 @@ of a device-mapper device fails, retry it and force removal.
- .BR lvm (8),
- .BR mdadm (8),
- .BR multipathd (8),
-+.BR vdo (8),
- .BR umount (8)
-diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
-index a4b8a8f..57b3e58 100644
---- a/scripts/blkdeactivate.sh.in
-+++ b/scripts/blkdeactivate.sh.in
-@@ -1,6 +1,6 @@
- #!/bin/bash
- #
--# Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved.
-+# Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
- #
- # This file is part of LVM2.
- #
-@@ -38,6 +38,7 @@ MDADM="/sbin/mdadm"
- MOUNTPOINT="/bin/mountpoint"
- MPATHD="/sbin/multipathd"
- UMOUNT="/bin/umount"
-+VDO="/bin/vdo"
- 
- sbindir="@SBINDIR@"
- DMSETUP="$sbindir/dmsetup"
-@@ -54,6 +55,7 @@ DMSETUP_OPTS=""
- LVM_OPTS=""
- MDADM_OPTS=""
- MPATHD_OPTS=""
-+VDO_OPTS=""
- 
- LSBLK="/bin/lsblk -r --noheadings -o TYPE,KNAME,NAME,MOUNTPOINT"
- LSBLK_VARS="local devtype local kname local name local mnt"
-@@ -124,6 +126,7 @@ usage() {
- 	echo "    -l | --lvmoptions    LVM_OPTIONS    Comma separated LVM specific options"
- 	echo "    -m | --mpathoptions  MPATH_OPTIONS  Comma separated DM-multipath specific options"
- 	echo "    -r | --mdraidoptions MDRAID_OPTIONS Comma separated MD RAID specific options"
-+        echo "    -o | --vdooptions    VDO_OPTIONS    Comma separated VDO specific options"
- 	echo "    -u | --umount                       Unmount the device if mounted"
- 	echo "    -v | --verbose                      Verbose mode (also implies -e)"
- 	echo
-@@ -138,6 +141,8 @@ usage() {
- 	echo "      wait            wait for resync, recovery or reshape to complete first"
- 	echo "    MPATH_OPTIONS:"
- 	echo "      disablequeueing disable queueing on all DM-multipath devices first"
-+        echo "    VDO_OPTIONS:"
-+        echo "      configfile=file use specified VDO configuration file"
- 
- 	exit
- }
-@@ -319,6 +324,23 @@ deactivate_md () {
- 	fi
- }
- 
-+deactivate_vdo() {
-+        local xname
-+        xname=$(printf "%s" "$name")
-+        test -b "$DEV_DIR/mapper/$xname" || return 0
-+        test -z "${SKIP_DEVICE_LIST["$kname"]}" || return 1
-+
-+        deactivate_holders "$DEV_DIR/mapper/$xname" || return 1
-+
-+        echo -n "  [VDO]: deactivating VDO volume $xname... "
-+        if eval "$VDO" stop $VDO_OPTS --name="$xname" "$OUT" "$ERR"; then
-+                echo "done"
-+        else
-+                echo "skipping"
-+                add_device_to_skip_list
-+        fi
-+}
-+
- deactivate () {
- 	######################################################################
- 	# DEACTIVATION HOOKS FOR NEW DEVICE TYPES GO HERE!                   #
-@@ -335,6 +357,8 @@ deactivate () {
- 	######################################################################
- 	if test "$devtype" = "lvm"; then
- 		deactivate_lvm
-+        elif test "$devtype" = "vdo"; then
-+                deactivate_vdo
- 	elif test "${kname:0:3}" = "dm-"; then
- 		deactivate_dm
- 	elif test "${kname:0:2}" = "md"; then
-@@ -479,6 +503,20 @@ get_mpathopts() {
- 	IFS=$ORIG_IFS
- }
- 
-+get_vdoopts() {
-+        ORIG_IFS=$IFS; IFS=','
-+
-+        for opt in $1; do
-+                case "$opt" in
-+                        "") ;;
-+                        configfile=*) tmp=${opt#*=}; VDO_OPTS+="--confFile=${tmp%%,*} " ;;
-+                        *) echo "$opt: unknown VDO option"
-+                esac
-+        done
-+
-+        IFS=$ORIG_IFS
-+}
-+
- set_env() {
- 	if test "$ERRORS" -eq "1"; then
- 		unset ERR
-@@ -493,6 +531,7 @@ set_env() {
- 		LVM_OPTS+="-vvvv"
- 		MDADM_OPTS+="-vv"
- 		MPATHD_OPTS+="-v 3"
-+                VDO_OPTS+="--verbose "
- 	else
- 		OUT="1>$DEV_DIR/null"
- 	fi
-@@ -509,6 +548,12 @@ set_env() {
- 		MDADM_AVAILABLE=0
- 	fi
- 
-+        if test -f $VDO; then
-+                VDO_AVAILABLE=1
-+        else
-+                VDO_AVAILABLE=0
-+        fi
-+
- 	MPATHD_RUNNING=0
- 	test "$MPATHD_DO_DISABLEQUEUEING" -eq 1 && {
- 		if test -f "$MPATHD"; then
-@@ -528,6 +573,7 @@ while test $# -ne 0; do
- 		"-l"|"--lvmoptions") get_lvmopts "$2" ; shift ;;
- 		"-m"|"--mpathoptions") get_mpathopts "$2" ; shift ;;
- 		"-r"|"--mdraidoptions") get_mdraidopts "$2"; shift ;;
-+                "-o"|"--vdooptions") get_vdoopts "$2"; shift ;;
- 		"-u"|"--umount") DO_UMOUNT=1 ;;
- 		"-v"|"--verbose") VERBOSE=1 ; ERRORS=1 ;;
- 		"-vv") VERBOSE=1 ; ERRORS=1 ; set -x ;;
diff --git a/SOURCES/lvm2-2_03_10-build-make-generate.patch b/SOURCES/lvm2-2_03_10-build-make-generate.patch
deleted file mode 100644
index 4b76f58..0000000
--- a/SOURCES/lvm2-2_03_10-build-make-generate.patch
+++ /dev/null
@@ -1,180 +0,0 @@
-From 7def94164ae6c18d84e40f00db2e2b74a7662b35 Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Tue, 5 May 2020 10:20:18 +0200
-Subject: [PATCH] build: make generate
-
-(cherry picked from commit bcc149048440dce5fc7962f88ed523469dd39a32)
----
- man/lvconvert.8_pregen | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
- man/lvcreate.8_pregen  | 53 ++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 116 insertions(+)
-
-diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen
-index b676e72..7440984 100644
---- a/man/lvconvert.8_pregen
-+++ b/man/lvconvert.8_pregen
-@@ -163,6 +163,18 @@ lvconvert - Change logical volume layout
- .ad b
- .br
- .ad l
-+    \fB--raidintegrity\fP \fBy\fP|\fBn\fP
-+.ad b
-+.br
-+.ad l
-+    \fB--raidintegrityblocksize\fP \fINumber\fP
-+.ad b
-+.br
-+.ad l
-+    \fB--raidintegritymode\fP \fIString\fP
-+.ad b
-+.br
-+.ad l
-  \fB-r\fP|\fB--readahead\fP \fBauto\fP|\fBnone\fP|\fINumber\fP
- .ad b
- .br
-@@ -982,6 +994,28 @@ Poll LV to continue conversion.
- .br
- -
- 
-+Add or remove data integrity checksums to raid images.
-+.br
-+.P
-+\fBlvconvert\fP \fB--raidintegrity\fP \fBy\fP|\fBn\fP \fILV\fP\fI_raid\fP
-+.br
-+.RS 4
-+.ad l
-+[    \fB--raidintegritymode\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--raidintegrityblocksize\fP \fINumber\fP ]
-+.ad b
-+.br
-+[ COMMON_OPTIONS ]
-+.RE
-+.br
-+.RS 4
-+[ \fIPV\fP ... ]
-+.RE
-+-
-+
- Common options for command:
- .
- .RS 4
-@@ -1405,6 +1439,35 @@ Repeat once to also suppress any prompts with answer 'no'.
- .ad b
- .HP
- .ad l
-+\fB--raidintegrity\fP \fBy\fP|\fBn\fP
-+.br
-+Enable or disable data integrity checksums for raid images.
-+.ad b
-+.HP
-+.ad l
-+\fB--raidintegrityblocksize\fP \fINumber\fP
-+.br
-+The block size to use for dm-integrity on raid images.
-+The integrity block size should usually match the device
-+logical block size, or the file system block size.
-+It may be less than the file system block size, but not
-+less than the device logical block size.
-+Possible values: 512, 1024, 2048, 4096.
-+.ad b
-+.HP
-+.ad l
-+\fB--raidintegritymode\fP \fIString\fP
-+.br
-+Use a journal (default) or bitmap for keeping integrity checksums consistent
-+in case of a crash. The bitmap areas are recalculated after a crash, so corruption
-+in those areas would not be detected. A journal does not have this problem.
-+The journal mode doubles writes to storage, but can improve performance for
-+scattered writes packed into a single journal write.
-+bitmap mode can in theory achieve full write throughput of the device,
-+but would not benefit from the potential scattered write optimization.
-+.ad b
-+.HP
-+.ad l
- \fB-r\fP|\fB--readahead\fP \fBauto\fP|\fBnone\fP|\fINumber\fP
- .br
- Sets read ahead sector count of an LV.
-diff --git a/man/lvcreate.8_pregen b/man/lvcreate.8_pregen
-index a80f9f5..be8e783 100644
---- a/man/lvcreate.8_pregen
-+++ b/man/lvcreate.8_pregen
-@@ -187,6 +187,18 @@ lvcreate - Create a logical volume
- .ad b
- .br
- .ad l
-+    \fB--raidintegrity\fP \fBy\fP|\fBn\fP
-+.ad b
-+.br
-+.ad l
-+    \fB--raidintegrityblocksize\fP \fINumber\fP
-+.ad b
-+.br
-+.ad l
-+    \fB--raidintegritymode\fP \fIString\fP
-+.ad b
-+.br
-+.ad l
-  \fB-r\fP|\fB--readahead\fP \fBauto\fP|\fBnone\fP|\fINumber\fP
- .ad b
- .br
-@@ -425,6 +437,18 @@ Create a raid LV (a specific raid level must be used, e.g. raid1).
- [    \fB--[raid]maxrecoveryrate\fP \fISize\fP[k|UNIT] ]
- .ad b
- .br
-+.ad l
-+[    \fB--raidintegrity\fP \fBy\fP|\fBn\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--raidintegritymode\fP \fIString\fP ]
-+.ad b
-+.br
-+.ad l
-+[    \fB--raidintegrityblocksize\fP \fINumber\fP ]
-+.ad b
-+.br
- [ COMMON_OPTIONS ]
- .RE
- .br
-@@ -1420,6 +1444,35 @@ Repeat once to also suppress any prompts with answer 'no'.
- .ad b
- .HP
- .ad l
-+\fB--raidintegrity\fP \fBy\fP|\fBn\fP
-+.br
-+Enable or disable data integrity checksums for raid images.
-+.ad b
-+.HP
-+.ad l
-+\fB--raidintegrityblocksize\fP \fINumber\fP
-+.br
-+The block size to use for dm-integrity on raid images.
-+The integrity block size should usually match the device
-+logical block size, or the file system block size.
-+It may be less than the file system block size, but not
-+less than the device logical block size.
-+Possible values: 512, 1024, 2048, 4096.
-+.ad b
-+.HP
-+.ad l
-+\fB--raidintegritymode\fP \fIString\fP
-+.br
-+Use a journal (default) or bitmap for keeping integrity checksums consistent
-+in case of a crash. The bitmap areas are recalculated after a crash, so corruption
-+in those areas would not be detected. A journal does not have this problem.
-+The journal mode doubles writes to storage, but can improve performance for
-+scattered writes packed into a single journal write.
-+bitmap mode can in theory achieve full write throughput of the device,
-+but would not benefit from the potential scattered write optimization.
-+.ad b
-+.HP
-+.ad l
- \fB-r\fP|\fB--readahead\fP \fBauto\fP|\fBnone\fP|\fINumber\fP
- .br
- Sets read ahead sector count of an LV.
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-lvconvert-no-validation-for-thin-pools-not-used-by-lvm.patch b/SOURCES/lvm2-2_03_10-lvconvert-no-validation-for-thin-pools-not-used-by-lvm.patch
deleted file mode 100644
index 90ca054..0000000
--- a/SOURCES/lvm2-2_03_10-lvconvert-no-validation-for-thin-pools-not-used-by-lvm.patch
+++ /dev/null
@@ -1,17 +0,0 @@
- tools/lvconvert.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/tools/lvconvert.c b/tools/lvconvert.c
-index f6d9a29..bb40930 100644
---- a/tools/lvconvert.c
-+++ b/tools/lvconvert.c
-@@ -2388,7 +2388,8 @@ static int _lvconvert_thin_pool_repair(struct cmd_context *cmd,
- 		goto deactivate_mlv;
- 	}
- 
--	if (thin_dump[0]) {
-+	/* Check matching transactionId when thin-pool is used by lvm2 (transactionId != 0) */
-+	if (first_seg(pool_lv)->transaction_id && thin_dump[0]) {
- 		argv[0] = thin_dump;
- 		argv[1] = pms_path;
- 		argv[2] = NULL;
diff --git a/SOURCES/lvm2-2_03_10-move-pv_list-code-into-lib.patch b/SOURCES/lvm2-2_03_10-move-pv_list-code-into-lib.patch
deleted file mode 100644
index ad900bb..0000000
--- a/SOURCES/lvm2-2_03_10-move-pv_list-code-into-lib.patch
+++ /dev/null
@@ -1,641 +0,0 @@
-From 945de675c47d891d1f181f15971d26ff959ac631 Mon Sep 17 00:00:00 2001
-From: David Teigland <teigland@redhat.com>
-Date: Tue, 14 Jan 2020 14:12:20 -0600
-Subject: [PATCH 1/3] move pv_list code into lib
-
-(cherry picked from commit b6b4ad8e28eff7476cb04c4cb93312b06605b82f)
----
- lib/Makefile.in                  |   1 +
- lib/metadata/metadata-exported.h |   4 +
- lib/metadata/pv_list.c           | 291 +++++++++++++++++++++++++++++++++++++++
- tools/toollib.c                  | 270 ------------------------------------
- tools/toollib.h                  |   9 --
- 5 files changed, 296 insertions(+), 279 deletions(-)
- create mode 100644 lib/metadata/pv_list.c
-
-diff --git a/lib/Makefile.in b/lib/Makefile.in
-index c037b41..2a064f3 100644
---- a/lib/Makefile.in
-+++ b/lib/Makefile.in
-@@ -74,6 +74,7 @@ SOURCES =\
- 	metadata/mirror.c \
- 	metadata/pool_manip.c \
- 	metadata/pv.c \
-+	metadata/pv_list.c \
- 	metadata/pv_manip.c \
- 	metadata/pv_map.c \
- 	metadata/raid_manip.c \
-diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
-index c61c85c..35c1231 100644
---- a/lib/metadata/metadata-exported.h
-+++ b/lib/metadata/metadata-exported.h
-@@ -1385,4 +1385,8 @@ int vg_is_foreign(struct volume_group *vg);
- 
- void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
- 
-+struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
-+		                                            char **argv, int allocatable_only);
-+struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl);
-+
- #endif
-diff --git a/lib/metadata/pv_list.c b/lib/metadata/pv_list.c
-new file mode 100644
-index 0000000..143b573
---- /dev/null
-+++ b/lib/metadata/pv_list.c
-@@ -0,0 +1,291 @@
-+/*
-+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-+ * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
-+ *
-+ * This file is part of LVM2.
-+ *
-+ * This copyrighted material is made available to anyone wishing to use,
-+ * modify, copy, or redistribute it subject to the terms and conditions
-+ * of the GNU Lesser General Public License v.2.1.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "lib/misc/lib.h"
-+#include "lib/misc/lvm-string.h"
-+#include "lib/datastruct/str_list.h"
-+#include "lib/device/device.h"
-+#include "lib/metadata/metadata.h"
-+
-+/*
-+ * Process physical extent range specifiers
-+ */
-+static int _add_pe_range(struct dm_pool *mem, const char *pvname,
-+			 struct dm_list *pe_ranges, uint32_t start, uint32_t count)
-+{
-+	struct pe_range *per;
-+
-+	log_debug("Adding PE range: start PE " FMTu32 " length " FMTu32 " on %s.",
-+		  start, count, pvname);
-+
-+	/* Ensure no overlap with existing areas */
-+	dm_list_iterate_items(per, pe_ranges) {
-+		if (((start < per->start) && (start + count - 1 >= per->start)) ||
-+		    ((start >= per->start) &&
-+			(per->start + per->count - 1) >= start)) {
-+			log_error("Overlapping PE ranges specified (" FMTu32
-+				  "-" FMTu32 ", " FMTu32 "-" FMTu32 ") on %s.",
-+				  start, start + count - 1, per->start,
-+				  per->start + per->count - 1, pvname);
-+			return 0;
-+		}
-+	}
-+
-+	if (!(per = dm_pool_alloc(mem, sizeof(*per)))) {
-+		log_error("Allocation of list failed.");
-+		return 0;
-+	}
-+
-+	per->start = start;
-+	per->count = count;
-+	dm_list_add(pe_ranges, &per->list);
-+
-+	return 1;
-+}
-+
-+static int _xstrtouint32(const char *s, char **p, int base, uint32_t *result)
-+{
-+	unsigned long ul;
-+
-+	errno = 0;
-+	ul = strtoul(s, p, base);
-+
-+	if (errno || *p == s || ul > UINT32_MAX)
-+		return 0;
-+
-+	*result = ul;
-+
-+	return 1;
-+}
-+
-+static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
-+		      const char *pvname, uint32_t size)
-+{
-+	char *endptr;
-+	uint32_t start, end, len;
-+
-+	/* Default to whole PV */
-+	if (!c) {
-+		if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size))
-+			return_0;
-+		return 1;
-+	}
-+
-+	while (*c) {
-+		if (*c != ':')
-+			goto error;
-+
-+		c++;
-+
-+		/* Disallow :: and :\0 */
-+		if (*c == ':' || !*c)
-+			goto error;
-+
-+		/* Default to whole range */
-+		start = UINT32_C(0);
-+		end = size - 1;
-+
-+		/* Start extent given? */
-+		if (isdigit(*c)) {
-+			if (!_xstrtouint32(c, &endptr, 10, &start))
-+				goto error;
-+			c = endptr;
-+			/* Just one number given? */
-+			if (!*c || *c == ':')
-+				end = start;
-+		}
-+		/* Range? */
-+		if (*c == '-') {
-+			c++;
-+			if (isdigit(*c)) {
-+				if (!_xstrtouint32(c, &endptr, 10, &end))
-+					goto error;
-+				c = endptr;
-+			}
-+		} else if (*c == '+') {	/* Length? */
-+			c++;
-+			if (isdigit(*c)) {
-+				if (!_xstrtouint32(c, &endptr, 10, &len))
-+					goto error;
-+				c = endptr;
-+				end = start + (len ? (len - 1) : 0);
-+			}
-+		}
-+
-+		if (*c && *c != ':')
-+			goto error;
-+
-+		if ((start > end) || (end > size - 1)) {
-+			log_error("PE range error: start extent %" PRIu32 " to "
-+				  "end extent %" PRIu32 ".", start, end);
-+			return 0;
-+		}
-+
-+		if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1))
-+			return_0;
-+
-+	}
-+
-+	return 1;
-+
-+      error:
-+	log_error("Physical extent parsing error at %s.", c);
-+	return 0;
-+}
-+
-+static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
-+			     char *colon, int allocatable_only, struct dm_list *r)
-+{
-+	const char *pvname;
-+	struct pv_list *new_pvl = NULL, *pvl2;
-+	struct dm_list *pe_ranges;
-+
-+	pvname = pv_dev_name(pvl->pv);
-+	if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
-+		log_warn("WARNING: Physical volume %s not allocatable.", pvname);
-+		return 1;
-+	}
-+
-+	if (allocatable_only && is_missing_pv(pvl->pv)) {
-+		log_warn("WARNING: Physical volume %s is missing.", pvname);
-+		return 1;
-+	}
-+
-+	if (allocatable_only &&
-+	    (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
-+		log_warn("WARNING: No free extents on physical volume \"%s\".", pvname);
-+		return 1;
-+	}
-+
-+	dm_list_iterate_items(pvl2, r)
-+		if (pvl->pv->dev == pvl2->pv->dev) {
-+			new_pvl = pvl2;
-+			break;
-+		}
-+
-+	if (!new_pvl) {
-+		if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
-+			log_error("Unable to allocate physical volume list.");
-+			return 0;
-+		}
-+
-+		memcpy(new_pvl, pvl, sizeof(*new_pvl));
-+
-+		if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
-+			log_error("Allocation of pe_ranges list failed.");
-+			return 0;
-+		}
-+		dm_list_init(pe_ranges);
-+		new_pvl->pe_ranges = pe_ranges;
-+		dm_list_add(r, &new_pvl->list);
-+	}
-+
-+	/* Determine selected physical extents */
-+	if (!_parse_pes(mem, colon, new_pvl->pe_ranges, pv_dev_name(pvl->pv),
-+			pvl->pv->pe_count))
-+		return_0;
-+
-+	return 1;
-+}
-+
-+struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
-+			    char **argv, int allocatable_only)
-+{
-+	struct dm_list *r;
-+	struct pv_list *pvl;
-+	struct dm_list tagsl, arg_pvnames;
-+	char *pvname = NULL;
-+	char *colon, *at_sign, *tagname;
-+	int i;
-+
-+	/* Build up list of PVs */
-+	if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
-+		log_error("Allocation of list failed.");
-+		return NULL;
-+	}
-+	dm_list_init(r);
-+
-+	dm_list_init(&tagsl);
-+	dm_list_init(&arg_pvnames);
-+
-+	for (i = 0; i < argc; i++) {
-+		dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
-+
-+		if (at_sign && (at_sign == argv[i])) {
-+			tagname = at_sign + 1;
-+			if (!validate_tag(tagname)) {
-+				log_error("Skipping invalid tag %s.", tagname);
-+				continue;
-+			}
-+			dm_list_iterate_items(pvl, &vg->pvs) {
-+				if (str_list_match_item(&pvl->pv->tags,
-+							tagname)) {
-+					if (!_create_pv_entry(mem, pvl, NULL,
-+							      allocatable_only,
-+							      r))
-+						return_NULL;
-+				}
-+			}
-+			continue;
-+		}
-+
-+		pvname = argv[i];
-+
-+		if (colon && !(pvname = dm_pool_strndup(mem, pvname,
-+					(unsigned) (colon - pvname)))) {
-+			log_error("Failed to clone PV name.");
-+			return NULL;
-+		}
-+
-+		if (!(pvl = find_pv_in_vg(vg, pvname))) {
-+			log_error("Physical Volume \"%s\" not found in "
-+				  "Volume Group \"%s\".", pvname, vg->name);
-+			return NULL;
-+		}
-+		if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r))
-+			return_NULL;
-+	}
-+
-+	if (dm_list_empty(r))
-+		log_error("No specified PVs have space available.");
-+
-+	return dm_list_empty(r) ? NULL : r;
-+}
-+
-+struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl)
-+{
-+	struct dm_list *r;
-+	struct pv_list *pvl, *new_pvl;
-+
-+	/* Build up list of PVs */
-+	if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
-+		log_error("Allocation of list failed.");
-+		return NULL;
-+	}
-+	dm_list_init(r);
-+
-+	dm_list_iterate_items(pvl, pvsl) {
-+		if (!(new_pvl = dm_pool_zalloc(mem, sizeof(*new_pvl)))) {
-+			log_error("Unable to allocate physical volume list.");
-+			return NULL;
-+		}
-+
-+		memcpy(new_pvl, pvl, sizeof(*new_pvl));
-+		dm_list_add(r, &new_pvl->list);
-+	}
-+
-+	return r;
-+}
-+
-diff --git a/tools/toollib.c b/tools/toollib.c
-index a5304bf..6386a69 100644
---- a/tools/toollib.c
-+++ b/tools/toollib.c
-@@ -457,276 +457,6 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name)
- 	return vg_name;
- }
- 
--/*
-- * Process physical extent range specifiers
-- */
--static int _add_pe_range(struct dm_pool *mem, const char *pvname,
--			 struct dm_list *pe_ranges, uint32_t start, uint32_t count)
--{
--	struct pe_range *per;
--
--	log_debug("Adding PE range: start PE " FMTu32 " length " FMTu32 " on %s.",
--		  start, count, pvname);
--
--	/* Ensure no overlap with existing areas */
--	dm_list_iterate_items(per, pe_ranges) {
--		if (((start < per->start) && (start + count - 1 >= per->start)) ||
--		    ((start >= per->start) &&
--			(per->start + per->count - 1) >= start)) {
--			log_error("Overlapping PE ranges specified (" FMTu32
--				  "-" FMTu32 ", " FMTu32 "-" FMTu32 ") on %s.",
--				  start, start + count - 1, per->start,
--				  per->start + per->count - 1, pvname);
--			return 0;
--		}
--	}
--
--	if (!(per = dm_pool_alloc(mem, sizeof(*per)))) {
--		log_error("Allocation of list failed.");
--		return 0;
--	}
--
--	per->start = start;
--	per->count = count;
--	dm_list_add(pe_ranges, &per->list);
--
--	return 1;
--}
--
--static int _xstrtouint32(const char *s, char **p, int base, uint32_t *result)
--{
--	unsigned long ul;
--
--	errno = 0;
--	ul = strtoul(s, p, base);
--
--	if (errno || *p == s || ul > UINT32_MAX)
--		return 0;
--
--	*result = ul;
--
--	return 1;
--}
--
--static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
--		      const char *pvname, uint32_t size)
--{
--	char *endptr;
--	uint32_t start, end, len;
--
--	/* Default to whole PV */
--	if (!c) {
--		if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size))
--			return_0;
--		return 1;
--	}
--
--	while (*c) {
--		if (*c != ':')
--			goto error;
--
--		c++;
--
--		/* Disallow :: and :\0 */
--		if (*c == ':' || !*c)
--			goto error;
--
--		/* Default to whole range */
--		start = UINT32_C(0);
--		end = size - 1;
--
--		/* Start extent given? */
--		if (isdigit(*c)) {
--			if (!_xstrtouint32(c, &endptr, 10, &start))
--				goto error;
--			c = endptr;
--			/* Just one number given? */
--			if (!*c || *c == ':')
--				end = start;
--		}
--		/* Range? */
--		if (*c == '-') {
--			c++;
--			if (isdigit(*c)) {
--				if (!_xstrtouint32(c, &endptr, 10, &end))
--					goto error;
--				c = endptr;
--			}
--		} else if (*c == '+') {	/* Length? */
--			c++;
--			if (isdigit(*c)) {
--				if (!_xstrtouint32(c, &endptr, 10, &len))
--					goto error;
--				c = endptr;
--				end = start + (len ? (len - 1) : 0);
--			}
--		}
--
--		if (*c && *c != ':')
--			goto error;
--
--		if ((start > end) || (end > size - 1)) {
--			log_error("PE range error: start extent %" PRIu32 " to "
--				  "end extent %" PRIu32 ".", start, end);
--			return 0;
--		}
--
--		if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1))
--			return_0;
--
--	}
--
--	return 1;
--
--      error:
--	log_error("Physical extent parsing error at %s.", c);
--	return 0;
--}
--
--static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
--			     char *colon, int allocatable_only, struct dm_list *r)
--{
--	const char *pvname;
--	struct pv_list *new_pvl = NULL, *pvl2;
--	struct dm_list *pe_ranges;
--
--	pvname = pv_dev_name(pvl->pv);
--	if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
--		log_warn("WARNING: Physical volume %s not allocatable.", pvname);
--		return 1;
--	}
--
--	if (allocatable_only && is_missing_pv(pvl->pv)) {
--		log_warn("WARNING: Physical volume %s is missing.", pvname);
--		return 1;
--	}
--
--	if (allocatable_only &&
--	    (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
--		log_warn("WARNING: No free extents on physical volume \"%s\".", pvname);
--		return 1;
--	}
--
--	dm_list_iterate_items(pvl2, r)
--		if (pvl->pv->dev == pvl2->pv->dev) {
--			new_pvl = pvl2;
--			break;
--		}
--
--	if (!new_pvl) {
--		if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
--			log_error("Unable to allocate physical volume list.");
--			return 0;
--		}
--
--		memcpy(new_pvl, pvl, sizeof(*new_pvl));
--
--		if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
--			log_error("Allocation of pe_ranges list failed.");
--			return 0;
--		}
--		dm_list_init(pe_ranges);
--		new_pvl->pe_ranges = pe_ranges;
--		dm_list_add(r, &new_pvl->list);
--	}
--
--	/* Determine selected physical extents */
--	if (!_parse_pes(mem, colon, new_pvl->pe_ranges, pv_dev_name(pvl->pv),
--			pvl->pv->pe_count))
--		return_0;
--
--	return 1;
--}
--
--struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
--			    char **argv, int allocatable_only)
--{
--	struct dm_list *r;
--	struct pv_list *pvl;
--	struct dm_list tagsl, arg_pvnames;
--	char *pvname = NULL;
--	char *colon, *at_sign, *tagname;
--	int i;
--
--	/* Build up list of PVs */
--	if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
--		log_error("Allocation of list failed.");
--		return NULL;
--	}
--	dm_list_init(r);
--
--	dm_list_init(&tagsl);
--	dm_list_init(&arg_pvnames);
--
--	for (i = 0; i < argc; i++) {
--		dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
--
--		if (at_sign && (at_sign == argv[i])) {
--			tagname = at_sign + 1;
--			if (!validate_tag(tagname)) {
--				log_error("Skipping invalid tag %s.", tagname);
--				continue;
--			}
--			dm_list_iterate_items(pvl, &vg->pvs) {
--				if (str_list_match_item(&pvl->pv->tags,
--							tagname)) {
--					if (!_create_pv_entry(mem, pvl, NULL,
--							      allocatable_only,
--							      r))
--						return_NULL;
--				}
--			}
--			continue;
--		}
--
--		pvname = argv[i];
--
--		if (colon && !(pvname = dm_pool_strndup(mem, pvname,
--					(unsigned) (colon - pvname)))) {
--			log_error("Failed to clone PV name.");
--			return NULL;
--		}
--
--		if (!(pvl = find_pv_in_vg(vg, pvname))) {
--			log_error("Physical Volume \"%s\" not found in "
--				  "Volume Group \"%s\".", pvname, vg->name);
--			return NULL;
--		}
--		if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r))
--			return_NULL;
--	}
--
--	if (dm_list_empty(r))
--		log_error("No specified PVs have space available.");
--
--	return dm_list_empty(r) ? NULL : r;
--}
--
--struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl)
--{
--	struct dm_list *r;
--	struct pv_list *pvl, *new_pvl;
--
--	/* Build up list of PVs */
--	if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
--		log_error("Allocation of list failed.");
--		return NULL;
--	}
--	dm_list_init(r);
--
--	dm_list_iterate_items(pvl, pvsl) {
--		if (!(new_pvl = dm_pool_zalloc(mem, sizeof(*new_pvl)))) {
--			log_error("Unable to allocate physical volume list.");
--			return NULL;
--		}
--
--		memcpy(new_pvl, pvl, sizeof(*new_pvl));
--		dm_list_add(r, &new_pvl->list);
--	}
--
--	return r;
--}
--
- const char _pe_size_may_not_be_negative_msg[] = "Physical extent size may not be negative.";
- 
- int vgcreate_params_set_defaults(struct cmd_context *cmd,
-diff --git a/tools/toollib.h b/tools/toollib.h
-index 9102f55..53a5e5b 100644
---- a/tools/toollib.h
-+++ b/tools/toollib.h
-@@ -182,15 +182,6 @@ void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
- int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
- int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
- 
--/*
-- * Builds a list of pv's from the names in argv.  Used in
-- * lvcreate/extend.
-- */
--struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
--			    char **argv, int allocatable_only);
--
--struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvs);
--
- int vgcreate_params_set_defaults(struct cmd_context *cmd,
- 				 struct vgcreate_params *vp_def,
- 				 struct volume_group *vg);
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-2_03_10-test-repair-of-thin-pool-used-by-foreign-apps.patch b/SOURCES/lvm2-2_03_10-test-repair-of-thin-pool-used-by-foreign-apps.patch
deleted file mode 100644
index c05d18d..0000000
--- a/SOURCES/lvm2-2_03_10-test-repair-of-thin-pool-used-by-foreign-apps.patch
+++ /dev/null
@@ -1,82 +0,0 @@
- test/shell/thin-foreign-repair.sh | 72 +++++++++++++++++++++++++++++++++++++++
- 1 file changed, 72 insertions(+)
- create mode 100644 test/shell/thin-foreign-repair.sh
-
-diff --git a/test/shell/thin-foreign-repair.sh b/test/shell/thin-foreign-repair.sh
-new file mode 100644
-index 0000000..147a9a0
---- /dev/null
-+++ b/test/shell/thin-foreign-repair.sh
-@@ -0,0 +1,72 @@
-+#!/usr/bin/env bash
-+
-+# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
-+#
-+# This copyrighted material is made available to anyone wishing to use,
-+# modify, copy, or redistribute it subject to the terms and conditions
-+# of the GNU General Public License v.2.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program; if not, write to the Free Software Foundation,
-+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+
-+# test foreing user of thin-pool
-+
-+
-+SKIP_WITH_LVMPOLLD=1
-+
-+. lib/inittest
-+
-+cleanup_mounted_and_teardown()
-+{
-+	dmsetup remove $THIN || true
-+	vgremove -ff $vg
-+	aux teardown
-+}
-+
-+#
-+# Main
-+#
-+aux have_thin 1 0 0 || skip
-+which mkfs.ext4 || skip
-+
-+# Use our mkfs config file to get approximately same results
-+# TODO: maybe use it for all test via some 'prepare' function
-+export MKE2FS_CONFIG="$TESTOLDPWD/lib/mke2fs.conf"
-+
-+aux prepare_vg 2 64
-+
-+# Create named pool only
-+lvcreate -L2 -T $vg/pool
-+
-+POOL="$vg-pool"
-+THIN="${PREFIX}_thin"
-+
-+# Foreing user is using own ioctl command to create thin devices
-+dmsetup message $POOL 0 "create_thin 0"
-+dmsetup message $POOL 0 "set_transaction_id 0 2"
-+
-+# Once the transaction id has changed, lvm2 shall not be able to create thinLV
-+fail lvcreate -V10 $vg/pool
-+
-+trap 'cleanup_mounted_and_teardown' EXIT
-+
-+# 20M thin device
-+dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
-+
-+mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN"
-+
-+dmsetup remove "$THIN"
-+
-+lvchange -an $vg/pool
-+
-+# Repair thin-pool used by 'foreing' apps (setting their own tid)
-+lvconvert --repair $vg/pool 2>&1 | tee out
-+
-+not grep "Transaction id" out
-+
-+lvchange -ay $vg/pool
-+
-+dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
-+
-+fsck -n "$DM_DEV_DIR/mapper/$THIN"
diff --git a/SOURCES/lvm2-rhel8.patch b/SOURCES/lvm2-rhel8.patch
index 5a2a411..faf3ec3 100644
--- a/SOURCES/lvm2-rhel8.patch
+++ b/SOURCES/lvm2-rhel8.patch
@@ -3,16 +3,16 @@
  2 files changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/VERSION b/VERSION
-index 8c4a9a8..00618e0 100644
+index a6ba8f6..2a15962 100644
 --- a/VERSION
 +++ b/VERSION
 @@ -1 +1 @@
--2.03.09(2) (2020-03-26)
-+2.03.09(2)-RHEL8 (2020-04-21)
+-2.03.11(2)-git (2020-08-09)
++2.03.11(2)-git (2020-11-03)
 diff --git a/VERSION_DM b/VERSION_DM
-index 0ae62fd..b9ec43e 100644
+index f44bc5f..2475a11 100644
 --- a/VERSION_DM
 +++ b/VERSION_DM
 @@ -1 +1 @@
--1.02.171 (2020-03-26)
-+1.02.171-RHEL8 (2020-04-21)
+-1.02.175-git (2020-08-09)
++1.02.175-git (2020-11-03)
diff --git a/SOURCES/lvm2-set-default-preferred_names.patch b/SOURCES/lvm2-set-default-preferred_names.patch
index ece62c4..37243e9 100644
--- a/SOURCES/lvm2-set-default-preferred_names.patch
+++ b/SOURCES/lvm2-set-default-preferred_names.patch
@@ -1,15 +1,9 @@
-From 6a078fe01b47fa165226a15263c8bd6350b1c307 Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Thu, 3 Jan 2019 13:49:08 +0100
-Subject: [PATCH 2/8] lvm2: set default preferred_names
-
----
  conf/example.conf.in         | 3 ++-
  lib/config/config_settings.h | 2 +-
  2 files changed, 3 insertions(+), 2 deletions(-)
 
 diff --git a/conf/example.conf.in b/conf/example.conf.in
-index 05b0857..88858fc 100644
+index 6b0622a..37bdced 100644
 --- a/conf/example.conf.in
 +++ b/conf/example.conf.in
 @@ -122,7 +122,8 @@ devices {
@@ -23,7 +17,7 @@ index 05b0857..88858fc 100644
  	# Configuration option devices/filter.
  	# Limit the block devices that are used by LVM commands.
 diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
-index 2bb72ba..dce9705 100644
+index e4e3dcd..b036606 100644
 --- a/lib/config/config_settings.h
 +++ b/lib/config/config_settings.h
 @@ -269,7 +269,7 @@ cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
@@ -35,6 +29,3 @@ index 2bb72ba..dce9705 100644
  	"Select which path name to display for a block device.\n"
  	"If multiple path names exist for a block device, and LVM needs to\n"
  	"display a name for the device, the path names are matched against\n"
--- 
-1.8.3.1
-
diff --git a/SOURCES/lvm2-test-skip-problematic-tests.patch b/SOURCES/lvm2-test-skip-problematic-tests.patch
index 80edd99..b8c65d9 100644
--- a/SOURCES/lvm2-test-skip-problematic-tests.patch
+++ b/SOURCES/lvm2-test-skip-problematic-tests.patch
@@ -1,18 +1,12 @@
-From 74f05f17ea3d1a3639a65ba337f2b7df7f4981bf Mon Sep 17 00:00:00 2001
-From: Marian Csontos <mcsontos@redhat.com>
-Date: Sun, 18 Aug 2019 17:31:30 +0200
-Subject: [PATCH 3/8] lvm2: test: skip-problematic-tests
-
----
  test/dbus/lvmdbustest.py     | 1 +
  test/shell/lvcreate-usage.sh | 6 +++---
  2 files changed, 4 insertions(+), 3 deletions(-)
 
 diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
-index 8753e65..b2986bf 100755
+index efa1afb..473bb94 100755
 --- a/test/dbus/lvmdbustest.py
 +++ b/test/dbus/lvmdbustest.py
-@@ -1821,6 +1821,7 @@ class TestDbusService(unittest.TestCase):
+@@ -1851,6 +1851,7 @@ class TestDbusService(unittest.TestCase):
  		# path to it.  Additionally, we will take the symlink and do a lookup
  		# (Manager.LookUpByLvmId) using it and the original device path to
  		# ensure that we can find the PV.
@@ -43,6 +37,3 @@ index 6d46939..9e00f1c 100644
  lvremove -ff $vg
  
  #
--- 
-1.8.3.1
-
diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec
index aea1291..0080957 100644
--- a/SPECS/lvm2.spec
+++ b/SPECS/lvm2.spec
@@ -1,4 +1,4 @@
-%global device_mapper_version 1.02.171
+%global device_mapper_version 1.02.175
 
 %global enable_cache 1
 %global enable_cluster 1
@@ -51,34 +51,26 @@
 
 # Do not reset Release to 1 unless both lvm2 and device-mapper
 # versions are increased together.
+%global commit 8801a86a3e0c87d92b250a6477f86ef9efdb2ba0
+%global shortcommit %(c=%{commit}; echo ${c:0:7})
 
 Summary: Userland logical volume management tools
 Name: lvm2
 %if 0%{?rhel}
 Epoch: %{rhel}
 %endif
-Version: 2.03.09
-Release: 5%{?dist}
+Version: 2.03.11
+Release: 0.2.20201103git%{shortcommit}%{?dist}
 License: GPLv2
 URL: http://sourceware.org/lvm2
-Source0: ftp://sourceware.org/pub/lvm2/releases/LVM2.%{version}.tgz
+#Source0: ftp://sourceware.org/pub/lvm2/releases/LVM2.%{version}.tgz
+Source0: https://github.com/lvm-team/lvm2/archive/%{commit}/lvm2-%{shortcommit}.tar.gz
 Patch0: lvm2-rhel8.patch
 Patch1: lvm2-set-default-preferred_names.patch
 Patch2: lvm2-test-skip-problematic-tests.patch
-Patch3: lvm2-2_03_10-lvconvert-no-validation-for-thin-pools-not-used-by-lvm.patch
-Patch4: lvm2-2_03_10-test-repair-of-thin-pool-used-by-foreign-apps.patch
-Patch5: lvm2-2_03_10-WHATS_NEWS-update.patch
-Patch6: lvm2-2_03_10-blkdeactivate-add-support-for-VDO-in-blkdeactivate-script.patch
-Patch7: lvm2-2_03_10-Fix-scripts-lvmlocks.service.in-using-nonexistent-lock-opt-autowait.patch
-Patch8:  lvm2-2_03_10-move-pv_list-code-into-lib.patch
-Patch9:  lvm2-2_03_10-Allow-dm-integrity-to-be-used-for-raid-images.patch
-Patch10: lvm2-2_03_10-WHATS_NEW-integrity-with-raid.patch
-Patch11: lvm2-2_03_10-build-make-generate.patch
-Patch12: 0001-Merge-master-up-to-commit-53803821de16.patch
-Patch13: 0002-Merge-master-up-to-commit-be61bd6ff5c6.patch
-Patch14: 0003-Merge-master-up-to-commit-c1d136fea3d1.patch
+# TODO: What shall we do with this?
 # BZ 1868169:
-Patch15: 0004-Revert-wipe_lv-changes.patch
+#Patch15: 0004-Revert-wipe_lv-changes.patch
 
 BuildRequires: gcc
 %if %{enable_testsuite}
@@ -133,23 +125,12 @@ or more physical volumes and creating one or more logical volumes
 (kind of logical partitions) in volume groups.
 
 %prep
-%setup -q -n LVM2.%{version}
+#%%setup -q -n LVM2.%{version}
+%setup -n lvm2-%{commit}
 %patch0 -p1 -b .backup0
 %patch1 -p1 -b .backup1
 %patch2 -p1 -b .backup2
-%patch3 -p1 -b .backup3
-%patch4 -p1 -b .backup4
-%patch5 -p1 -b .backup5
-%patch6 -p1 -b .backup6
-%patch7 -p1 -b .backup7
-%patch8 -p1 -b .backup8
-%patch9 -p1 -b .backup9
-%patch10 -p1 -b .backup10
-%patch11 -p1 -b .backup11
-%patch12 -p1 -b .backup12
-%patch13 -p1 -b .backup13
-%patch14 -p1 -b .backup14
-%patch15 -p1 -b .backup15
+#%%patch15 -p1 -b .backup15
 
 %build
 %global _default_pid_dir /run
@@ -754,6 +735,9 @@ An extensive functional testsuite for LVM2.
 %endif
 
 %changelog
+* Wed Nov 04 2020 Marian Csontos <mcsontos@redhat.com> - 2.03.11-0.2.20201103git8801a86
+- Merge fixes from upstream up to 8801a86.
+
 * Wed Aug 12 2020 Marian Csontos <mcsontos@redhat.com> - 2.03.09-5
 - Revert wipe_lv changes.