[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