[lvm2] Additional fixes from upcoming v104.

Peter Rajnoha prajnoha at fedoraproject.org
Fri Oct 25 06:51:56 UTC 2013


commit 8c6d94dbad5feeac11236e72a8b7daaeb20eab0e
Author: Peter Rajnoha <prajnoha at redhat.com>
Date:   Fri Oct 25 08:51:46 2013 +0200

    Additional fixes from upcoming v104.

 lvm2-2_02_104-additional-fixes-from-v104.patch | 2212 ++++++++++++++++++++++++
 lvm2.spec                                      |   38 +-
 2 files changed, 2248 insertions(+), 2 deletions(-)
---
diff --git a/lvm2-2_02_104-additional-fixes-from-v104.patch b/lvm2-2_02_104-additional-fixes-from-v104.patch
new file mode 100644
index 0000000..47c7194
--- /dev/null
+++ b/lvm2-2_02_104-additional-fixes-from-v104.patch
@@ -0,0 +1,2212 @@
+commit 11388698bad4336c156b11f8e1f51b664b34f57c
+Author: Peter Rajnoha <prajnoha at redhat.com>
+Date:   Fri Oct 25 08:22:33 2013 +0200
+
+    Additional fixes from upcoming v104.
+---
+ WHATS_NEW                                       |  29 ++++++
+ WHATS_NEW_DM                                    |   6 ++
+ configure                                       |  26 +++++-
+ configure.in                                    |  17 +++-
+ daemons/clvmd/clvmd.c                           |   2 +-
+ daemons/clvmd/lvm-functions.c                   |   2 +-
+ daemons/lvmetad/lvmetad-core.c                  |  25 +++--
+ lib/activate/activate.c                         |  90 ++++++++++++------
+ lib/activate/activate.h                         |  19 +++-
+ lib/activate/dev_manager.c                      |  19 +++-
+ lib/cache/lvmetad.c                             |   2 -
+ lib/device/device-types.h                       |   1 +
+ lib/format_text/flags.c                         |   6 +-
+ lib/locking/file_locking.c                      |   6 +-
+ lib/locking/no_locking.c                        |   6 +-
+ lib/metadata/lv.c                               |   8 +-
+ lib/metadata/lv_manip.c                         |  17 +++-
+ lib/metadata/metadata-exported.h                |   7 ++
+ lib/metadata/metadata.c                         |  76 ++++++++++------
+ lib/metadata/metadata.h                         |   3 -
+ lib/metadata/snapshot_manip.c                   |  10 ++
+ lib/metadata/thin_manip.c                       |   1 +
+ lib/snapshot/snapshot.c                         |  59 ++++++------
+ libdaemon/client/daemon-io.c                    |   2 +-
+ libdaemon/server/daemon-server.c                |   6 +-
+ libdm/Makefile.in                               |   2 +-
+ libdm/libdevmapper.h                            |   2 +-
+ libdm/libdm-common.c                            |  13 ++-
+ libdm/mm/pool-fast.c                            |   4 +
+ libdm/mm/pool.c                                 |   9 +-
+ man/pvscan.8.in                                 |   4 +-
+ scripts/Makefile.in                             |   2 +
+ scripts/blkdeactivate.sh.in                     |   5 +-
+ scripts/lvm2_pvscan_systemd_red_hat at .service.in |  14 +++
+ scripts/vgimportclone.sh                        |   8 +-
+ test/Makefile.in                                |  12 ++-
+ test/lib/aux.sh                                 |   2 +-
+ test/lib/get.sh                                 |   2 +-
+ test/lib/harness.c                              |  30 +++---
+ test/shell/lvconvert-repair-raid.sh             |   2 +-
+ test/shell/lvconvert-repair-thin.sh             | 116 ++++++++++++++++++++++++
+ test/shell/lvconvert-thin-external.sh           |   8 ++
+ test/shell/lvcreate-usage.sh                    |  18 ++--
+ test/shell/lvmcache-exercise.sh                 |  17 +++-
+ test/shell/snapshot-usage.sh                    |  37 +++++++-
+ test/shell/vgrename-usage.sh                    |  15 +++
+ tools/dmsetup.c                                 |   2 +-
+ tools/lvchange.c                                |   3 +-
+ tools/lvconvert.c                               |  23 ++++-
+ tools/lvremove.c                                |   8 --
+ tools/pvscan.c                                  |  61 ++++++++++---
+ tools/vgrename.c                                |   2 +
+ udev/11-dm-lvm.rules.in                         |  15 +++
+ udev/13-dm-disk.rules.in                        |   3 +-
+ udev/69-dm-lvm-metad.rules.in                   |   4 +-
+ udev/Makefile.in                                |   8 +-
+ 56 files changed, 697 insertions(+), 199 deletions(-)
+
+diff --git a/WHATS_NEW b/WHATS_NEW
+index d69e74e..49f37a4 100644
+--- a/WHATS_NEW
++++ b/WHATS_NEW
+@@ -1,3 +1,32 @@
++Version 2.02.104
++===================================
++  Add internal flag for temporary LVs to properly direct udev to not interfere.
++  Fix endless loop in blkdeactivate <device>... if unable to umount/deactivate.
++  Add dev-block-<major>:<minor>.device systemd alias for complete PV tracking.
++  Use major:minor as short form of --major and --minor arg for pvscan --cache.
++  Remove 2>/dev/null from three lvm commands executed by vgimportclone.
++  Add configure --enable-udev-systemd-background-jobs.
++  Add lvm2-pvscan at .service to run pvscan as a service for lvmetad/autoactivation.
++  Fix lvconvert swap of poolmetadata volume for active thin pool.
++  Check for open count with a timeout before removal/deactivation of an LV.
++  Report RAID images split with tracking as out-of-sync ("I").
++  Improve parsing of snapshot lv segment.
++  Add workaround for deactivation problem of opened virtual snapshot.
++  Disable unsupported merge for virtual snapshot.
++  Move code to remove virtual snapshot from tools to lib for lvm2app.
++  Fix possible race during daemon worker thread creation (lvmetad).
++  Fix possible deadlock while clearing lvmetad cache for full rescan.
++  Fix possible race while creating/destroying memory pools.
++  Recognise NVM Express devices in filter.
++  Fix failing metadata repair when lvmetad is used.
++  Fix incorrect memory handling when reading messages from lvmetad.
++  Fix locking in lvmetad when handling the PV which is gone.
++  Recognize new flag to skip udev scanning in udev rules and act appropriately.
++  Add support for flagging an LV to skip udev scanning during activation.
++  Improve message when unable to change discards setting on active thin pool.
++  Run full scan before vgrename operation to avoid any cache name collision.
++  Fix lvconvert when converting to a thin pool and thin LV at once.
++
+ Version 2.02.103 - 4th October 2013
+ ===================================
+   Ensure vgid matches before removing vgname entry from lvmetad cache.
+diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
+index 9dfd9bf..6742ad4 100644
+--- a/WHATS_NEW_DM
++++ b/WHATS_NEW_DM
+@@ -1,3 +1,9 @@
++Version 1.02.83
++==================================
++  Skip race errors when non-udev dmsetup build runs on udev-enabled system.
++  Skip error message when holders are not present in sysfs.
++  Use __linux__ instead of linux define to make libdevmapper.h C compliant.
++
+ Version 1.02.82 - 4th October 2013
+ ==================================
+   Define symbolic names for subsystem udev flags in libdevmapper for easier use.
+diff --git a/configure b/configure
+index 20a706a..002a7d2 100755
+--- a/configure
++++ b/configure
+@@ -613,6 +613,7 @@ DMEVENTD_PIDFILE
+ WRITE_INSTALL
+ UDEV_HAS_BUILTIN_BLKID
+ UDEV_RULE_EXEC_DETECTION
++UDEV_SYSTEMD_BACKGROUND_JOBS
+ UDEV_SYNC
+ UDEV_RULES
+ UDEV_PC
+@@ -849,6 +850,7 @@ enable_valgrind_pool
+ enable_devmapper
+ enable_lvmetad
+ with_lvmetad_pidfile
++enable_udev_systemd_background_jobs
+ enable_udev_sync
+ enable_udev_rules
+ enable_udev_rule_exec_detection
+@@ -1552,6 +1554,9 @@ Optional Features:
+   --enable-valgrind-pool  enable valgrind awareness of pools
+   --disable-devmapper     disable LVM2 device-mapper interaction
+   --enable-lvmetad        enable the LVM Metadata Daemon
++  --enable-udev-systemd-background-jobs
++                          enable udev-systemd protocol to instantiate a
++                          service for background job
+   --enable-udev_sync      enable synchronisation with udev processing
+   --enable-udev_rules     install rule files needed for udev synchronisation
+   --enable-udev-rule-exec-detection
+@@ -9090,6 +9095,19 @@ _ACEOF
+ fi
+ 
+ ################################################################################
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use udev-systemd protocol for jobs in background" >&5
++$as_echo_n "checking whether to use udev-systemd protocol for jobs in background... " >&6; }
++# Check whether --enable-udev-systemd-background-jobs was given.
++if test "${enable_udev_systemd_background_jobs+set}" = set; then :
++  enableval=$enable_udev_systemd_background_jobs; UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval
++else
++  UDEV_SYSTEMD_BACKGROUND_JOBS=no
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UDEV_SYSTEMD_BACKGROUND_JOBS" >&5
++$as_echo "$UDEV_SYSTEMD_BACKGROUND_JOBS" >&6; }
++
++################################################################################
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable synchronisation with udev processing" >&5
+ $as_echo_n "checking whether to enable synchronisation with udev processing... " >&6; }
+ # Check whether --enable-udev_sync was given.
+@@ -9668,8 +9686,7 @@ if [ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
+ fi
+ 
+ ################################################################################
+-if [ "$DMEVENTD" = yes -o "$CLVMD" != none ] ; then
+-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_lock in -lpthread" >&5
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_lock in -lpthread" >&5
+ $as_echo_n "checking for pthread_mutex_lock in -lpthread... " >&6; }
+ if test "${ac_cv_lib_pthread_pthread_mutex_lock+set}" = set; then :
+   $as_echo_n "(cached) " >&6
+@@ -9711,7 +9728,6 @@ else
+   hard_bailout
+ fi
+ 
+-fi
+ 
+ ################################################################################
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable selinux support" >&5
+@@ -10933,8 +10949,9 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
+ 
+ 
+ 
++
+ ################################################################################
+-ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/default.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability
 _init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
++ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/default.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability
 _init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat at .service scripts/lvm2_monitoring_init_red_hat scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.service scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
