mrc0mmand / rpms / lvm2

Forked from rpms/lvm2 2 years ago
Clone
Blob Blame History Raw
 WHATS_NEW                                          |  19 +
 WHATS_NEW_DM                                       |   5 +
 daemons/dmeventd/plugins/raid/dmeventd_raid.c      |  16 +
 daemons/dmeventd/plugins/thin/dmeventd_thin.c      |  12 +-
 daemons/dmfilemapd/dmfilemapd.c                    |  49 +-
 daemons/lvmdbusd/automatedproperties.py            |   2 +-
 daemons/lvmdbusd/background.py                     |  13 +-
 daemons/lvmdbusd/cmdhandler.py                     |  18 +-
 daemons/lvmdbusd/fetch.py                          |  10 +-
 daemons/lvmdbusd/objectmanager.py                  |  10 +-
 daemons/lvmdbusd/utils.py                          |   4 +-
 lib/activate/activate.c                            |   1 -
 lib/config/config_settings.h                       |   7 +-
 lib/config/defaults.h                              |   4 +-
 lib/format_text/export.c                           |  32 +-
 lib/format_text/flags.c                            | 107 +++-
 lib/format_text/import-export.h                    |  17 +-
 lib/format_text/import_vsn1.c                      |  23 +-
 lib/metadata/merge.c                               |   2 +-
 lib/metadata/metadata-exported.h                   |   5 +-
 lib/metadata/metadata.c                            | 129 ++++-
 lib/metadata/raid_manip.c                          | 598 ++++++++++++++++-----
 lib/metadata/segtype.h                             |  18 +
 lib/metadata/thin_manip.c                          |  19 +-
 lib/raid/raid.c                                    |   1 +
 libdm/libdm-stats.c                                |  24 +-
 liblvm/lvm_lv.c                                    |   2 +-
 man/clvmd.8_main                                   |   7 +-
 man/lvm-fullreport.8_des                           |   1 -
 man/lvm.8_main                                     |   2 +
 man/lvm.conf.5_main                                |   4 +
 man/lvmcache.7_main                                |  18 +
 man/lvmetad.8_main                                 |  11 +-
 man/lvmlockd.8_main                                |  97 ++--
 man/lvmraid.7_main                                 | 132 +++--
 man/lvmreport.7_main                               |   2 +-
 man/lvmsystemid.7_main                             |  19 +-
 man/pvchange.8_des                                 |   3 +
 man/see_also.end                                   |   2 +
 man/vgexport.8_des                                 |   2 +-
 scripts/fsadm.sh                                   | 203 +++++--
 test/dbus/lvmdbustest.py                           |  56 +-
 test/shell/fsadm-renamed.sh                        | 116 ++++
 test/shell/lvchange-raid.sh                        |   1 +
 test/shell/lvconvert-raid-regionsize.sh            |   8 +
 .../lvconvert-raid-reshape-striped_to_linear.sh    |   2 +-
 test/shell/lvconvert-raid.sh                       |  61 +++
 test/shell/lvconvert-thin.sh                       |   2 +-
 test/shell/lvcreate-cache.sh                       |   6 +
 test/shell/lvcreate-large-raid.sh                  |  10 +-
 test/shell/lvcreate-raid-nosync.sh                 |   6 +-
 test/shell/lvcreate-thin-big.sh                    |   2 +-
 test/shell/lvresize-full.sh                        |   1 +
 test/shell/thin-dmeventd-warns.sh                  |  85 +++
 test/shell/thin-large.sh                           |  54 ++
 test/shell/thin-resize-match.sh                    |   3 +-
 test/shell/unknown-segment.sh                      |   9 +-
 test/unit/Makefile.in                              |  14 +-
 tools/args.h                                       |  99 +++-
 tools/command-lines.in                             |   2 +-
 tools/command.c                                    |  27 +-
 tools/lvchange.c                                   |  10 +
 tools/lvcreate.c                                   |  44 +-
 tools/reporter.c                                   |   6 +-
 tools/toollib.c                                    |  18 +-
 65 files changed, 1829 insertions(+), 453 deletions(-)

diff --git a/WHATS_NEW b/WHATS_NEW
index 33a27e8..b2796f6 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,3 +1,22 @@
+Version 2.02.172 - 
+===============================
+  No longer necessary to '--force' a repair for RAID1
+  Linear to RAID1 upconverts now use "recover" sync action, not "resync".
+  Improve lvcreate --cachepool arg validation.
+  Limit maximal size of thin-pool for specific chunk size.
+  Print a warning about in-use PVs with no VG using them.
+  Disable automatic clearing of PVs that look like in-use orphans.
+  Cache format2 flag is now using segment name type field.
+  Support storing status flags via segtype name field.
+  Stop using '--yes' mode when fsadm runs without terminal.
+  Extend validation of filesystems resized by fsadm.
+  Enhance lvconvert automatic settings of possible (raid) LV types.
+  Allow lvchange to change properties on a thin pool data sub LV.
+  Fix lvcreate extent percentage calculation for mirrors.
+  Don't reinstate still-missing devices when correcting inconsistent metadata.
+  Properly handle subshell return codes in fsadm.
+  Disallow cachepool creation with policy cleaner and mode writeback.
+
 Version 2.02.171 - 3rd May 2017
 ===============================
   Fix memory warnings by using mempools for command definition processing.
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 20d6220..5718ab7 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,3 +1,8 @@
+Version 1.02.141 - 
+===============================
+  Accept truncated files in calls to dm_stats_update_regions_from_fd().
+  Restore Warning by 5% increment when thin-pool is over 80% (1.02.138).
+
 Version 1.02.140 - 3rd May 2017
 ===============================
   Add missing configure --enable-dmfilemapd status message and fix --disable.
diff --git a/daemons/dmeventd/plugins/raid/dmeventd_raid.c b/daemons/dmeventd/plugins/raid/dmeventd_raid.c
index 4f204bf..afeac28 100644
--- a/daemons/dmeventd/plugins/raid/dmeventd_raid.c
+++ b/daemons/dmeventd/plugins/raid/dmeventd_raid.c
@@ -58,6 +58,22 @@ static int _process_raid_event(struct dso_state *state, char *params, const char
 		dead = 1;
 	}
 
