lvm2/lvm2-2_02_104-additional-fixes-from-v104.patch
2013-10-25 08:51:46 +02:00

2213 lines
81 KiB
Diff

commit 11388698bad4336c156b11f8e1f51b664b34f57c
Author: Peter Rajnoha <prajnoha@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@.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@.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 <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@.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)/$(<F)