+ 
+ cat >confcache <<\_ACEOF
+ # This file is a shell script that caches the results of configure
+@@ -11671,6 +11688,7 @@ do
+     "scripts/lvm2_lvmetad_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_init_red_hat" ;;
+     "scripts/lvm2_lvmetad_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.socket" ;;
+     "scripts/lvm2_lvmetad_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.service" ;;
++    "scripts/lvm2_pvscan_systemd_red_hat at .service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_pvscan_systemd_red_hat at .service" ;;
+     "scripts/lvm2_monitoring_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_init_red_hat" ;;
+     "scripts/dm_event_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.socket" ;;
+     "scripts/dm_event_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/dm_event_systemd_red_hat.service" ;;
+diff --git a/configure.in b/configure.in
+index 611ab37..07b0afc 100644
+--- a/configure.in
++++ b/configure.in
+@@ -940,6 +940,15 @@ if test x$BUILD_LVMETAD = xyes; then
+ fi
+ 
+ ################################################################################
++dnl -- Enable udev-systemd protocol to instantiate a service for background jobs
++AC_MSG_CHECKING(whether to use udev-systemd protocol for jobs in background)
++AC_ARG_ENABLE(udev-systemd-background-jobs,
++	      AC_HELP_STRING([--enable-udev-systemd-background-jobs],
++			     [enable udev-systemd protocol to instantiate a service for background job]),
++	      UDEV_SYSTEMD_BACKGROUND_JOBS=$enableval, UDEV_SYSTEMD_BACKGROUND_JOBS=no)
++AC_MSG_RESULT($UDEV_SYSTEMD_BACKGROUND_JOBS)
++
++################################################################################
+ dnl -- Enable udev synchronisation
+ AC_MSG_CHECKING(whether to enable synchronisation with udev processing)
+ AC_ARG_ENABLE(udev_sync,
+@@ -1181,10 +1190,8 @@ Features cannot be 'shared' when building statically
+ fi
+ 
+ ################################################################################
+-if [[ "$DMEVENTD" = yes -o "$CLVMD" != none ]] ; then
+-	AC_CHECK_LIB([pthread], [pthread_mutex_lock],
+-		[PTHREAD_LIBS="-lpthread"], hard_bailout)
+-fi
++AC_CHECK_LIB([pthread], [pthread_mutex_lock],
++	[PTHREAD_LIBS="-lpthread"], hard_bailout)
+ 
+ ################################################################################
+ dnl -- Disable selinux
+@@ -1628,6 +1635,7 @@ AC_SUBST(UDEV_LIBS)
+ AC_SUBST(UDEV_PC)
+ AC_SUBST(UDEV_RULES)
+ AC_SUBST(UDEV_SYNC)
++AC_SUBST(UDEV_SYSTEMD_BACKGROUND_JOBS)
+ AC_SUBST(UDEV_RULE_EXEC_DETECTION)
+ AC_SUBST(UDEV_HAS_BUILTIN_BLKID)
+ AC_SUBST(CUNIT_LIBS)
+@@ -1702,6 +1710,7 @@ scripts/cmirrord_init_red_hat
+ scripts/lvm2_lvmetad_init_red_hat
+ scripts/lvm2_lvmetad_systemd_red_hat.socket
+ scripts/lvm2_lvmetad_systemd_red_hat.service
++scripts/lvm2_pvscan_systemd_red_hat at .service
+ scripts/lvm2_monitoring_init_red_hat
+ scripts/dm_event_systemd_red_hat.socket
+ scripts/dm_event_systemd_red_hat.service
+diff --git a/daemons/clvmd/clvmd.c b/daemons/clvmd/clvmd.c
+index bed8e68..d57c0fd 100644
+--- a/daemons/clvmd/clvmd.c
++++ b/daemons/clvmd/clvmd.c
+@@ -1124,7 +1124,7 @@ static int verify_message(char *buf, int len)
+ 
+ 	/* TODO: we may be able to narrow len/flags/clientid/arglen checks based on cmd */
+ 
+-	if (h->flags & ~(CLVMD_FLAG_LOCAL | CLVMD_FLAG_SYSTEMLV | CLVMD_FLAG_NODEERRS)) {
++	if (h->flags & ~(CLVMD_FLAG_LOCAL | CLVMD_FLAG_SYSTEMLV | CLVMD_FLAG_NODEERRS | CLVMD_FLAG_REMOTE)) {
+ 		log_error("verify_message bad flags %x", h->flags);
+ 		return -1;
+ 	}
+diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
+index da7d335..b15732f 100644
+--- a/daemons/clvmd/lvm-functions.c
++++ b/daemons/clvmd/lvm-functions.c
+@@ -401,7 +401,7 @@ static int do_activate_lv(char *resource, unsigned char command, unsigned char l
+ 	}
+ 
+ 	/* Now activate it */
+-	if (!lv_activate(cmd, resource, exclusive, NULL))
++	if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
+ 		goto error;
+ 
+ 	return 0;
+diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
+index e1ec5a8..285c8cc 100644
+--- a/daemons/lvmetad/lvmetad-core.c
++++ b/daemons/lvmetad/lvmetad-core.c
+@@ -551,7 +551,7 @@ static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
+ 	return result;
+ }
+ 
+-static int vg_remove_if_missing(lvmetad_state *s, const char *vgid);
++static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
+ 
+ /* You need to be holding the pvid_to_vgid lock already to call this. */
+ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
+@@ -590,7 +590,7 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
+ 	     n = dm_hash_get_next(to_check, n)) {
+ 		check_vgid = dm_hash_get_key(to_check, n);
+ 		lock_vg(s, check_vgid);
+-		vg_remove_if_missing(s, check_vgid);
++		vg_remove_if_missing(s, check_vgid, 0);
+ 		unlock_vg(s, check_vgid);
+ 	}
+ 
+@@ -631,7 +631,7 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
+ }
+ 
+ /* The VG must be locked. */
+-static int vg_remove_if_missing(lvmetad_state *s, const char *vgid)
++static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids)
+ {
+ 	struct dm_config_tree *vg;
+ 	struct dm_config_node *pv;
+@@ -658,7 +658,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid)
+ 
+ 	if (missing) {
+ 		DEBUGLOG(s, "removing empty VG %s", vgid);
+-		remove_metadata(s, vgid, 0);
++		remove_metadata(s, vgid, update_pvids);
+ 	}
+ 
+ 	unlock_pvid_to_pvmeta(s);
+@@ -796,11 +796,24 @@ static response pv_gone(lvmetad_state *s, request r)
+ 
+ 	pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
+ 	pvid_old = dm_hash_lookup_binary(s->device_to_pvid, &device, sizeof(device));
++	char *vgid = dm_hash_lookup(s->pvid_to_vgid, pvid);
++
++	if (vgid && !(vgid = dm_strdup(vgid))) {
++		unlock_pvid_to_pvmeta(s);
++		return reply_fail("out of memory");
++	}
++
+ 	dm_hash_remove_binary(s->device_to_pvid, &device, sizeof(device));
+ 	dm_hash_remove(s->pvid_to_pvmeta, pvid);
+-	vg_remove_if_missing(s, dm_hash_lookup(s->pvid_to_vgid, pvid));
+ 	unlock_pvid_to_pvmeta(s);
+ 
++	if (vgid) {
++		lock_vg(s, vgid);
++		vg_remove_if_missing(s, vgid, 1);
++		unlock_vg(s, vgid);
++		dm_free(vgid);
++	}
++
+ 	if (pvid_old)
+ 		dm_free(pvid_old);
+ 
+@@ -816,8 +829,8 @@ static response pv_clear_all(lvmetad_state *s, request r)
+ 	DEBUGLOG(s, "pv_clear_all");
+ 
+ 	lock_pvid_to_pvmeta(s);
+-	lock_vgid_to_metadata(s);
+ 	lock_pvid_to_vgid(s);
++	lock_vgid_to_metadata(s);
+ 
+ 	destroy_metadata_hashes(s);
+ 	create_metadata_hashes(s);
+diff --git a/lib/activate/activate.c b/lib/activate/activate.c
+index 28549fc..006681e 100644
+--- a/lib/activate/activate.c
++++ b/lib/activate/activate.c
+@@ -251,8 +251,8 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
+ {
+ 	return 0;
+ }
+-int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)),
+-			struct logical_volume *lv, struct lvinfo *info)
++int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
++			struct lvinfo *info)
+ {
+         return 0;
+ }
+@@ -337,12 +337,13 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
+ {
+ 	return 1;
+ }
+-int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv)
++int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, int noscan,
++		int temporary, struct logical_volume *lv)
+ {
+ 	return 1;
+ }
+ int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
+-			    struct logical_volume *lv)
++			    int noscan, int temporary, struct logical_volume *lv)
+ {
+ 	return 1;
+ }
+@@ -675,33 +676,48 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
+ 	return r;
+ }
+ 
+-int lv_check_not_in_use(struct cmd_context *cmd __attribute__((unused)),
+-			struct logical_volume *lv, struct lvinfo *info)
++#define OPEN_COUNT_CHECK_RETRIES 25
++#define OPEN_COUNT_CHECK_USLEEP_DELAY 200000
++
++int lv_check_not_in_use(struct cmd_context *cmd, struct logical_volume *lv,
++			struct lvinfo *info)
+ {
++	unsigned int open_count_check_retries;
++
+ 	if (!info->exists)
+ 		return 1;
+ 
+ 	/* If sysfs is not used, use open_count information only. */
+-	if (!*dm_sysfs_dir()) {
+-		if (info->open_count) {
+-			log_error("Logical volume %s/%s in use.",
++	if (dm_sysfs_dir()) {
++		if (dm_device_has_holders(info->major, info->minor)) {
++			log_error("Logical volume %s/%s is used by another device.",
+ 				  lv->vg->name, lv->name);
+ 			return 0;
+ 		}
+ 
+-		return 1;
+-	}
+-
+-	if (dm_device_has_holders(info->major, info->minor)) {
+-		log_error("Logical volume %s/%s is used by another device.",
+-			  lv->vg->name, lv->name);
+-		return 0;
++		if (dm_device_has_mounted_fs(info->major, info->minor)) {
++			log_error("Logical volume %s/%s contains a filesystem in use.",
++				  lv->vg->name, lv->name);
++			return 0;
++		}
+ 	}
+ 
+-	if (dm_device_has_mounted_fs(info->major, info->minor)) {
+-		log_error("Logical volume %s/%s contains a filesystem in use.",
+-			  lv->vg->name, lv->name);
+-		return 0;
++	open_count_check_retries = retry_deactivation() ? OPEN_COUNT_CHECK_RETRIES : 1;
++	while (open_count_check_retries--) {
++		if (info->open_count > 0) {
++			if (open_count_check_retries) {
++				usleep(OPEN_COUNT_CHECK_USLEEP_DELAY);
++				log_debug_activation("Retrying open_count check for %s/%s.",
++						     lv->vg->name, lv->name);
++				if (!lv_info(cmd, lv, 0, info, 1, 0))
++					return -1;
++				continue;
++			}
++			log_error("Logical volume %s/%s in use.",
++				  lv->vg->name, lv->name);
++			return 0;
++		} else
++			break;
+ 	}
+ 
+ 	return 1;
+@@ -887,6 +903,18 @@ int lv_raid_message(const struct logical_volume *lv, const char *msg)
+ 	struct dm_status_raid *status;
+ 
+ 	if (!seg_is_raid(first_seg(lv))) {
++		/*
++		 * Make it easier for user to know what to do when
++		 * they are using thinpool.
++		 */
++		if (lv_is_thin_pool(lv) &&
++		    (lv_is_raid(seg_lv(first_seg(lv), 0)) ||
++		     lv_is_raid(first_seg(lv)->metadata_lv))) {
++			log_error("Thinpool data or metadata volume"
++				  " must be specified. (e.g. \"%s/%s_tdata\")",
++				  lv->vg->name, lv->name);
++			return 0;
++		}
+ 		log_error("%s/%s must be a RAID logical volume to"
+ 			  " perform this action.", lv->vg->name, lv->name);
+ 		return 0;
+@@ -1928,7 +1956,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_vo
+ 		goto out;
+ 	}
+ 
+-	if (lv_is_visible(lv)) {
++	if (lv_is_visible(lv) || lv_is_virtual_origin(lv)) {
+ 		if (!lv_check_not_in_use(cmd, lv, &info))
+ 			goto_out;
+ 
+@@ -2027,9 +2055,11 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
+ 	if (filter)
+ 		laopts->read_only = _passes_readonly_filter(cmd, lv);
+ 
+-	log_debug_activation("Activating %s/%s%s%s.", lv->vg->name, lv->name,
++	log_debug_activation("Activating %s/%s%s%s%s%s.", lv->vg->name, lv->name,
+ 			     laopts->exclusive ? " exclusively" : "",
+-			     laopts->read_only ? " read-only" : "");
++			     laopts->read_only ? " read-only" : "",
++			     laopts->noscan ? " noscan" : "",
++			     laopts->temporary ? " temporary" : "");
+ 
+ 	if (!lv_info(cmd, lv, 0, &info, 0, 0))
+ 		goto_out;
+@@ -2066,9 +2096,12 @@ out:
+ }
+ 
+ /* Activate LV */
+-int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv)
++int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
++		int noscan, int temporary, struct logical_volume *lv)
+ {
+-	struct lv_activate_opts laopts = { .exclusive = exclusive };
++	struct lv_activate_opts laopts = { .exclusive = exclusive,
++					   .noscan = noscan,
++					   .temporary = temporary };
+ 
+ 	if (!_lv_activate(cmd, lvid_s, &laopts, 0, lv))
+ 		return_0;
+@@ -2077,9 +2110,12 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, stru
+ }
+ 
+ /* Activate LV only if it passes filter */
+-int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv)
++int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
++			    int noscan, int temporary, struct logical_volume *lv)
+ {
+-	struct lv_activate_opts laopts = { .exclusive = exclusive };
++	struct lv_activate_opts laopts = { .exclusive = exclusive,
++					   .noscan = noscan,
++					   .temporary = temporary };
+ 
+ 	if (!_lv_activate(cmd, lvid_s, &laopts, 1, lv))
+ 		return_0;
+diff --git a/lib/activate/activate.h b/lib/activate/activate.h
+index f34d376..df888cd 100644
+--- a/lib/activate/activate.h
++++ b/lib/activate/activate.h
+@@ -38,6 +38,18 @@ struct lv_activate_opts {
+ 	int skip_in_use;
+ 	unsigned revert;
+ 	unsigned read_only;
++	unsigned noscan;	/* Mark this LV to avoid its scanning. This also
++				   directs udev to use proper udev flag to avoid
++				   any scanning in udev. This udev flag is automatically
++				   dropped in udev db on any spurious event that follows. */
++	unsigned temporary;	/* Mark this LV as temporary. It means, the LV
++				 * is created, used and deactivated within single
++				 * LVM command execution. Such LVs are mostly helper
++				 * LVs to do some action or cleanup before the proper
++				 * LV is created. This also directs udev to use proper
++				 * set of flags to avoid any scanning in udev. These udev
++				 * flags are persistent in udev db for any spurious event
++				 * that follows. */
+ };
+ 
+ /* target attribute flags */
+@@ -80,9 +92,10 @@ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned o
+ int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only, struct logical_volume *lv);
+ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s,
+ 			unsigned origin_only, unsigned exclusive, unsigned revert, struct logical_volume *lv);
+-int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive, struct logical_volume *lv);
+-int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s,
+-			    int exclusive, struct logical_volume *lv);
++int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive,
++		int noscan, int temporary, struct logical_volume *lv);
++int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive,
++			    int noscan, int temporary, struct logical_volume *lv);
+ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, struct logical_volume *lv);
+ 
+ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
+diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
+index b8233bf..0b911f2 100644
+--- a/lib/activate/dev_manager.c
++++ b/lib/activate/dev_manager.c
+@@ -30,6 +30,7 @@
+ #include <dirent.h>
+ 
+ #define MAX_TARGET_PARAMSIZE 50000
++#define LVM_UDEV_NOSCAN_FLAG DM_SUBSYSTEM_UDEV_FLAG0
+ 
+ typedef enum {
+ 	PRELOAD,
+@@ -1399,7 +1400,7 @@ static int _check_udev_fallback(struct cmd_context *cmd)
+ #endif /* UDEV_SYNC_SUPPORT */
+ 
+ static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *lv,
+-				const char *layer)
++				const char *layer, int noscan, int temporary)
+ {
+ 	uint16_t udev_flags = 0;
+ 
+@@ -1447,6 +1448,16 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, struct logical_volume *l
+ 		udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
+ 			      DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
+ 
++	/*
++	 * LVM subsystem specific flags.
++	 */
++	if (noscan)
++		udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0;
++
++	if (temporary)
++		udev_flags |= DM_UDEV_DISABLE_DISK_RULES_FLAG |
++			      DM_UDEV_DISABLE_OTHER_RULES_FLAG;
++
+ 	return udev_flags;
+ }
+ 
+@@ -1493,7 +1504,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
+ 	}
+ 
+ 	if (info.exists && !dm_tree_add_dev_with_udev_flags(dtree, info.major, info.minor,
+-							_get_udev_flags(dm, lv, layer))) {
++							_get_udev_flags(dm, lv, layer, 0, 0))) {
+ 		log_error("Failed to add device (%" PRIu32 ":%" PRIu32") to dtree",
+ 			  info.major, info.minor);
+ 		return 0;
+@@ -2334,7 +2345,7 @@ static int _set_udev_flags_for_children(struct dev_manager *dm,
+ 		}
+ 
+ 		dm_tree_node_set_udev_flags(child,
+-					    _get_udev_flags(dm, lvl->lv, NULL));
++					    _get_udev_flags(dm, lvl->lv, NULL, 0, 0));
+ 	}
+ 
+ 	return 1;
+@@ -2411,7 +2422,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
+ 					     read_only_lv(lv, laopts),
+ 					     ((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
+ 					     lvlayer,
+-					     _get_udev_flags(dm, lv, layer))))
++					     _get_udev_flags(dm, lv, layer, laopts->noscan, laopts->temporary))))
+ 		return_0;
+ 
+ 	/* Store existing name so we can do rename later */
+diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
+index f43283f..8940704 100644
+--- a/lib/cache/lvmetad.c
++++ b/lib/cache/lvmetad.c
+@@ -392,8 +392,6 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
+ 				pvl->pv->dev = lvmcache_device(info);
+ 				if (!pvl->pv->dev)
+ 					pvl->pv->status |= MISSING_PV;
+-				else
+-					check_reappeared_pv(vg, pvl->pv);
+ 				if (!lvmcache_fid_add_mdas_pv(info, fid)) {
+ 					vg = NULL;
+ 					goto_out;	/* FIXME error path */
+diff --git a/lib/device/device-types.h b/lib/device/device-types.h
+index d25c2f0..d716878 100644
+--- a/lib/device/device-types.h
++++ b/lib/device/device-types.h
+@@ -61,5 +61,6 @@ static const dev_known_type_t _dev_known_types[] = {
+ 	{"skd", 16, "STEC"},
+ 	{"scm", 8, "Storage Class Memory (IBM S/390)"},
+ 	{"bcache", 1, "bcache block device cache"},
++	{"nvme", 64, "NVM Express"},
+ 	{"", 0, ""}
+ };
+diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
+index 5077576..e31429e 100644
+--- a/lib/format_text/flags.c
++++ b/lib/format_text/flags.c
+@@ -61,6 +61,8 @@ static const struct flag _lv_flags[] = {
+ 	{LV_REBUILD, "REBUILD", STATUS_FLAG},
+ 	{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
+ 	{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
++	{LV_NOSCAN, NULL, 0},
++	{LV_TEMPORARY, NULL, 0},
+ 	{POOL_METADATA_SPARE, NULL, 0},
+ 	{RAID, NULL, 0},
+ 	{RAID_META, NULL, 0},
+@@ -144,8 +146,8 @@ int print_flags(uint64_t status, int type, char *buffer, size_t size)
+ 		return 0;
+ 
+ 	if (status)
+-		log_warn("Metadata inconsistency: Not all flags successfully "
+-			 "exported.");
++		log_warn(INTERNAL_ERROR "Metadata inconsistency: "
++			 "Not all flags successfully exported.");
+ 
+ 	return 1;
+ }
+diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c
+index 5e49bc4..ab3dabd 100644
+--- a/lib/locking/file_locking.c
++++ b/lib/locking/file_locking.c
+@@ -305,7 +305,8 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
+ 			break;
+ 		case LCK_READ:
+ 			log_very_verbose("Locking LV %s (R)", resource);
+-			if (!lv_activate_with_filter(cmd, resource, 0, lv_ondisk(lv)))
++			if (!lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0,
++						     lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv)))
+ 				return 0;
+ 			break;
+ 		case LCK_PREAD:
+@@ -318,7 +319,8 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
+ 			break;
+ 		case LCK_EXCL:
+ 			log_very_verbose("Locking LV %s (EX)", resource);
+-			if (!lv_activate_with_filter(cmd, resource, 1, lv_ondisk(lv)))
++			if (!lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0,
++						     lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv)))
+ 				return 0;
+ 			break;
+ 		default:
+diff --git a/lib/locking/no_locking.c b/lib/locking/no_locking.c
+index 5f3f0b6..dac2f80 100644
+--- a/lib/locking/no_locking.c
++++ b/lib/locking/no_locking.c
+@@ -48,11 +48,13 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
+ 		case LCK_UNLOCK:
+ 			return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0, (flags & LCK_REVERT) ? 1 : 0, lv_ondisk(lv));
+ 		case LCK_READ:
+-			return lv_activate_with_filter(cmd, resource, 0, lv_ondisk(lv));
++			return lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0,
++						       lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv));
+ 		case LCK_WRITE:
+ 			return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0, 0, lv_ondisk(lv), lv);
+ 		case LCK_EXCL:
+-			return lv_activate_with_filter(cmd, resource, 1, lv_ondisk(lv));
++			return lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0,
++						       lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv));
+ 		default:
+ 			break;
+ 		}
+diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
+index e3fda18..e59bd8e 100644
+--- a/lib/metadata/lv.c
++++ b/lib/metadata/lv.c
+@@ -565,7 +565,13 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
+ 	else if (lv->status & MIRROR_IMAGE)
+ 		repstr[0] = (_lv_mimage_in_sync(lv)) ? 'i' : 'I';
+ 	else if (lv->status & RAID_IMAGE)
+-		repstr[0] = (_lv_raid_image_in_sync(lv)) ? 'i' : 'I';
++		/*
++		 * Visible RAID_IMAGES are sub-LVs that have been exposed for
++		 * top-level use by being split from the RAID array with
++		 * '--splitmirrors 1 --trackchanges'.  They always report 'I'.
++		 */
++		repstr[0] = (!lv_is_visible(lv) && _lv_raid_image_in_sync(lv)) ?
++			'i' : 'I';
+ 	else if (lv->status & MIRROR_LOG)
+ 		repstr[0] = 'l';
+ 	else if (lv_is_cow(lv))
+diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
+index f42db1d..88fceb2 100644
+--- a/lib/metadata/lv_manip.c
++++ b/lib/metadata/lv_manip.c
+@@ -89,7 +89,7 @@ static int _lv_is_on_pv(struct cmd_context *cmd,
+ 	struct physical_volume *pv2;
+ 	struct lv_segment *seg;
+ 
+-	if (!lv || !(seg = first_seg(lv)))
++	if (!lv || !(first_seg(lv)))
+ 		return_0;
+ 
+ 	/*
+@@ -4685,6 +4685,7 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
+ 	struct dm_list *snh, *snht;
+ 	struct lv_list *lvl;
+ 	struct lvinfo info;
++	struct logical_volume *origin;
+ 	int is_last_pool;
+ 
+ 	if (lv_is_cow(lv)) {
+@@ -4713,7 +4714,10 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
+ 					return 0;
+ 				}
+ 			}
+-		}
++		} else if (!level && lv_is_virtual_origin(origin = origin_from_cow(lv)))
++			/* If this is a sparse device, remove its origin too. */
++			/* Stacking is not supported */
++			lv = origin;
+ 	}
+ 
+ 	if (lv_is_origin(lv)) {
+@@ -5421,6 +5425,8 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
+ 	if (!dev_close_immediate(dev))
+ 		stack;
+ 
++	lv->status &= ~LV_NOSCAN;
++
+ 	return 1;
+ }
+ 
+@@ -5977,6 +5983,13 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
+ 		goto out;
+ 	}
+ 
++	/* Do not scan this LV until properly zeroed. */
++	if (lp->zero)
++		lv->status |= LV_NOSCAN;
++
++	if (lp->temporary)
++		lv->status |= LV_TEMPORARY;
++
+ 	if (lv_is_thin_pool(lv)) {
+ 		if (is_change_activating(lp->activate)) {
+ 			if (vg_is_clustered(lv->vg)) {
+diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
+index 308dcfe..c00e4e5 100644
+--- a/lib/metadata/metadata-exported.h
++++ b/lib/metadata/metadata-exported.h
+@@ -102,6 +102,12 @@
+ #define LV_WRITEMOSTLY		UINT64_C(0x0000020000000000)	/* LV (RAID1) */
+ 
+ #define LV_ACTIVATION_SKIP	UINT64_C(0x0000040000000000)	/* LV */
++#define LV_NOSCAN		UINT64_C(0x0000080000000000)	/* LV - internal use only - the LV
++									should not be scanned */
++#define LV_TEMPORARY		UINT64_C(0x0000100000000000)	/* LV - internal use only - the LV
++								        is supposed to be created and
++									removed during single LVM
++									command execution. */
+ 
+ /* Format features flags */
+ #define FMT_SEGMENTS		0x00000001U	/* Arbitrary segment params? */
+@@ -720,6 +726,7 @@ struct lvcreate_params {
+ 	int log_count; /* mirror */
+ 	int nosync; /* mirror */
+ 	int poolmetadataspare; /* thin pool */
++	int temporary; /* temporary LV */
+ #define ACTIVATION_SKIP_SET		0x01 /* request to set LV activation skip flag state */
+ #define ACTIVATION_SKIP_SET_ENABLED	0x02 /* set the LV activation skip flag state to 'enabled' */
+ #define ACTIVATION_SKIP_IGNORE		0x04 /* request to ignore LV activation skip flag (if any) */
+diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
+index 4ffd502..8571e0a 100644
+--- a/lib/metadata/metadata.c
++++ b/lib/metadata/metadata.c
+@@ -2883,10 +2883,11 @@ int vg_missing_pv_count(const struct volume_group *vg)
+ 	return ret;
+ }
+ 
+-void check_reappeared_pv(struct volume_group *correct_vg,
+-			 struct physical_volume *pv)
++static int _check_reappeared_pv(struct volume_group *correct_vg,
++				struct physical_volume *pv, int act)
+ {
+ 	struct pv_list *pvl;
++	int rv = 0;
+ 
+         /*
+          * Skip these checks in case the tool is going to deal with missing
+@@ -2894,21 +2895,47 @@ void check_reappeared_pv(struct volume_group *correct_vg,
+          * confusing.
+          */
+         if (correct_vg->cmd->handles_missing_pvs)
+-            return;
++            return rv;
+ 
+ 	dm_list_iterate_items(pvl, &correct_vg->pvs)
+ 		if (pv->dev == pvl->pv->dev && is_missing_pv(pvl->pv)) {
+-			log_warn("Missing device %s reappeared, updating "
+-				 "metadata for VG %s to version %u.",
+-				 pv_dev_name(pvl->pv),  pv_vg_name(pvl->pv), 
+-				 correct_vg->seqno);
++			if (act)
++				log_warn("Missing device %s reappeared, updating "
++					 "metadata for VG %s to version %u.",
++					 pv_dev_name(pvl->pv),  pv_vg_name(pvl->pv), 
++					 correct_vg->seqno);
+ 			if (pvl->pv->pe_alloc_count == 0) {
+-				pv->status &= ~MISSING_PV;
+-				pvl->pv->status &= ~MISSING_PV;
+-			} else
++				if (act) {
++					pv->status &= ~MISSING_PV;
++					pvl->pv->status &= ~MISSING_PV;
++				}
++				++ rv;
++			} else if (act)
+ 				log_warn("Device still marked missing because of allocated data "
+ 					 "on it, remove volumes and consider vgreduce --removemissing.");
+ 		}
++	return rv;
++}
++
++static int _repair_inconsistent_vg(struct volume_group *vg)
++{
++	unsigned saved_handles_missing_pvs = vg->cmd->handles_missing_pvs;
++
++	vg->cmd->handles_missing_pvs = 1;
++	if (!vg_write(vg)) {
++		log_error("Automatic metadata correction failed");
++		vg->cmd->handles_missing_pvs = saved_handles_missing_pvs;
++		return 0;
++	}
++
++	vg->cmd->handles_missing_pvs = saved_handles_missing_pvs;
++
++	if (!vg_commit(vg)) {
++		log_error("Automatic metadata correction commit failed");
++		return 0;
++	}
++
++	return 1;
+ }
+ 
+ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
+@@ -2951,12 +2978,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
+ 	int inconsistent_mdas = 0;
+ 	int inconsistent_mda_count = 0;
+ 	unsigned use_precommitted = precommitted;
+-	unsigned saved_handles_missing_pvs = cmd->handles_missing_pvs;
+ 	struct dm_list *pvids;
+ 	struct pv_list *pvl, *pvl2;
+ 	struct dm_list all_pvs;
+ 	char uuid[64] __attribute__((aligned(8)));
+ 	unsigned seqno = 0;
++	int reappeared = 0;
+ 
+ 	if (is_orphan_vg(vgname)) {
+ 		if (use_precommitted) {
+@@ -2969,8 +2996,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
+ 	}
+ 
+ 	if (lvmetad_active() && !use_precommitted) {
+-		*consistent = 1;
+-		return lvmcache_get_vg(cmd, vgname, vgid, 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);
++			if (reappeared && *consistent)
++				*consistent = _repair_inconsistent_vg(correct_vg);
++			else
++				*consistent = !reappeared;
++		}
++		return correct_vg;
+ 	}
+ 
+ 	/*
+@@ -3339,22 +3374,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
+ 		 * update metadata and remove MISSING flag
+ 		 */
+ 		dm_list_iterate_items(pvl, &all_pvs)
+-			check_reappeared_pv(correct_vg, pvl->pv);
++			_check_reappeared_pv(correct_vg, pvl->pv, 1);
+ 
+-		cmd->handles_missing_pvs = 1;
+-		if (!vg_write(correct_vg)) {
+-			log_error("Automatic metadata correction failed");
++		if (!_repair_inconsistent_vg(correct_vg)) {
+ 			_free_pv_list(&all_pvs);
+ 			release_vg(correct_vg);
+-			cmd->handles_missing_pvs = saved_handles_missing_pvs;
+-			return NULL;
+-		}
+-		cmd->handles_missing_pvs = saved_handles_missing_pvs;
+-
+-		if (!vg_commit(correct_vg)) {
+-			log_error("Automatic metadata correction commit "
+-				  "failed");
+-			release_vg(correct_vg);
+ 			return NULL;
+ 		}
+ 
+diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
+index 2408c23..21ac204 100644
+--- a/lib/metadata/metadata.h
++++ b/lib/metadata/metadata.h
+@@ -486,7 +486,4 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
+ uint64_t find_min_mda_size(struct dm_list *mdas);
+ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tags);
+ 
+-void check_reappeared_pv(struct volume_group *correct_vg,
+-			 struct physical_volume *pv);
+-
+ #endif
+diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
+index 325a4e8..fc1273e 100644
+--- a/lib/metadata/snapshot_manip.c
++++ b/lib/metadata/snapshot_manip.c
+@@ -227,6 +227,16 @@ int vg_remove_snapshot(struct logical_volume *cow)
+ 	struct logical_volume *origin = origin_from_cow(cow);
+ 	int is_origin_active = lv_is_active(origin);
+ 
++	if (is_origin_active &&
++	    lv_is_virtual_origin(origin)) {
++		if (!deactivate_lv(origin->vg->cmd, origin)) {
++			log_error("Failed to deactivate logical volume \"%s\"",
++				  origin->name);
++			return 0;
++		}
++		is_origin_active = 0;
++	}
++
+ 	dm_list_del(&cow->snapshot->origin_list);
+ 	origin->origin_count--;
+ 
+diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
+index a6e0fc2..bd5b117 100644
+--- a/lib/metadata/thin_manip.c
++++ b/lib/metadata/thin_manip.c
+@@ -809,6 +809,7 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
+ 		.stripes = 1,
+ 		.vg_name = vg->name,
+ 		.zero = 1,
++		.temporary = 1,
+ 	};
+ 
+ 	dm_list_init(&lp.tags);
+diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c
+index 506d618..91e778f 100644
+--- a/lib/snapshot/snapshot.c
++++ b/lib/snapshot/snapshot.c
+@@ -23,6 +23,10 @@
+ #include "str_list.h"
+ #include "defaults.h"
+ 
++#define SEG_LOG_ERROR(t, p...) \
++	log_error(t " segment %s of logical volume %s.", ## p, \
++		  dm_config_parent_name(sn), seg->lv->name), 0;
++
+ static const char *_snap_name(const struct lv_segment *seg)
+ {
+ 	return seg->segtype->name;
+@@ -41,50 +45,45 @@ static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node
+ 			struct dm_hash_table *pv_hash __attribute__((unused)))
+ {
+ 	uint32_t chunk_size;
+-	const char *org_name, *cow_name;
+ 	struct logical_volume *org, *cow;
+-	int old_suppress, merge = 0;
++	const char *org_name = NULL, *cow_name = NULL;
++	int merge = 0;
+ 
+ 	if (!dm_config_get_uint32(sn, "chunk_size", &chunk_size)) {
+ 		log_error("Couldn't read chunk size for snapshot.");
+ 		return 0;
+ 	}
+ 
+-	old_suppress = log_suppress(1);
+-
+-	if ((cow_name = dm_config_find_str(sn, "merging_store", NULL))) {
+-		if (dm_config_find_str(sn, "cow_store", NULL)) {
+-			log_suppress(old_suppress);
+-			log_error("Both snapshot cow and merging storage were specified.");
+-			return 0;
+-		}
++	if (dm_config_has_node(sn, "merging_store")) {
++		if (!(cow_name = dm_config_find_str(sn, "merging_store", NULL)))
++			return SEG_LOG_ERROR("Merging store must be a string in");
+ 		merge = 1;
+ 	}
+-	else if (!(cow_name = dm_config_find_str(sn, "cow_store", NULL))) {
+-		log_suppress(old_suppress);
+-		log_error("Snapshot cow storage not specified.");
+-		return 0;
+-	}
+ 
+-	if (!(org_name = dm_config_find_str(sn, "origin", NULL))) {
+-		log_suppress(old_suppress);
+-		log_error("Snapshot origin not specified.");
+-		return 0;
++	if (dm_config_has_node(sn, "cow_store")) {
++		if (cow_name)
++			return SEG_LOG_ERROR("Both snapshot cow and merging storage were specified in");
++
++		if (!(cow_name = dm_config_find_str(sn, "cow_store", NULL)))
++			return SEG_LOG_ERROR("Cow store must be a string in");
+ 	}
+ 
+-	log_suppress(old_suppress);
++	if (!cow_name)
++		return SEG_LOG_ERROR("Snapshot cow storage not specified in");
+ 
+-	if (!(cow = find_lv(seg->lv->vg, cow_name))) {
+-		log_error("Unknown logical volume specified for "
+-			  "snapshot cow store.");
+-		return 0;
+-	}
++	if (!dm_config_has_node(sn, "origin"))
++		return SEG_LOG_ERROR("Snapshot origin not specified in");
+ 
+-	if (!(org = find_lv(seg->lv->vg, org_name))) {
+-		log_error("Unknown logical volume specified for "
+-			  "snapshot origin.");
+-		return 0;
+-	}
++	if (!(org_name = dm_config_find_str(sn, "origin", NULL)))
++		return SEG_LOG_ERROR("Snapshot origin must be a string in");
++
++	if (!(cow = find_lv(seg->lv->vg, cow_name)))
++		return SEG_LOG_ERROR("Unknown logical volume %s specified for "
++				     "snapshot cow store in", cow_name);
++
++	if (!(org = find_lv(seg->lv->vg, org_name)))
++		return SEG_LOG_ERROR("Unknown logical volume %s specified for "
++			  "snapshot origin in", org_name);
+ 
+ 	init_snapshot_seg(seg, org, cow, chunk_size, merge);
+ 
+diff --git a/libdaemon/client/daemon-io.c b/libdaemon/client/daemon-io.c
+index 906f375..e2c5180 100644
+--- a/libdaemon/client/daemon-io.c
++++ b/libdaemon/client/daemon-io.c
+@@ -38,7 +38,7 @@ int buffer_read(int fd, struct buffer *buffer) {
+ 		result = read(fd, buffer->mem + buffer->used, buffer->allocated - buffer->used);
+ 		if (result > 0) {
+ 			buffer->used += result;
+-			if (!strncmp((buffer->mem) + buffer->used - 4, "\n##\n", 4)) {
++			if (buffer->used >= 4 && !strncmp((buffer->mem) + buffer->used - 4, "\n##\n", 4)) {
+ 				buffer->used -= 4;
+ 				buffer->mem[buffer->used] = 0;
+ 				break; /* success, we have the full message now */
+diff --git a/libdaemon/server/daemon-server.c b/libdaemon/server/daemon-server.c
+index df2c852..b114b9f 100644
+--- a/libdaemon/server/daemon-server.c
++++ b/libdaemon/server/daemon-server.c
+@@ -381,6 +381,7 @@ static void *client_thread(void *baton)
+ 	request req;
+ 	response res;
+ 
++	b->client.thread_id = pthread_self();
+ 	buffer_init(&req.buffer);
+ 
+ 	while (1) {
+@@ -431,6 +432,7 @@ static int handle_connect(daemon_state s)
+ 	struct sockaddr_un sockaddr;
+ 	client_handle client = { .thread_id = 0 };
+ 	socklen_t sl = sizeof(sockaddr);
++	pthread_t tid;
+ 
+ 	client.socket_fd = accept(s.socket_fd, (struct sockaddr *) &sockaddr, &sl);
+ 	if (client.socket_fd < 0)
+@@ -446,10 +448,10 @@ static int handle_connect(daemon_state s)
+ 	baton->s = s;
+ 	baton->client = client;
+ 
+-	if (pthread_create(&baton->client.thread_id, NULL, client_thread, baton))
++	if (pthread_create(&tid, NULL, client_thread, baton))
+ 		return 0;
+ 
+-	pthread_detach(baton->client.thread_id);
++	pthread_detach(tid);
+ 
+ 	return 1;
+ }
+diff --git a/libdm/Makefile.in b/libdm/Makefile.in
+index bddb0a0..2aa70d4 100644
+--- a/libdm/Makefile.in
++++ b/libdm/Makefile.in
+@@ -57,7 +57,7 @@ include $(top_builddir)/make.tmpl
+ DEFS += -DDM_DEVICE_UID=@DM_DEVICE_UID@ -DDM_DEVICE_GID=@DM_DEVICE_GID@ \
+ 	-DDM_DEVICE_MODE=@DM_DEVICE_MODE@
+ 
+-LIBS += $(SELINUX_LIBS) $(UDEV_LIBS)
++LIBS += $(SELINUX_LIBS) $(UDEV_LIBS) $(PTHREAD_LIBS)
+ 
+ device-mapper: all
+ 
+diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
+index aaf00b2..adfbb76 100644
+--- a/libdm/libdevmapper.h
++++ b/libdm/libdevmapper.h
+@@ -21,7 +21,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ 
+-#ifdef linux
++#ifdef __linux__
+ #  include <linux/types.h>
+ #endif
+ 
+diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c
+index b66911c..9a52f2e 100644
+--- a/libdm/libdm-common.c
++++ b/libdm/libdm-common.c
+@@ -966,7 +966,9 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
+ 
+ 	(void) dm_prepare_selinux_context(path, S_IFBLK);
+ 	old_mask = umask(0);
+-	if (mknod(path, S_IFBLK | mode, dev) < 0) {
++
++	/* The node may already have been created by udev. So ignore EEXIST. */
++	if (mknod(path, S_IFBLK | mode, dev) < 0 && errno != EEXIST) {
+ 		log_error("%s: mknod for %s failed: %s", path, dev_name, strerror(errno));
+ 		umask(old_mask);
+ 		(void) dm_prepare_selinux_context(NULL, 0);
+@@ -998,7 +1000,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
+ 		log_warn("Node %s was not removed by udev. "
+ 			 "Falling back to direct node removal.", path);
+ 
+-	if (unlink(path) < 0) {
++	/* udev may already have deleted the node. Ignore ENOENT. */
++	if (unlink(path) < 0 && errno != ENOENT) {
+ 		log_error("Unable to unlink device node for '%s'", dev_name);
+ 		return 0;
+ 	}
+@@ -1054,7 +1057,8 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
+ 			 "Falling back to direct node rename.",
+ 			 oldpath, newpath);
+ 
+-	if (rename(oldpath, newpath) < 0) {
++	/* udev may already have renamed the node. Ignore ENOENT. */
++	if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
+ 		log_error("Unable to rename device node from '%s' to '%s'",
+ 			  old_name, new_name);
+ 		return 0;
+@@ -1795,7 +1799,8 @@ int dm_device_has_holders(uint32_t major, uint32_t minor)
+ 	}
+ 
+ 	if (stat(sysfs_path, &st)) {
+-		log_sys_error("stat", sysfs_path);
++		if (errno != ENOENT)
++			log_sys_error("stat", sysfs_path);
+ 		return 0;
+ 	}
+ 
+diff --git a/libdm/mm/pool-fast.c b/libdm/mm/pool-fast.c
+index 2b494d6..edb31a0 100644
+--- a/libdm/mm/pool-fast.c
++++ b/libdm/mm/pool-fast.c
+@@ -62,7 +62,9 @@ struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
+ 	while (new_size < p->chunk_size)
+ 		new_size <<= 1;
+ 	p->chunk_size = new_size;
++	pthread_mutex_lock(&_dm_pools_mutex);
+ 	dm_list_add(&_dm_pools, &p->list);
++	pthread_mutex_unlock(&_dm_pools_mutex);
+ 	return p;
+ }
+ 
+@@ -77,7 +79,9 @@ void dm_pool_destroy(struct dm_pool *p)
+ 		c = pr;
+ 	}
+ 
++	pthread_mutex_lock(&_dm_pools_mutex);
+ 	dm_list_del(&p->list);
++	pthread_mutex_unlock(&_dm_pools_mutex);
+ 	dm_free(p);
+ }
+ 
+diff --git a/libdm/mm/pool.c b/libdm/mm/pool.c
+index fd08307..ef006a4 100644
+--- a/libdm/mm/pool.c
++++ b/libdm/mm/pool.c
+@@ -15,9 +15,10 @@
+ 
+ #include "dmlib.h"
+ #include <sys/mman.h>
++#include <pthread.h>
+ 
+-/* FIXME: thread unsafe */
+ static DM_LIST_INIT(_dm_pools);
++static pthread_mutex_t _dm_pools_mutex = PTHREAD_MUTEX_INITIALIZER;
+ void dm_pools_check_leaks(void);
+ 
+ #ifdef DEBUG_ENFORCE_POOL_LOCKING
+@@ -81,8 +82,11 @@ void dm_pools_check_leaks(void)
+ {
+ 	struct dm_pool *p;
+ 
+-	if (dm_list_empty(&_dm_pools))
++	pthread_mutex_lock(&_dm_pools_mutex);
++	if (dm_list_empty(&_dm_pools)) {
++		pthread_mutex_unlock(&_dm_pools_mutex);
+ 		return;
++	}
+ 
+ 	log_error("You have a memory leak (not released memory pool):");
+ 	dm_list_iterate_items(p, &_dm_pools) {
+@@ -94,6 +98,7 @@ void dm_pools_check_leaks(void)
+ 		log_error(" [%p] %s", p, p->name);
+ #endif
+ 	}
++	pthread_mutex_unlock(&_dm_pools_mutex);
+ 	log_error(INTERNAL_ERROR "Unreleased memory pool(s) found.");
+ }
+ 
+diff --git a/man/pvscan.8.in b/man/pvscan.8.in
+index 211c82b..37ecaaf 100644
+--- a/man/pvscan.8.in
++++ b/man/pvscan.8.in
+@@ -25,7 +25,9 @@ pvscan \- scan all disks for physical volumes
+ .B \-\-minor
+ .I minor
+ |
+-.IR DevicePath ]...
++.IR DevicePath
++|
++.IR major:minor ]...
+ .SH DESCRIPTION
+ pvscan scans all supported LVM block devices in the system for
+ physical volumes.
+diff --git a/scripts/Makefile.in b/scripts/Makefile.in
+index a658903..3616afa 100644
+--- a/scripts/Makefile.in
++++ b/scripts/Makefile.in
+@@ -107,6 +107,7 @@ endif
+ ifeq ("@BUILD_LVMETAD@", "yes")
+ 	$(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.socket $(systemd_unit_dir)/lvm2-lvmetad.socket
+ 	$(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.service $(systemd_unit_dir)/lvm2-lvmetad.service
++	$(INSTALL_DATA) lvm2_pvscan_systemd_red_hat at .service $(systemd_unit_dir)/lvm2-pvscan at .service
+ endif
+ 
+ install_tmpfiles_configuration:
+@@ -118,6 +119,7 @@ DISTCLEAN_TARGETS += clvmd_init_red_hat cmirrord_init_red_hat \
+ 		     dm_event_systemd_red_hat.socket dm_event_systemd_red_hat.service \
+ 		     lvm2_monitoring_systemd_red_hat.service \
+ 		     lvm2_lvmetad_systemd_red_hat.socket lvm2_lvmetad_systemd_red_hat.service \
++		     lvm2_pvscan_systemd_red_hat at .service \
+ 		     lvm2_tmpfiles_red_hat.conf blk_availability_init_red_hat \
+ 		     blk_availability_systemd_red_hat.service \
+ 		     blkdeactivate.sh
+diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
+index b6d0117..f454154 100644
+--- a/scripts/blkdeactivate.sh.in
++++ b/scripts/blkdeactivate.sh.in
+@@ -323,7 +323,10 @@ deactivate_all() {
+ 				$LSBLK_READ <<< "`$LSBLK --nodeps $1`"
+ 
+ 				# check if the device is not on the skip list already
+-				test -z ${SKIP_DEVICE_LIST["$kname"]} || continue
++				test -z ${SKIP_DEVICE_LIST["$kname"]} || {
++					shift
++					continue
++				}
+ 
+ 				deactivate
+ 			else
+diff --git a/scripts/lvm2_pvscan_systemd_red_hat at .service.in b/scripts/lvm2_pvscan_systemd_red_hat at .service.in
+new file mode 100644
+index 0000000..4225982
+--- /dev/null
++++ b/scripts/lvm2_pvscan_systemd_red_hat at .service.in
+@@ -0,0 +1,14 @@
++[Unit]
++Description=LVM2 PV scan on device %i
++Documentation=man:pvscan(8)
++DefaultDependencies=no
++BindsTo=dev-block-%i.device
++After=lvm2-lvmetad.socket
++Before=shutdown.target
++Conflicts=shutdown.target
++
++[Service]
++Type=oneshot
++RemainAfterExit=yes
++ExecStart=@sbindir@/pvscan --cache --activate ay /dev/block/%i
++ExecStop=@sbindir@/pvscan --cache %i
+diff --git a/scripts/vgimportclone.sh b/scripts/vgimportclone.sh
+index d6ad75d..7087557 100755
+--- a/scripts/vgimportclone.sh
++++ b/scripts/vgimportclone.sh
+@@ -204,8 +204,8 @@ for ARG
+ do
+     if [ -b "$ARG" ]
+     then
+-        PVS_OUT=`"${LVM}" pvs ${LVM_OPTS} --noheadings -o vg_name "$ARG" 2>/dev/null`
+-        checkvalue $? "$ARG is not a PV."
++        PVS_OUT=`"${LVM}" pvs ${LVM_OPTS} --noheadings -o vg_name "$ARG"`
++        checkvalue $? "$ARG could not be verified to be a PV without errors."
+         PV_VGNAME=$(echo $PVS_OUT | $GREP -v '[[:space:]]+$')
+         [ -z "$PV_VGNAME" ] && die 3 "$ARG is not in a VG."
+ 
+@@ -227,7 +227,7 @@ fi
+ ### Get the existing state so we can use it later
+ #####################################################################
+ 
+-OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null`
++OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings`
+ checkvalue $? "Current VG names could not be collected without errors"
+ 
+ #####################################################################
+@@ -280,7 +280,7 @@ export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR}
+ ### Rename the VG(s) and change the VG and PV UUIDs.
+ #####################################################################
+ 
+-PVINFO=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator : 2>/dev/null`
++PVINFO=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator :`
+ checkvalue $? "PV info could not be collected without errors"
+ 
+ # output VG info so each line looks like: name:exported?:disk1,disk2,...
+diff --git a/test/Makefile.in b/test/Makefile.in
+index 1b9789f..943a4ce 100644
+--- a/test/Makefile.in
++++ b/test/Makefile.in
+@@ -25,6 +25,10 @@ abs_top_builddir = "@abs_top_builddir@"
+ abs_top_srcdir = "@abs_top_srcdir@"
+ 
+ LVM_TEST_RESULTS ?= results
++export LVM_TEST_THIN_CHECK_CMD?=@THIN_CHECK_CMD@
++export LVM_TEST_THIN_DUMP_CMD?=@THIN_DUMP_CMD@
++export LVM_TEST_THIN_REPAIR_CMD?=@THIN_REPAIR_CMD@
++
+ SUBDIRS = api unit
+ SOURCES = lib/not.c lib/harness.c
+ 
+@@ -34,7 +38,8 @@ T ?= .
+ S ?= @ # never match anything by default
+ VERBOSE ?= 0
+ ALL = $(shell find $(srcdir) \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) | sort)
+-RUN = $(shell find $(srcdir) -regextype posix-egrep \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) -and -regex "$(srcdir)/.*($(T)).*" -and -not -regex "$(srcdir)/.*($(S)).*" | sort)
++comma = ,
++RUN = $(shell find $(srcdir) -regextype posix-egrep \( -path \*/shell/\*.sh -or -path \*/api/\*.sh \) -and -regex "$(srcdir)/.*($(subst $(comma),|,$(T))).*" -and -not -regex "$(srcdir)/.*($(subst $(comma),|,$(S))).*" | sort)
+ RUN_BASE = $(subst $(srcdir)/,,$(RUN))
+ 
+ # Shell quote;
+@@ -57,12 +62,15 @@ help:
+ 	@echo "  help			Display callable targets."
+ 	@echo -e "\nSupported variables:"
+ 	@echo "  LVM_TEST_DEVDIR	Set to '/dev' to run on real /dev."
+-	@echo "  LVM_TEST_DIR		Where to create test files [TMPDIR]."
++	@echo "  LVM_TEST_DIR		Where to create test files [$(LVM_TEST_DIR)]."
+ 	@echo "  LVM_TEST_LOCKING	Normal (1), Cluster (3)."
+ 	@echo "  LVM_TEST_LVMETAD	Start lvmetad (1)."
+ 	@echo "  LVM_TEST_NODEBUG	Do not debug lvm commands."
+ 	@echo "  LVM_TEST_PARALLEL	May skip agresive wipe of LVMTEST resources."
+ 	@echo "  LVM_TEST_RESULTS	Where to create result files [results]."
++	@echo "  LVM_TEST_THIN_CHECK_CMD  Command for thin_check  [$(LVM_TEST_THIN_CHECK_CMD)]."
++	@echo "  LVM_TEST_THIN_DUMP_CMD   Command for thin_dump   [$(LVM_TEST_THIN_DUMP_CMD)]."
++	@echo "  LVM_TEST_THIN_REPAIR_CMD Command for thin_repair [$(LVM_TEST_THIN_REPAIR_CMD)]."
+ 	@echo "  LVM_TEST_UNLIMITED	Set to get unlimited test log (>32MB)"
+ 	@echo "  LVM_VERIFY_UDEV	Default verify state for lvm.conf."
+ 	@echo "  S			Skip given test (regex)."
+diff --git a/test/lib/aux.sh b/test/lib/aux.sh
+index d27d263..f51fc0d 100644
+--- a/test/lib/aux.sh
++++ b/test/lib/aux.sh
+@@ -162,7 +162,7 @@ teardown_devs() {
+ 		local stray_loops=( $(losetup -a | grep "$COMMON_PREFIX" | cut -d: -f1) )
+ 		test ${#stray_loops[@]} -eq 0 || {
+ 			echo "Removing stray loop devices containing $COMMON_PREFIX: ${stray_loops[@]}"
+-			losetup -d "${stray_loops[@]}"
++			for i in "${stray_loops[@]}" ; do losetup -d $i ; done
+ 		}
+ 	}
+ }
+diff --git a/test/lib/get.sh b/test/lib/get.sh
+index 7b97c06..5dd5451 100644
+--- a/test/lib/get.sh
++++ b/test/lib/get.sh
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/usr/bin/env bash
+ # Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
+ #
+ # This copyrighted material is made available to anyone wishing to use,
+diff --git a/test/lib/harness.c b/test/lib/harness.c
+index 0036502..8c9f4a7 100644
+--- a/test/lib/harness.c
++++ b/test/lib/harness.c
+@@ -173,7 +173,7 @@ static void _append_buf(const char *buf, size_t len)
+ 				kill(-pid, SIGINT);
+ 			return;
+ 		}
+-		readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
++		readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 16384;
+ 		readbuf = realloc(readbuf, readbuf_sz);
+ 	}
+ 
+@@ -221,7 +221,7 @@ static const char *_append_with_stamp(const char *buf, int stamp)
+ 
+ static void drain(int fd)
+ {
+-	char buf[4096];
++	char buf[4096 + 1];
+ 	const char *bp;
+ 	int stamp = 0;
+ 	int sz;
+@@ -322,7 +322,7 @@ static void failed(int i, char *f, int st) {
+ 
+ 	++ s.nfailed;
+ 	s.status[i] = FAILED;
+-	printf("FAILED.\n");
++	printf("FAILED  (status %d).\n", WEXITSTATUS(st));
+ 	if (!verbose && readbuf) {
+ 		printf("-- FAILED %s ------------------------------------\n", f);
+ 		dump();
+@@ -340,12 +340,12 @@ static void run(int i, char *f) {
+ 		exit(201);
+ 	} else if (pid == 0) {
+ 		if (!interactive) {
+-			close(0);
+-			dup2(fds[0], 1);
+-			dup2(fds[0], 2);
+-			close(fds[0]);
++			close(STDIN_FILENO);
++			dup2(fds[1], STDOUT_FILENO);
++			dup2(fds[1], STDERR_FILENO);
+ 			close(fds[1]);
+ 		}
++		close(fds[0]);
+ 		if (strchr(f, ':')) {
+ 			strcpy(flavour, f);
+ 			*strchr(flavour, ':') = 0;
+@@ -372,6 +372,7 @@ static void run(int i, char *f) {
+ 		FILE *varlogmsg;
+ 		int fd_vlm = -1;
+ 
++		//close(fds[1]);
+ 		snprintf(buf, sizeof(buf), "%s ...", f);
+ 		printf("Running %-60s ", buf);
+ 		fflush(stdout);
+@@ -404,14 +405,14 @@ static void run(int i, char *f) {
+ 			}
+ 
+ 			FD_ZERO(&set);
+-			FD_SET(fds[1], &set);
++			FD_SET(fds[0], &set);
+ 			selectwait.tv_sec = 0;
+ 			selectwait.tv_usec = 500000; /* timeout 0.5s */
+-			if (select(fds[1] + 1, &set, NULL, NULL, &selectwait) <= 0) {
++			if (select(fds[0] + 1, &set, NULL, NULL, &selectwait) <= 0) {
+ 				no_write++;
+ 				continue;
+ 			}
+-			drain(fds[1]);
++			drain(fds[0]);
+ 			no_write = 0;
+ 			if (fd_vlm >= 0)
+ 				drain(fd_vlm);
+@@ -420,7 +421,7 @@ static void run(int i, char *f) {
+ 			perror("waitpid");
+ 			exit(206);
+ 		}
+-		drain(fds[1]);
++		drain(fds[0]);
+ 		if (fd_vlm >= 0)
+ 			drain(fd_vlm);
+ 		if (die == 2)
+@@ -472,12 +473,13 @@ int main(int argc, char **argv) {
+ 	results = getenv("LVM_TEST_RESULTS") ? : "results";
+ 	(void) snprintf(results_list, sizeof(results_list), "%s/list", results);
+ 
++	//if (pipe(fds)) {
+ 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
+ 		perror("socketpair");
+ 		return 201;
+ 	}
+ 
+-	if (fcntl(fds[1], F_SETFL, O_NONBLOCK ) == -1) {
++	if (fcntl(fds[0], F_SETFL, O_NONBLOCK ) == -1) {
+ 		perror("fcntl on socket");
+ 		return 202;
+ 	}
+@@ -537,10 +539,10 @@ int main(int argc, char **argv) {
+ 				printf("skipped: %s\n", argv[i]);
+ 				break;
+ 			case INTERRUPTED:
+-				printf("interrupted: %s\n", argv[i]);
++				printf("INTERRUPTED: %s\n", argv[i]);
+ 				break;
+ 			case TIMEOUT:
+-				printf("timeout: %s\n", argv[i]);
++				printf("TIMEOUT: %s\n", argv[i]);
+ 				break;
+ 			default: /* do nothing */ ;
+ 			}
+diff --git a/test/shell/lvconvert-repair-raid.sh b/test/shell/lvconvert-repair-raid.sh
+index 84e247d..71c84c1 100644
+--- a/test/shell/lvconvert-repair-raid.sh
++++ b/test/shell/lvconvert-repair-raid.sh
+@@ -29,7 +29,7 @@ vgextend $vg "$dev3"
+ lvremove -ff $vg
+ 
+ # RAID6 double replace
+-lvcreate --type raid5 -i 3 -l 2 -n $lv1 $vg \
++lvcreate --type raid6 -i 3 -l 2 -n $lv1 $vg \
+     "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+ aux wait_for_sync $vg $lv1
+ aux disable_dev "$dev4" "$dev5"
+diff --git a/test/shell/lvconvert-repair-thin.sh b/test/shell/lvconvert-repair-thin.sh
+new file mode 100644
+index 0000000..aa301d6
+--- /dev/null
++++ b/test/shell/lvconvert-repair-thin.sh
+@@ -0,0 +1,116 @@
++#!/bin/sh
++
++# Copyright (C) 2013 Red Hat, Inc. All rights reserved.
++#
++# This copyrighted material is made available to anyone wishing to use,
++# modify, copy, or redistribute it subject to the terms and conditions
++# of the GNU General Public License v.2.
++#
++# 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 repairing of broken thin pool metadata 
++
++. lib/test
++
++which mkfs.ext2 || skip
++
++# By default use tools from configuration (exported through Makefile)
++# Allow user to override location of binaries to take tools from different laces
++# Maybe check also version of the tools here?
++test -n "$LVM_TEST_THIN_CHECK_CMD" || LVM_TEST_THIN_CHECK_CMD=$(which thin_check) || skip
++test -n "$LVM_TEST_THIN_DUMP_CMD" || LVM_TEST_THIN_DUMP_CMD=$(which thin_dump) || skip
++test -n "$LVM_TEST_THIN_REPAIR_CMD" || LVM_TEST_THIN_REPAIR_CMD=$(which thin_repair) || skip
++
++#
++# Main
++#
++aux have_thin 1 0 0 || skip
++
++aux prepare_vg 4
++
++# Create LV
++lvcreate -T -L20 -V10 -n $lv1 $vg/pool  "$dev1" "$dev2"
++lvcreate -T -V10 -n $lv2 $vg/pool
++
++mkfs.ext2 $DM_DEV_DIR/$vg/$lv1
++mkfs.ext2 $DM_DEV_DIR/$vg/$lv2
++
++lvcreate -L20 -n repair $vg
++lvcreate -L2 -n fixed $vg
++
++lvs -a -o+seg_pe_ranges $vg
++#aux error_dev "$dev2" 2050:1
++
++# Make some repairable metadata damage??
++vgchange -an $vg
++
++lvconvert --repair $vg/pool
++
++lvs -a $vg
++
++# Test swapping - swap out thin-pool's metadata with our repair volume
++lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
++
++lvchange -aey $vg/repair $vg/fixed
++
++#dd if=$DM_DEV_DIR/$vg/repair of=back bs=1M
++
++# Make some 'repairable' damage??
++dd if=/dev/zero of=$DM_DEV_DIR/$vg/repair bs=1 seek=40960 count=1
++
++#dd if=$DM_DEV_DIR/$vg/repair of=back_trashed bs=1M
++#not vgchange -ay $vg
++
++#lvconvert --repair $vg/pool
++
++# Using now SHOULD - since thin tools currently do not seem to work
++should not $THIN_CHECK $DM_DEV_DIR/$vg/repair
++
++should not $LVM_TEST_THIN_DUMP_CMD $DM_DEV_DIR/$vg/repair | tee dump
++
++should $LVM_TEST_THIN_REPAIR_CMD -i $DM_DEV_DIR/$vg/repair -o $DM_DEV_DIR/$vg/fixed
++
++should $LVM_TEST_THIN_DUMP_CMD --repair $DM_DEV_DIR/$vg/repair | tee repaired_xml
++
++should $LVM_TEST_THIN_CHECK_CMD $DM_DEV_DIR/$vg/fixed
++
++# Swap repaired metadata back
++lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool
++lvs -a $vg
++
++# Activate pool - this should now work
++should vgchange -ay $vg
++
++lvs -a -o+devices $vg 
++dmsetup table
++dmsetup info -c
++dmsetup ls --tree
++
++lvchange -an $vg
++
++# FIXME: Currently in deep troubles - we can't remove thin volume from broken pool
++should lvremove -ff $vg
++
++# let's not block PVs with openned _tdata/_tmeta devices
++dmsetup remove $vg-pool_tdata || true
++dmsetup remove $vg-pool_tmeta || true
++
++dmsetup table
++
++# FIXME: needs  also --yes with double force 
++pvremove --yes -ff "$dev1"
++pvremove --yes -ff "$dev2"
++
++# FIXME: pv1 & pv2 are removed so pv3 & pv4 have no real LVs,
++# yet vgremove is refusing to do its jobs and suggest --partial??
++should vgremove -ff  $vg
++
++# FIXME: stressing even more - there are no pool PV, we do not pass...
++should vgreduce --removemissing -f $vg
++should vgremove -ff  $vg
++
++# Let's do a final forced cleanup
++pvremove --yes -ff "$dev3"
++pvremove --yes -ff "$dev4"
+diff --git a/test/shell/lvconvert-thin-external.sh b/test/shell/lvconvert-thin-external.sh
+index a700b37..d9d4d19 100644
+--- a/test/shell/lvconvert-thin-external.sh
++++ b/test/shell/lvconvert-thin-external.sh
+@@ -144,5 +144,13 @@ lvs -a -o+origin_size,seg_size,segtype $vg
+ lvremove -f $vg/extorg2
+ # Only pool is left
+ check vg_field $vg lv_count 1
++lvremove -ff $vg
++
++# Test conversion to the pool and thin external at the same time (rhbz #1003461)
++lvcreate -l50 -n pool $vg
++lvcreate -l100 -n thin $vg
++lvconvert --thin --thinpool $vg/pool $vg/thin --originname thin-origin
++check lv_field $vg/thin segtype thin
++check lv_field $vg/thin-origin segtype linear
+ 
+ vgremove -ff $vg
+diff --git a/test/shell/lvcreate-usage.sh b/test/shell/lvcreate-usage.sh
+index 68a15a9..105fbce 100644
+--- a/test/shell/lvcreate-usage.sh
++++ b/test/shell/lvcreate-usage.sh
+@@ -1,5 +1,5 @@
+ #!/bin/sh
+-# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
++# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
+ #
+ # This copyrighted material is made available to anyone wishing to use,
+ # modify, copy, or redistribute it subject to the terms and conditions
+@@ -15,7 +15,7 @@
+ 
+ aux prepare_pvs 4
+ aux pvcreate --metadatacopies 0 "$dev1"
+-vgcreate -cn $vg $(cat DEVICES)
++vgcreate $vg $(cat DEVICES)
+ 
+ # "lvcreate rejects repeated invocation (run 2 times) (bz178216)" 
+ lvcreate -n $lv -l 4 $vg 
+@@ -58,7 +58,7 @@ test -z "$(lvdisplay $vg)"
+ # Setting max_lv works. (bz490298)
+ lvremove -ff $vg
+ vgchange -l 3 $vg
+-lvcreate -l1 -n $lv1 $vg
++lvcreate -aey -l1 -n $lv1 $vg
+ lvcreate -l1 -s -n $lv2 $vg/$lv1
+ lvcreate -l1 -n $lv3 $vg
+ not lvcreate -l1 -n $lv4 $vg
+@@ -71,13 +71,13 @@ not lvcreate -l1 -n $lv4 $vg
+ not lvcreate -l1 --type mirror -m1 -n $lv4 $vg
+ 
+ lvremove -ff $vg/$lv3
+-lvcreate -l1 --type mirror -m1 -n $lv3 $vg
++lvcreate -aey -l1 --type mirror -m1 -n $lv3 $vg
+ vgs -o +max_lv $vg
+ not lvcreate -l1 -n $lv4 $vg
+ not lvcreate -l1 --type mirror -m1 -n $lv4 $vg
+ 
+ lvconvert -m0 $vg/$lv3
+-lvconvert -m2 -i 1 $vg/$lv3
++lvconvert -m2 --type mirror -i 1 $vg/$lv3
+ lvconvert -m1 $vg/$lv3
+ 
+ not vgchange -l 2
+@@ -90,8 +90,8 @@ vgchange -l 0 $vg
+ # lvcreate rejects invalid chunksize, accepts between 4K and 512K
+ # validate origin_size
+ vgremove -ff $vg
+-vgcreate -cn $vg $(cat DEVICES)
+-lvcreate -L 32m -n $lv1 $vg
++vgcreate $vg $(cat DEVICES)
++lvcreate -aey -L 32m -n $lv1 $vg
+ not lvcreate -L 8m -n $lv2 -s --chunksize 3k $vg/$lv1
+ not lvcreate -L 8m -n $lv2 -s --chunksize 1024k $vg/$lv1
+ lvcreate -L 8m -n $lv2 -s --chunksize 4k $vg/$lv1
+@@ -111,10 +111,10 @@ not lvcreate -L 32m -n $lv -R0 $vg 2>err
+ grep "Non-zero region size must be supplied." err
+ not lvcreate -L 32m -n $lv -R 11k $vg
+ not lvcreate -L 32m -n $lv -R 1k $vg
+-lvcreate -L 32m -n $lv --regionsize 128m  --type mirror -m 1 $vg
++lvcreate -aey -L 32m -n $lv --regionsize 128m  --type mirror -m 1 $vg
+ check lv_field $vg/$lv regionsize "32.00m"
+ lvremove -ff $vg
+-lvcreate -L 32m -n $lv --regionsize 4m --type mirror -m 1 $vg
++lvcreate -aey -L 32m -n $lv --regionsize 4m --type mirror -m 1 $vg
+ check lv_field $vg/$lv regionsize "4.00m"
+ lvremove -ff $vg
+ 
+diff --git a/test/shell/lvmcache-exercise.sh b/test/shell/lvmcache-exercise.sh
+index b1e2b92..6e8efda 100644
+--- a/test/shell/lvmcache-exercise.sh
++++ b/test/shell/lvmcache-exercise.sh
+@@ -1,5 +1,5 @@
+ #!/bin/sh
+-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
++# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
+ #
+ # This copyrighted material is made available to anyone wishing to use,
+ # modify, copy, or redistribute it subject to the terms and conditions
+@@ -14,10 +14,23 @@
+ aux prepare_pvs 5
+ 
+ vgcreate $vg1 "$dev1"
+-vgcreate $vg2 "$dev3"
++vgcreate $vg2 "$dev3" "$dev4" "$dev5"
+ 
+ aux disable_dev "$dev1"
+ pvscan
+ vgcreate $vg1 "$dev2"
+ aux enable_dev "$dev1"
+ pvs
++
++# reappearing device (rhbz 995440)
++lvcreate -aey -m2 --type mirror -l4 --alloc anywhere --corelog -n $lv1 $vg2
++
++aux disable_dev "$dev3"
++lvconvert --yes --repair $vg2/$lv1
++aux enable_dev "$dev3"
++
++# here it should fix any reappeared devices
++lvs
++
++lvs -a $vg2 -o+devices 2>&1 | tee out
++not grep reappeared out
+diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh
+index 9c1c2f6..3d4d308 100644
+--- a/test/shell/snapshot-usage.sh
++++ b/test/shell/snapshot-usage.sh
+@@ -17,6 +17,13 @@ fill() {
+ 	dd if=/dev/zero of=$DM_DEV_DIR/$vg1/lvol0 bs=$1 count=1
+ }
+ 
++cleanup_tail()
++{
++	test -z "$SLEEP_PID" || kill $SLEEP_PID
++	wait
++	aux teardown
++}
++
+ aux prepare_pvs 1
+ vgcreate -s 4M $vg $(cat DEVICES)
+ 
+@@ -30,6 +37,34 @@ aux lvmconf "activation/snapshot_autoextend_percent = 20" \
+ pvcreate --setphysicalvolumesize 4T $DM_DEV_DIR/$vg/$lv
+ vgcreate -s 1K $vg1 $DM_DEV_DIR/$vg/$lv
+ 
++# Test removal of opened snapshot
++lvcreate -V50 -L10 -n $lv1 -s $vg1
++
++lvs -a -o+lv_active $vg1
++lvchange -an $vg1
++
++# Snapshot get exclusive activation
++lvchange -ay $vg1
++lvs -a -o+lv_active $vg1
++
++trap 'cleanup_tail' EXIT
++# Keep device busy (but not mounted) for a while
++sleep 30 < $DM_DEV_DIR/$vg1/$lv1 &
++SLEEP_PID=$!
++
++# Opened virtual snapshot device is not removable
++# it should retry device removal for a few seconds
++not lvremove -f $vg1/$lv1
++
++kill $SLEEP_PID
++SLEEP_PID=
++# Wait for killed task, so there is no device holder
++wait
++
++lvremove -f $vg1/$lv1
++not dmsetup info $vg1-$lv1 >/dev/null || \
++	die "$vg1/$lv1 expected to be removed, but there are mappings!"
++
+ # Check border size
+ lvcreate -aey -L4095G $vg1
+ lvcreate -s -L100K $vg1/lvol0
+@@ -79,7 +114,7 @@ lvcreate -an -Zn -l50%FREE -n $lv1 $vg1
+ lvcreate -s -l100%FREE -n $lv2 $vg1/$lv1
+ check lv_field $vg1/$lv2 size "7.50p"
+ lvremove -ff $vg1
+- 
++
+ lvcreate -aey -V15E -l1 -n $lv1 -s $vg1
+ check lv_field $vg1/$lv1 origin_size "15.00e"
+ 
+diff --git a/test/shell/vgrename-usage.sh b/test/shell/vgrename-usage.sh
+index 2b8ac5a..59576ac 100644
+--- a/test/shell/vgrename-usage.sh
++++ b/test/shell/vgrename-usage.sh
+@@ -38,3 +38,18 @@ vgcreate $vg1 "$dev1"
+ vgcreate $vg2 "$dev2"
+ not vgrename $vg1 $vg2
+ vgremove $vg1 $vg2
++
++# vgrename duplicate name
++vgcreate $vg1 "$dev1"
++aux disable_dev "$dev1"
++vgcreate $vg1 "$dev2"
++UUID=$(vgs --noheading -o vg_uuid $vg1)
++aux enable_dev "$dev1"
++
++not vgrename $vg1 $vg2
++vgrename $UUID $vg2
++not vgrename $UUID $vg1
++
++vgs
++
++vgremove $vg1 $vg2
+diff --git a/tools/dmsetup.c b/tools/dmsetup.c
+index 517e8aa..a0ee23e 100644
+--- a/tools/dmsetup.c
++++ b/tools/dmsetup.c
+@@ -1147,7 +1147,7 @@ static int _udevcomplete_all(CMD_ARGS)
+ 	unsigned age = 0;
+ 	time_t t;
+ 
+-	if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) {
++	if (argc == 2 && (sscanf(argv[1], "%u", &age) != 1)) {
+ 		log_error("Failed to read age_in_minutes parameter.");
+ 		return 0;
+ 	}
+diff --git a/tools/lvchange.c b/tools/lvchange.c
+index 1d4f0a5..6ae9720 100644
+--- a/tools/lvchange.c
++++ b/tools/lvchange.c
+@@ -120,8 +120,7 @@ static int lvchange_pool_update(struct cmd_context *cmd,
+ 			if (((discards == THIN_DISCARDS_IGNORE) ||
+ 			     (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) &&
+ 			    pool_is_active(lv))
+-				log_error("Cannot change discards state for active "
+-					  "pool volume \"%s\".", lv->name);
++				log_error("Cannot change support for discards while pool volume \"%s\" is active.", lv->name);
+ 			else {
+ 				first_seg(lv)->discards = discards;
+ 				update++;
+diff --git a/tools/lvconvert.c b/tools/lvconvert.c
+index 49881fa..a6c1187 100644
+--- a/tools/lvconvert.c
++++ b/tools/lvconvert.c
+@@ -1891,6 +1891,10 @@ static int lvconvert_merge(struct cmd_context *cmd,
+ 			  find_merging_snapshot(origin)->cow->name);
+ 		return 0;
+ 	}
++	if (lv_is_virtual_origin(origin)) {
++		log_error("Snapshot %s has virtual origin.", lv->name);
++		return 0;
++	}
+ 
+ 	/*
+ 	 * Prevent merge with open device(s) as it would likely lead
+@@ -2266,11 +2270,12 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
+ 	int r = 0;
+ 	const char *old_name;
+ 	struct lv_segment *seg;
+-	struct logical_volume *data_lv = pool_lv;
++	struct logical_volume *data_lv;
+ 	struct logical_volume *metadata_lv;
+ 	struct logical_volume *pool_metadata_lv;
+ 	struct logical_volume *external_lv = NULL;
+ 	char metadata_name[NAME_LEN], data_name[NAME_LEN];
++	int activate_pool;
+ 
+ 	if (!lv_is_visible(pool_lv)) {
+ 		log_error("Can't convert internal LV %s/%s.",
+@@ -2299,17 +2304,22 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
+ 		}
+ 
+ 		if (lv_is_thin_pool(pool_lv)) {
++			activate_pool = lv_is_active(pool_lv);
+ 			r = 1; /* Already existing thin pool */
+ 			goto out;
+ 		}
+ 	}
+ 
++	data_lv = pool_lv;
+ 	if (lv_is_thin_type(pool_lv) && !lp->pool_metadata_lv_name) {
+ 		log_error("Can't use thin logical volume %s/%s for thin pool data.",
+ 			  pool_lv->vg->name, pool_lv->name);
+ 		return 0;
+ 	}
+ 
++	/* Allow to have only thinpool active and restore it's active state */
++	activate_pool = lv_is_active(pool_lv);
++
+ 	/* We are changing target type, so deactivate first */
+ 	if (!deactivate_lv(cmd, pool_lv)) {
+ 		log_error("Aborting. Failed to deactivate logical volume %s/%s.",
+@@ -2317,6 +2327,13 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
+ 		return 0;
+ 	}
+ 
++	if (lv_is_thin_pool(pool_lv) && pool_is_active(pool_lv)) {
++		/* If any thin volume is also active - abort here */
++		log_error("Cannot convert pool %s/%s with active thin volumes.",
++			  pool_lv->vg->name, pool_lv->name);
++		return 0;
++	}
++
+ 	if ((dm_snprintf(metadata_name, sizeof(metadata_name), "%s_tmeta",
+ 			 pool_lv->name) < 0) ||
+ 	    (dm_snprintf(data_name, sizeof(data_name), "%s_tdata",
+@@ -2418,6 +2435,7 @@ static int _lvconvert_thinpool(struct cmd_context *cmd,
+ 			goto mda_write;
+ 		}
+ 
++		metadata_lv->status |= LV_NOSCAN;
+ 		if (!lv_is_active(metadata_lv) &&
+ 		    !activate_lv_local(cmd, metadata_lv)) {
+ 			log_error("Aborting. Failed to activate thin metadata lv.");
+@@ -2510,7 +2528,8 @@ mda_write:
+ 	if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg))
+ 		return_0;
+ 
+-	if (!activate_lv_excl(cmd, pool_lv)) {
++	if (activate_pool &&
++	    !activate_lv_excl(cmd, pool_lv)) {
+ 		log_error("Failed to activate pool logical volume %s/%s.",
+ 			  pool_lv->vg->name, pool_lv->name);
+ 		/* Deactivate subvolumes */
+diff --git a/tools/lvremove.c b/tools/lvremove.c
+index 4f48746..dfc435c 100644
+--- a/tools/lvremove.c
++++ b/tools/lvremove.c
+@@ -18,14 +18,6 @@
+ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
+ 			   void *handle __attribute__((unused)))
+ {
+-	struct logical_volume *origin;
+-
+-	/*
+-	 * If this is a sparse device, remove its origin too.
+-	 */
+-        if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
+-                lv = origin;
+-
+ 	if (!lv_remove_with_dependencies(cmd, lv, (force_t) arg_count(cmd, force_ARG), 0))
+ 		return_ECMD_FAILED;
+ 
+diff --git a/tools/pvscan.c b/tools/pvscan.c
+index 3f16b05..b6a07bd 100644
+--- a/tools/pvscan.c
++++ b/tools/pvscan.c
+@@ -132,6 +132,27 @@ out:
+ 	return r;
+ }
+ 
++static int _clear_dev_from_lvmetad_cache(dev_t devno, int32_t major, int32_t minor,
++					 activation_handler handler)
++{
++	char *buf;
++
++	if (!dm_asprintf(&buf, "%" PRIi32 ":%" PRIi32, major, minor))
++		stack;
++	if (!lvmetad_pv_gone(devno, buf ? : "", handler)) {
++		if (buf)
++			dm_free(buf);
++		return 0;
++	}
++
++	log_print_unless_silent("Device %s not found. "
++				"Cleared from lvmetad cache.", buf ? : "");
++	if (buf)
++		dm_free(buf);
++
++	return 1;
++}
++
+ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+ {
+ 	int ret = ECMD_PROCESSED;
+@@ -142,7 +163,6 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+ 	int devno_args = 0;
+ 	struct arg_value_group_list *current_group;
+ 	dev_t devno;
+-	char *buf;
+ 	activation_handler handler = NULL;
+ 
+ 	/*
+@@ -193,11 +213,30 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+ 	/* Process any command line PVs first. */
+ 	while (argc--) {
+ 		pv_name = *argv++;
+-		dev = dev_cache_get(pv_name, cmd->lvmetad_filter);
+-		if (!dev) {
+-			log_error("Physical Volume %s not found.", pv_name);
+-			ret = ECMD_FAILED;
+-			continue;
++		if (pv_name[0] == '/') {
++			/* device path */
++			if (!(dev = dev_cache_get(pv_name, cmd->lvmetad_filter))) {
++				log_error("Physical Volume %s not found.", pv_name);
++				ret = ECMD_FAILED;
++				continue;
++			}
++		}
++		else {
++			/* device major:minor */
++			if (sscanf(pv_name, "%d:%d", &major, &minor) != 2) {
++				log_error("Failed to parse major:minor from %s", pv_name);
++				ret = ECMD_FAILED;
++				continue;
++			}
++			devno = MKDEV((dev_t)major, minor);
++			if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
++				if (!(_clear_dev_from_lvmetad_cache(devno, major, minor, handler))) {
++					stack;
++					ret = ECMD_FAILED;
++					break;
++				}
++				continue;
++			}
+ 		}
+ 		if (sigint_caught()) {
+ 			ret = ECMD_FAILED;
+@@ -225,19 +264,11 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+ 		devno = MKDEV((dev_t)major, minor);
+ 
+ 		if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
+-			if (!dm_asprintf(&buf, "%" PRIi32 ":%" PRIi32, major, minor))
++			if (!(_clear_dev_from_lvmetad_cache(devno, major, minor, handler))) {
+ 				stack;
+-			if (!lvmetad_pv_gone(devno, buf ? : "", handler)) {
+ 				ret = ECMD_FAILED;
+-				if (buf)
+-					dm_free(buf);
+ 				break;
+ 			}
+-
+-			log_print_unless_silent("Device %s not found. "
+-						"Cleared from lvmetad cache.", buf ? : "");
+-			if (buf)
+-				dm_free(buf);
+ 			continue;
+ 		}
+ 		if (sigint_caught()) {
+diff --git a/tools/vgrename.c b/tools/vgrename.c
+index 154a6f3..b5e778f 100644
+--- a/tools/vgrename.c
++++ b/tools/vgrename.c
+@@ -83,6 +83,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
+ 	if (!lvmetad_vg_list_to_lvmcache(cmd))
+ 		stack;
+ 
++	lvmcache_label_scan(cmd, 2);
++
+ 	/* Avoid duplicates */
+ 	if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
+ 		log_error("No complete volume groups found");
+diff --git a/udev/11-dm-lvm.rules.in b/udev/11-dm-lvm.rules.in
+index f21d0aa..5032280 100644
+--- a/udev/11-dm-lvm.rules.in
++++ b/udev/11-dm-lvm.rules.in
+@@ -20,6 +20,21 @@ ENV{DM_UUID}!="LVM-?*", GOTO="lvm_end"
+ # Use DM name and split it up into its VG/LV/layer constituents.
+ IMPORT{program}="(DM_EXEC)/dmsetup splitname --nameprefixes --noheadings --rows $env{DM_NAME}"
+ 
++# DM_SUBSYSTEM_UDEV_FLAG0 is the 'NOSCAN' flag for LVM subsystem.
++# This flag is used to temporarily disable selected rules to prevent any
++# processing or scanning done on the LVM volume before LVM has any chance
++# to zero any stale metadata found within the LV data area. Such stale
++# metadata could cause false claim of the LV device, keeping it open etc.
++#
++# If the NOSCAN flag is present, backup selected existing flags used to
++# disable rules, then set them firmly so those selected rules are surely skipped.
++# Restore these flags once the NOSCAN flag is dropped (which is normally any
++# uevent that follows for this LV, even an artificially generated one).
++ENV{DM_SUBSYSTEM_UDEV_FLAG0}=="1", ENV{DM_NOSCAN}="1", ENV{DM_DISABLE_OTHER_RULES_FLAG_OLD}="$env{DM_UDEV_DISABLE_OTHER_RULES_FLAG}", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
++ENV{DM_SUBSYSTEM_UDEV_FLAG0}!="1", IMPORT{db}="DM_NOSCAN", IMPORT{db}="DM_DISABLE_OTHER_RULES_FLAG_OLD"
++ENV{DM_SUBSYSTEM_UDEV_FLAG0}!="1", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="$env{DM_DISABLE_OTHER_RULES_FLAG_OLD}", \
++				   ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG_OLD}="", ENV{DM_NOSCAN}=""
++
+ ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end"
+ 
+ OPTIONS+="event_timeout=180"
+diff --git a/udev/13-dm-disk.rules.in b/udev/13-dm-disk.rules.in
+index 1920260..4b64dd6 100644
+--- a/udev/13-dm-disk.rules.in
++++ b/udev/13-dm-disk.rules.in
+@@ -18,6 +18,7 @@ SYMLINK+="disk/by-id/dm-name-$env{DM_NAME}"
+ ENV{DM_UUID}=="?*", SYMLINK+="disk/by-id/dm-uuid-$env{DM_UUID}"
+ 
+ ENV{DM_SUSPENDED}=="1", GOTO="dm_end"
++ENV{DM_NOSCAN}=="1", GOTO="dm_watch"
+ 
+ (BLKID_RULE)
+ ENV{DM_UDEV_LOW_PRIORITY_FLAG}=="1", OPTIONS="link_priority=-100"
+@@ -32,7 +33,7 @@ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk
+ # (like creating a filesystem, changing filesystem label etc.).
+ #
+ # But let's use this until we have something better...
+-
++LABEL="dm_watch"
+ OPTIONS+="watch"
+ 
+ LABEL="dm_end"
+diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in
+index ba43396..3e303b1 100644
+--- a/udev/69-dm-lvm-metad.rules.in
++++ b/udev/69-dm-lvm-metad.rules.in
+@@ -17,6 +17,8 @@
+ SUBSYSTEM!="block", GOTO="lvm_end"
+ (LVM_EXEC_RULE)
+ 
++ENV{DM_NOSCAN}=="1", GOTO="lvm_end"
++
+ # If the PV label got lost, inform lvmetad immediately.
+ # Detect the lost PV label by comparing previous ID_FS_TYPE value with current one.
+ ENV{.ID_FS_TYPE_NEW}="$env{ID_FS_TYPE}"
+@@ -77,6 +79,6 @@ LABEL="lvm_scan"
+ #  MD    |          |      X      |       X*       |                   |
+ #  loop  |          |      X      |       X*       |                   |
+ #  other |    X     |             |       X        |                   |   X
+-RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor", ENV{LVM_SCANNED}="1"
++(PVSCAN_RULE)
+ 
+ LABEL="lvm_end"
+diff --git a/udev/Makefile.in b/udev/Makefile.in
+index 5c15bdb..40a4671 100644
+--- a/udev/Makefile.in
++++ b/udev/Makefile.in
+@@ -46,8 +46,14 @@ else
+ BLKID_RULE=IMPORT{program}=\"${SBIN}\/blkid -o udev -p \$$tempnode\"
+ endif
+ 
++ifeq ("@UDEV_SYSTEMD_BACKGROUND_JOBS@", "yes")
++PVSCAN_RULE=ENV{SYSTEMD_ALIAS}=\"\/dev\/block\/\$$major:\$$minor\"\nENV{ID_MODEL}=\"LVM PV \$$env{ID_FS_UUID_ENC} on \/dev\/\$$name\"\nENV{SYSTEMD_WANTS}=\"lvm2-pvscan@\$$major:\$$minor.service\"
++else
++PVSCAN_RULE=RUN\+\=\"$(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major \$$major --minor \$$minor\", ENV{LVM_SCANNED}=\"1\"
++endif
++
+ %.rules: %.rules.in
+-	$(SED) -e "s+(DM_DIR)+$(DM_DIR)+;s+(BLKID_RULE)+$(BLKID_RULE)+;s+(DM_EXEC_RULE)+$(DM_EXEC_RULE)+;s+(DM_EXEC)+$(DM_EXEC)+;s+(LVM_EXEC_RULE)+$(LVM_EXEC_RULE)+;s+(LVM_EXEC)+$(LVM_EXEC)+;" $< >$@
++	$(SED) -e "s+(DM_DIR)+$(DM_DIR)+;s+(BLKID_RULE)+$(BLKID_RULE)+;s+(PVSCAN_RULE)+$(PVSCAN_RULE)+;s+(DM_EXEC_RULE)+$(DM_EXEC_RULE)+;s+(DM_EXEC)+$(DM_EXEC)+;s+(LVM_EXEC_RULE)+$(LVM_EXEC_RULE)+;s+(LVM_EXEC)+$(LVM_EXEC)+;" $< >$@
+ 
+ %_install: %.rules
+ 	$(INSTALL_DATA) -D $< $(udevdir)/$(<F)
diff --git a/lvm2.spec b/lvm2.spec
index db341af..4c8b494 100644
--- a/lvm2.spec
+++ b/lvm2.spec
@@ -37,13 +37,14 @@
 Summary: Userland logical volume management tools 
 Name: lvm2
 Version: 2.02.103
-Release: 1%{?dist}
+Release: 2%{?dist}
 License: GPLv2
 Group: System Environment/Base
 URL: http://sources.redhat.com/lvm2
 Source0: ftp://sources.redhat.com/pub/lvm2/releases/LVM2.%{version}.tgz
 Patch0: lvm2-set-default-preferred_names.patch
 Patch1: lvm2-enable-lvmetad-by-default.patch
+Patch2: lvm2-2_02_104-additional-fixes-from-v104.patch
 
 BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel
 BuildRequires: ncurses-devel
@@ -80,6 +81,7 @@ or more physical volumes and creating one or more logical volumes
 %setup -q -n LVM2.%{version}
 %patch0 -p1 -b .preferred_names
 %patch1 -p1 -b .enable_lvmetad
+%patch2 -p1 -b .v104
 
 %build
 %define _default_pid_dir /run
@@ -97,7 +99,7 @@ or more physical volumes and creating one or more logical volumes
 %endif
 
 %if %{enable_lvmetad}
-%define configure_lvmetad --enable-lvmetad
+%define configure_lvmetad --enable-lvmetad --enable-udev-systemd-background-jobs
 %endif
 
 %configure --with-default-dm-run-dir=%{_default_dm_run_dir} --with-default-run-dir=%{_default_run_dir} --with-default-pid-dir=%{_default_pid_dir} --with-default-locking-dir=%{_default_locking_dir} --with-usrlibdir=%{_libdir} --enable-lvm1_fallback --enable-fsadm --with-pool=internal --with-user= --with-group= --with-device-uid=0 --with-device-gid=6 --with-device-mode=0660 --enable-pkgconfig --enable-applib --enable-cmdlib --enable-python-bindings --enable-dmeventd %{?configure_cluster} %{?configure_cmirror} %{?configure_udev} %{?configure_thin} %{?configure_lvmetad}
@@ -267,6 +269,7 @@ rm -rf $RPM_BUILD_ROOT
 %if %{enable_lvmetad}
 %{_unitdir}/lvm2-lvmetad.socket
 %{_unitdir}/lvm2-lvmetad.service
+%{_unitdir}/lvm2-pvscan at .service
 %endif
 
 ##############################################################################
@@ -576,6 +579,37 @@ the device-mapper event library.
 %{_libdir}/pkgconfig/devmapper-event.pc
 
 %changelog
+* Fri Oct 26 2013 Peter Rajnoha <prajnoha at redhat.com> - 2.02.103-2
+- Add internal flag for temporary LVs to properly direct udev to not interfere.
+- Fix endless loop in blkdeactivate <device>... if unable to umount/deactivate.
+- Add dev-block-<major>:<minor>.device systemd alias for complete PV tracking.
+- Use major:minor as short form of --major and --minor arg for pvscan --cache.
+- Remove 2>/dev/null from three lvm commands executed by vgimportclone.
+- Add configure --enable-udev-systemd-background-jobs.
+- Add lvm2-pvscan at .service to run pvscan as a service for lvmetad/autoactivation.
+- Fix lvconvert swap of poolmetadata volume for active thin pool.
+- Check for open count with a timeout before removal/deactivation of an LV.
+- Report RAID images split with tracking as out-of-sync ("I").
+- Improve parsing of snapshot lv segment.
+- Add workaround for deactivation problem of opened virtual snapshot.
+- Disable unsupported merge for virtual snapshot.
+- Move code to remove virtual snapshot from tools to lib for lvm2app.
+- Fix possible race during daemon worker thread creation (lvmetad).
+- Fix possible deadlock while clearing lvmetad cache for full rescan.
+- Fix possible race while creating/destroying memory pools.
+- Recognise NVM Express devices in filter.
+- Fix failing metadata repair when lvmetad is used.
+- Fix incorrect memory handling when reading messages from lvmetad.
+- Fix locking in lvmetad when handling the PV which is gone.
+- Recognize new flag to skip udev scanning in udev rules and act appropriately.
+- Add support for flagging an LV to skip udev scanning during activation.
+- Improve message when unable to change discards setting on active thin pool.
+- Run full scan before vgrename operation to avoid any cache name collision.
+- Fix lvconvert when converting to a thin pool and thin LV at once.
+- Skip race errors when non-udev dmsetup build runs on udev-enabled system.
+- Skip error message when holders are not present in sysfs.
+- Use __linux__ instead of linux define to make libdevmapper.h C compliant.
+
 * Fri Oct 04 2013 Peter Rajnoha <prajnoha at redhat.com> - 2.02.103-1
 - Ensure vgid matches before removing vgname entry from lvmetad cache.
 - Add --ignoreskippedcluster for exit status success when clustered VGs skipped.


More information about the scm-commits mailing list