+	/*
+	 * if we are converting from non-RAID to RAID (e.g. linear -> raid1)
+	 * and too many original devices die, such that we cannot continue
+	 * the "recover" operation, the sync action will go to "idle", the
+	 * unsynced devs will remain at 'a', and the original devices will
+	 * NOT SWITCH TO 'D', but will remain at 'A' - hoping to be revived.
+	 *
+	 * This is simply the way the kernel works...
+	 */
+	if (!strcmp(status->sync_action, "idle") &&
+	    strchr(status->dev_health, 'a')) {
+		log_error("Primary sources for new RAID, %s, have failed.",
+			  device);
+		dead = 1; /* run it through LVM repair */
+	}
+
 	if (dead) {
 		if (status->insync_regions < status->total_regions) {
 			if (!state->warned) {
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index e7d24c5..7fd7b0e 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -47,10 +47,8 @@ struct dso_state {
 	struct dm_pool *mem;
 	int metadata_percent_check;
 	int metadata_percent;
-	int metadata_warn_once;
 	int data_percent_check;
 	int data_percent;
-	int data_warn_once;
 	uint64_t known_metadata_size;
 	uint64_t known_data_size;
 	unsigned fails;
@@ -253,9 +251,8 @@ void process_event(struct dm_task *dmt,
 	 * action is called for:  >50%, >55% ... >95%, 100%
 	 */
 	state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
-	if (state->metadata_percent <= WARNING_THRESH)
-		state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */
-	else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
+	if ((state->metadata_percent > WARNING_THRESH) &&
+	    (state->metadata_percent > state->metadata_percent_check))
 		log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
 			 device, dm_percent_to_float(state->metadata_percent));
 	if (state->metadata_percent > CHECK_MINIMUM) {
@@ -269,9 +266,8 @@ void process_event(struct dm_task *dmt,
 		state->metadata_percent_check = CHECK_MINIMUM;
 
 	state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
-	if (state->data_percent <= WARNING_THRESH)
-		state->data_warn_once = 0;
-	else if (!state->data_warn_once++)
+	if ((state->data_percent > WARNING_THRESH) &&
+	    (state->data_percent > state->data_percent_check))
 		log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
 			 device, dm_percent_to_float(state->data_percent));
 	if (state->data_percent > CHECK_MINIMUM) {
diff --git a/daemons/dmfilemapd/dmfilemapd.c b/daemons/dmfilemapd/dmfilemapd.c
index 2dd069a..43ae970 100644
--- a/daemons/dmfilemapd/dmfilemapd.c
+++ b/daemons/dmfilemapd/dmfilemapd.c
@@ -266,8 +266,6 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
 		return 0;
 	}
 
-	memset(fm, 0, sizeof(*fm));
-
 	/*
 	 * We don't know the true nr_regions at daemon start time,
 	 * and it is not worth a dm_stats_list()/group walk to count:
@@ -359,30 +357,33 @@ static int _parse_args(int argc, char **argv, struct filemap_monitor *fm)
 	return 1;
 }
 
-static int _filemap_fd_check_changed(struct filemap_monitor *fm)
+static int _filemap_fd_update_blocks(struct filemap_monitor *fm)
 {
-	int64_t blocks, old_blocks;
 	struct stat buf;
 
 	if (fm->fd < 0) {
 		log_error("Filemap fd is not open.");
-		return -1;
+		return 0;
 	}
 
 	if (fstat(fm->fd, &buf)) {
 		log_error("Failed to fstat filemap file descriptor.");
-		return -1;
+		return 0;
 	}
 
-	blocks = buf.st_blocks;
+	fm->blocks = buf.st_blocks;
 
-	/* first check? */
-	if (fm->blocks < 0)
-		old_blocks = buf.st_blocks;
-	else
-		old_blocks = fm->blocks;
+	return 1;
+}
+
+static int _filemap_fd_check_changed(struct filemap_monitor *fm)
+{
+	int64_t old_blocks;
+
+	old_blocks = fm->blocks;
 
-	fm->blocks = blocks;
+	if (!_filemap_fd_update_blocks(fm))
+		return -1;
 
 	return (fm->blocks != old_blocks);
 }
@@ -564,6 +565,7 @@ static int _filemap_monitor_check_file_unlinked(struct filemap_monitor *fm)
 	ssize_t len;
 
 	fm->deleted = 0;
+	same = 0;
 
 	if ((fd = open(fm->path, O_RDONLY)) < 0)
 		goto check_unlinked;
@@ -684,7 +686,10 @@ static int _update_regions(struct dm_stats *dms, struct filemap_monitor *fm)
 	for (region = regions; *region != DM_STATS_REGIONS_ALL; region++)
 		nr_regions++;
 
-	if (regions[0] != fm->group_id) {
+	if (!nr_regions)
+		log_warn("File contains no extents: exiting.");
+
+	if (nr_regions && (regions[0] != fm->group_id)) {
 		log_warn("group_id changed from " FMTu64 " to " FMTu64,
 			 fm->group_id, regions[0]);
 		fm->group_id = regions[0];
@@ -715,6 +720,9 @@ static int _dmfilemapd(struct filemap_monitor *fm)
 	if (!_filemap_monitor_set_notify(fm))
 		goto bad;
 
+	if (!_filemap_fd_update_blocks(fm))
+		goto bad;
+
 	if (!dm_stats_list(dms, DM_STATS_ALL_PROGRAMS)) {
 		log_error("Failed to list stats handle.");
 		goto bad;
@@ -748,17 +756,16 @@ static int _dmfilemapd(struct filemap_monitor *fm)
 		if ((check = _filemap_fd_check_changed(fm)) < 0)
 			goto bad;
 
-		if (!check)
-			goto wait;
-
-		if (!_update_regions(dms, fm))
+		if (check && !_update_regions(dms, fm))
 			goto bad;
 
+		running = !!fm->nr_regions;
+		if (!running)
+			continue;
+
 wait:
 		_filemap_monitor_wait(FILEMAPD_WAIT_USECS);
 
-		running = !!fm->nr_regions;
-
 		/* mode=inode termination condions */
 		if (fm->mode == DM_FILEMAPD_FOLLOW_INODE) {
 			if (!_filemap_monitor_check_file_unlinked(fm))
@@ -801,6 +808,8 @@ int main(int argc, char **argv)
 {
 	struct filemap_monitor fm;
 
+	memset(&fm, 0, sizeof(fm));
+
 	if (!_parse_args(argc, argv, &fm)) {
 		dm_free(fm.path);
 		return 1;
diff --git a/daemons/lvmdbusd/automatedproperties.py b/daemons/lvmdbusd/automatedproperties.py
index 68cea6e..e188fa4 100644
--- a/daemons/lvmdbusd/automatedproperties.py
+++ b/daemons/lvmdbusd/automatedproperties.py
@@ -100,7 +100,7 @@ class AutomatedProperties(dbus.service.Object):
 		raise dbus.exceptions.DBusException(
 			obj._ap_interface,
 			'The object %s does not implement the %s interface'
-			% (self.__class__, interface_name))
+			% (obj.__class__, interface_name))
 
 	@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
 							in_signature='s', out_signature='a{sv}',
diff --git a/daemons/lvmdbusd/background.py b/daemons/lvmdbusd/background.py
index f7f77d5..90e8b68 100644
--- a/daemons/lvmdbusd/background.py
+++ b/daemons/lvmdbusd/background.py
@@ -9,12 +9,13 @@
 
 import subprocess
 from . import cfg
-from .cmdhandler import options_to_cli_args
+from .cmdhandler import options_to_cli_args, LvmExecutionMeta
 import dbus
 from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
 	add_no_notify
 import os
 import threading
+import time
 
 
 def pv_move_lv_cmd(move_options, lv_full_name,
@@ -47,6 +48,11 @@ def _move_merge(interface_name, command, job_state):
 	# Instruct lvm to not register an event with us
 	command = add_no_notify(command)
 
+	#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
+	meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
+
+	cfg.blackbox.add(meta)
+
 	process = subprocess.Popen(command, stdout=subprocess.PIPE,
 								env=os.environ,
 								stderr=subprocess.PIPE, close_fds=True)
@@ -74,6 +80,11 @@ def _move_merge(interface_name, command, job_state):
 
 	out = process.communicate()
 
+	with meta.lock:
+		meta.ended = time.time()
+		meta.ec = process.returncode
+		meta.stderr_txt = out[1]
+
 	if process.returncode == 0:
 		job_state.Percent = 100
 	else:
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 8ed38cb..4fb1670 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -37,6 +37,7 @@ cmd_lock = threading.RLock()
 class LvmExecutionMeta(object):
 
 	def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
+		self.lock = threading.RLock()
 		self.start = start
 		self.ended = ended
 		self.cmd = cmd
@@ -45,12 +46,13 @@ class LvmExecutionMeta(object):
 		self.stderr_txt = stderr_txt
 
 	def __str__(self):
-		return "EC= %d for %s\n" \
-			"STARTED: %f, ENDED: %f\n" \
-			"STDOUT=%s\n" \
-			"STDERR=%s\n" % \
-			(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
-			self.stderr_txt)
+		with self.lock:
+			return "EC= %d for %s\n" \
+				"STARTED: %f, ENDED: %f\n" \
+				"STDOUT=%s\n" \
+				"STDERR=%s\n" % \
+				(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
+				self.stderr_txt)
 
 
 class LvmFlightRecorder(object):
@@ -618,10 +620,10 @@ def vg_reduce(vg_name, missing, pv_devices, reduce_options):
 	cmd = ['vgreduce']
 	cmd.extend(options_to_cli_args(reduce_options))
 
-	if len(pv_devices) == 0:
-		cmd.append('--all')
 	if missing:
 		cmd.append('--removemissing')
+	elif len(pv_devices) == 0:
+		cmd.append('--all')
 
 	cmd.append(vg_name)
 	cmd.extend(pv_devices)
diff --git a/daemons/lvmdbusd/fetch.py b/daemons/lvmdbusd/fetch.py
index 78c3a4b..c053685 100644
--- a/daemons/lvmdbusd/fetch.py
+++ b/daemons/lvmdbusd/fetch.py
@@ -82,10 +82,10 @@ class StateUpdate(object):
 
 	@staticmethod
 	def update_thread(obj):
+		queued_requests = []
 		while cfg.run.value != 0:
 			# noinspection PyBroadException
 			try:
-				queued_requests = []
 				refresh = True
 				emit_signal = True
 				cache_refresh = True
@@ -96,7 +96,7 @@ class StateUpdate(object):
 					wait = not obj.deferred
 					obj.deferred = False
 
-				if wait:
+				if len(queued_requests) == 0 and wait:
 					queued_requests.append(obj.queue.get(True, 2))
 
 				# Ok we have one or the deferred queue has some,
@@ -131,11 +131,17 @@ class StateUpdate(object):
 				for i in queued_requests:
 					i.set_result(num_changes)
 
+				# Only clear out the requests after we have given them a result
+				# otherwise we can orphan the waiting threads and they never
+				# wake up if we get an exception
+				queued_requests = []
+
 			except queue.Empty:
 				pass
 			except Exception:
 				st = traceback.format_exc()
 				log_error("update_thread exception: \n%s" % st)
+				cfg.blackbox.dump()
 
 	def __init__(self):
 		self.lock = threading.RLock()
diff --git a/daemons/lvmdbusd/objectmanager.py b/daemons/lvmdbusd/objectmanager.py
index a9d13a7..563b9ec 100644
--- a/daemons/lvmdbusd/objectmanager.py
+++ b/daemons/lvmdbusd/objectmanager.py
@@ -223,8 +223,9 @@ class ObjectManager(AutomatedProperties):
 		:param lvm_id: The lvm identifier
 		"""
 		with self.rlock:
-			if lvm_id in self._id_to_object_path:
-				return self.get_object_by_path(self._id_to_object_path[lvm_id])
+			lookup_rc = self._id_lookup(lvm_id)
+			if lookup_rc:
+				return self.get_object_by_path(lookup_rc)
 			return None
 
 	def get_object_path_by_lvm_id(self, lvm_id):
@@ -234,8 +235,9 @@ class ObjectManager(AutomatedProperties):
 		:return: Object path or '/' if not found
 		"""
 		with self.rlock:
-			if lvm_id in self._id_to_object_path:
-				return self._id_to_object_path[lvm_id]
+			lookup_rc = self._id_lookup(lvm_id)
+			if lookup_rc:
+				return lookup_rc
 			return '/'
 
 	def _uuid_verify(self, path, uuid, lvm_id):
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index af9e10a..170824d 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -519,7 +519,9 @@ def add_no_notify(cmdline):
 		if '--config' in cmdline:
 			for i, arg in enumerate(cmdline):
 				if arg == '--config':
-					cmdline[i] += "global/notify_dbus=0"
+					if len(cmdline) <= i+1:
+						raise dbus.exceptions.DBusException("Missing value for --config option.")
+					cmdline[i+1] += " global/notify_dbus=0"
 					break
 		else:
 			cmdline.extend(['--config', 'global/notify_dbus=0'])
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index a3978ad..282dd4f 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -835,7 +835,6 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
 				 * When merge is in progress, query merging origin LV instead.
 				 * COW volume is already mapped as error target in this case.
 				 */
-				status->lv = olv;
 				return 1;
 			}
 
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index 3b0eebb..40b64ab 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -469,8 +469,9 @@ cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separa
 
 cfg(allocation_raid_stripe_all_devices_CFG, "raid_stripe_all_devices", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES, vsn(2, 2, 162), NULL, 0, NULL,
 	"Stripe across all PVs when RAID stripes are not specified.\n"
-	"If enabled, all PVs in the VG or on the command line are used for raid0/4/5/6/10\n"
-	"when the command does not specify the number of stripes to use.\n"
+	"If enabled, all PVs in the VG or on the command line are used for\n"
+	"raid0/4/5/6/10 when the command does not specify the number of\n"
+	"stripes to use.\n"
 	"This was the default behaviour until release 2.02.162.\n")
 
 cfg(allocation_cache_pool_metadata_require_separate_pvs_CFG, "cache_pool_metadata_require_separate_pvs", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_BOOL, DEFAULT_CACHE_POOL_METADATA_REQUIRE_SEPARATE_PVS, vsn(2, 2, 106), NULL, 0, NULL,
@@ -934,7 +935,7 @@ cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL,
 	"devices/global_filter.\n")
 
 cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMETAD_UPDATE_WAIT_TIME, vsn(2, 2, 151), NULL, 0, NULL,
-	"The number of seconds a command will wait for lvmetad update to finish.\n"
+	"Number of seconds a command will wait for lvmetad update to finish.\n"
 	"After waiting for this period, a command will not use lvmetad, and\n"
 	"will revert to disk scanning.\n")
 
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 65b81f1..d9e19d9 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -104,9 +104,9 @@
 #define DEFAULT_THIN_REPAIR_OPTION1 ""
 #define DEFAULT_THIN_REPAIR_OPTIONS_CONFIG "#S" DEFAULT_THIN_REPAIR_OPTION1
 #define DEFAULT_THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS 0
-#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (16 * 1024 * 1024)  /* KB */
+#define DEFAULT_THIN_POOL_MAX_METADATA_SIZE (DM_THIN_MAX_METADATA_SIZE / 2)  /* KB */
 #define DEFAULT_THIN_POOL_MIN_METADATA_SIZE 2048  /* KB */
-#define DEFAULT_THIN_POOL_OPTIMAL_SIZE     (128 * 1024 * 1024)	/* KB */
+#define DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE (128 * 1024) /* KB */
 #define DEFAULT_THIN_POOL_CHUNK_SIZE_POLICY "generic"
 #define DEFAULT_THIN_POOL_CHUNK_SIZE	    64	  /* KB */
 #define DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE 512 /* KB */
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index 473275d..f369089 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -358,11 +358,12 @@ static int _print_header(struct cmd_context *cmd, struct formatter *f,
 static int _print_flag_config(struct formatter *f, uint64_t status, int type)
 {
 	char buffer[4096];
-	if (!print_flags(status, type | STATUS_FLAG, buffer, sizeof(buffer)))
+
+	if (!print_flags(buffer, sizeof(buffer), type, STATUS_FLAG, status))
 		return_0;
 	outf(f, "status = %s", buffer);
 
-	if (!print_flags(status, type, buffer, sizeof(buffer)))
+	if (!print_flags(buffer, sizeof(buffer), type, COMPATIBLE_FLAG, status))
 		return_0;
 	outf(f, "flags = %s", buffer);
 
@@ -501,7 +502,13 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
  */
 static const char *_get_pv_name_from_uuid(struct formatter *f, char *uuid)
 {
-	return dm_hash_lookup(f->pv_names, uuid);
+	const char *pv_name = dm_hash_lookup(f->pv_names, uuid);
+
+	if (!pv_name)
+		log_error(INTERNAL_ERROR "PV name for uuid %s missing from text metadata export hash table.",
+			  uuid);
+
+	return pv_name;
 }
 
 static const char *_get_pv_name(struct formatter *f, struct physical_volume *pv)
@@ -577,6 +584,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
 static int _print_segment(struct formatter *f, struct volume_group *vg,
 			  int count, struct lv_segment *seg)
 {
+	char buffer[2048];
+
+	if (!print_segtype_lvflags(buffer, sizeof(buffer), seg->lv->status))
+		return_0;
+
 	outf(f, "segment%u {", count);
 	_inc_indent(f);
 
@@ -587,7 +599,8 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
 	if (seg->reshape_len)
 		outsize(f, (uint64_t) seg->reshape_len * vg->extent_size,
 			"reshape_count = %u", seg->reshape_len);
-	outf(f, "type = \"%s\"", seg->segtype->name);
+
+	outf(f, "type = \"%s%s\"", seg->segtype->name, buffer);
 
 	if (!_out_list(f, &seg->tags, "tags"))
 		return_0;
@@ -607,6 +620,7 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
 {
 	const char *name;
 	unsigned int s;
+	struct physical_volume *pv;
 
 	outnl(f);
 
@@ -616,7 +630,13 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
 	for (s = 0; s < seg->area_count; s++) {
 		switch (seg_type(seg, s)) {
 		case AREA_PV:
-			if (!(name = _get_pv_name(f, seg_pv(seg, s))))
+			if (!(pv = seg_pv(seg, s))) {
+				log_error(INTERNAL_ERROR "Missing PV for area %" PRIu32 " of %s segment of LV %s.",
+					  s, type, display_lvname(seg->lv));
+				return 0;
+			}
+				
+			if (!(name = _get_pv_name(f, pv)))
 				return_0;
 
 			outf(f, "\"%s\", %u%s", name,
@@ -650,6 +670,8 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
 
 			break;
 		case AREA_UNASSIGNED:
+			log_error(INTERNAL_ERROR "Invalid type for area %" PRIu32 " of %s segment of LV %s.",
+				  s, type, display_lvname(seg->lv));
 			return 0;
 		}
 	}
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index a9f81f5..88fb091 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -47,6 +47,7 @@ static const struct flag _pv_flags[] = {
 	{ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
 	{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
 	{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
+	{MISSING_PV, "MISSING", STATUS_FLAG},
 	{UNLABELLED_PV, NULL, 0},
 	{0, NULL, 0}
 };
@@ -61,13 +62,14 @@ static const struct flag _lv_flags[] = {
 	{LOCKED, "LOCKED", STATUS_FLAG},
 	{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
 	{LV_REBUILD, "REBUILD", STATUS_FLAG},
-	{LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", STATUS_FLAG},
-	{LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", STATUS_FLAG},
-	{LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", STATUS_FLAG},
+	{LV_RESHAPE, "RESHAPE", SEGTYPE_FLAG},
+	{LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", SEGTYPE_FLAG},
+	{LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", SEGTYPE_FLAG},
+	{LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", SEGTYPE_FLAG},
 	{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
 	{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
 	{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
-	{LV_METADATA_FORMAT, "METADATA_FORMAT", STATUS_FLAG},
+	{LV_METADATA_FORMAT, "METADATA_FORMAT", SEGTYPE_FLAG},
 	{LV_NOSCAN, NULL, 0},
 	{LV_TEMPORARY, NULL, 0},
 	{POOL_METADATA_SPARE, NULL, 0},
@@ -101,9 +103,9 @@ static const struct flag _lv_flags[] = {
 	{0, NULL, 0}
 };
 
-static const struct flag *_get_flags(int type)
+static const struct flag *_get_flags(enum pv_vg_lv_e type)
 {
-	switch (type & ~STATUS_FLAG) {
+	switch (type) {
 	case VG_FLAGS:
 		return _vg_flags;
 
@@ -114,7 +116,7 @@ static const struct flag *_get_flags(int type)
 		return _lv_flags;
 	}
 
-	log_error("Unknown flag set requested.");
+	log_error(INTERNAL_ERROR "Unknown flag set requested.");
 	return NULL;
 }
 
@@ -123,7 +125,7 @@ static const struct flag *_get_flags(int type)
  * using one of the tables defined at the top of
  * the file.
  */
-int print_flags(uint64_t status, int type, char *buffer, size_t size)
+int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint64_t status)
 {
 	int f, first = 1;
 	const struct flag *flags;
@@ -132,13 +134,13 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
 		return_0;
 
 	if (!emit_to_buffer(&buffer, &size, "["))
-		return 0;
+		return_0;
 
 	for (f = 0; flags[f].mask; f++) {
 		if (status & flags[f].mask) {
 			status &= ~flags[f].mask;
 
-			if ((type & STATUS_FLAG) != flags[f].kind)
+			if (mask != flags[f].kind)
 				continue;
 
 			/* Internal-only flag? */
@@ -147,18 +149,18 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
 
 			if (!first) {
 				if (!emit_to_buffer(&buffer, &size, ", "))
-					return 0;
+					return_0;
 			} else
 				first = 0;
 	
 			if (!emit_to_buffer(&buffer, &size, "\"%s\"",
-			    flags[f].description))
-				return 0;
+					    flags[f].description))
+				return_0;
 		}
 	}
 
 	if (!emit_to_buffer(&buffer, &size, "]"))
-		return 0;
+		return_0;
 
 	if (status)
 		log_warn(INTERNAL_ERROR "Metadata inconsistency: "
@@ -167,9 +169,9 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
 	return 1;
 }
 
-int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
+int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm_config_value *cv)
 {
-	int f;
+	unsigned f;
 	uint64_t s = UINT64_C(0);
 	const struct flag *flags;
 
@@ -186,7 +188,8 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
 		}
 
 		for (f = 0; flags[f].description; f++)
-			if (!strcmp(flags[f].description, cv->v.str)) {
+			if ((flags[f].kind & mask) &&
+			    !strcmp(flags[f].description, cv->v.str)) {
 				s |= flags[f].mask;
 				break;
 			}
@@ -200,7 +203,7 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
 			 * by this case.
 			 */
 			s |= PARTIAL_VG;
-		} else if (!flags[f].description && (type & STATUS_FLAG)) {
+		} else if (!flags[f].description && (mask & STATUS_FLAG)) {
 			log_error("Unknown status flag '%s'.", cv->v.str);
 			return 0;
 		}
@@ -212,3 +215,71 @@ int read_flags(uint64_t *status, int type, const struct dm_config_value *cv)
 	*status |= s;
 	return 1;
 }
+
+/*
+ * Parse extra status flags from segment "type" string.
+ * These flags are seen as INCOMPATIBLE by any older lvm2 code.
+ * All flags separated by '+' are trimmed from passed string.
+ * All UNKNOWN flags will again cause the "UNKNOWN" segtype.
+ *
+ * Note: using these segtype status flags instead of actual
+ * status flags ensures wanted incompatiblity.
+ */
+int read_segtype_lvflags(uint64_t *status, char *segtype_str)
+{
+	unsigned i;
+	const struct flag *flags = _lv_flags;
+	char *delim;
+	char *flag, *buffer, *str;
+
+	if (!(str = strchr(segtype_str, '+')))
+		return 1; /* No flags */
+
+	if (!(buffer = dm_strdup(str + 1))) {
+		log_error("Cannot duplicate segment string.");
+		return 0;
+	}
+
+	delim = buffer;
+
+	do {
+		flag = delim;
+		if ((delim = strchr(delim, '+')))
+			*delim++ = '\0';
+
+		for (i = 0; flags[i].description; i++)
+			if ((flags[i].kind & SEGTYPE_FLAG) &&
+			    !strcmp(flags[i].description, flag)) {
+				*status |= flags[i].mask;
+				break;
+			}
+
+	} while (delim && flags[i].description); /* Till no more flags in type appear */
+
+	if (!flags[i].description)
+		/* Unknown flag is incompatible - returns unmodified segtype_str */
+		log_warn("WARNING: Unrecognised flag %s in segment type %s.",
+			 flag, segtype_str);
+	else
+		*str = '\0'; /* Cut away 1st. '+' */
+
+	dm_free(buffer);
+
+	return 1;
+}
+
+int print_segtype_lvflags(char *buffer, size_t size, uint64_t status)
+{
+	unsigned i;
+	const struct flag *flags = _lv_flags;
+
+	buffer[0] = 0;
+	for (i = 0; flags[i].mask; i++)
+		if ((flags[i].kind & SEGTYPE_FLAG) &&
+		    (status & flags[i].mask) &&
+		    !emit_to_buffer(&buffer, &size, "+%s",
+				    flags[i].description))
+			return 0;
+
+	return 1;
+}
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index c081c51..4b47636 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -35,14 +35,16 @@
  * VGs, PVs and LVs all have status bitsets, we gather together
  * common code for reading and writing them.
  */
-enum {
-	COMPATIBLE_FLAG = 0x0,
+enum pv_vg_lv_e {
+	PV_FLAGS = 1,
 	VG_FLAGS,
-	PV_FLAGS,
 	LV_FLAGS,
-	STATUS_FLAG = 0x8,
 };
 
+#define COMPATIBLE_FLAG	0x01
+#define STATUS_FLAG	0x02
+#define SEGTYPE_FLAG	0x04
+
 struct text_vg_version_ops {
 	int (*check_version) (const struct dm_config_tree * cf);
 	struct volume_group *(*read_vg) (struct format_instance * fid,
@@ -58,8 +60,11 @@ struct text_vg_version_ops {
 
 struct text_vg_version_ops *text_vg_vsn1_init(void);
 
-int print_flags(uint64_t status, int type, char *buffer, size_t size);
-int read_flags(uint64_t *status, int type, const struct dm_config_value *cv);
+int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint64_t status);
+int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm_config_value *cv);
+
+int print_segtype_lvflags(char *buffer, size_t size, uint64_t status);
+int read_segtype_lvflags(uint64_t *status, char *segtype_scr);
 
 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
 size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index e545008..7d9257e 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -140,13 +140,14 @@ static int _read_flag_config(const struct dm_config_node *n, uint64_t *status, i
 		return 0;
 	}
 
-	if (!(read_flags(status, type | STATUS_FLAG, cv))) {
+	/* For backward compatible metadata accept both type of flags */
+	if (!(read_flags(status, type, STATUS_FLAG | SEGTYPE_FLAG, cv))) {
 		log_error("Could not read status flags.");
 		return 0;
 	}
 
 	if (dm_config_get_list(n, "flags", &cv)) {
-		if (!(read_flags(status, type, cv))) {
+		if (!(read_flags(status, type, COMPATIBLE_FLAG, cv))) {
 			log_error("Could not read flags.");
 			return 0;
 		}
@@ -357,6 +358,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
 	uint32_t area_extents, start_extent, extent_count, reshape_count, data_copies;
 	struct segment_type *segtype;
 	const char *segtype_str;
+	char *segtype_with_flags;
 
 	if (!sn_child) {
 		log_error("Empty segment section.");
@@ -388,9 +390,24 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
 		return 0;
 	}
 
-	if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_str)))
+        /* Locally duplicate to parse out status flag bits */
+	if (!(segtype_with_flags = dm_pool_strdup(mem, segtype_str))) {
+		log_error("Cannot duplicate segtype string.");
+		return 0;
+	}
+
+	if (!read_segtype_lvflags(&lv->status, segtype_with_flags)) {
+		log_error("Couldn't read segtype for logical volume %s.",
+			  display_lvname(lv));
+	       return 0;
+	}
+
+	if (!(segtype = get_segtype_from_string(lv->vg->cmd, segtype_with_flags)))
 		return_0;
 
+	/* Can drop temporary string here as nothing has allocated from VGMEM meanwhile */
+	dm_pool_free(mem, segtype_with_flags);
+
 	if (segtype->ops->text_import_area_count &&
 	    !segtype->ops->text_import_area_count(sn_child, &area_count))
 		return_0;
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 3d82a05..e642459 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -222,7 +222,7 @@ static void _check_non_raid_seg_members(struct lv_segment *seg, int *error_count
 }
 
 /*
- * Check RAID segment sruct members of @seg for acceptable
+ * Check RAID segment struct members of @seg for acceptable
  * properties and increment @error_count for any bogus ones.
  */
 static void _check_raid_seg(struct lv_segment *seg, int *error_count)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 8b4310b..c4bebd0 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -142,7 +142,10 @@
 
 #define LV_REMOVE_AFTER_RESHAPE	UINT64_C(0x0400000000000000)	/* LV needs to be removed after a shrinking reshape */
 #define LV_METADATA_FORMAT	UINT64_C(0x0800000000000000)    /* LV has segments with metadata format */
-/* Next unused flag:		UINT64_C(0x1000000000000000)    */
+
+#define LV_RESHAPE		UINT64_C(0x1000000000000000)    /* Ongoing reshape (number of stripes, stripesize or raid algorithm change):
+								   used as SEGTYPE_FLAG to prevent activation on old runtime */
+/* Next unused flag:		UINT64_C(0x2000000000000000)    */
 
 /* Format features flags */
 #define FMT_SEGMENTS		0x00000001U	/* Arbitrary segment params? */
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 1b500ed..4ba81c7 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -1089,8 +1089,7 @@ static struct volume_group *_vg_make_handle(struct cmd_context *cmd,
 	if (!vg && !(vg = alloc_vg("vg_make_handle", cmd, NULL)))
 		return_NULL;
 
-	if (vg->read_status != failure)
-		vg->read_status = failure;
+	vg->read_status = failure;
 
 	if (vg->fid && !_vg_update_vg_committed(vg))
 		vg->read_status |= FAILED_ALLOCATION;
@@ -1122,6 +1121,7 @@ int vg_has_unknown_segments(const struct volume_group *vg)
 struct volume_group *vg_lock_and_create(struct cmd_context *cmd, const char *vg_name)
 {
 	uint32_t rc;
+	struct volume_group *vg;
 
 	if (!validate_name(vg_name)) {
 		log_error("Invalid vg name %s", vg_name);
@@ -1134,7 +1134,11 @@ struct volume_group *vg_lock_and_create(struct cmd_context *cmd, const char *vg_
 		/* NOTE: let caller decide - this may be check for existence */
 		return _vg_make_handle(cmd, NULL, rc);
 
-	return vg_create(cmd, vg_name);
+	vg = vg_create(cmd, vg_name);
+	if (!vg || vg_read_error(vg))
+		unlock_vg(cmd, NULL, vg_name);
+
+	return vg;
 }
 
 /*
@@ -3707,6 +3711,37 @@ struct _vg_read_orphan_baton {
 	int repair;
 };
 
+/*
+ * If we know that the PV is orphan, meaning there's at least one MDA on
+ * that PV which does not reference any VG and at the same time there's
+ * PV_EXT_USED flag set, we're certainly in an inconsistent state and we
+ * need to fix this.
+ *
+ * For example, such situation can happen during vgremove/vgreduce if we
+ * removed/reduced the VG, but we haven't written PV headers yet because
+ * vgremove stopped abruptly for whatever reason just before writing new
+ * PV headers with updated state, including PV extension flags (and so the
+ * PV_EXT_USED flag).
+ *
+ * However, in case the PV has no MDAs at all, we can't double-check
+ * whether the PV_EXT_USED is correct or not - if that PV is marked
+ * as used, it's either:
+ *  - really used (but other disks with MDAs are missing)
+ *  - or the error state as described above is hit
+ *
+ * User needs to overwrite the PV header directly if it's really clear
+ * the PV having no MDAs does not belong to any VG and at the same time
+ * it's still marked as being in use (pvcreate -ff <dev_name> will fix this).
+ *
+ * Note that the above doesn't account for the case where the PV has
+ * VG metadata that fails to be parsed.  In that case, the PV looks
+ * like an in-use orphan, and is auto-repaired here.  A PV with
+ * unparsable metadata should be kept on a special list of devices
+ * (like duplicate PVs) that are not auto-repaired, cannot be used
+ * by pvcreate, and are displayed with a special flag by 'pvs'.
+ */
+
+#if 0
 static int _check_or_repair_orphan_pv_ext(struct physical_volume *pv,
 					  struct lvmcache_info *info,
 					  struct _vg_read_orphan_baton *b)
@@ -3760,12 +3795,15 @@ static int _check_or_repair_orphan_pv_ext(struct physical_volume *pv,
 
 	return 1;
 }
+#endif
 
 static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
 {
 	struct _vg_read_orphan_baton *b = baton;
 	struct physical_volume *pv = NULL;
 	struct pv_list *pvl;
+	uint32_t ext_version;
+	uint32_t ext_flags;
 
 	if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
 			    b->vg->fid, b->warn_flags, 0))) {
@@ -3781,10 +3819,59 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
 	pvl->pv = pv;
 	add_pvl_to_vgs(b->vg, pvl);
 
+	/*
+	 * FIXME: this bit of code that does the auto repair is disabled
+	 * until we can distinguish cases where the repair should not
+	 * happen, i.e. the VG metadata could not be read/parsed.
+	 *
+	 * A PV holding VG metadata that lvm can't understand
+	 * (e.g. damaged, checksum error, unrecognized flag)
+	 * will appear as an in-use orphan, and would be cleared
+	 * by this repair code.  Disable this repair until the
+	 * code can keep track of these problematic PVs, and
+	 * distinguish them from actual in-use orphans.
+	 */
+
+	/*
 	if (!_check_or_repair_orphan_pv_ext(pv, info, baton)) {
 		stack;
 		return 0;
 	}
+	*/
+
+	/*
+	 * Nothing to do if PV header extension < 2:
+	 *  - version 0 is PV header without any extensions,
+	 *  - version 1 has bootloader area support only and
+	 *    we're not checking anything for that one here.
+	 */
+	ext_version = lvmcache_ext_version(info);
+	ext_flags = lvmcache_ext_flags(info);
+
+	/*
+	 * Warn about a PV that has the in-use flag set, but appears in
+	 * the orphan VG (no VG was found referencing it.)
+	 * There are a number of conditions that could lead to this:
+	 *
+	 * . The PV was created with no mdas and is used in a VG with
+	 * other PVs (with metadata) that have not yet appeared on
+	 * the system.  So, no VG metadata is found by lvm which
+	 * references the in-use PV with no mdas.
+	 *
+	 * . vgremove could have failed after clearing mdas but
+	 * before clearing the in-use flag.  In this case, the
+	 * in-use flag needs to be manually cleared on the PV.
+	 *
+	 * . The PV may have damanged/unrecognized VG metadata
+	 * that lvm could not read.
+	 *
+	 * . The PV may have no mdas, and the PVs with the metadata
+	 * may have damaged/unrecognized metadata.
+	 */
+	if ((ext_version >= 2) && (ext_flags & PV_EXT_USED)) {
+		log_warn("WARNING: PV %s is marked in use but no VG was found using it.", pv_dev_name(pv));
+		log_warn("WARNING: PV %s might need repairing.", pv_dev_name(pv));
+	}
 
 	return 1;
 }
@@ -3910,7 +3997,13 @@ static int _check_reappeared_pv(struct volume_group *correct_vg,
          * confusing.
          */
         if (correct_vg->cmd->handles_missing_pvs)
-            return rv;
+		return rv;
+
+	/*
+	 * Skip this if there is no underlying device present for this PV.
+	 */
+	if (!pv->dev)
+		return rv;
 
 	dm_list_iterate_items(pvl, &correct_vg->pvs)
 		if (pv->dev == pvl->pv->dev && is_missing_pv(pvl->pv)) {
@@ -4039,6 +4132,7 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd,
 				   struct volume_group *vg,
 				   int repair, int *inconsistent_pvs)
 {
+	char uuid[64] __attribute__((aligned(8)));
 	struct lvmcache_info *info;
 	uint32_t ext_version, ext_flags;
 	struct pv_list *pvl;
@@ -4052,6 +4146,14 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd,
 		if (is_missing_pv(pvl->pv))
 			continue;
 
+		if (!pvl->pv->dev) {
+			/* is_missing_pv doesn't catch NULL dev */
+			memset(&uuid, 0, sizeof(uuid));
+			id_write_format(&pvl->pv->id, uuid, sizeof(uuid));
+			log_warn("WARNING: Not repairing PV %s with missing device.", uuid);
+			continue;
+		}
+
 		if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, pvl->pv->dev, 0))) {
 			log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
 			goto out;
@@ -4165,8 +4267,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
 	if (lvmetad_used() && !use_precommitted) {
 		if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted))) {
 			dm_list_iterate_items(pvl, &correct_vg->pvs)
-				if (pvl->pv->dev)
-					reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent);
+				reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent);
 			if (reappeared && *consistent)
 				*consistent = _repair_inconsistent_vg(correct_vg);
 			else
@@ -5863,7 +5964,11 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
 	if (failure)
 		goto_bad;
 
-	return _vg_make_handle(cmd, vg, failure);
+	if (!(vg = _vg_make_handle(cmd, vg, failure)) || vg_read_error(vg))
+		if (!already_locked)
+			unlock_vg(cmd, vg, vg_name);
+
+	return vg;
 
 bad:
 	if (!already_locked)
@@ -5924,7 +6029,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
 struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
 			 const char *vgid, uint32_t read_flags, uint32_t lockd_state)
 {
-	return vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state);
+	struct volume_group *vg = vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state);
+
+	if (!vg || vg_read_error(vg))
+		stack;
+
+	return vg;
 }
 
 /*
@@ -5953,9 +6063,8 @@ uint32_t vg_read_error(struct volume_group *vg_handle)
  */
 uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
 {
-	if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) {
+	if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL))
 		return FAILED_LOCKING;
-	}
 
 	/* Find the vgname in the cache */
 	/* If it's not there we must do full scan to be completely sure */
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index b708442..52def78 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -57,6 +57,25 @@ static int _reshape_is_supported(struct cmd_context *cmd, const struct segment_t
 }
 
 /*
+ * Check if rebuild CTR args are allowed when other images exist in the array
+ * with empty metadata areas for this kernel.
+ */
+static int _rebuild_with_emptymeta_is_supported(struct cmd_context *cmd,
+						const struct segment_type *segtype)
+{
+	unsigned attrs;
+
+	if (!segtype->ops->target_present ||
+            !segtype->ops->target_present(cmd, NULL, &attrs) ||
+            !(attrs & RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD)) {
+		log_verbose("RAID module does not support rebuild+emptymeta.");
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
  * Ensure region size exceeds the minimum for @lv because
  * MD's bitmap is limited to tracking 2^21 regions.
  *
@@ -285,6 +304,17 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r
 	struct lv_list *lvl;
 
 	dm_list_iterate_items(lvl, removal_lvs) {
+		if (!lv_is_visible(lvl->lv)) {
+			log_error(INTERNAL_ERROR
+				  "LVs must be set visible before removing.");
+			return 0;
+		}
+		/* Got to get any cluster lock an SubLVs to be removed. */
+		if (!activate_lv_excl_local(vg->cmd, lvl->lv))
+			return_0;
+	}
+
+	dm_list_iterate_items(lvl, removal_lvs) {
 		if (!deactivate_lv(vg->cmd, lvl->lv))
 			return_0;
 		if (!lv_remove(lvl->lv))
@@ -379,23 +409,6 @@ int lv_raid_in_sync(const struct logical_volume *lv)
 	return _raid_in_sync(lv);
 }
 
-/* Check if RaidLV @lv is synced or any raid legs of @lv are not synced */
-static int _raid_devs_sync_healthy(struct logical_volume *lv)
-{
-	char *raid_health;
-
-	if (!_raid_in_sync(lv))
-		return 0;
-
-	if (!seg_is_raid1(first_seg(lv)))
-		return 1;
-
-	if (!lv_raid_dev_health(lv, &raid_health))
-		return_0;
-
-	return (strchr(raid_health, 'a') || strchr(raid_health, 'D')) ? 0 : 1;
-}
-
 /*
  * _raid_remove_top_layer
  * @lv
@@ -427,8 +440,10 @@ static int _raid_remove_top_layer(struct logical_volume *lv,
 		return 0;
 	}
 
-	if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl))))
+	if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, 2 * sizeof(*lvl)))) {
+		log_error("Memory allocation failed.");
 		return_0;
+	}
 
 	/* Add last metadata area to removal_lvs */
 	lvl_array[0].lv = seg_metalv(seg, 0);
@@ -786,8 +801,10 @@ static int _reorder_raid10_near_seg_areas(struct lv_segment *seg, enum raid0_rai
 	/* FIXME: once more data copies supported with raid10 */
 	stripes /= data_copies;
 
-	if (!(idx = dm_pool_zalloc(seg_lv(seg, 0)->vg->vgmem, seg->area_count * sizeof(*idx))))
-		return 0;
+	if (!(idx = dm_pool_zalloc(seg_lv(seg, 0)->vg->vgmem, seg->area_count * sizeof(*idx)))) {
+		log_error("Memory allocation failed.");
+		return_0;
+	}
 
 	/* Set up positional index array */
 	switch (conv) {
@@ -1056,8 +1073,10 @@ static int _alloc_image_components(struct logical_volume *lv,
 	const char *raid_segtype;
 
 	if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem,
-					sizeof(*lvl_array) * count * 2)))
+					sizeof(*lvl_array) * count * 2))) {
+		log_error("Memory allocation failed.");
 		return_0;
+	}
 
 	if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 1)))
 		return_0;
@@ -1250,6 +1269,10 @@ static int _cmp_level(const struct segment_type *t1, const struct segment_type *
 	    (!segtype_is_any_raid10(t1) && segtype_is_any_raid10(t2)))
 		return 0;
 
+	if ((segtype_is_raid4(t1) && segtype_is_raid5_n(t2)) ||
+	    (segtype_is_raid5_n(t1) && segtype_is_raid4(t2)))
+		return 1;
+
 	return !strncmp(t1->name, t2->name, 5);
 }
 
@@ -1627,6 +1650,8 @@ static int _lv_free_reshape_space_with_status(struct logical_volume *lv, enum al
 	} else if (where_it_was)
 		*where_it_was = alloc_none;
 
+	lv->status &= ~LV_RESHAPE;
+
 	return 1;
 }
 
@@ -1834,6 +1859,9 @@ static int _raid_reshape_add_images(struct logical_volume *lv,
 
 	seg->stripe_size = new_stripe_size;
 
+	/* Define image adding reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */
+	lv->status |= LV_RESHAPE;
+
 	return 1;
 }
 
@@ -1933,6 +1961,8 @@ static int _raid_reshape_remove_images(struct logical_volume *lv,
 		if (seg_is_any_raid5(seg) && new_image_count == 2)
 			seg->data_copies = 2;
 
+		/* Define image removing reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */
+		lv ->status |= LV_RESHAPE;
 		break;
 
 	case 1:
@@ -1971,7 +2001,6 @@ static int _raid_reshape_remove_images(struct logical_volume *lv,
 			return 0;
 
 		seg->area_count = new_image_count;
-
 		break;
 
 	default:
@@ -1986,10 +2015,11 @@ static int _raid_reshape_remove_images(struct logical_volume *lv,
 /*
  * HM Helper:
  *
- * Reshape: keep images in RAID @lv but change stripe size or data copies
+ * Reshape: keep images in RAID @lv but change layout, stripe size or data copies
  *
  */
 static const char *_get_segtype_alias(const struct segment_type *segtype);
+static const char *_get_segtype_alias_str(const struct logical_volume *lv, const struct segment_type *segtype);
 static int _raid_reshape_keep_images(struct logical_volume *lv,
 				     const struct segment_type *new_segtype,
 				     int yes, int force, int *force_repair,
@@ -2001,10 +2031,13 @@ static int _raid_reshape_keep_images(struct logical_volume *lv,
 	struct lv_segment *seg = first_seg(lv);
 
 	if (seg->segtype != new_segtype)
-		log_print_unless_silent("Converting %s LV %s to %s.",
-					lvseg_name(seg), display_lvname(lv), new_segtype->name);
-	if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s? [y/n]: ",
-				  lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') {
+		log_print_unless_silent("Converting %s%s LV %s to %s%s.",
+					lvseg_name(seg), _get_segtype_alias_str(lv, seg->segtype),
+					display_lvname(lv), new_segtype->name,
+					_get_segtype_alias_str(lv, new_segtype));
+
+	if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s? [y/n]: ",
+				  lvseg_name(seg), display_lvname(lv)) == 'n') {
 			log_error("Logical volume %s NOT converted.", display_lvname(lv));
 			return 0;
 	}
@@ -2022,12 +2055,9 @@ static int _raid_reshape_keep_images(struct logical_volume *lv,
 	 * The dm-raid target is able to use the space whereever it
 	 * is found by appropriately selecting forward or backward reshape.
 	 */
-	if (seg->segtype != new_segtype) {
-		const char *alias = _get_segtype_alias(seg->segtype);
-
-		if (!strcmp(alias, new_segtype->name))
-			alloc_reshape_space = 0;
-	}
+	if (seg->segtype != new_segtype &&
+	    !strcmp(_get_segtype_alias(seg->segtype), new_segtype->name))
+		alloc_reshape_space = 0;
 
 	if (seg->stripe_size != new_stripe_size)
 		alloc_reshape_space = 1;
@@ -2043,6 +2073,9 @@ static int _raid_reshape_keep_images(struct logical_volume *lv,
 
 	seg->segtype = new_segtype;
 
+	/* Define stripesize/raid algorithm reshape (used as SEGTYPE_FLAG to avoid incompatible activations on old runtime) */
+	lv->status |= LV_RESHAPE;
+
 	return 1;
 }
 
@@ -2226,6 +2259,8 @@ static int _raid_reshape(struct logical_volume *lv,
 		return 0;
 	}
 
+	lv->status &= ~LV_RESHAPE; /* Reset any reshaping segtype flag */
+
 	dm_list_init(&removal_lvs);
 
 	/* No change in layout requested ? */
@@ -2311,6 +2346,12 @@ static int _raid_reshape(struct logical_volume *lv,
 
 	/* Handle disk addition reshaping */
 	if (old_image_count < new_image_count) {
+		/* FIXME: remove once MD kernel rhbz1443999 got fixed. */
+		if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
+			log_error("Can't add stripes to LV %s on single core.", display_lvname(lv));
+			return 0;
+		}
+
 		if (!_raid_reshape_add_images(lv, new_segtype, yes,
 					      old_image_count, new_image_count,
 					      new_stripes, new_stripe_size, allocate_pvs))
@@ -2318,6 +2359,12 @@ static int _raid_reshape(struct logical_volume *lv,
 
 	/* Handle disk removal reshaping */
 	} else if (old_image_count > new_image_count) {
+		/* FIXME: remove once MD kernel rhbz1443999 got fixed. */
+		if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
+			log_error("Can't remove stripes from LV %s on single core.", display_lvname(lv));
+			return 0;
+		}
+
 		if (!_raid_reshape_remove_images(lv, new_segtype, yes, force,
 						 old_image_count, new_image_count,
 						 new_stripes, new_stripe_size,
@@ -2505,6 +2552,7 @@ static int _raid_add_images_without_commit(struct logical_volume *lv,
 	struct dm_list meta_lvs, data_lvs;
 	struct lv_list *lvl;
 	struct lv_segment_area *new_areas;
+	struct segment_type *segtype;
 
 	if (lv_is_not_synced(lv)) {
 		log_error("Can't add image to out-of-sync RAID LV:"
@@ -2536,8 +2584,19 @@ static int _raid_add_images_without_commit(struct logical_volume *lv,
 	 * LV to accompany it.
 	 */
 	if (seg_is_linear(seg)) {
-		/* A complete resync will be done, no need to mark each sub-lv */
-		status_mask = ~(LV_REBUILD);
+		/*
+		 * As of dm-raid version 1.9.0, it is possible to specify
+		 * RAID table lines with the 'rebuild' parameters necessary
+		 * to force a "recover" instead of a "resync" on upconvert.
+		 *
+		 * LVM's interaction with older kernels should be as before -
+		 * performing a complete resync rather than a set of rebuilds.
+		 */
+		if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_RAID1)))
+			return_0;
+
+		if (!_rebuild_with_emptymeta_is_supported(lv->vg->cmd, segtype))
+			status_mask = ~(LV_REBUILD);
 
 		/* FIXME: allow setting region size on upconvert from linear */
 		seg->region_size = get_default_region_size(lv->vg->cmd);
@@ -2803,6 +2862,87 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
 }
 
 /*
+ * _raid_allow_extraction
+ * @lv
+ * @extract_count
+ * @target_pvs
+ *
+ * returns: 0 if no, 1 if yes
+ */
+static int _raid_allow_extraction(struct logical_volume *lv,
+				  int extract_count,
+				  struct dm_list *target_pvs)
+{
+	int s, redundancy = 0;
+	char *dev_health;
+	char *sync_action;
+	struct lv_segment *seg = first_seg(lv);
+	struct cmd_context *cmd = lv->vg->cmd;
+
+	/* If in-sync or hanlding repairs, allow to proceed. */
+	if (_raid_in_sync(lv) || lv->vg->cmd->handles_missing_pvs)
+		return 1;
+
+	/*
+	 * FIXME:
+	 * Right now, we are primarily concerned with down-converting of
+	 * RAID1 LVs, but parity RAIDs and RAID10 will also have to be
+	 * considered.
+	 * (e.g. It would not be good to allow extracting a dev from a
+	 * stripe set while upconverting to RAID5/6.)
+	 */
+	if (!segtype_is_raid1(seg->segtype))
+		return 1;
+
+	/*
+	 * We can allow extracting images if the array is performing a
+	 * sync operation as long as it is "recover" and the image is not
+	 * a primary image or if "resync".
+	 */
+	if (!lv_raid_sync_action(lv, &sync_action) ||
+	    !lv_raid_dev_health(lv, &dev_health))
+		return_0;
+
+	if (!strcmp("idle", sync_action)) {
+		log_error(INTERNAL_ERROR
+			  "RAID LV should not be out-of-sync and \"idle\"");
+		return 0;
+	}
+
+	if (!strcmp("resync", sync_action))
+		return 1;
+
+	/* If anything other than "recover" */
+	if (strcmp("recover", sync_action)) {
+		log_error("Unable to remove RAID image while array"
+			  " is performing \"%s\"", sync_action);
+		return 0;
+	}
+
+	if (seg->area_count != strlen(dev_health)) {
+		log_error(INTERNAL_ERROR
+			  "RAID LV area_count differs from number of health characters");
+		return 0;
+	}
+
+	for (s = 0; s < seg->area_count; s++)
+		if (dev_health[s] == 'A')
+			redundancy++;
+
+	for (s = 0; (s < seg->area_count) && extract_count; s++) {
+		if (!lv_is_on_pvs(seg_lv(seg, s), target_pvs) &&
+		    !lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
+			continue;
+		if ((dev_health[s] == 'A') && !--redundancy) {
+			log_error("Unable to remove all primary source devices");
+			return 0;
+		}
+		extract_count--;
+	}
+	return 1;
+}
+
+/*
  * _raid_extract_images
  * @lv
  * @force: force a replacement in case of primary mirror leg
@@ -2833,6 +2973,10 @@ static int _raid_extract_images(struct logical_volume *lv,
 	struct segment_type *error_segtype;
 
 	extract = seg->area_count - new_count;
+
+	if (!_raid_allow_extraction(lv, extract, target_pvs))
+		return_0;
+
 	log_verbose("Extracting %u %s from %s.", extract,
 		    (extract > 1) ? "images" : "image",
 		    display_lvname(lv));
@@ -2888,20 +3032,8 @@ static int _raid_extract_images(struct logical_volume *lv,
 			if (!lv_is_on_pvs(seg_lv(seg, s), target_pvs) &&
 			    !lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
 				continue;
-
-			/*
-			 * Kernel may report raid LV in-sync but still
-			 * image devices may not be in-sync or faulty.
-			 */
-			if (!_raid_devs_sync_healthy(lv) &&
-			    (!seg_is_mirrored(seg) || (s == 0 && !force))) {
-				log_error("Unable to extract %sRAID image"
-					  " while RAID array is not in-sync%s.",
-					  seg_is_mirrored(seg) ? "primary " : "",
-					  seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
-				return 0;
-			}
 		}
+
 		if (!_extract_image_components(seg, s, &rmeta_lv, &rimage_lv)) {
 			log_error("Failed to extract %s from %s.",
 				  display_lvname(seg_lv(seg, s)),
@@ -3035,6 +3167,13 @@ 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";
 
+	/* LV must be active to perform raid conversion operations */
+	if (!lv_is_active(lv)) {
+		log_error("%s must be active to perform this operation.",
+			  display_lvname(lv));
+		return 0;
+	}
+
 	if (new_count != 1 && /* Already prompted for in _raid_remove_images() */
 	    !yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s%u images %s resilience? [y/n]: ",
 				  lvseg_name(first_seg(lv)), display_lvname(lv), level, new_count, resil) == 'n') {
@@ -4437,6 +4576,7 @@ static int _log_possible_conversion(uint64_t *processed_segtypes, void *data)
 	return 1;
 }
 
+/* Return any segment type alias name for @segtype or empty string */
 static const char *_get_segtype_alias(const struct segment_type *segtype)
 {
 	if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID5))
@@ -4460,12 +4600,28 @@ static const char *_get_segtype_alias(const struct segment_type *segtype)
 	return "";
 }
 
+/* Return any segment type alias string (format " (same as raid*)") for @segtype or empty string */
+static const char *_get_segtype_alias_str(const struct logical_volume *lv, const struct segment_type *segtype)
+{
+	const char *alias = _get_segtype_alias(segtype);
+
+	if (*alias) {
+		const char *msg = " (same as ";
+		size_t sz = strlen(msg) + strlen(alias) + 2;
+		char *buf = dm_pool_alloc(lv->vg->cmd->mem, sz);
+
+		if (buf)
+			alias = (dm_snprintf(buf, sz, "%s%s)", msg, alias) < 0) ? "" : buf;
+	}
+
+	return alias;
+}
+
 static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
 {
 	unsigned possible_conversions = 0;
 	const struct lv_segment *seg = first_seg(lv);
 	struct possible_type *pt = NULL;
-	const char *alias;
 	uint64_t processed_segtypes = UINT64_C(0);
 
 	/* Count any possible segment types @seg an be directly converted to */
@@ -4476,12 +4632,10 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const
 	if (!possible_conversions)
 		log_error("Direct conversion of %s LV %s is not possible.", lvseg_name(seg), display_lvname(lv));
 	else {
-			alias = _get_segtype_alias(seg->segtype);
-
-			log_error("Converting %s from %s%s%s%s is "
+			log_error("Converting %s from %s%s is "
 				  "directly possible to the following layout%s:",
 				  display_lvname(lv), lvseg_name(seg),
-				  *alias ? " (same as " : "", alias, *alias ? ")" : "",
+				  _get_segtype_alias_str(lv, seg->segtype),
 				  possible_conversions > 1 ? "s" : "");
 
 			pt = NULL;
@@ -4526,10 +4680,16 @@ static int _takeover_noop(TAKEOVER_FN_ARGS)
 
 static int _takeover_unsupported(TAKEOVER_FN_ARGS)
 {
-	log_error("Converting the segment type for %s from %s to %s is not supported.",
-		  display_lvname(lv), lvseg_name(first_seg(lv)),
-		  (segtype_is_striped_target(new_segtype) &&
-		   (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name);
+	struct lv_segment *seg = first_seg(lv);
+
+	if (seg->segtype == new_segtype)
+		log_error("Logical volume %s already is type %s.",
+			  display_lvname(lv), lvseg_name(seg));
+	else
+		log_error("Converting the segment type for %s from %s to %s is not supported.",
+			  display_lvname(lv), lvseg_name(seg),
+			  (segtype_is_striped_target(new_segtype) &&
+			  (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name);
 
 	if (!_log_possible_conversion_types(lv, new_segtype))
 		stack;
@@ -4749,9 +4909,6 @@ static int _rename_area_lvs(struct logical_volume *lv, const char *suffix)
 			return_0;
 	}
 
-	for (s = 0; s < SLV_COUNT; s++)
-		dm_pool_free(lv->vg->cmd->mem, sfx[s]);
-
 	return 1;
 }
 
@@ -4844,6 +5001,15 @@ static int _raid45_to_raid54_wrapper(TAKEOVER_FN_ARGS)
 		return 0;
 	}
 
+	if (!yes && yes_no_prompt("Are you sure you want to convert %s%s LV %s to %s%s type? [y/n]: ",
+				  lvseg_name(seg), _get_segtype_alias_str(lv, seg->segtype),
+				  display_lvname(lv), new_segtype->name,
+				  _get_segtype_alias_str(lv, new_segtype)) == 'n') {
+		log_error("Logical volume %s NOT converted to \"%s\".",
+			  display_lvname(lv), new_segtype->name);
+		return 0;
+	}
+
 	log_debug_metadata("Converting LV %s from %s to %s.", display_lvname(lv),
 			   (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID4 : SEG_TYPE_NAME_RAID5_N),
 			   (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID5_N : SEG_TYPE_NAME_RAID4));
@@ -5018,7 +5184,7 @@ static int _takeover_downconvert_wrapper(TAKEOVER_FN_ARGS)
 	}
 
 	if (segtype_is_raid4(new_segtype))
-		return _raid45_to_raid54_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count,
+		return _raid45_to_raid54_wrapper(lv, new_segtype, 1 /* yes */, force, first_seg(lv)->area_count,
 						 1 /* data_copies */, 0, 0, 0, allocate_pvs);
 
 	return 1;
@@ -5200,7 +5366,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS)
 		if (!(raid5_n_segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID5_N)))
 			return_0;
 
-		/* raid6 upconvert: vonvert to raid5_n preserving already allocated new image component pair */
+		/* raid6 upconvert: convert to raid5_n preserving already allocated new image component pair */
 		if (segtype_is_any_raid6(new_segtype)) {
 			struct logical_volume *meta_lv, *data_lv;
 
@@ -5217,7 +5383,7 @@ static int _takeover_upconvert_wrapper(TAKEOVER_FN_ARGS)
 						      extents_copied, seg_len);
 			seg->area_count--;
 
-			if (!_raid45_to_raid54_wrapper(lv, raid5_n_segtype, yes, force, seg->area_count,
+			if (!_raid45_to_raid54_wrapper(lv, raid5_n_segtype, 1 /* yes */, force, seg->area_count,
 						       1 /* data_copies */, 0, 0, 0, allocate_pvs))
 				return 0;
 
@@ -5751,94 +5917,172 @@ static uint64_t _r5_to_r6[][2] = {
 
 
 /* Return segment type flag for raid5 -> raid6 conversions */
-static uint64_t _get_r56_flag(const struct lv_segment *seg, unsigned idx)
+static uint64_t _get_r56_flag(const struct segment_type *segtype, unsigned idx)
 {
 	unsigned elems = ARRAY_SIZE(_r5_to_r6);
 
 	while (elems--)
-		if (seg->segtype->flags & _r5_to_r6[elems][idx])
+		if (segtype->flags & _r5_to_r6[elems][idx])
 			return _r5_to_r6[elems][!idx];
 
 	return 0;
 }
 
-/* Return segment type flag for raid5 -> raid6 conversions */
+/* Return segment type flag of @seg for raid5 -> raid6 conversions */
 static uint64_t _raid_seg_flag_5_to_6(const struct lv_segment *seg)
 {
-	return _get_r56_flag(seg, 0);
+	return _get_r56_flag(seg->segtype, 0);
 }
 
-/* Return segment type flag for raid6 -> raid5 conversions */
+/* Return segment type flag of @seg for raid6 -> raid5 conversions */
 static uint64_t _raid_seg_flag_6_to_5(const struct lv_segment *seg)
 {
-	return _get_r56_flag(seg, 1);
+	return _get_r56_flag(seg->segtype, 1);
 }
 
-/* Change segtype for raid4 <-> raid5 <-> raid6 where necessary. */
-static int _set_convenient_raid1456_segtype_to(const struct lv_segment *seg_from,
-					       const struct segment_type **segtype,
-					       int yes)
+/* Return segment type flag of @segtype for raid5 -> raid6 conversions */
+static uint64_t _raid_segtype_flag_5_to_6(const struct segment_type *segtype)
 {
-	size_t len = min(strlen((*segtype)->name), strlen(lvseg_name(seg_from)));
-	uint64_t seg_flag;
+	return _get_r56_flag(segtype, 0);
+}
+
+/* Change segtype for raid* for convenience where necessary. */
+/* FIXME: do this like _conversion_options_allowed()? */
+static int _set_convenient_raid145610_segtype_to(const struct lv_segment *seg_from,
+						 const struct segment_type **segtype,
+						 int yes)
+{
+	uint64_t seg_flag = 0;
 	struct cmd_context *cmd = seg_from->lv->vg->cmd;
 	const struct segment_type *segtype_sav = *segtype;
 
 	/* Bail out if same RAID level is requested. */
-	if (!strncmp((*segtype)->name, lvseg_name(seg_from), len))
+	if (is_same_level(seg_from->segtype, *segtype))
 		return 1;
 
-	/* Striped/raid0 -> raid5/6 */
+	log_debug("Checking LV %s requested %s segment type for convenience",
+		  display_lvname(seg_from->lv), (*segtype)->name);
+
+	/* striped/raid0 -> raid5/6 */
 	if (seg_is_striped(seg_from) || seg_is_any_raid0(seg_from)) {
 		/* If this is any raid5 conversion request -> enforce raid5_n, because we convert from striped */
-		if (segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype)) {
+		if (segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype))
 			seg_flag = SEG_RAID5_N;
-			goto replaced;
 
 		/* If this is any raid6 conversion request -> enforce raid6_n_6, because we convert from striped */
-		} else if (segtype_is_any_raid6(*segtype) && !segtype_is_raid6_n_6(*segtype)) {
+		else if (segtype_is_any_raid6(*segtype) && !segtype_is_raid6_n_6(*segtype))
 			seg_flag = SEG_RAID6_N_6;
-			goto replaced;
+
+	/* raid1 -> */
+	} else if (seg_is_raid1(seg_from) && !segtype_is_mirror(*segtype)) {
+		if (seg_from->area_count != 2) {
+			log_warn("Convert %s LV %s to 2 images first.",
+				 lvseg_name(seg_from), display_lvname(seg_from->lv));
+			return 0;
+
+		} else if (segtype_is_striped(*segtype) ||
+			   segtype_is_any_raid0(*segtype) ||
+			   segtype_is_raid10(*segtype))
+			seg_flag = SEG_RAID5_N;
+
+		else if (!segtype_is_raid4(*segtype) && !segtype_is_any_raid5(*segtype))
+			seg_flag = SEG_RAID5_LS;
+
+	/* raid4/raid5 -> striped/raid0/raid1/raid6/raid10 */
+	} else if (seg_is_raid4(seg_from) || seg_is_any_raid5(seg_from)) {
+		if (segtype_is_raid1(*segtype) &&
+		    seg_from->area_count != 2) {
+			log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).",
+				 lvseg_name(seg_from), display_lvname(seg_from->lv));
+			return 0;
+
+		} else if (seg_is_raid4(seg_from) &&
+			   segtype_is_any_raid5(*segtype) &&
+			   !segtype_is_raid5_n(*segtype))
+			seg_flag = SEG_RAID5_N;
+
+		else if (seg_is_any_raid5(seg_from) &&
+			 segtype_is_raid4(*segtype) &&
+			 !segtype_is_raid5_n(*segtype))
+			seg_flag = SEG_RAID5_N;
+
+		else if (segtype_is_raid10(*segtype)) {
+			if (seg_from->area_count < 3) {
+				log_warn("Convert %s LV %s to minimum 3 stripes first (i.e. --stripes 2).",
+					 lvseg_name(seg_from), display_lvname(seg_from->lv));
+				return 0;
+			}
+
+			seg_flag = SEG_RAID0_META;
+
+		} else if (segtype_is_any_raid6(*segtype)) {
+			if (seg_from->area_count < 4) {
+				log_warn("Convert %s LV %s to minimum 4 stripes first (i.e. --stripes 3).",
+					 lvseg_name(seg_from), display_lvname(seg_from->lv));
+				return 0;
+
+			} else if (seg_is_raid4(seg_from) && !segtype_is_raid6_n_6(*segtype))
+				seg_flag = SEG_RAID6_N_6;
+			else
+				seg_flag = _raid_seg_flag_5_to_6(seg_from);
 		}
 
-	/* raid4 -> raid5_n */
-	} else if (seg_is_raid4(seg_from) && segtype_is_any_raid5(*segtype)) {
-		seg_flag = SEG_RAID5_N;
-		goto replaced;
+	/* raid6 -> striped/raid0/raid5/raid10 */
+	} else if (seg_is_any_raid6(seg_from)) {
+		if (segtype_is_raid1(*segtype)) {
+			/* No result for raid6_{zr,nr,nc} */
+			if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)) ||
+			    !(seg_flag & (*segtype)->flags))
+				seg_flag = SEG_RAID6_LS_6;
 
-	/* raid4/raid5_n -> striped/raid0/raid6 */
-	} else if ((seg_is_raid4(seg_from) || seg_is_raid5_n(seg_from)) &&
-		   !segtype_is_striped(*segtype) &&
-		   !segtype_is_any_raid0(*segtype) &&
-		   !segtype_is_raid1(*segtype) &&
-		   !segtype_is_raid4(*segtype) &&
-		   !segtype_is_raid5_n(*segtype) &&
-		   !segtype_is_raid6_n_6(*segtype)) {
-		seg_flag = SEG_RAID6_N_6;
-		goto replaced;
-
-	/* Got to do check for raid5 -> raid6 ... */
-	} else if (seg_is_any_raid5(seg_from) && segtype_is_any_raid6(*segtype)) {
-		if (!(seg_flag = _raid_seg_flag_5_to_6(seg_from)))
-			return_0;
-		goto replaced;
+		} else if (segtype_is_any_raid10(*segtype)) {
+			seg_flag = seg_is_raid6_n_6(seg_from) ? SEG_RAID0_META : SEG_RAID6_N_6;
+
+		} else if ((segtype_is_striped(*segtype) || segtype_is_any_raid0(*segtype)) &&
+			   !seg_is_raid6_n_6(seg_from)) {
+			seg_flag = SEG_RAID6_N_6;
+
+		} else if (segtype_is_raid4(*segtype) && !seg_is_raid6_n_6(seg_from)) {
+			seg_flag = SEG_RAID6_N_6;
 
-	/* ... and raid6 -> raid5 */
-	} else if (seg_is_any_raid6(seg_from) && segtype_is_any_raid5(*segtype)) {
-		/* No result for raid6_{zr,nr,nc} */
-		if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)))
+		} else if (segtype_is_any_raid5(*segtype))
+			/* No result for raid6_{zr,nr,nc} */
+			if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)) ||
+			    !(seg_flag & (*segtype)->flags))
+				seg_flag = _raid_segtype_flag_5_to_6(*segtype);
+
+	/* -> raid1 */
+	} else if (!seg_is_mirror(seg_from) && segtype_is_raid1(*segtype)) {
+		if (!seg_is_raid4(seg_from) && !seg_is_any_raid5(seg_from)) {
+			log_warn("Convert %s LV %s to raid4/raid5 first.",
+				 lvseg_name(seg_from), display_lvname(seg_from->lv));
 			return 0;
-		goto replaced;
-	}
 
-	return 1;
+		} else if (seg_from->area_count != 2) {
+			log_warn("Convert %s LV %s to 2 stripes first (i.e. --stripes 1).",
+				 lvseg_name(seg_from), display_lvname(seg_from->lv));
+			return 0;
+
+		}
+
+	/* raid10 -> ... */
+	} else if (seg_is_raid10(seg_from) &&
+		   !segtype_is_striped(*segtype) &&
+		   !segtype_is_any_raid0(*segtype))
+		seg_flag = SEG_RAID0_META;
+
+	if (seg_flag) {
+		if (!(*segtype = get_segtype_from_flag(cmd, seg_flag)))
+			return_0;
+		if (segtype_sav != *segtype) {
+			log_warn("Replaced LV type %s%s with possible type %s.",
+				 segtype_sav->name, _get_segtype_alias_str(seg_from->lv, segtype_sav),
+				 (*segtype)->name);
+			log_warn("Repeat this command to convert to %s after an interim conversion has finished.",
+				 segtype_sav->name);
+		}
+	}
 
-replaced:
-	if (!(*segtype = get_segtype_from_flag(cmd, seg_flag)))
-		return_0;
-	if (segtype_sav != *segtype)
-		log_warn("Replaced LV type %s with possible type %s.",
-			 segtype_sav->name, (*segtype)->name);
 	return 1;
 }
 
@@ -5905,6 +6149,8 @@ static int _region_size_change_requested(struct logical_volume *lv, int yes, con
 		return 0;
 	}
 
+	lv->status &= ~LV_RESHAPE;
+
 	if (!lv_update_and_reload_origin(lv))
 		return_0;
 
@@ -5924,7 +6170,7 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from,
 	int r = 1;
 	uint32_t opts;
 
-	if (!new_image_count && !_set_convenient_raid1456_segtype_to(seg_from, segtype_to, yes))
+	if (!new_image_count && !_set_convenient_raid145610_segtype_to(seg_from, segtype_to, yes))
 		return_0;
 
 	if (!_get_allowed_conversion_options(seg_from, *segtype_to, new_image_count, &opts)) {
@@ -5952,12 +6198,28 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from,
 	}
 
 	if (r &&
+	    !yes &&
 	    strcmp((*segtype_to)->name, SEG_TYPE_NAME_MIRROR) && /* "mirror" is prompted for later */
-	    !yes && yes_no_prompt("Are you sure you want to convert %s LV %s to %s type? [y/n]: ",
-				  lvseg_name(seg_from), display_lvname(seg_from->lv),
+	    !is_same_level(seg_from->segtype, *segtype_to)) { /* Prompt here for takeover */
+		const char *basic_fmt = "Are you sure you want to convert %s LV %s";
+		const char *type_fmt = " to %s type";
+		const char *question_fmt = "? [y/n]: ";
+		char *fmt;
+		size_t sz = strlen(basic_fmt) + ((seg_from->segtype == *segtype_to) ? 0 : strlen(type_fmt)) + strlen(question_fmt) + 1;
+
+		if (!(fmt = dm_pool_alloc(seg_from->lv->vg->cmd->mem, sz)))
+			return_0;
+
+		if (dm_snprintf(fmt, sz, "%s%s%s", basic_fmt, (seg_from->segtype == *segtype_to) ? "" : type_fmt, question_fmt) < 0) {
+			log_error(INTERNAL_ERROR "dm_snprintf failed.");
+			return_0;
+		}
+
+		if (yes_no_prompt(fmt, lvseg_name(seg_from), display_lvname(seg_from->lv),
 				  (*segtype_to)->name) == 'n') {
-		log_error("Logical volume %s NOT converted.", display_lvname(seg_from->lv));
-		r = 0;
+			log_error("Logical volume %s NOT converted.", display_lvname(seg_from->lv));
+			r = 0;
+		}
 	}
 
 	return r;
@@ -6014,6 +6276,15 @@ int lv_raid_convert(struct logical_volume *lv,
 	uint32_t available_slvs, removed_slvs;
 	takeover_fn_t takeover_fn;
 
+	/* FIXME If not active, prompt and activate */
+	/* FIXME Some operations do not require the LV to be active */
+	/* LV must be active to perform raid conversion operations */
+	if (!lv_is_active(lv)) {
+		log_error("%s must be active to perform this operation.",
+			  display_lvname(lv));
+		return 0;
+	}
+
 	new_segtype = new_segtype ? : seg->segtype;
 	if (!new_segtype) {
 		log_error(INTERNAL_ERROR "New segtype not specified.");
@@ -6040,6 +6311,15 @@ int lv_raid_convert(struct logical_volume *lv,
 	region_size = region_size ? : get_default_region_size(lv->vg->cmd);
 
 	/*
+	 * Check acceptible options mirrors, region_size,
+	 * stripes and/or stripe_size have been provided.
+	 */
+	if (!_conversion_options_allowed(seg, &new_segtype, yes,
+					 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size,
+					 new_stripes, new_stripe_size_supplied))
+		return _log_possible_conversion_types(lv, new_segtype);
+
+	/*
 	 * reshape of capable raid type requested
 	 */
 	switch (_reshape_requested(lv, new_segtype, data_copies, region_size, stripes, stripe_size)) {
@@ -6074,15 +6354,6 @@ int lv_raid_convert(struct logical_volume *lv,
 		return 0;
 	}
 
-	/*
-	 * Check acceptible options mirrors, region_size,
-	 * stripes and/or stripe_size have been provided.
-	 */
-	if (!_conversion_options_allowed(seg, &new_segtype, yes,
-					 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size,
-					 new_stripes, new_stripe_size_supplied))
-		return _log_possible_conversion_types(lv, new_segtype);
-	
 	takeover_fn = _get_takeover_fn(first_seg(lv), new_segtype, new_image_count);
 
 	/* Exit without doing activation checks if the combination isn't possible */
@@ -6117,15 +6388,6 @@ int lv_raid_convert(struct logical_volume *lv,
 		    (segtype_is_striped_target(new_segtype) &&
 		    (new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name);
 
-	/* FIXME If not active, prompt and activate */
-	/* FIXME Some operations do not require the LV to be active */
-	/* LV must be active to perform raid conversion operations */
-	if (!lv_is_active(lv)) {
-		log_error("%s must be active to perform this operation.",
-			  display_lvname(lv));
-		return 0;
-	}
-
 	/* In clustered VGs, the LV must be active on this node exclusively. */
 	if (vg_is_clustered(lv->vg) && !lv_is_active_exclusive_locally(lv)) {
 		log_error("%s must be active exclusive locally to "
@@ -6140,6 +6402,8 @@ int lv_raid_convert(struct logical_volume *lv,
 		return 0;
 	}
 
+	lv->status &= ~LV_RESHAPE;
+
 	return takeover_fn(lv, new_segtype, yes, force, new_image_count, 0, new_stripes, stripe_size,
 			   region_size, allocate_pvs);
 }
@@ -6229,6 +6493,39 @@ has_enough_space:
 }
 
 /*
+ * _lv_raid_has_primary_failure_on_recover
+ * @lv
+ *
+ * The kernel behaves strangely in the presense of a primary failure
+ * during a "recover" sync operation.  It's not technically a bug, I
+ * suppose, but the output of the status line can make it difficult
+ * to determine that we are in this state.  The sync ratio will be
+ * 100% and the sync action will be "idle", but the health characters
+ * will be e.g. "Aaa" or "Aa", where the 'A' is the dead
+ * primary source that cannot be marked dead by the kernel b/c
+ * it is the only source for the remainder of data.
+ *
+ * This function helps to detect that condition.
+ *
+ * Returns: 1 if the state is detected, 0 otherwise.
+ * FIXME: would be better to return -1,0,1 to allow error report.
+ */
+int _lv_raid_has_primary_failure_on_recover(struct logical_volume *lv)
+{
+	char *tmp_dev_health;
+	char *tmp_sync_action;
+
+	if (!lv_raid_sync_action(lv, &tmp_sync_action) ||
+	    !lv_raid_dev_health(lv, &tmp_dev_health))
+		return_0;
+
+	if (!strcmp(tmp_sync_action, "idle") && strchr(tmp_dev_health, 'a'))
+		return 1;
+
+	return 0;
+}
+
+/*
  * Helper:
  *
  * _lv_raid_rebuild_or_replace
@@ -6279,11 +6576,38 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
 	}
 
 	if (!_raid_in_sync(lv)) {
+		/*
+		 * FIXME: There is a bug in the kernel that prevents 'rebuild'
+		 *        from being specified when the array is not in-sync.
+		 *        There are conditions where this should be allowed,
+		 *        but only when we are doing a repair - as indicated by
+		 *        'lv->vg->cmd->handles_missing_pvs'.  The above
+		 *        conditional should be:
+		 (!lv->vg->cmd->handles_missing_pvs && !_raid_in_sync(lv))
+		 */
 		log_error("Unable to replace devices in %s while it is "
 			  "not in-sync.", display_lvname(lv));
 		return 0;
 	}
 
+	if (_lv_raid_has_primary_failure_on_recover(lv)) {
+		/*
+		 * I hate having multiple error lines, but this
+		 * seems to work best for syslog and CLI.
+		 */
+		log_error("Unable to repair %s/%s.  Source devices failed"
+			  " before the RAID could synchronize.",
+			  lv->vg->name, lv->name);
+		log_error("You should choose one of the following:");
+		log_error("  1) deactivate %s/%s, revive failed "
+			  "device, re-activate LV, and proceed.",
+			  lv->vg->name, lv->name);
+		log_error("  2) remove the LV (all data is lost).");
+		log_error("  3) Seek expert advice to attempt to salvage any"
+			  " data from remaining devices.");
+		return 0;
+	}
+
 	/*
 	 * How many sub-LVs are being removed?
 	 */
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index 93132c3..2acb894 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -290,6 +290,24 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
 #define RAID_FEATURE_RAID4			(1U << 3) /* ! version 1.8 or 1.9.0 */
 #define RAID_FEATURE_SHRINK			(1U << 4) /* version 1.9.0 */
 #define RAID_FEATURE_RESHAPE			(1U << 5) /* version 1.10.1 */
+/*
+ * RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD
+ * This signifies a behavioral change in dm-raid.  Prior to upstream kernel
+ * commit 33e53f068, the kernel would refuse to allow 'rebuild' CTR args to
+ * be submitted when other devices in the array had uninitialized superblocks.
+ * After the commit, these parameters were allowed.
+ *
+ * The most obvious useful case of this new behavior is up-converting a
+ * linear device to RAID1.  A new superblock is allocated for the linear dev
+ * and it will be uninitialized, while all the new images are specified for
+ * 'rebuild'.  This valid scenario would not have been allowed prior to
+ * commit 33e53f068.
+ *
+ * Commit 33e53f068 did not bump the dm-raid version number.  So it exists
+ * in some, but not all 1.8.1 versions of dm-raid.  The only way to be
+ * certain the new behavior exists is to check for version 1.9.0.
+ */
+#define RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD	(1U << 6) /* version 1.9.0 */
 
 #ifdef RAID_INTERNAL
 int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index f9cd3d0..ad45ce9 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -563,6 +563,12 @@ static uint64_t _estimate_metadata_size(uint32_t data_extents, uint32_t extent_s
 	return _estimate_size(data_extents, extent_size, chunk_size);
 }
 
+/* Estimate maximal supportable thin pool data size for given chunk_size */
+static uint64_t _estimate_max_data_size(uint32_t chunk_size)
+{
+	return  chunk_size * (DEFAULT_THIN_POOL_MAX_METADATA_SIZE * 2) * SECTOR_SIZE / UINT64_C(64);
+}
+
 /* Estimate thin pool chunk size from data and metadata size (in sector units) */
 static uint32_t _estimate_chunk_size(uint32_t data_extents, uint32_t extent_size,
 				     uint64_t metadata_size, int attr)
@@ -628,6 +634,7 @@ int update_thin_pool_params(struct cmd_context *cmd,
 {
 	uint64_t pool_metadata_size = (uint64_t) *pool_metadata_extents * extent_size;
 	uint32_t estimate_chunk_size;
+	uint64_t max_pool_data_size;
 	const char *str;
 
 	if (!*chunk_size &&
@@ -666,7 +673,7 @@ int update_thin_pool_params(struct cmd_context *cmd,
 
 			/* Check if we should eventually use bigger chunk size */
 			while ((pool_metadata_size >
-				(DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) &&
+				(DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE * 2)) &&
 			       (*chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) {
 				*chunk_size <<= 1;
 				pool_metadata_size >>= 1;
@@ -704,6 +711,16 @@ int update_thin_pool_params(struct cmd_context *cmd,
 		}
 	}
 
+	max_pool_data_size = _estimate_max_data_size(*chunk_size);
+	if ((max_pool_data_size / extent_size) < pool_data_extents) {
+		log_error("Selected chunk size %s cannot address more then %s of thin pool data space.",
+			  display_size(cmd, *chunk_size), display_size(cmd, max_pool_data_size));
+		return 0;
+	}
+
+	log_print_unless_silent("Thin pool volume with chunk size %s can address at most %s of data.",
+				display_size(cmd, *chunk_size), display_size(cmd, max_pool_data_size));
+
 	if (!validate_thin_pool_chunk_size(cmd, *chunk_size))
 		return_0;
 
diff --git a/lib/raid/raid.c b/lib/raid/raid.c
index 25009f6..8a53d7e 100644
--- a/lib/raid/raid.c
+++ b/lib/raid/raid.c
@@ -474,6 +474,7 @@ static int _raid_target_present(struct cmd_context *cmd,
 		{ 1, 3, 0, RAID_FEATURE_RAID10, SEG_TYPE_NAME_RAID10 },
 		{ 1, 7, 0, RAID_FEATURE_RAID0, SEG_TYPE_NAME_RAID0 },
 		{ 1, 9, 0, RAID_FEATURE_SHRINK, "shrinking" },
+		{ 1, 9, 0, RAID_FEATURE_NEW_DEVICES_ACCEPT_REBUILD, "rebuild+emptymeta" },
 		{ 1, 10, 1, RAID_FEATURE_RESHAPE, "reshaping" },
 	};
 
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 6ce6c57..b0c9e4b 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4466,6 +4466,7 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
 	return extents;
 
 bad:
+	*count = 0;
 	dm_pool_abandon_object(mem);
 	dm_free(buf);
 	return NULL;
@@ -4536,7 +4537,7 @@ static int _stats_unmap_regions(struct dm_stats *dms, uint64_t group_id,
 		region = &dms->regions[i];
 		nr_old++;
 
-		if (_find_extent(*count, extents,
+		if (extents && _find_extent(*count, extents,
 				  region->start, region->len)) {
 			ext.start = region->start;
 			ext.len = region->len;
@@ -4653,11 +4654,12 @@ static uint64_t *_stats_map_file_regions(struct dm_stats *dms, int fd,
          * causing complications in the error path.
          */
 	if (!(extent_mem = dm_pool_create("extents", sizeof(*extents))))
-		return_0;
+		return_NULL;
 
 	if (!(extents = _stats_get_extents_for_file(extent_mem, fd, count))) {
-		dm_pool_destroy(extent_mem);
-		return_0;
+		log_very_verbose("No extents found in fd %d", fd);
+		if (!update)
+			goto out;
 	}
 
 	if (update) {
@@ -4734,7 +4736,10 @@ static uint64_t *_stats_map_file_regions(struct dm_stats *dms, int fd,
 	if (bounds)
 		dm_free(hist_arg);
 
-	dm_pool_free(extent_mem, extents);
+	/* the extent table will be empty if the file has been truncated. */
+	if (extents)
+		dm_pool_free(extent_mem, extents);
+
 	dm_pool_destroy(extent_mem);
 
 	return regions;
@@ -4755,12 +4760,6 @@ out_remove:
 	*count = 0;
 
 out:
-	/*
-	 * The table of file extents in 'extents' is always built, so free
-	 * it explicitly: this will also free any 'old_extents' table that
-	 * was later allocated from the 'extent_mem' pool by this function.
-	 */
-	dm_pool_free(extent_mem, extents);
 	dm_pool_destroy(extent_mem);
 	dm_free(hist_arg);
 	dm_free(regions);
@@ -4872,7 +4871,8 @@ uint64_t *dm_stats_update_regions_from_fd(struct dm_stats *dms, int fd,
 	if (!dm_stats_list(dms, NULL))
 		goto bad;
 
-	if (regroup)
+	/* regroup if there are regions to group */
+	if (regroup && (*regions != DM_STATS_REGION_NOT_PRESENT))
 		if (!_stats_group_file_regions(dms, regions, count, alias))
 			goto bad;
 
diff --git a/liblvm/lvm_lv.c b/liblvm/lvm_lv.c
index d5ca821..13d6cbf 100644
--- a/liblvm/lvm_lv.c
+++ b/liblvm/lvm_lv.c
@@ -507,7 +507,7 @@ static int _lv_set_pool_params(struct lvcreate_params *lp,
 		pool_metadata_size = extents * vg->extent_size /
 			(lp->chunk_size * (SECTOR_SIZE / 64));
 		while ((pool_metadata_size >
-			(2 * DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) &&
+			(DEFAULT_THIN_POOL_OPTIMAL_METADATA_SIZE * 2)) &&
 		       lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE) {
 			lp->chunk_size <<= 1;
 			pool_metadata_size >>= 1;
diff --git a/man/clvmd.8_main b/man/clvmd.8_main
index 8e9921d..de6ce25 100644
--- a/man/clvmd.8_main
+++ b/man/clvmd.8_main
@@ -31,6 +31,9 @@ clvmd \(em cluster LVM daemon
 clvmd is the daemon that distributes LVM metadata updates around a cluster.
 It must be running on all nodes in the cluster and will give an error
 if a node in the cluster does not have this daemon running.
+
+Also see \fBlvmlockd\fP(8) for a newer method of using LVM on shared
+storage.
 .
 .SH OPTIONS
 .
@@ -196,4 +199,6 @@ Defaults to \fI#LVM_PATH#\fP.
 .SH SEE ALSO
 .BR syslog (3),
 .BR lvm.conf (5),
-.BR lvm (8)
+.BR lvm (8),
+.BR lvmlockd (8),
+.BR lvmsystemid (7)
diff --git a/man/lvm-fullreport.8_des b/man/lvm-fullreport.8_des
index f350a0a..741cd12 100644
--- a/man/lvm-fullreport.8_des
+++ b/man/lvm-fullreport.8_des
@@ -3,4 +3,3 @@ and LV segments. The information is all gathered together for each VG
 (under a per-VG lock) so it is consistent. Information gathered from
 separate calls to \fBvgs\fP, \fBpvs\fP, and \fBlvs\fP can be inconsistent
 if information changes between commands.
-
diff --git a/man/lvm.8_main b/man/lvm.8_main
index 7506eaf..bd5d8a7 100644
--- a/man/lvm.8_main
+++ b/man/lvm.8_main
@@ -537,6 +537,8 @@ directly.
 .BR lvs (8)
 .BR lvscan (8)
 
+.BR lvm-fullreport (8)
+.BR lvm-lvpoll (8)
 .BR lvm2-activation-generator (8)
 .BR blkdeactivate (8)
 .BR lvmdump (8)
diff --git a/man/lvm.conf.5_main b/man/lvm.conf.5_main
index 7b777af..3a45f1c 100644
--- a/man/lvm.conf.5_main
+++ b/man/lvm.conf.5_main
@@ -10,6 +10,10 @@ being loaded - settings read in later override earlier
 settings.  File timestamps are checked between commands and if
 any have changed, all the files are reloaded.
 
+For a description of each lvm.conf setting, run:
+
+.B lvmconfig --typeconfig default --withcomments --withspaces
+
 The settings defined in lvm.conf can be overridden by any
 of these extended configuration methods:
 .TP
diff --git a/man/lvmcache.7_main b/man/lvmcache.7_main
index e573b58..1f29185 100644
--- a/man/lvmcache.7_main
+++ b/man/lvmcache.7_main
@@ -404,6 +404,24 @@ This is equivalent to:
 .B lvconvert --type cache --cachepool VG/CachePoolLV VG/OriginLV
 
 
+.SS Cache metadata formats
+
+\&
+
+There are two disk formats for cache metadata.  The metadata format can be
+specified when a cache pool is created, and cannot be changed.
+Format \fB2\fP has better performance; it is more compact, and stores
+dirty bits in a separate btree, which improves the speed of shutting down
+the cache.
+With \fBauto\fP, lvm selects the best option provided by the current
+dm-cache kernel target.
+
+.B lvconvert --type cache-pool --cachemetadataformat auto|1|2
+.RS
+.B VG/CacheDataLV
+.RE
+
+
 .SH SEE ALSO
 .BR lvm.conf (5),
 .BR lvchange (8),
diff --git a/man/lvmetad.8_main b/man/lvmetad.8_main
index 31a89cc..ec55171 100644
--- a/man/lvmetad.8_main
+++ b/man/lvmetad.8_main
@@ -53,10 +53,13 @@ metadata.
 In some cases, lvmetad will be temporarily disabled while it continues
 running.  In this state, LVM commands will ignore the lvmetad cache and
 revert to scanning disks.  A warning will also be printed which includes
-the reason why lvmetad is not being used.  The most common reason is the
-existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs.)
-Once duplicates have been resolved, the lvmetad cache is can be updated
-with pvscan --cache and commands will return to using the cache.
+the reason why lvmetad is not being used.  The most common reasons are the
+existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs),
+or an 'lvconvert --repair' command has been run (the lvmetad cache may
+not be reliable while repairs are neeeded.)
+Once duplicates have been resolved, or repairs have been completed,
+the lvmetad cache is can be updated with pvscan --cache and commands
+will return to using the cache.
 
 Use of lvmetad is enabled/disabled by:
 .br
diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main
index 1a1c2fc..552eb94 100644
--- a/man/lvmlockd.8_main
+++ b/man/lvmlockd.8_main
@@ -117,17 +117,22 @@ Assign each host a unique host_id in the range 1-2000 by setting
 
 .SS 3. start lvmlockd
 
-Use a service/init file if available, or just run "lvmlockd".
+Use a unit/init file, or run the lvmlockd daemon directly:
+.br
+systemctl start lvm2-lvmlockd
 
 .SS 4. start lock manager
 
 .I sanlock
 .br
+Use unit/init files, or start wdmd and sanlock daemons directly:
+.br
 systemctl start wdmd sanlock
 
 .I dlm
 .br
-Follow external clustering documentation when applicable, otherwise:
+Follow external clustering documentation when applicable, or use
+unit/init files:
 .br
 systemctl start corosync dlm
 
@@ -146,8 +151,8 @@ vgchange --lock-start
 lvmlockd requires shared VGs to be started before they are used.  This is
 a lock manager operation to start (join) the VG lockspace, and it may take
 some time.  Until the start completes, locks for the VG are not available.
-LVM commands are allowed to read the VG while start is in progress.  (An
-init/unit file can also be used to start VGs.)
+LVM commands are allowed to read the VG while start is in progress.  (A
+unit/init file can also be used to start VGs.)
 
 .SS 7. create and activate LVs
 
@@ -247,9 +252,9 @@ clvmd for clustering.  See below for converting a clvm VG to a lockd VG.
 .SS lockd VGs from hosts not using lvmlockd
 
 Only hosts that use lockd VGs should be configured to run lvmlockd.
-However, shared devices used by lockd VGs may be visible from hosts not
-using lvmlockd.  From a host not using lvmlockd, visible lockd VGs are
-ignored in the same way as foreign VGs (see
+However, shared devices in lockd VGs may be visible from hosts not
+using lvmlockd.  From a host not using lvmlockd, lockd VGs are ignored
+in the same way as foreign VGs (see
 .BR lvmsystemid (7).)
 
 The --shared option for reporting and display commands causes lockd VGs
@@ -267,9 +272,9 @@ for all vgcreate options.
 .B vgcreate <vgname> <devices>
 
 .IP \[bu] 2
-Creates a local VG with the local system ID when neither lvmlockd nor clvm are configured.
+Creates a local VG with the local host's system ID when neither lvmlockd nor clvm are configured.
 .IP \[bu] 2
-Creates a local VG with the local system ID when lvmlockd is configured.
+Creates a local VG with the local host's system ID when lvmlockd is configured.
 .IP \[bu] 2
 Creates a clvm VG when clvm is configured.
 
@@ -300,10 +305,11 @@ LVM commands request locks from clvmd to use the VG.
 
 .SS creating the first sanlock VG
 
-Creating the first sanlock VG is not protected by locking and requires
-special attention.  This is because sanlock locks exist within the VG, so
-they are not available until the VG exists.  The first sanlock VG will
-contain the "global lock".
+Creating the first sanlock VG is not protected by locking, so it requires
+special attention.  This is because sanlock locks exist on storage within
+the VG, so they are not available until the VG exists.  The first sanlock
+VG created will automatically contain the "global lock".  Be aware of the
+following special considerations:
 
 .IP \[bu] 2
 The first vgcreate command needs to be given the path to a device that has
@@ -313,6 +319,11 @@ global lock, which will not be available until after the first sanlock VG
 is created.
 
 .IP \[bu] 2
+Because the first sanlock VG will contain the global lock, this VG needs
+to be accessible to all hosts that will use sanlock shared VGs.  All hosts
+will need to use the global lock from the first sanlock VG.
+
+.IP \[bu] 2
 While running vgcreate for the first sanlock VG, ensure that the device
 being used is not used by another LVM command.  Allocation of shared
 devices is usually protected by the global lock, but this cannot be done
@@ -323,11 +334,6 @@ While running vgcreate for the first sanlock VG, ensure that the VG name
 being used is not used by another LVM command.  Uniqueness of VG names is
 usually ensured by the global lock.
 
-.IP \[bu] 2
-Because the first sanlock VG will contain the global lock, this VG needs
-to be accessible to all hosts that will use sanlock shared VGs.  All hosts
-will need to use the global lock from the first sanlock VG.
-
 See below for more information about managing the sanlock global lock.
 
 
@@ -383,7 +389,7 @@ lvmlockd is running
 the lock manager is running
 .br
 \[bu]
-the VG is visible to the system
+the VG's devices are visible on the system
 .br
 
 A lockd VG can be stopped if all LVs are deactivated.
@@ -425,22 +431,23 @@ activation {
 
 .SS automatic starting and automatic activation
 
-Scripts or programs on a host that automatically start VGs will use the
-"auto" option to indicate that the command is being run automatically by
-the system:
+When system-level scripts/programs automatically start VGs, they should
+use the "auto" option.  This option indicates that the command is being
+run automatically by the system:
 
 vgchange --lock-start --lock-opt auto [<vgname> ...]
 
-Without any additional configuration, including the "auto" option has no
-effect; all VGs are started unless restricted by lock_start_list.
+The "auto" option causes the command to follow the lvm.conf
+activation/auto_lock_start_list.  If auto_lock_start_list is undefined,
+all VGs are started, just as if the auto option was not used.
 
-However, when the lvm.conf activation/auto_lock_start_list is defined, the
-auto start command performs an additional filtering phase to all VGs being
-started, testing each VG name against the auto_lock_start_list.  The
-auto_lock_start_list defines lockd VGs that will be started by the auto
-start command.  Visible lockd VGs not included in the list are ignored by
-the auto start command.  If the list is undefined, all VG names pass this
-filter.  (The lock_start_list is also still used to filter all VGs.)
+When auto_lock_start_list is defined, it lists the lockd VGs that should
+be started by the auto command.  VG names that do not match an item in the
+list will be ignored by the auto start command.
+
+(The lock_start_list is also still used to filter VG names from all start
+commands, i.e. with or without the auto option.  When the lock_start_list
+is defined, only VGs matching a list item can be started with vgchange.)
 
 The auto_lock_start_list allows a user to select certain lockd VGs that
 should be automatically started by the system (or indirectly, those that
@@ -470,14 +477,12 @@ The set of orphan PVs and unused devices.
 The properties of orphan PVs, e.g. PV size.
 .br
 
-The global lock is used in shared mode by commands that read this
-information, or in exclusive mode by commands that change it.
-
-The command 'vgs' acquires the global lock in shared mode because it
-reports the list of all VG names.
-
-The vgcreate command acquires the global lock in exclusive mode because it
-creates a new VG name, and it takes a PV from the list of unused PVs.
+The global lock is acquired in shared mode by commands that read this
+information, or in exclusive mode by commands that change it.  For
+example, the command 'vgs' acquires the global lock in shared mode because
+it reports the list of all VG names, and the vgcreate command acquires the
+global lock in exclusive mode because it creates a new VG name, and it
+takes a PV from the list of unused PVs.
 
 When an LVM command is given a tag argument, or uses select, it must read
 all VGs to match the tag or selection, which causes the global lock to be
@@ -485,10 +490,10 @@ acquired.
 
 .I VG lock
 
-A VG lock is associated with each VG.  The VG lock is acquired in shared
-mode to read the VG and in exclusive mode to change the VG (modify the VG
-metadata or activate LVs).  This lock serializes access to a VG with all
-other LVM commands accessing the VG from all hosts.
+A VG lock is associated with each lockd VG.  The VG lock is acquired in
+shared mode to read the VG and in exclusive mode to change the VG (modify
+the VG metadata or activating LVs).  This lock serializes access to a VG
+with all other LVM commands accessing the VG from all hosts.
 
 The command 'vgs' will not only acquire the GL lock to read the list of
 all VG names, but will acquire the VG lock for each VG prior to reading
@@ -502,7 +507,7 @@ argument.
 
 An LV lock is acquired before the LV is activated, and is released after
 the LV is deactivated.  If the LV lock cannot be acquired, the LV is not
-activated.  LV locks are persistent and remain in place after the
+activated.  LV locks are persistent and remain in place when the
 activation command is done.  GL and VG locks are transient, and are held
 only while an LVM command is running.
 
@@ -822,8 +827,8 @@ While lvmlockd and clvmd are entirely different systems, LVM command usage
 remains similar.  Differences are more notable when using lvmlockd's
 sanlock option.
 
-Visible usage differences between lockd VGs with lvmlockd and clvm VGs
-with clvmd:
+Visible usage differences between lockd VGs (using lvmlockd) and clvm VGs
+(using clvmd):
 
 .IP \[bu] 2
 lvm.conf must be configured to use either lvmlockd (use_lvmlockd=1) or
diff --git a/man/lvmraid.7_main b/man/lvmraid.7_main
index f0d28f5..c27f1fa 100644
--- a/man/lvmraid.7_main
+++ b/man/lvmraid.7_main
@@ -896,7 +896,7 @@ between linear and raid1.
 .IP \(bu 3
 between mirror and raid1.
 .IP \(bu 3
-between 2-legged raid1 and raid4/5.
+between raid1 with two images and raid4/5.
 .IP \(bu 3
 between striped/raid0 and raid4.
 .IP \(bu 3
@@ -912,39 +912,90 @@ between striped/raid0 and raid10.
 .IP \(bu 3
 between striped and raid4.
 
-.SS Examples
+.SS Indirect conversions
 
-1. Converting an LV from \fBlinear\fP to \fBraid1\fP.
+Converting from one raid level to another may require multiple steps,
+converting first to intermediate raid levels.
 
-.nf
-# lvs -a -o name,segtype,size vg
-  LV   Type   LSize
-  lv   linear 300.00g
+.B linear to raid6
 
-# lvconvert --type raid1 --mirrors 1 vg/lv
+To convert an LV from linear to raid6:
+.br
+1. convert to raid1 with two images
+.br
+2. convert to raid5 (internally raid5_ls) with two images
+.br
+3. convert to raid5 with three or more stripes (reshape)
+.br
+4. convert to raid6 (internally raid6_ls_6)
+.br
+5. convert to raid6 (internally raid6_zr, reshape)
 
-# lvs -a -o name,segtype,size vg
-  LV            Type   LSize
-  lv            raid1  300.00g
-  [lv_rimage_0] linear 300.00g
-  [lv_rimage_1] linear 300.00g
-  [lv_rmeta_0]  linear   3.00m
-  [lv_rmeta_1]  linear   3.00m
-.fi
+The commands to perform the steps above are:
+.br
+1. lvconvert --type raid1 --mirrors 1 LV
+.br
+2. lvconvert --type raid5 LV
+.br
+3. lvconvert --stripes 3 LV
+.br
+4. lvconvert --type raid6 LV
+.br
+5. lvconvert --type raid6 LV
 
-2. Converting an LV from \fBmirror\fP to \fBraid1\fP.
+The final conversion from raid6_ls_6 to raid6_zr is done to avoid the
+potential write/recovery performance reduction in raid6_ls_6 because of
+the dedicated parity device.  raid6_zr rotates data and parity blocks to
+avoid this.
+
+.B linear to striped
+
+To convert an LV from linear to striped:
+.br
+1. convert to raid1 with two images
+.br
+2. convert to raid5_n
+.br
+3. convert to raid5_n with five 128k stripes (reshape)
+.br
+4. convert raid5_n to striped
+
+The commands to perform the steps above are:
+.br
+1. lvconvert --type raid1 --mirrors 1 LV
+.br
+2. lvconvert --type raid5_n LV
+.br
+3. lvconvert --stripes 5 --stripesize 128k LV
+.br
+4. lvconvert --type striped LV
+
+The raid5_n type in step 2 is used because it has dedicated parity SubLVs
+at the end, and can be converted to striped directly.  The stripe size is
+increased in step 3 to add extra space for the conversion process.  This
+step grows the LV size by a factor of five.  After conversion, this extra
+space can be reduced (or used to grow the file system using the LV).
+
+Reversing these steps will convert a striped LV to linear.
+
+.B raid6 to striped
+
+To convert an LV from raid6_nr to striped:
+.br
+1. convert to raid6_n_6
+.br
+2. convert to striped
+
+The commands to perform the steps above are:
+.br
+1. lvconvert --type raid6_n_6 LV
+.br
+2. lvconvert --type striped LV
 
-.nf
-# lvs -a -o name,segtype,size vg
-  LV            Type   LSize
-  lv            mirror 100.00g
-  [lv_mimage_0] linear 100.00g
-  [lv_mimage_1] linear 100.00g
-  [lv_mlog]     linear   3.00m
 
 .SS Examples
 
-1. Converting an LV from \fBlinear\fP to \fBraid1\fP.
+Converting an LV from \fBlinear\fP to \fBraid1\fP.
 
 .nf
 # lvs -a -o name,segtype,size vg
@@ -962,7 +1013,7 @@ between striped and raid4.
   [lv_rmeta_1]  linear   3.00m
 .fi
 
-2. Converting an LV from \fBmirror\fP to \fBraid1\fP.
+Converting an LV from \fBmirror\fP to \fBraid1\fP.
 
 .nf
 # lvs -a -o name,segtype,size vg
@@ -983,28 +1034,17 @@ between striped and raid4.
   [lv_rmeta_1]  linear   3.00m
 .fi
 
-3. Converting an LV from \fBlinear\fP to \fBraid1\fP (with 3 images).
+Converting an LV from \fBlinear\fP to \fBraid1\fP (with 3 images).
 
 .nf
-Start with a linear LV:
-
-# lvcreate -L1G -n lv vg
-
-Convert the linear LV to raid1 with three images
-(original linear image plus 2 mirror images):
-
 # lvconvert --type raid1 --mirrors 2 vg/lv
 .fi
 
-4. Converting an LV from \fBstriped\fP (with 4 stripes) to \fBraid6_n_6\fP.
+Converting an LV from \fBstriped\fP (with 4 stripes) to \fBraid6_n_6\fP.
 
 .nf
-Start with a striped LV:
-
 # lvcreate --stripes 4 -L64M -n lv vg
 
-Convert the striped LV to raid6_n_6:
-
 # lvconvert --type raid6 vg/lv
 
 # lvs -a -o lv_name,segtype,sync_percent,data_copies
@@ -1051,7 +1091,9 @@ that is done, the new stripe is unquiesced and used.)
 
 .SS Examples
 
-1. Converting raid6_n_6 to raid6_nr with rotating data/parity.
+(Command output shown in examples may change.)
+
+Converting raid6_n_6 to raid6_nr with rotating data/parity.
 
 This conversion naturally follows a previous conversion from striped/raid0
 to raid6_n_6 (shown above).  It completes the transition to a more
@@ -1318,7 +1360,8 @@ In case the RaidLV should be converted to striped:
 .nf
 # lvconvert --type striped vg/lv
   Unable to convert LV vg/lv from raid6_nr to striped.
-  Converting vg/lv from raid6_nr is directly possible to the following layouts:
+  Converting vg/lv from raid6_nr is directly possible to the \\
+  following layouts:
     raid6_nc
     raid6_zr
     raid6_la_6
@@ -1621,7 +1664,9 @@ RAID6 last parity devices
 .br
 \[bu]
 Fixed dedicated last devices (P-Syndrome N-1 and Q-Syndrome N)
+.RS 2
 with striped data used for striped/raid0 conversions
+.RE
 .br
 \[bu]
 Used for RAID Takeover
@@ -1632,7 +1677,10 @@ raid6_{ls,rs,la,ra}_6
 RAID6 last parity device
 .br
 \[bu]
-Dedicated last parity device used for conversions from/to raid5_{ls,rs,la,ra}
+Dedicated last parity device used for conversions from/to
+.RS 2
+raid5_{ls,rs,la,ra}
+.RE
 
 raid6_ls_6
 .br
diff --git a/man/lvmreport.7_main b/man/lvmreport.7_main
index 7a26401..7167df0 100644
--- a/man/lvmreport.7_main
+++ b/man/lvmreport.7_main
@@ -948,7 +948,7 @@ configuration directly on command line.
 
 You can obtain the same information with single command where all the
 information about PVs, PV segments, LVs and LV segments are obtained
-per VG under a single VG lock for consistency, see also \fBlvm fullreport\fP(8)
+per VG under a single VG lock for consistency, see also \fBlvm-fullreport\fP(8)
 man page for more information. The fullreport has its own configuration
 settings to define field sets to use, similar to individual reports as
 displayed above, but configuration settings have "_full" suffix now.
diff --git a/man/lvmsystemid.7_main b/man/lvmsystemid.7_main
index 8c57042..9b36dc3 100644
--- a/man/lvmsystemid.7_main
+++ b/man/lvmsystemid.7_main
@@ -94,19 +94,18 @@ corrupting the PVs.  See the
 section for more information.
 
 .IP \[bu] 2
-The system ID does not protect devices in VG from programs other than LVM.
+The system ID does not protect devices in a VG from programs other than LVM.
 
 .IP \[bu] 2
-A host using an old version of LVM without the system ID feature will not
-recognize a system ID in VGs from other hosts.  Even though the old
-version of LVM is not blocked from reading a VG with a system ID, it is
-blocked from writing to the VG (or its LVs).  The system ID feature
-changes the write mode of a VG, making it appear read-only to previous
-versions of LVM.
-
-This also means that if a host downgrades its version of LVM, it would
+A host using an old LVM version (without the system ID feature) will not
+recognize a system ID set in VGs.  The old LVM can read a VG with a
+system ID, but is prevented from writing to the VG (or its LVs).
+The system ID feature changes the write mode of a VG, making it appear
+read-only to previous versions of LVM.
+
+This also means that if a host downgrades to the old LVM version, it would
 lose access to any VGs it had created with a system ID.  To avoid this,
-the system ID should be removed from VGs before downgrading to an LVM
+the system ID should be removed from local VGs before downgrading LVM to a
 version without the system ID feature.
 
 
diff --git a/man/pvchange.8_des b/man/pvchange.8_des
index 802850f..e914e13 100644
--- a/man/pvchange.8_des
+++ b/man/pvchange.8_des
@@ -1 +1,4 @@
 pvchange changes PV attributes in the VG.
+
+For options listed in parentheses, any one is required, after which the
+others are optional.
diff --git a/man/see_also.end b/man/see_also.end
index 9e7d3b2..5b07719 100644
--- a/man/see_also.end
+++ b/man/see_also.end
@@ -46,6 +46,8 @@
 .BR lvs (8)
 .BR lvscan (8)
 
+.BR lvm-fullreport (8)
+.BR lvm-lvpoll (8)
 .BR lvm2-activation-generator (8)
 .BR blkdeactivate (8)
 .BR lvmdump (8)
diff --git a/man/vgexport.8_des b/man/vgexport.8_des
index f9fa49c..66d3af3 100644
--- a/man/vgexport.8_des
+++ b/man/vgexport.8_des
@@ -1,6 +1,6 @@
 vgexport makes inactive VGs unknown to the system. In this state, all the
 PVs in the VG can be moved to a different system, from which
-\fBvgimport\fP can then be run.
+\fBvgimport\fP(8) can then be run.
 
 Most LVM tools ignore exported VGs.
 
diff --git a/scripts/fsadm.sh b/scripts/fsadm.sh
index 26be102..ea14efe 100755
--- a/scripts/fsadm.sh
+++ b/scripts/fsadm.sh
@@ -75,8 +75,9 @@ BLOCKCOUNT=
 MOUNTPOINT=
 MOUNTED=
 REMOUNT=
-PROCMOUNTS="/proc/mounts"
-PROCSELFMOUNTINFO="/proc/self/mountinfo"
+PROCDIR="/proc"
+PROCMOUNTS="$PROCDIR/mounts"
+PROCSELFMOUNTINFO="$PROCDIR/self/mountinfo"
 NULL="$DM_DEV_DIR/null"
 
 IFS_OLD=$IFS
@@ -113,8 +114,11 @@ verbose() {
 	test -n "$VERB" && echo "$TOOL: $@" || true
 }
 
+# Support multi-line error messages
 error() {
-	echo "$TOOL: $@" >&2
+	for i in "$@" ;  do
+		echo "$TOOL: $i" >&2
+	done
 	cleanup 1
 }
 
@@ -178,52 +182,135 @@ decode_size() {
 	fi
 }
 
+decode_major_minor() {
+	# 0x00000fff00  mask MAJOR
+	# 0xfffff000ff  mask MINOR
+
+	#MINOR=$(( $1 / 1048576 ))
+	#MAJOR=$(( ($1 - ${MINOR} * 1048576) / 256 ))
+	#MINOR=$(( $1 - ${MINOR} * 1048576 - ${MAJOR} * 256 + ${MINOR} * 256))
+
+	echo "$(( ( $1 >> 8 ) & 4095 )):$(( ( ( $1 >> 12 ) & 268435200 ) | ( $1 & 255 ) ))"
+}
+
 # detect filesystem on the given device
 # dereference device name if it is symbolic link
 detect_fs() {
 	VOLUME_ORIG=$1
 	VOLUME=${1/#"${DM_DEV_DIR}/"/}
-	VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") || error "Cannot get readlink \"$1\""
+	VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME")
+	test -n "$VOLUME" || error "Cannot get readlink \"$1\"."
 	RVOLUME=$VOLUME
 	case "$RVOLUME" in
-          # hardcoded /dev  since udev does not create these entries elsewhere
+	  # hardcoded /dev  since udev does not create these entries elsewhere
 	  /dev/dm-[0-9]*)
 		read </sys/block/${RVOLUME#/dev/}/dm/name SYSVOLUME 2>&1 && VOLUME="$DM_DEV_DIR/mapper/$SYSVOLUME"
-		read </sys/block/${RVOLUME#/dev/}/dev MAJORMINOR 2>&1 || error "Cannot get major:minor for \"$VOLUME\""
+		read </sys/block/${RVOLUME#/dev/}/dev MAJORMINOR 2>&1 || error "Cannot get major:minor for \"$VOLUME\"."
+		MAJOR=${MAJORMINOR%%:*}
+		MINOR=${MAJORMINOR##*:}
 		;;
 	  *)
-		STAT=$(stat --format "MAJOR=%t MINOR=%T" ${RVOLUME}) || error "Cannot get major:minor for \"$VOLUME\""
-		eval $STAT
-		MAJOR=$((0x${MAJOR}))
-		MINOR=$((0x${MINOR}))
-		MAJORMINOR=${MAJOR}:${MINOR}
+		STAT=$(stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" ${RVOLUME})
+		test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"."
+		eval "$STAT"
+		MAJORMINOR="${MAJOR}:${MINOR}"
 		;;
 	esac
 	# use null device as cache file to be sure about the result
 	# not using option '-o value' to be compatible with older version of blkid
-	FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\""
+	FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME")
+	test -n "$FSTYPE" || error "Cannot get FSTYPE of \"$VOLUME\"."
 	FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks
 	FSTYPE=${FSTYPE%%\"*}
-	verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
+	verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\"."
+}
+
+
+# Check that passed mounted MAJOR:MINOR is not matching $MAJOR:MINOR of resized $VOLUME
+validate_mounted_major_minor() {
+	test "$1" = "$MAJORMINOR" || {
+		local REFNAME=$(dmsetup info -c -j "${1%%:*}" -m "${1##*:}" -o name --noheadings 2>/dev/null)
+		local CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings 2>/dev/null)
+		error "Cannot ${CHECK+CHECK}${RESIZE+RESIZE} device \"$VOLUME\" without umounting filesystem $MOUNTED first." \
+		      "Mounted filesystem is using device $CURNAME, but referenced device is $REFNAME." \
+		      "Filesystem utilities currently do not support renamed devices."
+	}
+}
+
+# ATM fsresize & fsck tools are not able to work properly
+# when mounted device has changed its name.
+# So whenever such device no longer exists with original name
+# abort further command processing
+check_valid_mounted_device() {
+	local MOUNTEDMAJORMINOR
+	local VOL=$("$READLINK" $READLINK_E "$1")
+	local CURNAME=$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o name --noheadings)
+	local SUGGEST="Possibly device \"$1\" has been renamed to \"$CURNAME\"?"
+
+	# more confused, device is not DM....
+	test -n "$CURNAME" || SUGGEST="Mounted volume is not a device mapper device???"
+
+	test -n "$VOL" ||
+		error "Cannot access device \"$1\" referenced by mounted filesystem \"$MOUNTED\"." \
+		"$SUGGEST" \
+		"Filesystem utilities currently do not support renamed devices."
+
+	case "$VOL" in
+	  # hardcoded /dev  since udev does not create these entries elsewhere
+	  /dev/dm-[0-9]*)
+		read </sys/block/${VOL#/dev/}/dev MOUNTEDMAJORMINOR 2>&1 || error "Cannot get major:minor for \"$VOLUME\"."
+		;;
+	  *)
+		STAT=$(stat --format "MOUNTEDMAJORMINOR=\$((0x%t)):\$((0x%T))" "$VOL")
+		test -n "$STAT" || error "Cannot get major:minor for \"$VOLUME\"."
+		eval "$STAT"
+		;;
+	esac
+
+	validate_mounted_major_minor "$MOUNTEDMAJORMINOR"
 }
 
-detect_mounted_with_proc_self_mountinfo()  {
-	MOUNTED=$("$GREP" "^[0-9]* [0-9]* $MAJORMINOR " "$PROCSELFMOUNTINFO")
+detect_mounted_with_proc_self_mountinfo() {
+	# Check self mountinfo
+	# grab major:minor mounted_device mount_point
+	MOUNTED=$("$GREP" "^[0-9]* [0-9]* $MAJORMINOR " "$PROCSELFMOUNTINFO" 2>/dev/null | head -1)
+
+	# If device is opened and not yet found as self mounted
+	# check all other mountinfos (since it can be mounted in cgroups)
+	# Use 'find' to not fail on to long list of args with too many pids
+	# only 1st. line is needed
+	test -z "$MOUNTED" &&
+		test $(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR") -gt 0 &&
+		MOUNTED=$(find "$PROCDIR" -maxdepth 2 -name mountinfo -print0 |  xargs -0 "$GREP" "^[0-9]* [0-9]* $MAJORMINOR " 2>/dev/null | head -1 2>/dev/null)
 
-	# extract 5th field which is mount point
+	# TODO: for performance compare with sed and stop with 1st. match:
+	# sed -n "/$MAJORMINOR/ {;p;q;}"
+
+	# extract 2nd field after ' - ' separator as mouted device
+	MOUNTDEV=$(echo ${MOUNTED##* - } | cut -d ' ' -f 2)
+	MOUNTDEV=$(echo -n -e ${MOUNTDEV})
+
+	# extract 5th field as mount point
 	# echo -e translates \040 to spaces
-	MOUNTED=$(echo ${MOUNTED} | cut -d " " -f 5)
+	MOUNTED=$(echo ${MOUNTED} | cut -d ' ' -f 5)
 	MOUNTED=$(echo -n -e ${MOUNTED})
 
-	test -n "$MOUNTED"
+	test -n "$MOUNTED" || return 1   # Not seen mounted anywhere
+
+	check_valid_mounted_device "$MOUNTDEV"
 }
 
-detect_mounted_with_proc_mounts()  {
+# With older systems without /proc/*/mountinfo we may need to check
+# every mount point as cannot easily depend on the name of mounted
+# device (which could have been renamed).
+# We need to visit every mount point and check it's major minor
+detect_mounted_with_proc_mounts() {
 	MOUNTED=$("$GREP" "^$VOLUME[ \t]" "$PROCMOUNTS")
 
 	# for empty string try again with real volume name
 	test -z "$MOUNTED" && MOUNTED=$("$GREP" "^$RVOLUME[ \t]" "$PROCMOUNTS")
 
+	MOUNTDEV=$(echo -n -e ${MOUNTED%% *})
 	# cut device name prefix and trim everything past mountpoint
 	# echo translates \040 to spaces
 	MOUNTED=${MOUNTED#* }
@@ -231,24 +318,43 @@ detect_mounted_with_proc_mounts()  {
 
 	# for systems with different device names - check also mount output
 	if test -z "$MOUNTED" ; then
+		# will not work with spaces in paths
 		MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^$VOLUME[ \t]")
 		test -z "$MOUNTED" && MOUNTED=$(LC_ALL=C "$MOUNT" | "$GREP" "^$RVOLUME[ \t]")
+		MOUNTDEV=${MOUNTED%% on *}
 		MOUNTED=${MOUNTED##* on }
 		MOUNTED=${MOUNTED% type *} # allow type in the mount name
 	fi
 
-	test -n "$MOUNTED"
+	if test -n "$MOUNTED" ; then
+		check_valid_mounted_device "$MOUNTDEV"
+		return 0  # mounted
+	fi
+
+	# If still nothing found and volume is in use
+	# check every known mount point against MAJOR:MINOR
+	if test $(dmsetup info -c --noheading -o open -j "$MAJOR" -m "$MINOR") -gt 0 ; then
+		while IFS=$'\n' read -r i ; do
+			MOUNTDEV=$(echo -n -e ${i%% *})
+			MOUNTED=${i#* }
+			MOUNTED=$(echo -n -e ${MOUNTED%% *})
+			STAT=$(stat --format "%d" $MOUNTED)
+			validate_mounted_major_minor $(decode_major_minor "$STAT")
+		done < "$PROCMOUNTS"
+	fi
+
+	return 1  # nothing is mounted
 }
 
 # check if the given device is already mounted and where
 # FIXME: resolve swap usage and device stacking
-detect_mounted()  {
+detect_mounted() {
 	if test -e "$PROCSELFMOUNTINFO"; then
 		detect_mounted_with_proc_self_mountinfo
 	elif test -e "$PROCMOUNTS"; then
 		detect_mounted_with_proc_mounts
 	else
-		error "Cannot detect mounted device \"$VOLUME\""
+		error "Cannot detect mounted device \"$VOLUME\"."
 	fi
 }
 
@@ -257,10 +363,13 @@ detect_device_size() {
 	# check if blockdev supports getsize64
 	"$BLOCKDEV" 2>&1 | "$GREP" getsize64 >"$NULL"
 	if test $? -eq 0; then
-		DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
+		DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME")
+		test -n "$DEVSIZE" || error "Cannot read size of device \"$VOLUME\"."
 	else
-		DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
-		SSSIZE=$("$BLOCKDEV" --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\""
+		DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME")
+		test -n "$DEVSIZE" || error "Cannot read size of device \"$VOLUME\"."
+		SSSIZE=$("$BLOCKDEV" --getss "$VOLUME")
+		test -n "$SSSIZE" || error "Cannot read sector size of device \"$VOLUME\"."
 		DEVSIZE=$(($DEVSIZE * $SSSIZE))
 	fi
 }
@@ -273,14 +382,14 @@ round_up_block_size() {
 }
 
 temp_mount() {
-	dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
-	dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
+	dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR."
+	dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR."
 }
 
 temp_umount() {
-	dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\""
-	dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\""
-	dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\""
+	dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\"."
+	dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\","
+	dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\"."
 }
 
 yes_no() {
@@ -292,19 +401,24 @@ yes_no() {
 
 	while read -r -s -n 1 ANS ; do
 		case "$ANS" in
-		 "y" | "Y" | "") echo y ; return 0 ;;
-		 "n" | "N") echo n ; return 1 ;;
+		 "y" | "Y" ) echo y ; return 0 ;;
+		 "" ) if [ -t 1 ] ; then
+			echo y ; return 0
+		      fi ;;
 		esac
 	done
+
+	echo n
+	return 1
 }
 
 try_umount() {
 	yes_no "Do you want to unmount \"$MOUNTED\"" && dry "$UMOUNT" "$MOUNTED" && return 0
-	error "Cannot proceed with mounted filesystem \"$MOUNTED\""
+	error "Cannot proceed with mounted filesystem \"$MOUNTED\"."
 }
 
 validate_parsing() {
-	test -n "$BLOCKSIZE" && test -n "$BLOCKCOUNT" || error "Cannot parse $1 output"
+	test -n "$BLOCKSIZE" && test -n "$BLOCKCOUNT" || error "Cannot parse $1 output."
 }
 ####################################
 # Resize ext2/ext3/ext4 filesystem
@@ -312,6 +426,9 @@ validate_parsing() {
 # - unmounted for downsize
 ####################################
 resize_ext() {
+	local IS_MOUNTED=0
+	detect_mounted && IS_MOUNTED=1
+
 	verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
 	for i in $(LC_ALL=C "$TUNE_EXT" -l "$VOLUME"); do
 		case "$i" in
@@ -324,7 +441,7 @@ resize_ext() {
 	FSFORCE=$FORCE
 
 	if [ "$NEWBLOCKCOUNT" -lt "$BLOCKCOUNT" -o "$EXTOFF" -eq 1 ]; then
-		detect_mounted && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
+		test $IS_MOUNTED -eq 1 && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
 		REMOUNT=$MOUNTED
 		if test -n "$MOUNTED" ; then
 			# Forced fsck -f for umounted extX filesystem.
@@ -374,7 +491,7 @@ resize_xfs() {
 	MOUNTPOINT=$MOUNTED
 	if [ -z "$MOUNTED" ]; then
 		MOUNTPOINT=$TEMPDIR
-		temp_mount || error "Cannot mount Xfs filesystem"
+		temp_mount || error "Cannot mount Xfs filesystem."
 	fi
 	verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
 	for i in $(LC_ALL=C "$TUNE_XFS" "$MOUNTPOINT"); do
@@ -392,7 +509,7 @@ resize_xfs() {
 	elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then
 		verbose "Xfs filesystem already has the right size"
 	else
-		error "Xfs filesystem shrinking is unsupported"
+		error "Xfs filesystem shrinking is unsupported."
 	fi
 }
 
@@ -412,8 +529,8 @@ resize() {
 	  "ext3"|"ext2"|"ext4") resize_ext $NEWSIZE ;;
 	  "reiserfs") resize_reiser $NEWSIZE ;;
 	  "xfs") resize_xfs $NEWSIZE ;;
-	  *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool" ;;
-	esac || error "Resize $FSTYPE failed"
+	  *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool." ;;
+	esac || error "Resize $FSTYPE failed."
 	cleanup 0
 }
 
@@ -494,12 +611,12 @@ for i in "$TUNE_EXT" "$RESIZE_EXT" "$TUNE_REISER" "$RESIZE_REISER" \
 	test -n "$i" || error "Required command definitions in the script are missing!"
 done
 
-"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\""
+"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\"."
 $("$READLINK" -e / >"$NULL" 2>&1) || READLINK_E="-f"
 TEST64BIT=$(( 1000 * 1000000000000 ))
-test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic"
-$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly"
-test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work"
+test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic."
+$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly."
+test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work."
 
 
 if [ "$#" -eq 0 ] ; then
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
index 50f6ad4..3dca9d5 100755
--- a/test/dbus/lvmdbustest.py
+++ b/test/dbus/lvmdbustest.py
@@ -18,6 +18,8 @@ import pyudev
 from testlib import *
 import testlib
 from subprocess import Popen, PIPE
+from glob import glob
+import os
 
 g_tmo = 0
 
@@ -68,8 +70,12 @@ def lv_n(suffix=None):
 	return g_prefix + rs(8, s)
 
 
+def _is_testsuite_pv(pv_name):
+	return g_prefix != "" and pv_name[-1].isdigit() and pv_name[:-1].endswith(g_prefix + "pv")
+
+
 def is_nested_pv(pv_name):
-	return pv_name.count('/') == 3
+	return pv_name.count('/') == 3 and not _is_testsuite_pv(pv_name)
 
 
 def _root_pv_name(res, pv_name):
@@ -239,6 +245,7 @@ class TestDbusService(unittest.TestCase):
 
 		# Check to make sure the PVs we had to start exist, else re-create
 		# them
+		self.objs, self.bus = get_objects()
 		if len(self.pvs) != len(self.objs[PV_INT]):
 			for p in self.pvs:
 				found = False
@@ -714,9 +721,9 @@ class TestDbusService(unittest.TestCase):
 			LV_BASE_INT)
 		self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
 
-	def _create_lv(self, thinpool=False, size=None, vg=None):
+	def _create_lv(self, thinpool=False, size=None, vg=None, suffix=None):
 
-		lv_name = lv_n()
+		lv_name = lv_n(suffix=suffix)
 		interfaces = list(LV_BASE_INT)
 
 		if thinpool:
@@ -1840,7 +1847,8 @@ class TestDbusService(unittest.TestCase):
 		self.assertIn(pv_object_path, vg.Vg.Pvs,
 						"Expecting PV object path in Vg.Pvs")
 
-		lv = self._create_lv(vg=vg.Vg, size=vg.Vg.FreeBytes)
+		lv = self._create_lv(vg=vg.Vg, size=vg.Vg.FreeBytes,
+								suffix="_pv")
 		device_path = '/dev/%s/%s' % (vg.Vg.Name, lv.LvCommon.Name)
 		new_pv_object_path = self._pv_create(device_path)
 
@@ -1865,6 +1873,46 @@ class TestDbusService(unittest.TestCase):
 		for i in range(0, 5):
 			pv_object_path = self._create_nested(pv_object_path)
 
+	def test_pv_symlinks(self):
+		# Lets take one of our test PVs, pvremove it, find a symlink to it
+		# and re-create using the symlink to ensure we return an object
+		# 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.
+		symlink = None
+
+		pv = self.objs[PV_INT][0]
+		pv_device_path = pv.Pv.Name
+
+		self._pv_remove(pv)
+
+		# Make sure we no longer find the pv
+		rc = self._lookup(pv_device_path)
+		self.assertEqual(rc, '/')
+
+		# Lets locate a symlink for it
+		devices = glob('/dev/disk/*/*')
+		for d in devices:
+			if pv_device_path == os.path.realpath(d):
+				symlink = d
+				break
+
+		self.assertIsNotNone(symlink, "We expected to find at least 1 symlink!")
+
+		# Make sure symlink look up fails too
+		rc = self._lookup(symlink)
+		self.assertEqual(rc, '/')
+
+		pv_object_path = self._pv_create(symlink)
+		self.assertNotEqual(pv_object_path, '/')
+
+		pv_proxy = ClientProxy(self.bus, pv_object_path, interfaces=(PV_INT, ))
+		self.assertEqual(pv_proxy.Pv.Name, pv_device_path)
+
+		# Lets check symlink lookup
+		self.assertEqual(pv_object_path, self._lookup(symlink))
+		self.assertEqual(pv_object_path, self._lookup(pv_device_path))
+
 
 class AggregateResults(object):
 
diff --git a/test/shell/fsadm-renamed.sh b/test/shell/fsadm-renamed.sh
new file mode 100644
index 0000000..9f3cd3c
--- /dev/null
+++ b/test/shell/fsadm-renamed.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+# Copyright (C) 2017 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+test_description='Exercise fsadm operation on renamed device'
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1 80
+
+vg_lv=$vg/$lv1
+vg_lv_ren=${vg_lv}_renamed
+
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv_ren="$DM_DEV_DIR/$vg_lv_ren"
+
+mount_dir="mnt"
+mount_space_dir="mnt space dir"
+mount_dolar_dir="mnt \$SPACE dir"
+# for recursive call
+export LVM_BINARY=$(which lvm)
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+test ! -d "$mount_space_dir" && mkdir "$mount_space_dir"
+test ! -d "$mount_dolar_dir" && mkdir "$mount_dolar_dir"
+
+cleanup_mounted_and_teardown()
+{
+	umount "$mount_dir" || true
+	umount "$mount_space_dir" || true
+	umount "$mount_dolar_dir" || true
+	aux teardown
+}
+
+# Test for block sizes != 1024 (rhbz #480022)
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Iterate over supported filesystems
+for i in mkfs.ext3 mkfs.xfs mkfs.reiserfs
+do
+
+if not which "$i" ; then
+	echo "Skipping tests for missing $i"
+	continue
+fi
+
+lvcreate -n $lv1 -L20M $vg
+
+case "$i" in
+*ext3)		MKFS_ARGS="-b1024 -j" ;;
+*xfs)		MKFS_ARGS="-l internal,size=1000b -f" ;;
+*reiserfs)	MKFS_ARGS="-s 513 -f" ;;
+esac
+
+echo "$i"
+"$i" $MKFS_ARGS "$dev_vg_lv"
+
+# Adding couple udev wait ops as some older systemd
+# might get confused and was 'randomly/racy' umounting
+# devices  just mounted.
+# 
+# See for explanation: 
+#   https://github.com/systemd/systemd/commit/628c89cc68ab96fce2de7ebba5933725d147aecc
+#   https://github.com/systemd/systemd/pull/2017
+aux udev_wait
+
+mount "$dev_vg_lv" "$mount_dir"
+
+aux udev_wait
+
+lvrename $vg_lv $vg_lv_ren
+
+mount | tee out
+grep $vg out
+
+# fails on renamed LV
+fail lvresize -L+10M -r $vg_lv_ren
+
+# fails on unknown mountpoint  (FIXME: umount)
+not umount "$dev_vg_lv"
+
+lvcreate -L20 -n $lv1 $vg
+"$i" $MKFS_ARGS "$dev_vg_lv"
+
+aux udev_wait
+
+mount "$dev_vg_lv" "$mount_dolar_dir"
+
+mount | tee out
+grep $vg out
+
+not lvresize -L+10M -r $vg_lv_ren
+
+umount "$mount_dir"
+
+# FIXME:  lvresize  CANNOT handle/propagage '--yes' to fsadm
+echo y | lvresize -L+10M -r $vg_lv
+
+aux udev_wait
+
+umount "$mount_dolar_dir"
+
+lvremove -ff $vg
+
+done
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-raid.sh b/test/shell/lvchange-raid.sh
index 34a40dc..7418cd5 100644
--- a/test/shell/lvchange-raid.sh
+++ b/test/shell/lvchange-raid.sh
@@ -42,6 +42,7 @@ run_writemostly_check() {
 
 	printf "#\n#\n#\n# %s/%s (%s): run_writemostly_check\n#\n#\n#\n" \
 		$vg $lv $segtype
+	aux wait_for_sync $vg $lv
 
 	# No writemostly flag should be there yet.
 	check lv_attr_bit health $vg/${lv}_rimage_0 "-"
diff --git a/test/shell/lvconvert-raid-regionsize.sh b/test/shell/lvconvert-raid-regionsize.sh
index 9884c1b..d2c8a54 100644
--- a/test/shell/lvconvert-raid-regionsize.sh
+++ b/test/shell/lvconvert-raid-regionsize.sh
@@ -64,6 +64,7 @@ _test_regionsizes raid1
 # Clean up
 lvremove --yes $vg
 
+if aux have_raid 1 10 1; then
 # Create 5-way raid6
 lvcreate --yes -aey --type raid6 -i 3 --stripesize 128K -R 256K -L8M -n $lv1 $vg
 check lv_field $vg/$lv1 segtype "raid6"
@@ -78,7 +79,11 @@ _test_regionsizes raid6
 
 # Clean up
 lvremove --yes $vg
+else
+  echo "Skipping RAID6 tests"
+fi
 
+if aux have_raid 1 10 1; then
 # Create 6-way raid01
 lvcreate --yes -aey --type raid10 -i 3 -m 1 --stripesize 128K -R 256K -L8M -n $lv1 $vg
 check lv_field $vg/$lv1 segtype "raid10"
@@ -90,5 +95,8 @@ aux wait_for_sync $vg $lv1
 fsck -fn "$DM_DEV_DIR/$vg/$lv1"
 
 _test_regionsizes raid10
+else
+  echo "Skipping RAID10 tests"
+fi
 
 vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-striped_to_linear.sh b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh
index 4051862..d926827 100644
--- a/test/shell/lvconvert-raid-reshape-striped_to_linear.sh
+++ b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh
@@ -79,7 +79,7 @@ aux wait_for_sync $vg $lv1 1
 fsck -fn $DM_DEV_DIR/$vg/$lv1
 
 # Remove the now freed legs
-lvconvert --stripes 1 $vg/$lv1
+lvconvert -y --stripes 1 $vg/$lv1
 check lv_first_seg_field $vg/$lv1 segtype "raid5_n"
 check lv_first_seg_field $vg/$lv1 data_stripes 1
 check lv_first_seg_field $vg/$lv1 stripes 2
diff --git a/test/shell/lvconvert-raid.sh b/test/shell/lvconvert-raid.sh
index e173d66..fba7864 100644
--- a/test/shell/lvconvert-raid.sh
+++ b/test/shell/lvconvert-raid.sh
@@ -223,6 +223,67 @@ for i in 1 2 3 ; do
 done
 
 ###########################################
+# Upconverted RAID1 should not allow loss of primary
+#  - don't allow removal of primary while syncing
+#  - DO allow removal of secondaries while syncing
+###########################################
+aux delay_dev $dev2 0 100
+lvcreate -aey -l 2 -n $lv1 $vg $dev1 $dev2
+lvconvert -y -m 1 $vg/$lv1 \
+	--config 'global { mirror_segtype_default = "raid1" }'
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*r'
+not lvconvert --yes -m 0 $vg/$lv1 $dev1
+lvconvert --yes -m 0 $vg/$lv1 $dev2
+aux enable_dev $dev2
+lvremove -ff $vg
+
+###########################################
+# lvcreated RAID1 should allow all down-conversion
+#  - DO allow removal of primary while syncing
+#  - DO allow removal of secondaries while syncing
+###########################################
+aux delay_dev $dev2 0 100
+lvcreate --type raid1 -m 2 -aey -l 2 -n $lv1 $vg $dev1 $dev2 $dev3
+lvconvert --yes -m 1 $vg/$lv1 $dev3
+lvconvert --yes -m 0 $vg/$lv1 $dev1
+aux enable_dev $dev2
+lvremove -ff $vg
+
+###########################################
+# Converting from 2-way RAID1 to 3-way
+#  - DO allow removal of one of primary sources
+#  - Do not allow removal of all primary sources
+###########################################
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2
+aux wait_for_sync $vg $lv1
+aux delay_dev $dev3 0 100
+lvconvert --yes -m +1 $vg/$lv1 $dev3
+# should allow 1st primary to be removed
+lvconvert --yes -m -1 $vg/$lv1 $dev1
+# should NOT allow last primary to be removed
+not lvconvert --yes -m -1 $vg/$lv1 $dev2
+# should allow non-primary to be removed
+lvconvert --yes -m 0 $vg/$lv1 $dev3
+aux enable_dev $dev3
+lvremove -ff $vg
+
+###########################################
+# Converting from 2-way RAID1 to 3-way
+#  - Should allow removal of two devices,
+#    as long as they aren't both primary
+###########################################
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg $dev1 $dev2
+aux wait_for_sync $vg $lv1
+aux delay_dev $dev3 0 100
+lvconvert --yes -m +1 $vg/$lv1 $dev3
+# should NOT allow both primaries to be removed
+not lvconvert -m 0 $vg/$lv1 $dev1 $dev2
+# should allow primary + non-primary
+lvconvert --yes -m 0 $vg/$lv1 $dev1 $dev3
+aux enable_dev $dev3
+lvremove -ff $vg
+
+###########################################
 # Device Replacement Testing
 ###########################################
 # RAID1: Replace up to n-1 devices - trying different combinations
diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh
index c08b95a..992a1f2 100644
--- a/test/shell/lvconvert-thin.sh
+++ b/test/shell/lvconvert-thin.sh
@@ -135,7 +135,7 @@ lvremove -f $vg
 if test "$TSIZE" = 64T; then
 lvcreate -L24T -n $lv1 $vg
 # Warning about bigger then needed (24T data and 16G -> 128K chunk)
-lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
+fail lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
 grep "WARNING: Chunk size is too small" err
 lvremove -f $vg
 fi
diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh
index faa78b2..410e105 100644
--- a/test/shell/lvcreate-cache.sh
+++ b/test/shell/lvcreate-cache.sh
@@ -26,6 +26,7 @@ aux prepare_vg 5 80000
 
 aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
 
+
 #######################
 # Cache_Pool creation #
 #######################
@@ -62,6 +63,11 @@ grep "No command with matching syntax recognised" err
 # Check nothing has been created yet
 check vg_field $vg lv_count 0
 
+# Checks that argument passed with --cachepool is really a cache-pool
+lvcreate -an -l 1 -n $lv1 $vg
+# Hint: nice way to 'tee' only stderr.log so we can check it's log_error()
+fail lvcreate -L10 --cachepool $vg/$lv1 2> >(tee -a stderr.log >&2)
+grep "not a cache pool" stderr.log
 
 # With --type cache-pool we are clear which segtype has to be created
 lvcreate -l 1 --type cache-pool $vg/pool1
diff --git a/test/shell/lvcreate-large-raid.sh b/test/shell/lvcreate-large-raid.sh
index ca3f715..7ec140b 100644
--- a/test/shell/lvcreate-large-raid.sh
+++ b/test/shell/lvcreate-large-raid.sh
@@ -101,7 +101,15 @@ lvremove -ff $vg1
 lvcreate -aey -L 200T -n $lv1 $vg1
 lvconvert -y --type raid1 -m 1 $vg1/$lv1
 check lv_field $vg1/$lv1 size "200.00t"
-check raid_leg_status $vg1 $lv1 "aa"
+if aux have_raid 1 9 0; then
+	# The 1.9.0 version of dm-raid is capable of performing
+	# linear -> RAID1 upconverts as "recover" not "resync"
+	# The LVM code now checks the dm-raid version when
+	# upconverting and if 1.9.0+ is found, it uses "recover"
+	check raid_leg_status $vg1 $lv1 "Aa"
+else
+	check raid_leg_status $vg1 $lv1 "aa"
+fi
 lvremove -ff $vg1
 
 # bz837927 END
diff --git a/test/shell/lvcreate-raid-nosync.sh b/test/shell/lvcreate-raid-nosync.sh
index 1f01f47..bd7ec81 100644
--- a/test/shell/lvcreate-raid-nosync.sh
+++ b/test/shell/lvcreate-raid-nosync.sh
@@ -35,7 +35,7 @@ _sync() {
 
 # Delay 1st leg so that rebuilding status characters
 #  can be read before resync finished too quick.
-aux delay_dev "$dev1" 0 90 $(get first_extent_sector "$dev1")
+aux delay_dev "$dev1" 0 100 $(get first_extent_sector "$dev1")
 
 # raid0/raid0_meta don't support resynchronization
 for r in raid0 raid0_meta
@@ -58,7 +58,7 @@ lvremove --yes $vg/$lv1
 for r in $segtypes
 do
 	# raid4/5 support resynchronization
-	lvcreate --type $r -Zn -i 3 -l 4 -n $lv1 $vg
+	lvcreate --type $r -Zn -i 3 -L10 -n $lv1 $vg
 	check raid_leg_status $vg $lv1 "aaaa"
 	_sync "AAAA"
 
@@ -77,7 +77,7 @@ _sync "AAAAA"
 not lvcreate --type raid6 --nosync -Zn -i 3 -l 1 -n $lv1 $vg
 
 # raid10 supports resynchronization
-lvcreate --type raid10 -m 1 -Zn -i 3 -l 4 -n $lv1 $vg
+lvcreate --type raid10 -m 1 -Zn -i 3 -L10 -n $lv1 $vg
 check raid_leg_status $vg $lv1 "aaaaaa"
 _sync "AAAAAA"
 
diff --git a/test/shell/lvcreate-thin-big.sh b/test/shell/lvcreate-thin-big.sh
index da7812f..9c84288 100644
--- a/test/shell/lvcreate-thin-big.sh
+++ b/test/shell/lvcreate-thin-big.sh
@@ -36,7 +36,7 @@ grep "WARNING: Minimum" out
 lvcreate -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out
 grep "WARNING: Maximum" out
 check lv_field $vg/pool1_tmeta size "2.00m"
-check lv_field $vg/pool2_tmeta size "16.00g"
+check lv_field $vg/pool2_tmeta size "15.81g"
 
 # Check can start and see thinpool with metadata size above kernel limit
 lvcreate -L4M --poolmetadatasize 16G -T $vg/poolM
diff --git a/test/shell/lvresize-full.sh b/test/shell/lvresize-full.sh
index 17ee6aa..3eef11a 100644
--- a/test/shell/lvresize-full.sh
+++ b/test/shell/lvresize-full.sh
@@ -20,6 +20,7 @@ SKIP_WITH_LVMPOLLD=1
 FSCK=${FSCK-fsck}
 MKFS=${MKFS-mkfs.ext3}
 RESIZEFS=${RESIZEFS-resize2fs}
+export LVM_BINARY=$(which lvm)
 
 which $FSCK || skip
 which $MKFS || skip
diff --git a/test/shell/thin-dmeventd-warns.sh b/test/shell/thin-dmeventd-warns.sh
new file mode 100644
index 0000000..d22863b
--- /dev/null
+++ b/test/shell/thin-dmeventd-warns.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+# Copyright (C) 2017 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 if dmeventd produces multiple warnings when pools runs above 80%
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMETAD=1
+
+. lib/inittest
+
+which blkdiscard || skip
+
+percent_() {
+	get lv_field $vg/pool data_percent | cut -d. -f1
+}
+
+wait_warn_() {
+
+	for i in $(seq 1 7)
+	do
+		test $(egrep "WARNING: Thin pool.*is now" debug.log_DMEVENTD_out | wc -l) -eq $1 && return 0
+		sleep 2
+	done
+
+	die "Waiting too log for dmeventd log warning"
+}
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_dmeventd
+aux prepare_vg
+
+lvcreate -L8 -V8 -T $vg/pool -n $lv1
+
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=26
+test $(percent_) -gt 80
+
+# Give it some time to dmeventd to log WARNING
+wait_warn_ 1
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30
+test $(percent_) -gt 90
+
+# Give it some time to dmeventd to log WARNING
+wait_warn_ 2
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=8
+test $(percent_) -eq 100
+
+wait_warn_ 3
+
+blkdiscard "$DM_DEV_DIR/$vg/$lv1"
+
+# FIXME: Enforce thin-pool metadata commit with flushing status
+dmsetup status ${vg}-pool-tpool
+# Wait for thin-pool monitoring to notice lower values
+sleep 11
+# ATM dmeventd is not logging event for thin-pool getting
+# below 'WARNED' threshold.
+
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30
+test $(percent_) -gt 90
+
+lvs -a $vg
+dmsetup status ${vg}-pool-tpool
+
+# Check pool again Warns
+wait_warn_ 4
+
+vgremove -f $vg
diff --git a/test/shell/thin-large.sh b/test/shell/thin-large.sh
new file mode 100644
index 0000000..da5a7ec
--- /dev/null
+++ b/test/shell/thin-large.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Copyright (C) 2017 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
+
+# 'Exercise logic around boundary sizes of thin-pool data and chunksize
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# FIXME  update test to make something useful on <16T
+aux can_use_16T || skip
+
+aux have_thin 1 0 0 || skip
+
+# Prepare ~1P sized devices
+aux prepare_vg 1 1000000000
+
+lvcreate -an -T -L250T $vg/pool250
+
+lvcreate -an -T -L250T --poolmetadatasize 16G $vg/pool16
+
+fail lvcreate -an -T -L250T --chunksize 64K --poolmetadatasize 16G $vg/pool64
+
+# Creation of thin-pool with proper chunk-size but not enough metadata size
+# which can grow later needs to pass
+lvcreate -an -T -L250T --chunksize 1M --poolmetadatasize 4G $vg/pool1024
+
+# Creation of chunk should fit
+lvcreate -an -T -L12T --chunksize 64K --poolmetadatasize 16G $vg/pool64
+
+check lv_field $vg/pool64 chunksize "64.00k"
+
+lvremove -ff $vg
+
+
+### Check also lvconvert ###
+
+lvcreate -an -L250T -n pool $vg
+
+fail lvconvert -y --chunksize 64 --thinpool $vg/pool
+lvconvert -y --chunksize 1M --thinpool $vg/pool
+
+check lv_field $vg/pool chunksize "1.00m"
+
+vgremove -ff $vg
diff --git a/test/shell/thin-resize-match.sh b/test/shell/thin-resize-match.sh
index c78842f..46b4531 100644
--- a/test/shell/thin-resize-match.sh
+++ b/test/shell/thin-resize-match.sh
@@ -12,13 +12,12 @@
 # ensure there is no data loss during thin-pool resize
 
 SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
 
 export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
 
 . lib/inittest
 
-test -e LOCAL_LVMPOLLD && skip
-
 which md5sum || skip
 
 aux have_thin 1 0 0 || skip
diff --git a/test/shell/unknown-segment.sh b/test/shell/unknown-segment.sh
index 27cea88..20fc920 100644
--- a/test/shell/unknown-segment.sh
+++ b/test/shell/unknown-segment.sh
@@ -18,9 +18,10 @@ aux prepare_vg 4
 
 lvcreate -an -Zn -l 1 -n $lv1 $vg
 lvcreate -an -Zn -l 2 --type mirror -m 1 -n $lv2 $vg
+lvcreate -an -Zn --type zero -l 1 -n $lv3 $vg
 
 vgcfgbackup -f bak0 $vg
-sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0
+sed -e 's,striped,unstriped,;s,mirror,unmirror,;s,zero,zero+NEWFLAG,' -i.orig bak0
 vgcfgrestore -f bak0 $vg
 
 # we have on-disk metadata with unknown segments now
@@ -28,11 +29,13 @@ not lvchange -aey $vg/$lv1 # check that activation is refused
 
 # try once more to catch invalid memory access with valgrind
 # when clvmd flushes cmd mem pool
-not lvchange -aey $vg/$lv1 # check that activation is refused
+not lvchange -aey $vg/$lv2 # check that activation is refused
+
+not lvchange -aey $vg/$lv3 # check that activation is refused
 
 vgcfgbackup -f bak1 $vg
 cat bak1
-sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1
+sed -e 's,unstriped,striped,;s,unmirror,mirror,;s,zero+NEWFLAG,zero,' -i.orig bak1
 vgcfgrestore -f bak1 $vg
 vgcfgbackup -f bak2 $vg
 
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
index 70b7e79..7aa180f 100644
--- a/test/unit/Makefile.in
+++ b/test/unit/Makefile.in
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
 #
 # This file is part of LVM2.
 #
@@ -24,15 +24,15 @@ UNITS = \
 	string_t.c\
 	run.c
 
-include $(top_builddir)/make.tmpl
-
-ifeq ($(MAKECMDGOALS),distclean)
+ifeq ("@TESTING@", "yes")
 SOURCES = $(UNITS)
+TARGETS = run
 endif
 
-ifeq ("$(TESTING)", "yes")
+include $(top_builddir)/make.tmpl
+
+ifeq ($(MAKECMDGOALS),distclean)
 SOURCES = $(UNITS)
-TARGETS = run
 endif
 
 ifeq ("$(TESTING)", "yes")
@@ -42,6 +42,8 @@ CFLAGS += @CUNIT_CFLAGS@
 check: unit
 
 $(TARGETS): $(OBJECTS) $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
+	      -o $@ $(OBJECTS) $(LDLIBS)
 
 unit: $(TARGETS)
 	@echo Running unit tests
diff --git a/tools/args.h b/tools/args.h
index 87b33e7..f5e864f 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -42,7 +42,7 @@ arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0,
 
 arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0,
     "Adds a tag to a PV, VG or LV. This option can be repeated to add\n"
-    "multiple tags at once. See lvm(8) for information about tags.\n")
+    "multiple tags at once. See \\fBlvm\\fP(8) for information about tags.\n")
 
 arg(aligned_ARG, '\0', "aligned", 0, 0, 0,
     "Use with --separator to align the output columns\n")
@@ -132,10 +132,41 @@ arg(config_ARG, '\0', "config", string_VAL, 0, 0,
     "See \\fBlvm.conf\\fP(5) for more information about config.\n")
 
 arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1,
-    "See lvmreport(7).\n")
+    "See \\fBlvmreport\\fP(7).\n")
 
 arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0,
-    "See lvmreport(7).\n")
+    "\\fBcurrent\\fP prints the config settings that would be applied\n"
+    "to an lvm command (assuming the command does not override them\n"
+    "on the command line.) This includes:\n"
+    "settings that have been modified in lvm config files,\n"
+    "settings that get their default values from config files,\n"
+    "and default settings that have been uncommented in config files.\n"
+    "\\fBdefault\\fP prints all settings with their default values.\n"
+    "Changes made in lvm config files are not reflected in the output.\n"
+    "Some settings get their default values internally,\n"
+    "and these settings are printed as comments.\n"
+    "Other settings get their default values from config files,\n"
+    "and these settings are not printed as comments.\n"
+    "\\fBdiff\\fP prints only config settings that have been modified\n"
+    "from their default values in config files (the difference between\n"
+    "current and default.)\n"
+    "\\fBfull\\fP prints every setting uncommented and set to the\n"
+    "current value, i.e. how it would be used by an lvm command.\n"
+    "This includes settings modified in config files, settings that usually\n"
+    "get defaults internally, and settings that get defaults from config files.\n"
+    "\\fBlist\\fP prints all config names without values.\n"
+    "\\fBmissing\\fP prints settings that are missing from the\n"
+    "lvm config files. A missing setting that usually gets its default\n"
+    "from config files is printed uncommented and set to the internal default.\n"
+    "Settings that get their default internally and are not set in config files\n"
+    "are printed commented with the internal default.\n"
+    "\\fBnew\\fP prints config settings that have been added since\n"
+    "the lvm version specified by --sinceversion. They are printed\n"
+    "with their default values.\n"
+    "\\fBprofilable\\fP prints settings with their default values that can be set from a profile.\n"
+    "\\fBprofilable-command\\fP prints settings with their default values that can be set from a command profile.\n"
+    "\\fBprofilable-metadata\\fP prints settings with their default values that can be set from a metadata profile.\n"
+    "Also see \\fBlvm.conf\\fP(5).\n")
 
 arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0,
     "Align the start of the data to a multiple of this number.\n"
@@ -149,7 +180,7 @@ arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0,
 
 arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0,
     "Deletes a tag from a PV, VG or LV. This option can be repeated to delete\n"
-    "multiple tags at once. See lvm(8) for information about tags.\n")
+    "multiple tags at once. See \\fBlvm\\fP(8) for information about tags.\n")
 
 arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0,
     "Detaches a metadata profile from a VG or LV.\n"
@@ -188,7 +219,7 @@ arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0,
 
 arg(foreign_ARG, '\0', "foreign", 0, 0, 0,
     "Report/display foreign VGs that would otherwise be skipped.\n"
-    "See lvmsystemid(7) for more information about foreign VGs.\n")
+    "See \\fBlvmsystemid\\fP(7) for more information about foreign VGs.\n")
 
 arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0,
     "Allows a polling operation to continue when PVs are missing,\n"
@@ -198,7 +229,10 @@ arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0,
     "Exclude advanced configuration settings from the output.\n")
 
 arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0,
-    "Ignore local section.\n")
+    "Ignore the local section. The local section should be defined in\n"
+    "the lvmlocal.conf file, and should contain config settings\n"
+    "specific to the local host which should not be copied to\n"
+    "other hosts.\n")
 
 arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0,
     "Allows a command to continue with read-only metadata\n"
@@ -227,25 +261,25 @@ arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
 
 arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0,
     "Used to pass options for special cases to lvmlockd.\n"
-    "See lvmlockd(8) for more information.\n")
+    "See \\fBlvmlockd\\fP(8) for more information.\n")
 
 arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0,
     "Start the lockspace of a shared VG in lvmlockd.\n"
     "lvmlockd locks becomes available for the VG, allowing LVM to use the VG.\n"
-    "See lvmlockd(8) for more information.\n")
+    "See \\fBlvmlockd\\fP(8) for more information.\n")
 
 arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0,
     "Stop the lockspace of a shared VG in lvmlockd.\n"
     "lvmlockd locks become unavailable for the VG, preventing LVM from using the VG.\n"
-    "See lvmlockd(8) for more information.\n")
+    "See \\fBlvmlockd\\fP(8) for more information.\n")
 
 arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0,
     "#vgchange\n"
     "Change the VG lock type to or from a shared lock type used with lvmlockd.\n"
-    "See lvmlockd(8) for more information.\n"
+    "See \\fBlvmlockd\\fP(8) for more information.\n"
     "#vgcreate\n"
     "Specify the VG lock type directly in place of using --shared.\n"
-    "See lvmlockd(8) for more information.\n")
+    "See \\fBlvmlockd\\fP(8) for more information.\n")
 
 arg(logonly_ARG, '\0', "logonly", 0, 0, 0,
     "Suppress command report and display only log report.\n")
@@ -345,7 +379,7 @@ arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0,
     "Start (yes) or stop (no) monitoring an LV with dmeventd.\n"
     "dmeventd monitors kernel events for an LV, and performs\n"
     "automated maintenance for the LV in reponse to specific events.\n"
-    "See dmeventd(8) for more information.\n")
+    "See \\fBdmeventd\\fP(8) for more information.\n")
 
 arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0,
     "Add an \"LVM2_\" prefix plus the field name to the output. Useful\n"
@@ -552,7 +586,7 @@ arg(shared_ARG, '\0', "shared", 0, 0, 0,
     "manager is running. This allows multiple hosts to share a VG on shared\n"
     "devices. lvmlockd and a lock manager must be configured and running.\n"
     "(A shared VG using lvmlockd is different from a clustered VG using clvmd.)\n"
-    "See lvmlockd(8) for more information about shared VGs.\n"
+    "See \\fBlvmlockd\\fP(8) for more information about shared VGs.\n"
     "#vgs\n"
     "#lvs\n"
     "#pvs\n"
@@ -562,7 +596,7 @@ arg(shared_ARG, '\0', "shared", 0, 0, 0,
     "#pvdisplay\n"
     "Report/display shared VGs that would otherwise be skipped when\n"
     "lvmlockd is not being used on the host.\n"
-    "See lvmlockd(8) for more information about shared VGs.\n")
+    "See \\fBlvmlockd\\fP(8) for more information about shared VGs.\n")
 
 arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0,
     "Specify an LVM version in x.y.z format where x is the major version,\n"
@@ -644,12 +678,12 @@ arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0,
     "the host creating it. Using this option requires caution because the\n"
     "system ID of the new VG may not match the system ID of the host running\n"
     "the command, leaving the VG inaccessible to the host.\n"
-    "See lvmsystemid(7) for more information.\n"
+    "See \\fBlvmsystemid\\fP(7) for more information.\n"
     "#vgchange\n"
     "Changes the system ID of the VG.  Using this option requires caution\n"
     "because the VG may become foreign to the host running the command,\n"
     "leaving the host unable to access it.\n"
-    "See lvmsystemid(7) for more information.\n")
+    "See \\fBlvmsystemid\\fP(7) for more information.\n")
 
 arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0,
     "The name of a thin pool LV.\n")
@@ -808,6 +842,9 @@ arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0, NULL)
  * ... and now the short args.
  */
 arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0,
+    "#pvscan\n"
+    "Auto-activate LVs in a VG when the PVs scanned have completed the VG.\n"
+    "(Only \\fBay\\fP is applicable.)\n"
     "#lvchange\n"
     "#vgchange\n"
     "Change the active state of LVs.\n"
@@ -828,8 +865,8 @@ arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0,
     "if the list is set but empty, no LVs match.\n"
     "Autoactivation should be used during system boot to make it possible\n"
     "to select which LVs should be automatically activated by the system.\n"
-    "See lvmlockd(8) for more information about activation options \\fBey\\fP and \\fBsy\\fP for shared VGs.\n"
-    "See clvmd(8) for more information about activation options \\fBey\\fP, \\fBsy\\fP, \\fBly\\fP and \\fBln\\fP for clustered VGs.\n"
+    "See \\fBlvmlockd\\fP(8) for more information about activation options \\fBey\\fP and \\fBsy\\fP for shared VGs.\n"
+    "See \\fBclvmd\\fP(8) for more information about activation options \\fBey\\fP, \\fBsy\\fP, \\fBly\\fP and \\fBln\\fP for clustered VGs.\n"
     "#lvcreate\n"
     "Controls the active state of the new LV.\n"
     "\\fBy\\fP makes the LV active, or available.\n"
@@ -842,12 +879,16 @@ arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0,
     "If autoactivation \\fBay\\fP is used, the LV is only activated\n"
     "if it matches an item in lvm.conf activation/auto_activation_volume_list.\n"
     "\\fBay\\fP implies --zero n and --wipesignatures n.\n"
-    "See lvmlockd(8) for more information about activation options for shared VGs.\n"
-    "See clvmd(8) for more information about activation options for clustered VGs.\n")
+    "See \\fBlvmlockd\\fP(8) for more information about activation options for shared VGs.\n"
+    "See \\fBclvmd\\fP(8) for more information about activation options for clustered VGs.\n")
 
 arg(all_ARG, 'a', "all", 0, 0, 0,
     "#vgreduce\n"
     "Removes all empty PVs if none are named on the command line.\n"
+    "#pvchange\n"
+    "Change all visible PVs.\n"
+    "#vgimport\n"
+    "Import all visible VGs.\n"
     "#lvscan\n"
     "#lvdisplay\n"
     "#lvs\n"
@@ -863,7 +904,7 @@ arg(all_ARG, 'a', "all", 0, 0, 0,
 
 arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0,
     "Specifies if metadata should be backed up automatically after a change.\n"
-    "Enabling this is strongly advised! See vgcfgbackup(8) for more information.\n")
+    "Enabling this is strongly advised! See \\fBvgcfgbackup\\fP(8) for more information.\n")
 
 arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0,
     "Only select active VGs. The VG is considered active\n"
@@ -907,20 +948,20 @@ arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0,
     "This allows multiple hosts to share a VG on shared devices.\n"
     "clvmd and a lock manager must be configured and running.\n"
     "(A clustered VG using clvmd is different from a shared VG using lvmlockd.)\n"
-    "See clvmd(8) for more information about clustered VGs.\n"
+    "See \\fBclvmd\\fP(8) for more information about clustered VGs.\n"
     "#vgchange\n"
     "Change the clustered property of a VG using clvmd.\n"
-    "See clvmd(8) for more information about clustered VGs.\n"
+    "See \\fBclvmd\\fP(8) for more information about clustered VGs.\n"
     "#vgsplit\n"
     "Specifies the clustered property of the new VG.\n")
 
 arg(colon_ARG, 'c', "colon", 0, 0, 0,
     "Generate colon separated output for easier parsing in scripts or programs.\n"
-    "Also see vgs(8) which provides considerably more control over the output.\n")
+    "Also see \\fBvgs\\fP(8) which provides considerably more control over the output.\n")
 
 arg(columns_ARG, 'C', "columns", 0, 0, 0,
-    "Display output in columns, the equivalent of vgs(8).\n"
-    "Options listed are the same as options given in vgs(8).\n")
+    "Display output in columns, the equivalent of \\fBvgs\\fP(8).\n"
+    "Options listed are the same as options given in \\fBvgs\\fP(8).\n")
 
 arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0,
     "Sets or resets the contiguous allocation policy for LVs.\n"
@@ -1208,7 +1249,7 @@ arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0,
     "\\fBseg_all\\fP all LV segment fields, and\n"
     "\\fBpvseg_all\\fP all PV segment columns.\n"
     "See the lvm.conf report section for more config options.\n"
-    "See lvmreport(7) for more information about reporting.\n")
+    "See \\fBlvmreport\\fP(7) for more information about reporting.\n")
 
 arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0,
     "Comma-separated ordered list of columns to sort by. Replaces the default\n"
@@ -1348,11 +1389,11 @@ arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0,
     "Specify a UUID for the device.\n"
     "Without this option, a random UUID is generated.\n"
     "This option is needed before restoring a backup of LVM metadata\n"
-    "onto a replacement device; see vgcfgrestore(8). As such, use of\n"
+    "onto a replacement device; see \\fBvgcfgrestore\\fP(8). As such, use of\n"
     "--restorefile is compulsory unless the --norestorefile is used.\n"
     "All PVs must have unique UUIDs, and LVM will prevent certain operations\n"
     "if multiple devices are seen with the same UUID.\n"
-    "See vgimportclone(8) for more information.\n")
+    "See \\fBvgimportclone\\fP(8) for more information.\n")
 
 /* Not used */
 arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0, NULL)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 2d9e48e..7f9c31f 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1417,7 +1417,7 @@ DESC: Display PV information.
 
 pvscan --cache_long
 OO: --ignorelockingfailure, --reportformat ReportFmt, --background,
---activate Active, --major Number, --minor Number
+--activate ay, --major Number, --minor Number
 OP: PV|String ...
 ID: pvscan_cache
 DESC: Populate the lvmetad cache by scanning PVs.
diff --git a/tools/command.c b/tools/command.c
index 0f69bbb..a08d068 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -40,6 +40,8 @@
  */
 #ifdef MAN_PAGE_GENERATOR
 
+#define stack
+
 struct cmd_context {
 	void *libmem;
 };
@@ -699,9 +701,16 @@ static void set_opt_def(struct cmd_context *cmdtool, struct command *cmd, char *
 		if (val_enum == constnum_VAL)
 			def->num = (uint64_t)atoi(name);
 
-		if (val_enum == conststr_VAL)
+		if (val_enum == conststr_VAL) {
 			def->str = dm_pool_strdup(cmdtool->libmem, name);
 
+			if (!def->str) {
+				/* FIXME */
+				stack;
+				return;
+			}
+		}
+
 		if (val_enum == lv_VAL) {
 			if (strchr(name, '_'))
 				def->lvt_bits = lv_to_bits(cmd, name);
@@ -1416,6 +1425,12 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
 			cmd_count++;
 			cmd->name = dm_pool_strdup(cmdtool->libmem, name);
 
+			if (!cmd->name) {
+				/* FIXME */
+				stack;
+				return 0;
+			}
+
 			if (run_name && strcmp(run_name, name)) {
 				skip = 1;
 				prev_was_oo_def = 0;
@@ -1447,6 +1462,10 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
 					memset(newdesc, 0, newlen);
 					snprintf(newdesc, newlen, "%s %s", cmd->desc, desc);
 					cmd->desc = newdesc;
+				} else {
+					/* FIXME */
+					stack;
+					return 0;
 				}
 			} else
 				cmd->desc = desc;
@@ -1465,6 +1484,12 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
 
 		if (is_id_line(line_argv[0]) && cmd) {
 			cmd->command_id = dm_pool_strdup(cmdtool->libmem, line_argv[1]);
+
+			if (!cmd->command_id) {
+				/* FIXME */
+				stack;
+				return 0;
+			}
 			continue;
 		}
 
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 660570a..92161e2 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -1238,6 +1238,16 @@ static int _lvchange_properties_check(struct cmd_context *cmd,
 				     int lv_is_named_arg)
 {
 	if (!lv_is_visible(lv)) {
+		/*
+		 * Exceptions where we allow lvchange properties on
+		 * a hidden sub lv.
+		 *
+		 * lv_is_thin_pool_data: e.g. needed when the data sublv
+		 * is a cache lv and we need to change cache properties.
+		 */
+		if (lv_is_thin_pool_data(lv))
+			return 1;
+
 		if (lv_is_named_arg)
 			log_error("Operation not permitted on hidden LV %s.", display_lvname(lv));
 		return 0;
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index f775290..f464896 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -251,6 +251,7 @@ static int _update_extents_params(struct volume_group *vg,
 	uint32_t size_rest;
 	uint32_t stripesize_extents;
 	uint32_t extents;
+	uint32_t base_calc_extents;
 
 	if (lcp->size &&
 	    !(lp->extents = extents_from_size(vg->cmd, lcp->size,
@@ -275,17 +276,17 @@ static int _update_extents_params(struct volume_group *vg,
 
 	switch (lcp->percent) {
 		case PERCENT_VG:
-			extents = percent_of_extents(lp->extents, vg->extent_count, 0);
+			extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0);
 			break;
 		case PERCENT_FREE:
-			extents = percent_of_extents(lp->extents, vg->free_count, 0);
+			extents = percent_of_extents(lp->extents, base_calc_extents = vg->free_count, 0);
 			break;
 		case PERCENT_PVS:
 			if (lcp->pv_count) {
 				pv_extent_count = pv_list_extents_free(lp->pvh);
-				extents = percent_of_extents(lp->extents, pv_extent_count, 0);
+				extents = percent_of_extents(lp->extents, base_calc_extents = pv_extent_count, 0);
 			} else
-				extents = percent_of_extents(lp->extents, vg->extent_count, 0);
+				extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0);
 			break;
 		case PERCENT_LV:
 			log_error("Please express size as %%FREE%s, %%PVS or %%VG.",
@@ -304,7 +305,7 @@ static int _update_extents_params(struct volume_group *vg,
 			}
 			/* Add whole metadata size estimation */
 			extents = cow_max_extents(origin_lv, lp->chunk_size) - origin_lv->le_count +
-				percent_of_extents(lp->extents, origin_lv->le_count, 1);
+				percent_of_extents(lp->extents, base_calc_extents = origin_lv->le_count, 1);
 			break;
 		case PERCENT_NONE:
 			extents = lp->extents;
@@ -314,10 +315,27 @@ static int _update_extents_params(struct volume_group *vg,
 			return 0;
 	}
 
-	if (lcp->percent) {
+	if (lcp->percent != PERCENT_NONE) {
 		/* FIXME Don't do the adjustment for parallel allocation with PERCENT_ORIGIN! */
 		lp->approx_alloc = 1;
-		log_verbose("Converted %" PRIu32 "%%%s into %" PRIu32 " extents.", lp->extents, get_percent_string(lcp->percent), extents);
+		if (!extents) {
+			log_error("Calculated size of logical volume is 0 extents. Needs to be larger.");
+			return 0;
+		}
+
+		/* For mirrors and raid with percentages based on physical extents, convert the total number of PEs 
+		 * into the number of logical extents per image (minimum 1) */
+		/* FIXME Handle all the supported raid layouts here based on already-known segtype. */
+		if ((lcp->percent != PERCENT_ORIGIN) && lp->mirrors) {
+			extents /= lp->mirrors;
+			if (!extents)
+				extents = 1;
+		}
+
+		log_verbose("Converted %" PRIu32 "%% of %s (%" PRIu32 ") extents into %" PRIu32 " (with mimages %" PRIu32 " and stripes %" PRIu32
+			    " for segtype %s).", lp->extents, get_percent_string(lcp->percent), base_calc_extents,
+			    extents, lp->mirrors, lp->stripes, lp->segtype->name);
+
 		lp->extents = extents;
 	}
 
@@ -389,6 +407,11 @@ static int _update_extents_params(struct volume_group *vg,
 		}
 	}
 
+	if ((lcp->percent != PERCENT_NONE) && !lp->extents) {
+		log_error("Adjusted size of logical volume is 0 extents. Needs to be larger.");
+		return 0;
+	}
+
 	return 1;
 }
 
@@ -1170,6 +1193,13 @@ static int _determine_cache_argument(struct volume_group *vg,
 		lp->create_pool = 0;
 		lp->origin_name = NULL;
 	} else if (lv) {
+		if (arg_is_set(cmd, cachepool_ARG)) {
+			/* Argument of --cachepool has to be a cache-pool */
+			log_error("Logical volume %s is not a cache pool.",
+				  display_lvname(lv));
+			return 0;
+		}
+
 		/* Origin exists, create cache pool volume */
 		if (!validate_lv_cache_create_origin(lv))
 			return_0;
diff --git a/tools/reporter.c b/tools/reporter.c
index 980f39c..b9c4153 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -172,7 +172,7 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
 	if (lv_is_merging_origin(lv)) {
 		if (!_check_merging_origin(lv, &status, &merged))
 		      goto_out;
-		if (merged)
+		if (merged && lv_is_thin_volume(lv->snapshot->lv))
 			lv = lv->snapshot->lv;
 	}
 
@@ -234,13 +234,13 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
 	if (lv_is_merging_origin(seg->lv)) {
 		if (!_check_merging_origin(seg->lv, &status, &merged))
 			goto_out;
-		if (merged)
+		if (merged && lv_is_thin_volume(seg->lv->snapshot->lv))
 			seg = seg->lv->snapshot;
 	}
 
 	if (!report_object(sh ? : handle->custom_handle, sh != NULL,
 			   seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
-	goto_out;
+		goto_out;
 
 	r = ECMD_PROCESSED;
 out:
diff --git a/tools/toollib.c b/tools/toollib.c
index f3cf4ca..e5a854f 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -1335,9 +1335,17 @@ int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtyp
 	return _validate_stripe_params(cmd, segtype, stripes, stripe_size);
 }
 
-static int _validate_cachepool_params(const char *name,
-				      const struct dm_config_tree *settings)
+static int _validate_cachepool_params(const char *policy_name, cache_mode_t cache_mode)
 {
+	/*
+	 * FIXME: it might be nice if cmd def rules could check option values,
+	 * then a rule could do this.
+	 */
+	if ((cache_mode == CACHE_MODE_WRITEBACK) && policy_name && !strcmp(policy_name, "cleaner")) {
+		log_error("Cache mode \"writeback\" is not compatible with cache policy \"cleaner\".");
+		return 0;
+	}
+
 	return 1;
 }
 
@@ -1371,6 +1379,9 @@ int get_cache_params(struct cmd_context *cmd,
 
 	*name = arg_str_value(cmd, cachepolicy_ARG, NULL);
 
+	if (!_validate_cachepool_params(*name, *cache_mode))
+		goto_out;
+
 	dm_list_iterate_items(group, &cmd->arg_value_groups) {
 		if (!grouped_arg_is_set(group->arg_values, cachesettings_ARG))
 			continue;
@@ -1401,9 +1412,6 @@ int get_cache_params(struct cmd_context *cmd,
 			cn->child = result->root;
 			result->root = cn;
 		}
-
-		if (!_validate_cachepool_params(*name, result))
-			goto_out;
 	}
 
 	ok = 1;