From 8c6d94dbad5feeac11236e72a8b7daaeb20eab0e Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Oct 25 2013 06:51:46 +0000 Subject: Additional fixes from upcoming v104. --- 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 +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@.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 ... if unable to umount/deactivate. ++ Add dev-block-:.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@.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@.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@.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_pvscan_systemd_red_hat@.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@.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 + + #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 + #include + +-#ifdef linux ++#ifdef __linux__ + # include + #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 ++#include + +-/* 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@.service $(systemd_unit_dir)/lvm2-pvscan@.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@.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@.service.in b/scripts/lvm2_pvscan_systemd_red_hat@.service.in +new file mode 100644 +index 0000000..4225982 +--- /dev/null ++++ b/scripts/lvm2_pvscan_systemd_red_hat@.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)/$(= %{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@.service %endif ############################################################################## @@ -576,6 +579,37 @@ the device-mapper event library. %{_libdir}/pkgconfig/devmapper-event.pc %changelog +* Fri Oct 26 2013 Peter Rajnoha - 2.02.103-2 +- Add internal flag for temporary LVs to properly direct udev to not interfere. +- Fix endless loop in blkdeactivate ... if unable to umount/deactivate. +- Add dev-block-:.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@.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 - 2.02.103-1 - Ensure vgid matches before removing vgname entry from lvmetad cache. - Add --ignoreskippedcluster for exit status success when clustered VGs skipped.