main - vgremove: remove forgotten pmspare
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=5042463c5083cc71546...
Commit: 5042463c5083cc71546297344058bd0fa523aa5c
Parent: d38fdb25e4debc035f1e4585432c2627460d5e50
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jul 20 22:28:13 2021 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jul 21 13:19:51 2021 +0200
vgremove: remove forgotten pmspare
As pmspare is an invisible LV it's not getting automatically removed
since vgremove removes only visible LVs and it depending LVs.
If there was no other thin/cache pool volume, such pmspare stayed
undeleted and caused command failure.
So handle explicitelly such forgotten pmspare and remove it.
---
tools/vgremove.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tools/vgremove.c b/tools/vgremove.c
index 8f73297dc..b6685ae2a 100644
--- a/tools/vgremove.c
+++ b/tools/vgremove.c
@@ -65,6 +65,10 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
}
}
+ if (vg->pool_metadata_spare_lv &&
+ !lvremove_single(cmd, vg->pool_metadata_spare_lv, &void_handle))
+ return_ECMD_FAILED;
+
if (!lockd_free_vg_before(cmd, vg, 0))
return_ECMD_FAILED;
2 years, 9 months
main - thin: fix component detection of external origin
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d38fdb25e4debc035f1...
Commit: d38fdb25e4debc035f1e4585432c2627460d5e50
Parent: e33c2e032cab40cf8607afa1cb92176400d1cabd
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jul 14 12:53:47 2021 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Jul 14 12:56:08 2021 +0200
thin: fix component detection of external origin
When check active componet of thinLV with external origin,
we need to check if the external origin isn't already active.
For this however we need to use layered check for -real device.
---
WHATS_NEW | 1 +
lib/activate/activate.c | 5 ++++-
test/shell/lvconvert-cache-thin.sh | 22 ++++++++++++++++++++++
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 810411914..b06071c42 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.13 -
===============================
+ Fix detection of active components of external origin volume.
Add vdoimport tool to support conversion of VDO volumes.
Support configurable allocation/vdo_pool_header_size.
Fix handling of lvconvert --type vdo-pool --virtualsize.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 6bda7385b..94fc9441d 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -2740,7 +2740,10 @@ static int _component_cb(struct logical_volume *lv, void *data)
(lv_is_thin_pool(lv) && pool_is_active(lv)))
return -1;
- if (lv_is_active(lv)) {
+ /* External origin is activated through thinLV and uses -real suffix.
+ * Note: for old clustered logic we would need to check for all thins */
+ if ((lv_is_external_origin(lv) && lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0)) ||
+ lv_is_active(lv)) {
if (!lv_is_component(lv) || lv_is_visible(lv))
return -1; /* skip whole subtree */
diff --git a/test/shell/lvconvert-cache-thin.sh b/test/shell/lvconvert-cache-thin.sh
index 7dda6e6ff..9254239ee 100644
--- a/test/shell/lvconvert-cache-thin.sh
+++ b/test/shell/lvconvert-cache-thin.sh
@@ -67,4 +67,26 @@ fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv
# Thin-pool CAN use cached data LV
lvconvert --yes --thinpool $vg/$lv
+lvremove -f $vg
+
+# Check we can active snapshot of cached external origin (BZ: 1967744)
+lvcreate -T -L10M $vg/pool "$dev1"
+
+lvcreate -L10M -n origin $vg "$dev1"
+lvcreate -H -L4M -n CPOOL $vg/origin "$dev2"
+
+# Use cached origin as external origin
+lvconvert -y -T --thinpool $vg/pool --originname extorig origin
+
+# Check we can easily create snapshot of such LV
+lvcreate -y -kn -n snap -s $vg/origin
+
+# Deactivate everything and do a component activation of _cmeta volume
+lvchange -an $vg
+lvchange -ay -y $vg/CPOOL_cpool_cmeta
+
+# Now this must fail since component volume is active
+not lvcreate -y -kn -n snap2 -s $vg/origin |& tee err
+grep "cmeta is active" err
+
vgremove -f $vg
2 years, 9 months
main - pvscan: narrow the previous commit slightly
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e33c2e032cab40cf860...
Commit: e33c2e032cab40cf8607afa1cb92176400d1cabd
Parent: 25f0f5daac5606e557d2124c219f5bb255c5d9dc
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 13 16:26:36 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 13 16:38:04 2021 -0500
pvscan: narrow the previous commit slightly
to avoid change to pvscan-autoactivate.sh
---
tools/pvscan.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 78cb5e764..6787c4cfc 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1611,6 +1611,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
struct pvscan_aa_params pp = { 0 };
struct dm_list complete_vgnames;
int do_activate = arg_is_set(cmd, activate_ARG);
+ int event_activation;
int devno_args = 0;
int do_all;
int ret;
@@ -1619,6 +1620,13 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
cmd->check_devs_used = 0;
+ event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
+
+ if (do_activate && !event_activation) {
+ log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
+ return ECMD_PROCESSED;
+ }
+
if (arg_is_set(cmd, major_ARG) + arg_is_set(cmd, minor_ARG))
devno_args = 1;
@@ -1629,17 +1637,17 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
do_all = !argc && !devno_args;
- if (!do_all && !find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
- log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
- return ECMD_PROCESSED;
- }
-
_online_dir_setup();
if (do_all) {
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
} else {
+ if (!event_activation) {
+ /* Avoid doing anything for device removal: pvscan --cache <devno> */
+ log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
+ return ECMD_PROCESSED;
+ }
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
}
2 years, 9 months
main - pvscan: do nothing for device removal and event_activation=0
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=25f0f5daac5606e557d...
Commit: 25f0f5daac5606e557d2124c219f5bb255c5d9dc
Parent: f8b52f2763cd029422147fa97928661bd67ebd03
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 13 15:34:05 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 13 16:09:54 2021 -0500
pvscan: do nothing for device removal and event_activation=0
The lvm2-pvscan service runs pvscan --cache -aay <dev> for
device addition, and pvscan --cache <dev> on device removal.
For event_activation=0, the addition does nothing. Fix
device removal to also do nothing for event_activation=0.
Device removal was previously doing some work to process
the removal which slowed down stopping lvm2-pvscan services.
---
tools/pvscan.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 40a93957c..78cb5e764 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1619,12 +1619,6 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
cmd->check_devs_used = 0;
- if (do_activate &&
- !find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
- log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
- return ECMD_PROCESSED;
- }
-
if (arg_is_set(cmd, major_ARG) + arg_is_set(cmd, minor_ARG))
devno_args = 1;
@@ -1635,6 +1629,11 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
do_all = !argc && !devno_args;
+ if (!do_all && !find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
+ log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
+ return ECMD_PROCESSED;
+ }
+
_online_dir_setup();
if (do_all) {
2 years, 9 months
main - fix multipath component detection for multiple holders
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f8b52f2763cd0294221...
Commit: f8b52f2763cd029422147fa97928661bd67ebd03
Parent: deaf43d6f0341d8d15e8ff5ffd25d7e0a7d2092a
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jul 9 15:05:11 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 13 11:11:23 2021 -0500
fix multipath component detection for multiple holders
sysfs-based multipath component detection quit if a
device had multiple holders, and in this case would
fail to detect a device was an mpath component.
---
lib/device/dev-mpath.c | 169 ++++++++++++++++++++++++-------------------------
1 file changed, 83 insertions(+), 86 deletions(-)
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
index 1fb281d41..d3eaf42a3 100644
--- a/lib/device/dev-mpath.c
+++ b/lib/device/dev-mpath.c
@@ -240,38 +240,6 @@ static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, cons
return 0;
}
-static int _get_holder_name(const char *dir, char *name, int max_size)
-{
- struct dirent *d;
- DIR *dr;
- int r = 0;
-
- if (!(dr = opendir(dir))) {
- log_sys_error("opendir", dir);
- return 0;
- }
-
- *name = '\0';
- while ((d = readdir(dr))) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
- continue;
-
- /* There should be only one holder if it is multipath */
- if (*name) {
- r = 0;
- break;
- }
-
- strncpy(name, d->d_name, max_size);
- r = 1;
- }
-
- if (closedir(dr))
- log_sys_debug("closedir", dir);
-
- return r;
-}
-
#ifdef UDEV_SYNC_SUPPORT
static int _dev_is_mpath_component_udev(struct device *dev)
{
@@ -310,15 +278,18 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
const char *name; /* e.g. "sda" for "/dev/sda" */
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
- char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
- char holder_name[256]; /* e.g. "dm-1" */
+ char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
+ char *holder_name; /* e.g. "dm-1" */
const char *sysfs_dir = dm_sysfs_dir();
+ DIR *dr;
+ struct dirent *de;
int dev_major = MAJOR(dev->dev);
int dev_minor = MINOR(dev->dev);
int dm_dev_major;
int dm_dev_minor;
struct stat info;
dev_t primary_dev;
+ int is_mpath_component = 0;
/* multipathing is only known to exist for SCSI or NVME devices */
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
@@ -365,70 +336,96 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
}
/*
- * If holders dir contains an entry such as "dm-1", then this sets
- * holder_name to "dm-1".
- *
- * If holders dir is empty, return 0 (this is generally where
- * devs that are not mpath components return.)
+ * If any holder is a dm mpath device, then return 1;
*/
- if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
- return 0;
- if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
- log_warn("dm device path to check mpath is too long.");
+ if (!(dr = opendir(holders_path))) {
+ log_debug("Device %s has no holders dir", dev_name(dev));
return 0;
}
- /*
- * stat "/dev/dm-1" which is the holder of the dev we're checking
- * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
- */
- if (stat(dm_dev_path, &info)) {
- log_debug_devs("dev_is_mpath_component %s holder %s stat result %d",
- dev_name(dev), dm_dev_path, errno);
- return 0;
- }
- dm_dev_major = (int)MAJOR(info.st_rdev);
- dm_dev_minor = (int)MINOR(info.st_rdev);
+ while ((de = readdir(dr))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ /*
+ * holder_name is e.g. "dm-1"
+ * dm_dev_path is then e.g. "/dev/dm-1"
+ */
+ holder_name = de->d_name;
+
+ if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
+ log_warn("dm device path to check mpath is too long.");
+ continue;
+ }
+
+ /*
+ * stat "/dev/dm-1" which is the holder of the dev we're checking
+ * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
+ */
+ if (stat(dm_dev_path, &info)) {
+ log_debug_devs("dev_is_mpath_component %s holder %s stat result %d",
+ dev_name(dev), dm_dev_path, errno);
+ continue;
+ }
+ dm_dev_major = (int)MAJOR(info.st_rdev);
+ dm_dev_minor = (int)MINOR(info.st_rdev);
- if (dm_dev_major != dt->device_mapper_major) {
- log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
- dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
- return 0;
- }
+ if (dm_dev_major != dt->device_mapper_major) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
+ dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
+ continue;
+ }
- /*
- * Save the result of checking that "/dev/dm-1" is an mpath device
- * to avoid repeating it for each path component.
- * The minor number of "/dev/dm-1" is added to the hash table with
- * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
- * and const value 1 meaning that dm minor 1 is not a multipath dev.
- */
- if (_minor_hash_tab) {
- long look = (long) dm_hash_lookup_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor));
- if (look > 0) {
- log_debug_devs("dev_is_mpath_component %s holder %s %u:%u already checked as %sbeing mpath.",
- dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
- return (look > 1) ? 1 : 0;
+ /*
+ * A previous call may have checked if dm_dev_minor is mpath and saved
+ * the result in the hash table. If there's a saved result just use that.
+ *
+ * The minor number of "/dev/dm-1" is added to the hash table with
+ * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
+ * and const value 1 meaning that dm minor 1 is not a multipath dev.
+ */
+
+ if (_minor_hash_tab) {
+ long look = (long) dm_hash_lookup_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor));
+ if (look > 0) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %u:%u already checked as %sbeing mpath.",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
+
+ is_mpath_component = (look == 2);
+ goto out;
+ }
+
+ /* no saved result for dm_dev_minor, so check the uuid for it */
}
- }
- /*
- * Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
- * <holder_name> is a dm device with dm uuid prefix mpath-.
- * When true, <holder_name> will be something like "dm-1".
- */
- if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
- log_debug_devs("dev_is_mpath_component %s holder %s %u:%u ignore mpath component",
- dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
+ /*
+ * Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
+ * <holder_name> is a dm device with dm uuid prefix mpath-.
+ * When true, <holder_name> will be something like "dm-1".
+ */
+ if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %u:%u ignore mpath component",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
+
+ /* For future checks, save that the dm minor refers to mpath ("2" == is mpath) */
+ if (_minor_hash_tab)
+ (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
+
+ is_mpath_component = 1;
+ goto out;
+ }
+
+ /* For future checks, save that the dm minor does not refer to mpath ("1" == is not mpath) */
if (_minor_hash_tab)
- (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
- return 1;
+ (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
}
- if (_minor_hash_tab)
- (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
- return 0;
+ out:
+ if (closedir(dr))
+ stack;
+
+ return is_mpath_component;
}
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
2 years, 9 months
main - filter-usable: remove udev dev size check
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=deaf43d6f0341d8d15e...
Commit: deaf43d6f0341d8d15e8ff5ffd25d7e0a7d2092a
Parent: 90485650931d3fc04d00c92a729050c8743969e5
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jun 15 11:22:32 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 13 11:11:23 2021 -0500
filter-usable: remove udev dev size check
For the pv_min_size check, always use dev_get_size()
which is commonly used elsewhere, and don't bother
asking libudev for the device size when
external_device_info_source=udev.
---
lib/filters/filter-usable.c | 77 +++------------------------------------------
1 file changed, 4 insertions(+), 73 deletions(-)
diff --git a/lib/filters/filter-usable.c b/lib/filters/filter-usable.c
index 43a37afd0..062fb6c74 100644
--- a/lib/filters/filter-usable.c
+++ b/lib/filters/filter-usable.c
@@ -16,10 +16,6 @@
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/activate/activate.h"
-#ifdef UDEV_SYNC_SUPPORT
-#include <libudev.h>
-#include "lib/device/dev-ext-udev-constants.h"
-#endif
struct filter_data {
filter_mode_t mode;
@@ -28,7 +24,7 @@ struct filter_data {
static const char *_too_small_to_hold_pv_msg = "Too small to hold a PV";
-static int _native_check_pv_min_size(struct device *dev)
+static int _check_pv_min_size(struct device *dev)
{
uint64_t size;
int ret = 0;
@@ -50,61 +46,6 @@ out:
return ret;
}
-#ifdef UDEV_SYNC_SUPPORT
-static int _udev_check_pv_min_size(struct device *dev)
-{
- struct dev_ext *ext;
- const char *size_str;
- char *endp;
- uint64_t size;
-
- if (!(ext = dev_ext_get(dev)))
- return_0;
-
- if (!(size_str = udev_device_get_sysattr_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_SYSFS_ATTR_SIZE))) {
- log_debug_devs("%s: Skipping: failed to get size from sysfs [%s:%p]",
- dev_name(dev), dev_ext_name(dev), dev->ext.handle);
- return 0;
- }
-
- errno = 0;
- size = strtoull(size_str, &endp, 10);
- if (errno || !endp || *endp) {
- log_debug_devs("%s: Skipping: failed to parse size from sysfs [%s:%p]",
- dev_name(dev), dev_ext_name(dev), dev->ext.handle);
- return 0;
- }
-
- if (size < pv_min_size()) {
- log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
- _too_small_to_hold_pv_msg,
- dev_ext_name(dev), dev->ext.handle);
- return 0;
- }
-
- return 1;
-}
-#else
-static int _udev_check_pv_min_size(struct device *dev)
-{
- return 1;
-}
-#endif
-
-static int _check_pv_min_size(struct device *dev)
-{
- if (dev->ext.src == DEV_EXT_NONE)
- return _native_check_pv_min_size(dev);
-
- if (dev->ext.src == DEV_EXT_UDEV)
- return _udev_check_pv_min_size(dev);
-
- log_error(INTERNAL_ERROR "Missing hook for PV min size check "
- "using external device info source %s", dev_ext_name(dev));
-
- return 0;
-}
-
static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct filter_data *data = f->private;
@@ -156,19 +97,9 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
}
if (r) {
- /* check if the device is not too small to hold a PV */
- switch (mode) {
- case FILTER_MODE_NO_LVMETAD:
- /* fall through */
- case FILTER_MODE_PRE_LVMETAD:
- r = _check_pv_min_size(dev);
- if (!r)
- dev->filtered_flags |= DEV_FILTERED_MINSIZE;
- break;
- case FILTER_MODE_POST_LVMETAD:
- /* nothing to do here */
- break;
- }
+ r = _check_pv_min_size(dev);
+ if (!r)
+ dev->filtered_flags |= DEV_FILTERED_MINSIZE;
}
return r;
2 years, 9 months
main - devices: rework libudev usage
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=90485650931d3fc04d0...
Commit: 90485650931d3fc04d00c92a729050c8743969e5
Parent: db22a389cfb12eef77dfc2e1ce124ac83ed6c5a2
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jun 8 17:12:09 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 13 11:11:23 2021 -0500
devices: rework libudev usage
related to config settings:
obtain_device_info_from_udev (controls if lvm gets
a list of devices from readdir /dev or from libudev)
external_device_info_source (controls if lvm asks
libudev for device information)
. Make the obtain_device_list_from_udev setting
affect only the choice of readdir /dev vs libudev.
The setting no longer controls if udev is used for
device type checks.
. Change obtain_device_list_from_udev default to 0.
This helps avoid boot timeouts due to slow libudev
queries, avoids reported failures from
udev_enumerate_scan_devices, and avoids delays from
"device not initialized in udev database" errors.
Even without errors, for a system booting with 1024 PVs,
lvm2-pvscan times improve from about 100 sec to 15 sec,
and the pvscan command from about 64 sec to about 4 sec.
. For external_device_info_source="none", remove all
libudev device info queries, and use only lvm
native device info.
. For external_device_info_source="udev", first check
lvm native device info, then check libudev info.
. Remove sleep/retry loop when attempting libudev
queries for device info. udev info will simply
be skipped if it's not immediately available.
. Only set up a libdev connection if it will be used by
obtain_device_list_from_udev/external_device_info_source.
. For native multipath component detection, use
/etc/multipath/wwids. If a device has a wwid
matching an entry in the wwids file, then it's
considered a multipath component. This is
necessary to natively detect multipath
components when the mpath device is not set up.
---
lib/Makefile.in | 1 +
lib/cache/lvmcache.c | 6 +-
lib/commands/toolcontext.c | 56 ++---
lib/config/config_settings.h | 24 +-
lib/config/defaults.h | 4 +-
lib/device/dev-luks.c | 2 +-
lib/device/dev-md.c | 75 ++----
lib/device/dev-mpath.c | 486 +++++++++++++++++++++++++++++++++++++++
lib/device/dev-swap.c | 2 +-
lib/device/dev-type.c | 197 +++-------------
lib/device/dev-type.h | 11 +-
lib/device/device.h | 3 +
lib/device/device_id.c | 38 +--
lib/device/device_id.h | 2 +
lib/filters/filter-composite.c | 25 +-
lib/filters/filter-md.c | 2 +-
lib/filters/filter-mpath.c | 362 +----------------------------
lib/filters/filter-partitioned.c | 4 +-
lib/filters/filter.h | 2 +-
lib/misc/lvm-wrappers.c | 14 +-
tools/lvmcmdline.c | 14 +-
tools/pvscan.c | 12 +-
22 files changed, 659 insertions(+), 683 deletions(-)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 900ae2f83..8b3eac60a 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -34,6 +34,7 @@ SOURCES =\
device/dev-ext.c \
device/dev-io.c \
device/dev-md.c \
+ device/dev-mpath.c \
device/dev-swap.c \
device/dev-type.c \
device/dev-luks.c \
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index e15b6ce85..f5df5e10c 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -692,7 +692,7 @@ next:
*/
info = lvmcache_info_from_pvid(pvid, NULL, 0);
- if (info && dev_is_md_component(info->dev, NULL, 1)) {
+ if (info && dev_is_md_component(cmd, info->dev, NULL, 1)) {
/* does not go in del_cache_devs which become unused_duplicates */
log_debug_cache("PV %s drop MD component from scan selection %s", pvid, dev_name(info->dev));
lvmcache_del(info);
@@ -700,7 +700,7 @@ next:
}
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
- if (dev_is_md_component(devl->dev, NULL, 1)) {
+ if (dev_is_md_component(cmd, devl->dev, NULL, 1)) {
log_debug_cache("PV %s drop MD component from scan duplicates %s", pvid, dev_name(devl->dev));
dm_list_del(&devl->list);
}
@@ -1204,7 +1204,7 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
(unsigned long long)pvsize, (unsigned long long)devsize,
device_hint ?: "none", dev_name(dev));
- if (dev_is_md_component(dev, NULL, 1)) {
+ if (dev_is_md_component(cmd, dev, NULL, 1)) {
log_debug("dropping PV from md component %s", dev_name(dev));
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
/* lvmcache_del will also delete vginfo if info was last one */
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 742bdd9c2..ecd50dbf7 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -402,15 +402,12 @@ static void _init_logging(struct cmd_context *cmd)
reset_lvm_errno(1);
}
-static int _check_disable_udev(const char *msg) {
+static int _check_disable_udev(const char *msg)
+{
if (getenv("DM_DISABLE_UDEV")) {
- log_very_verbose("DM_DISABLE_UDEV environment variable set. "
- "Overriding configuration to use "
- "udev_rules=0, udev_sync=0, verify_udev_operations=1.");
- if (udev_is_running())
- log_warn("Udev is running and DM_DISABLE_UDEV environment variable is set. "
- "Bypassing udev, LVM will %s.", msg);
-
+ log_very_verbose("DM_DISABLE_UDEV environment variable set.");
+ log_very_verbose("Overriding configuration to use udev_rules=0, udev_sync=0, verify_udev_operations=1.");
+ log_very_verbose("LVM will %s.", msg);
return 1;
}
@@ -563,7 +560,7 @@ static int _init_system_id(struct cmd_context *cmd)
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
- const char *dev_ext_info_src;
+ const char *dev_ext_info_src = NULL;
const char *read_ahead;
struct stat st;
const struct dm_config_node *cn;
@@ -597,15 +594,26 @@ static int _process_config(struct cmd_context *cmd)
#endif
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
- if (dev_ext_info_src && !strcmp(dev_ext_info_src, "none"))
- init_external_device_info_source(DEV_EXT_NONE);
- else if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev"))
- init_external_device_info_source(DEV_EXT_UDEV);
- else {
- log_error("Invalid external device info source specification.");
- return 0;
+
+ if (dev_ext_info_src &&
+ strcmp(dev_ext_info_src, "none") &&
+ strcmp(dev_ext_info_src, "udev")) {
+ log_warn("WARNING: unknown external device info source, using none.");
+ dev_ext_info_src = NULL;
}
+ if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev")) {
+ if (udev_init_library_context()) {
+ init_external_device_info_source(DEV_EXT_UDEV);
+ } else {
+ log_warn("WARNING: failed to init udev for external device info, using none.");
+ dev_ext_info_src = NULL;
+ }
+ }
+
+ if (!dev_ext_info_src || !strcmp(dev_ext_info_src, "none"))
+ init_external_device_info_source(DEV_EXT_NONE);
+
/* proc dir */
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
@@ -1018,16 +1026,10 @@ static int _init_dev_cache(struct cmd_context *cmd)
if (!dev_cache_init(cmd))
return_0;
- /*
- * Override existing config and hardcode device_list_from_udev = 0 if:
- * - udev is not running
- * - udev is disabled using DM_DISABLE_UDEV environment variable
- */
- if (_check_disable_udev("obtain device list by scanning device directory"))
- device_list_from_udev = 0;
- else
- device_list_from_udev = udev_is_running() ?
- find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL) : 0;
+ if ((device_list_from_udev = find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL))) {
+ if (!udev_init_library_context())
+ device_list_from_udev = 0;
+ }
init_obtain_device_list_from_udev(device_list_from_udev);
@@ -1182,7 +1184,7 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
nr_filt++;
}
- if (!(composite = composite_filter_create(nr_filt, 1, filters)))
+ if (!(composite = composite_filter_create(nr_filt, filters)))
goto_bad;
return composite;
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index d66a9a3a7..fa87bea23 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -238,22 +238,10 @@ cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", de
"udev support for this setting to apply.\n")
cfg(devices_external_device_info_source_CFG, "external_device_info_source", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE, vsn(2, 2, 116), NULL, 0, NULL,
- "Select an external device information source.\n"
- "Some information may already be available in the system and LVM can\n"
- "use this information to determine the exact type or use of devices it\n"
- "processes. Using an existing external device information source can\n"
- "speed up device processing as LVM does not need to run its own native\n"
- "routines to acquire this information. For example, this information\n"
- "is used to drive LVM filtering like MD component detection, multipath\n"
- "component detection, partition detection and others.\n"
- "#\n"
- "Accepted values:\n"
- " none\n"
- " No external device information source is used.\n"
- " udev\n"
- " Reuse existing udev database records. Applicable only if LVM is\n"
- " compiled with udev support.\n"
- "#\n")
+ "Enable device information from udev.\n"
+ "If set to \"udev\", lvm will supplement its own native device information\n"
+ "with information from libudev. This can potentially improve the detection\n"
+ "of MD component devices and multipath component devices.\n")
cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_HINTS, vsn(2, 3, 2), NULL, 0, NULL,
"Use a local file to remember which devices have PVs on them.\n"
@@ -393,6 +381,10 @@ cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEF
cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL, 0, NULL,
"Ignore devices that are components of DM multipath devices.\n")
+cfg(devices_multipath_wwids_file_CFG, "multipath_wwids_file", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_WWIDS_FILE, vsn(2, 3, 13), NULL, 0, NULL,
+ "The path to the multipath wwids file used for multipath component detection.\n"
+ "Set this to an empty string to disable the use of the multipath wwids file.\n")
+
cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL, 0, NULL,
"Enable detection and exclusion of MD component devices.\n"
"An MD component device is a block device that MD uses as part\n"
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index d5e5b3b1a..66eece53a 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -42,7 +42,7 @@
#define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_SYSTEM_ID_SOURCE "none"
-#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
+#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 0
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
#define DEFAULT_SYSFS_SCAN 1
#define DEFAULT_MD_COMPONENT_DETECTION 1
@@ -327,4 +327,6 @@
#define DEFAULT_SEARCH_FOR_DEVNAMES "auto"
+#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
+
#endif /* _LVM_DEFAULTS_H */
diff --git a/lib/device/dev-luks.c b/lib/device/dev-luks.c
index 344a55432..d8c422519 100644
--- a/lib/device/dev-luks.c
+++ b/lib/device/dev-luks.c
@@ -18,7 +18,7 @@
#define LUKS_SIGNATURE "LUKS\xba\xbe"
#define LUKS_SIGNATURE_SIZE 6
-int dev_is_luks(struct device *dev, uint64_t *offset_found, int full)
+int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
char buf[LUKS_SIGNATURE_SIZE];
int ret = -1;
diff --git a/lib/device/dev-md.c b/lib/device/dev-md.c
index 6ddeb5b9e..4debe9e99 100644
--- a/lib/device/dev-md.c
+++ b/lib/device/dev-md.c
@@ -17,6 +17,7 @@
#include "lib/device/dev-type.h"
#include "lib/mm/xlate.h"
#include "lib/misc/crc.h"
+#include "lib/commands/toolcontext.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h> /* for MD detection using udev db records */
#include "lib/device/dev-ext-udev-constants.h"
@@ -144,25 +145,16 @@ static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint
return 0;
}
-/*
- * _udev_dev_is_md_component() only works if
- * external_device_info_source="udev"
- *
- * but
- *
- * udev_dev_is_md_component() in dev-type.c only works if
- * obtain_device_list_from_udev=1
- *
- * and neither of those config setting matches very well
- * with what we're doing here.
- */
-
#ifdef UDEV_SYNC_SUPPORT
-static int _udev_dev_is_md_component(struct device *dev)
+static int _dev_is_md_component_udev(struct device *dev)
{
const char *value;
struct dev_ext *ext;
+ /*
+ * external_device_info_source="udev" enables these udev checks.
+ * external_device_info_source="none" disables them.
+ */
if (!(ext = dev_ext_get(dev)))
return_0;
@@ -172,7 +164,7 @@ static int _udev_dev_is_md_component(struct device *dev)
return !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID);
}
#else
-static int _udev_dev_is_md_component(struct device *dev)
+static int _dev_is_md_component_udev(struct device *dev)
{
return 0;
}
@@ -181,13 +173,16 @@ static int _udev_dev_is_md_component(struct device *dev)
/*
* Returns -1 on error
*/
-static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
+static int _dev_is_md_component_native(struct device *dev, uint64_t *offset_found, int full)
{
uint64_t size, sb_offset = 0;
int ret;
- if (!scan_bcache)
- return -EAGAIN;
+ /* i/o layer has not been set up */
+ if (!scan_bcache) {
+ log_error(INTERNAL_ERROR "dev_is_md_component_native requires io layer.");
+ return -1;
+ }
if (!dev_get_size(dev, &size)) {
stack;
@@ -295,41 +290,20 @@ out:
return ret;
}
-int dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
+int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
- int ret;
+ if (_dev_is_md_component_native(dev, offset_found, full) == 1)
+ goto found;
- /*
- * If non-native device status source is selected, use it
- * only if offset_found is not requested as this
- * information is not in udev db.
- */
- if ((dev->ext.src == DEV_EXT_NONE) || offset_found) {
- ret = _native_dev_is_md_component(dev, offset_found, full);
-
- if (!full) {
- if (!ret || (ret == -EAGAIN)) {
- if (udev_dev_is_md_component(dev))
- ret = 1;
- }
- }
- if (ret && (ret != -EAGAIN))
- dev->flags |= DEV_IS_MD_COMPONENT;
- return ret;
- }
-
- if (dev->ext.src == DEV_EXT_UDEV) {
- ret = _udev_dev_is_md_component(dev);
- if (ret && (ret != -EAGAIN))
- dev->flags |= DEV_IS_MD_COMPONENT;
- return ret;
+ if (external_device_info_source() == DEV_EXT_UDEV) {
+ if (_dev_is_md_component_udev(dev) == 1)
+ goto found;
}
+ return 0;
- log_error(INTERNAL_ERROR "Missing hook for MD device recognition "
- "using external device info source %s", dev_ext_name(dev));
-
- return -1;
-
+found:
+ dev->flags |= DEV_IS_MD_COMPONENT;
+ return 1;
}
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
@@ -552,7 +526,8 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev)
#else
-int dev_is_md_component(struct device *dev __attribute__((unused)),
+int dev_is_md_component(struct cmd_context *cmd __attribute__((unused)),
+ struct device *dev __attribute__((unused)),
uint64_t *sb __attribute__((unused)))
{
return 0;
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
new file mode 100644
index 000000000..1fb281d41
--- /dev/null
+++ b/lib/device/dev-mpath.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "base/memory/zalloc.h"
+#include "lib/misc/lib.h"
+#include "lib/activate/activate.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/device/device_id.h"
+#ifdef UDEV_SYNC_SUPPORT
+#include <libudev.h>
+#include "lib/device/dev-ext-udev-constants.h"
+#endif
+
+#include <dirent.h>
+
+#define MPATH_PREFIX "mpath-"
+
+/*
+ * This hash table keeps track of whether a given dm device
+ * is a mpath device or not.
+ *
+ * If dm-3 is an mpath device, then the constant "2" is stored in
+ * the hash table with the key of the dm minor number ("3" for dm-3).
+ * If dm-3 is not an mpath device, then the constant "1" is stored in
+ * the hash table with the key of the dm minor number.
+ */
+static struct dm_pool *_hash_mem;
+static struct dm_hash_table *_minor_hash_tab;
+static struct dm_hash_table *_wwid_hash_tab;
+
+#define MAX_WWID_LINE 512
+
+/*
+ * do we need to check the multipath.conf blacklist?
+ */
+
+static void _read_wwid_file(const char *config_wwids_file)
+{
+ FILE *fp;
+ char line[MAX_WWID_LINE];
+ char *wwid, *p;
+ int count = 0;
+
+ if (config_wwids_file[0] != '/') {
+ log_print("Ignoring unknown multipath_wwids_file.");
+ return;
+ }
+
+ if (!(fp = fopen(config_wwids_file, "r"))) {
+ log_debug("multipath wwids file not found");
+ return;
+ }
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (line[0] == '#')
+ continue;
+
+ wwid = line;
+
+ if (line[0] == '/')
+ wwid++;
+
+ /* skip the initial '3' */
+ wwid++;
+
+ if ((p = strchr(wwid, '/')))
+ *p = '\0';
+
+ (void) dm_hash_insert_binary(_wwid_hash_tab, wwid, strlen(wwid), (void*)1);
+ count++;
+ }
+
+ if (fclose(fp))
+ stack;
+
+ log_debug("multipath wwids read %d from %s", count, config_wwids_file);
+}
+
+int dev_mpath_init(const char *config_wwids_file)
+{
+ struct dm_pool *mem;
+ struct dm_hash_table *minor_tab;
+ struct dm_hash_table *wwid_tab;
+
+ if (!(mem = dm_pool_create("mpath", 256))) {
+ log_error("mpath pool creation failed.");
+ return 0;
+ }
+
+ if (!(minor_tab = dm_hash_create(110))) {
+ log_error("mpath hash table creation failed.");
+ dm_pool_destroy(mem);
+ return 0;
+ }
+
+ _hash_mem = mem;
+ _minor_hash_tab = minor_tab;
+
+ /* multipath_wwids_file="" disables the use of the file */
+ if (config_wwids_file && !strlen(config_wwids_file)) {
+ log_debug("multipath wwids file disabled.");
+ return 1;
+ }
+
+ if (!(wwid_tab = dm_hash_create(110))) {
+ log_error("mpath hash table creation failed.");
+ dm_hash_destroy(_minor_hash_tab);
+ dm_pool_destroy(_hash_mem);
+ _minor_hash_tab = NULL;
+ _hash_mem = NULL;
+ return 0;
+ }
+
+ _wwid_hash_tab = wwid_tab;
+
+ _read_wwid_file(config_wwids_file);
+
+ return 1;
+}
+
+void dev_mpath_exit(void)
+{
+ if (_minor_hash_tab)
+ dm_hash_destroy(_minor_hash_tab);
+ if (_wwid_hash_tab)
+ dm_hash_destroy(_wwid_hash_tab);
+ if (_hash_mem)
+ dm_pool_destroy(_hash_mem);
+
+ _minor_hash_tab = NULL;
+ _wwid_hash_tab = NULL;
+ _hash_mem = NULL;
+}
+
+
+/*
+ * given "/dev/foo" return "foo"
+ */
+static const char *_get_sysfs_name(struct device *dev)
+{
+ const char *name;
+
+ if (!(name = strrchr(dev_name(dev), '/'))) {
+ log_error("Cannot find '/' in device name.");
+ return NULL;
+ }
+ name++;
+
+ if (!*name) {
+ log_error("Device name is not valid.");
+ return NULL;
+ }
+
+ return name;
+}
+
+/*
+ * given major:minor
+ * readlink translates /sys/dev/block/major:minor to /sys/.../foo
+ * from /sys/.../foo return "foo"
+ */
+static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
+ char *buf, size_t buf_size)
+{
+ const char *name;
+ char path[PATH_MAX];
+ int size;
+
+ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
+ (int) MAJOR(devno), (int) MINOR(devno)) < 0) {
+ log_error("Sysfs path string is too long.");
+ return NULL;
+ }
+
+ if ((size = readlink(path, buf, buf_size - 1)) < 0) {
+ log_sys_error("readlink", path);
+ return NULL;
+ }
+ buf[size] = '\0';
+
+ if (!(name = strrchr(buf, '/'))) {
+ log_error("Cannot find device name in sysfs path.");
+ return NULL;
+ }
+ name++;
+
+ return name;
+}
+
+static int _get_sysfs_string(const char *path, char *buffer, int max_size)
+{
+ FILE *fp;
+ int r = 0;
+
+ if (!(fp = fopen(path, "r"))) {
+ log_sys_error("fopen", path);
+ return 0;
+ }
+
+ if (!fgets(buffer, max_size, fp))
+ log_sys_error("fgets", path);
+ else
+ r = 1;
+
+ if (fclose(fp))
+ log_sys_error("fclose", path);
+
+ return r;
+}
+
+static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
+{
+ char path[PATH_MAX];
+ char buffer[128];
+
+ if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
+ log_error("Sysfs path string is too long.");
+ return 0;
+ }
+
+ buffer[0] = '\0';
+
+ if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
+ return_0;
+
+ if (!strncmp(buffer, MPATH_PREFIX, 6))
+ return 1;
+
+ return 0;
+}
+
+static int _get_holder_name(const char *dir, char *name, int max_size)
+{
+ struct dirent *d;
+ DIR *dr;
+ int r = 0;
+
+ if (!(dr = opendir(dir))) {
+ log_sys_error("opendir", dir);
+ return 0;
+ }
+
+ *name = '\0';
+ while ((d = readdir(dr))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ /* There should be only one holder if it is multipath */
+ if (*name) {
+ r = 0;
+ break;
+ }
+
+ strncpy(name, d->d_name, max_size);
+ r = 1;
+ }
+
+ if (closedir(dr))
+ log_sys_debug("closedir", dir);
+
+ return r;
+}
+
+#ifdef UDEV_SYNC_SUPPORT
+static int _dev_is_mpath_component_udev(struct device *dev)
+{
+ const char *value;
+ struct dev_ext *ext;
+
+ /*
+ * external_device_info_source="udev" enables these udev checks.
+ * external_device_info_source="none" disables them.
+ */
+
+ if (!(ext = dev_ext_get(dev)))
+ return_0;
+
+ value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
+ if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
+ return 1;
+
+ value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
+ if (value && !strcmp(value, "1"))
+ return 1;
+
+ return 0;
+}
+#else
+static int _dev_is_mpath_component_udev(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev)
+{
+ struct dev_types *dt = cmd->dev_types;
+ const char *part_name;
+ const char *name; /* e.g. "sda" for "/dev/sda" */
+ char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
+ char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
+ char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
+ char holder_name[256]; /* e.g. "dm-1" */
+ const char *sysfs_dir = dm_sysfs_dir();
+ int dev_major = MAJOR(dev->dev);
+ int dev_minor = MINOR(dev->dev);
+ int dm_dev_major;
+ int dm_dev_minor;
+ struct stat info;
+ dev_t primary_dev;
+
+ /* multipathing is only known to exist for SCSI or NVME devices */
+ if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
+ return 0;
+
+ switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
+
+ case 2: /* The dev is partition. */
+ part_name = dev_name(dev); /* name of original dev for log_debug msg */
+
+ /* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
+ if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
+ return_0;
+
+ log_debug_devs("%s: Device is a partition, using primary "
+ "device %s for mpath component detection",
+ part_name, name);
+ break;
+
+ case 1: /* The dev is already a primary dev. Just continue with the dev. */
+
+ /* gets "foo" for "/dev/foo" */
+ if (!(name = _get_sysfs_name(dev)))
+ return_0;
+ break;
+
+ default: /* 0, error. */
+ log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
+ return 0;
+ }
+
+ if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
+ log_warn("Sysfs path to check mpath is too long.");
+ return 0;
+ }
+
+ /* also will filter out partitions */
+ if (stat(holders_path, &info))
+ return 0;
+
+ if (!S_ISDIR(info.st_mode)) {
+ log_warn("Path %s is not a directory.", holders_path);
+ return 0;
+ }
+
+ /*
+ * If holders dir contains an entry such as "dm-1", then this sets
+ * holder_name to "dm-1".
+ *
+ * If holders dir is empty, return 0 (this is generally where
+ * devs that are not mpath components return.)
+ */
+ if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
+ return 0;
+
+ if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
+ log_warn("dm device path to check mpath is too long.");
+ return 0;
+ }
+
+ /*
+ * stat "/dev/dm-1" which is the holder of the dev we're checking
+ * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
+ */
+ if (stat(dm_dev_path, &info)) {
+ log_debug_devs("dev_is_mpath_component %s holder %s stat result %d",
+ dev_name(dev), dm_dev_path, errno);
+ return 0;
+ }
+ dm_dev_major = (int)MAJOR(info.st_rdev);
+ dm_dev_minor = (int)MINOR(info.st_rdev);
+
+ if (dm_dev_major != dt->device_mapper_major) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
+ dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
+ return 0;
+ }
+
+ /*
+ * Save the result of checking that "/dev/dm-1" is an mpath device
+ * to avoid repeating it for each path component.
+ * The minor number of "/dev/dm-1" is added to the hash table with
+ * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
+ * and const value 1 meaning that dm minor 1 is not a multipath dev.
+ */
+ if (_minor_hash_tab) {
+ long look = (long) dm_hash_lookup_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor));
+ if (look > 0) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %u:%u already checked as %sbeing mpath.",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
+ return (look > 1) ? 1 : 0;
+ }
+ }
+
+ /*
+ * Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
+ * <holder_name> is a dm device with dm uuid prefix mpath-.
+ * When true, <holder_name> will be something like "dm-1".
+ */
+ if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
+ log_debug_devs("dev_is_mpath_component %s holder %s %u:%u ignore mpath component",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
+ if (_minor_hash_tab)
+ (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
+ return 1;
+ }
+
+ if (_minor_hash_tab)
+ (void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
+ return 0;
+}
+
+static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
+{
+ char sysbuf[PATH_MAX] = { 0 };
+ char *wwid;
+ long look;
+
+ if (!_wwid_hash_tab)
+ return 0;
+
+ if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
+ return 0;
+
+ if (!sysbuf[0])
+ return 0;
+
+ /*
+ * sysfs prints wwid as <typestr>.<value>
+ * multipath wwid uses '3'<value>
+ * does "<typestr>." always correspond to "3"?
+ */
+ if (!(wwid = strchr(sysbuf, '.')))
+ return 0;
+
+ /* skip the type and dot, just as '3' was skipped from wwids entry */
+ wwid++;
+
+ look = (long) dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid));
+
+ if (look) {
+ log_debug_devs("dev_is_mpath_component %s multipath wwid %s", dev_name(dev), wwid);
+ return 1;
+ }
+ return 0;
+}
+
+int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev)
+{
+ if (_dev_is_mpath_component_sysfs(cmd, dev) == 1)
+ goto found;
+
+ if (_dev_in_wwid_file(cmd, dev))
+ goto found;
+
+ if (external_device_info_source() == DEV_EXT_UDEV) {
+ if (_dev_is_mpath_component_udev(dev) == 1)
+ goto found;
+ }
+
+ return 0;
+found:
+ return 1;
+}
+
diff --git a/lib/device/dev-swap.c b/lib/device/dev-swap.c
index 564bb58ec..1d2a4c9d1 100644
--- a/lib/device/dev-swap.c
+++ b/lib/device/dev-swap.c
@@ -35,7 +35,7 @@ static int _swap_detect_signature(const char *buf)
return 0;
}
-int dev_is_swap(struct device *dev, uint64_t *offset_found, int full)
+int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
{
char buf[10];
uint64_t size;
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 3c6dd1693..067a9ffad 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -621,12 +621,16 @@ static int _has_partition_table(struct device *dev)
}
#ifdef UDEV_SYNC_SUPPORT
-static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
+static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
{
struct dev_ext *ext;
struct udev_device *device;
const char *value;
+ /*
+ * external_device_info_source="udev" enables these udev checks.
+ * external_device_info_source="none" disables them.
+ */
if (!(ext = dev_ext_get(dev)))
return_0;
@@ -657,21 +661,20 @@ static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
return !strcmp(value, DEV_EXT_UDEV_DEVTYPE_DISK);
}
#else
-static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
+static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
{
return 0;
}
#endif
-static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
+static int _dev_is_partitioned_native(struct dev_types *dt, struct device *dev)
{
int r;
- if (!scan_bcache)
- return -EAGAIN;
-
- if (!_is_partitionable(dt, dev))
- return 0;
+ if (!scan_bcache) {
+ log_error(INTERNAL_ERROR "dev_is_partitioned_native requires i/o.");
+ return -1;
+ }
/* Unpartitioned DASD devices are not supported. */
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
@@ -682,16 +685,20 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
return r;
}
-int dev_is_partitioned(struct dev_types *dt, struct device *dev)
+int dev_is_partitioned(struct cmd_context *cmd, struct device *dev)
{
- if (dev->ext.src == DEV_EXT_NONE)
- return _native_dev_is_partitioned(dt, dev);
+ struct dev_types *dt = cmd->dev_types;
- if (dev->ext.src == DEV_EXT_UDEV)
- return _udev_dev_is_partitioned(dt, dev);
+ if (!_is_partitionable(dt, dev))
+ return 0;
- log_error(INTERNAL_ERROR "Missing hook for partition table recognition "
- "using external device info source %s", dev_ext_name(dev));
+ if (_dev_is_partitioned_native(dt, dev) == 1)
+ return 1;
+
+ if (external_device_info_source() == DEV_EXT_UDEV) {
+ if (_dev_is_partitioned_udev(dt, dev) == 1)
+ return 1;
+ }
return 0;
}
@@ -1003,14 +1010,14 @@ out:
#endif /* BLKID_WIPING_SUPPORT */
-static int _wipe_signature(struct device *dev, const char *type, const char *name,
+static int _wipe_signature(struct cmd_context *cmd, struct device *dev, const char *type, const char *name,
int wipe_len, int yes, force_t force, int *wiped,
- int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found, int full))
+ int (*signature_detection_fn)(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full))
{
int wipe;
uint64_t offset_found = 0;
- wipe = signature_detection_fn(dev, &offset_found, 1);
+ wipe = signature_detection_fn(cmd, dev, &offset_found, 1);
if (wipe == -1) {
log_error("Fatal error while trying to detect %s on %s.",
type, name);
@@ -1038,7 +1045,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
return 1;
}
-static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
+static int _wipe_known_signatures_with_lvm(struct cmd_context *cmd, struct device *dev, const char *name,
uint32_t types_to_exclude __attribute__((unused)),
uint32_t types_no_prompt __attribute__((unused)),
int yes, force_t force, int *wiped)
@@ -1049,9 +1056,9 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
wiped = &wiped_tmp;
*wiped = 0;
- if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
- !_wipe_signature(dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
- !_wipe_signature(dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
+ if (!_wipe_signature(cmd, dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
+ !_wipe_signature(cmd, dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
+ !_wipe_signature(cmd, dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
return 0;
return 1;
@@ -1076,7 +1083,7 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
"while LVM is not compiled with blkid wiping support.");
log_warn("WARNING: Falling back to native LVM signature detection.");
}
- return _wipe_known_signatures_with_lvm(dev, name,
+ return _wipe_known_signatures_with_lvm(cmd, dev, name,
types_to_exclude,
types_no_prompt,
yes, force, wiped);
@@ -1266,147 +1273,3 @@ int dev_is_pmem(struct dev_types *dt, struct device *dev)
}
#endif
-#ifdef UDEV_SYNC_SUPPORT
-
-/*
- * Udev daemon usually has 30s timeout to process each event by default.
- * But still, that value can be changed in udev configuration and we
- * don't have libudev API to read the actual timeout value used.
- */
-
-/* FIXME: Is this long enough to wait for udev db to get initialized?
- *
- * Take also into consideration that this check is done for each
- * device that is scanned so we don't want to wait for a long time
- * if there's something wrong with udev, e.g. timeouts! With current
- * libudev API, we can't recognize whether the event processing has
- * not finished yet and it's still being processed or whether it has
- * failed already due to timeout in udev - in both cases the
- * udev_device_get_is_initialized returns 0.
- */
-#define UDEV_DEV_IS_COMPONENT_ITERATION_COUNT 100
-#define UDEV_DEV_IS_COMPONENT_USLEEP 100000
-
-static struct udev_device *_udev_get_dev(struct device *dev)
-{
- struct udev *udev_context = udev_get_library_context();
- struct udev_device *udev_device = NULL;
- int initialized = 0;
- unsigned i = 0;
-
- if (!udev_context) {
- log_warn("WARNING: No udev context available to check if device %s is multipath component.", dev_name(dev));
- return NULL;
- }
-
- while (1) {
- if (i >= UDEV_DEV_IS_COMPONENT_ITERATION_COUNT)
- break;
-
- if (udev_device)
- udev_device_unref(udev_device);
-
- if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', dev->dev))) {
- log_warn("WARNING: Failed to get udev device handler for device %s.", dev_name(dev));
- return NULL;
- }
-
-#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
- if ((initialized = udev_device_get_is_initialized(udev_device)))
- break;
-#else
- if ((initialized = (udev_device_get_property_value(udev_device, DEV_EXT_UDEV_DEVLINKS) != NULL)))
- break;
-#endif
-
- log_debug("Device %s not initialized in udev database (%u/%u, %u microseconds).", dev_name(dev),
- i + 1, UDEV_DEV_IS_COMPONENT_ITERATION_COUNT,
- i * UDEV_DEV_IS_COMPONENT_USLEEP);
-
- if (!udev_sleeping())
- break;
-
- usleep(UDEV_DEV_IS_COMPONENT_USLEEP);
- i++;
- }
-
- if (!initialized) {
- log_warn("WARNING: Device %s not initialized in udev database even after waiting %u microseconds.",
- dev_name(dev), i * UDEV_DEV_IS_COMPONENT_USLEEP);
- goto out;
- }
-
-out:
- return udev_device;
-}
-
-int udev_dev_is_mpath_component(struct device *dev)
-{
- struct udev_device *udev_device;
- const char *value;
- int ret = 0;
-
- if (!obtain_device_list_from_udev())
- return 0;
-
- if (!(udev_device = _udev_get_dev(dev)))
- return 0;
-
- value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
- if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH)) {
- log_debug("Device %s is multipath component based on blkid variable in udev db (%s=\"%s\").",
- dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
- ret = 1;
- goto out;
- }
-
- value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
- if (value && !strcmp(value, "1")) {
- log_debug("Device %s is multipath component based on multipath variable in udev db (%s=\"%s\").",
- dev_name(dev), DEV_EXT_UDEV_MPATH_DEVICE_PATH, value);
- ret = 1;
- goto out;
- }
-out:
- udev_device_unref(udev_device);
- return ret;
-}
-
-int udev_dev_is_md_component(struct device *dev)
-{
- struct udev_device *udev_device;
- const char *value;
- int ret = 0;
-
- if (!obtain_device_list_from_udev())
- return 0;
-
- if (!(udev_device = _udev_get_dev(dev)))
- return 0;
-
- value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
- if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID)) {
- log_debug("Device %s is md raid component based on blkid variable in udev db (%s=\"%s\").",
- dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
- dev->flags |= DEV_IS_MD_COMPONENT;
- ret = 1;
- goto out;
- }
-out:
- udev_device_unref(udev_device);
- return ret;
-}
-
-#else
-
-int udev_dev_is_mpath_component(struct device *dev)
-{
- return 0;
-}
-
-int udev_dev_is_md_component(struct device *dev)
-{
- return 0;
-}
-
-#endif
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index 097be72cd..f3521c6e0 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -57,12 +57,11 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev);
int major_is_scsi_device(struct dev_types *dt, int major);
/* Signature/superblock recognition with position returned where found. */
-int dev_is_md_component(struct device *dev, uint64_t *sb, int full);
-int dev_is_swap(struct device *dev, uint64_t *signature, int full);
-int dev_is_luks(struct device *dev, uint64_t *signature, int full);
+int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *sb, int full);
+int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev);
+int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
+int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
int dasd_is_cdl_formatted(struct device *dev);
-int udev_dev_is_mpath_component(struct device *dev);
-int udev_dev_is_md_component(struct device *dev);
int dev_is_lvm1(struct device *dev, char *buf, int buflen);
int dev_is_pool(struct device *dev, char *buf, int buflen);
@@ -81,7 +80,7 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev);
/* Partitioning */
int major_max_partitions(struct dev_types *dt, int major);
-int dev_is_partitioned(struct dev_types *dt, struct device *dev);
+int dev_is_partitioned(struct cmd_context *cmd, struct device *dev);
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result);
int dev_get_partition_number(struct device *dev, int *num);
diff --git a/lib/device/device.h b/lib/device/device.h
index ca8b3cdd8..a30a1288b 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -205,4 +205,7 @@ void dev_destroy_file(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
+int dev_mpath_init(const char *config_wwids_file);
+void dev_mpath_exit(void);
+
#endif
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index 87a46a73a..baba48c05 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -180,7 +180,7 @@ void free_dids(struct dm_list *ids)
}
}
-static int _read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
+int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
{
char path[PATH_MAX];
dev_t devt = dev->dev;
@@ -246,7 +246,7 @@ static int _dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
- if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
+ if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "mpath-"))
@@ -265,7 +265,7 @@ static int _dev_has_crypt_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
- if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
+ if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "CRYPT-"))
@@ -284,7 +284,7 @@ static int _dev_has_lvmlv_uuid(struct cmd_context *cmd, struct device *dev, cons
char sysbuf[PATH_MAX] = { 0 };
const char *idname;
- if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
+ if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
return 0;
if (!_dm_uuid_has_prefix(sysbuf, "LVM-"))
@@ -304,10 +304,10 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
const char *idname = NULL;
if (idtype == DEV_ID_TYPE_SYS_WWID) {
- _read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
if (!sysbuf[0])
- _read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
/* scsi_debug wwid begins "t10.Linux scsi_debug ..." */
if (strstr(sysbuf, "scsi_debug"))
@@ -319,22 +319,22 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
}
else if (idtype == DEV_ID_TYPE_SYS_SERIAL)
- _read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_MPATH_UUID)
- _read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_CRYPT_UUID)
- _read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_LVMLV_UUID)
- _read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_MD_UUID)
- _read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
else if (idtype == DEV_ID_TYPE_LOOP_FILE) {
- _read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
+ read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
/* if backing file is deleted, fall back to devname */
if (strstr(sysbuf, "(deleted)"))
sysbuf[0] = '\0';
@@ -372,17 +372,17 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
return 1;
}
- if (_read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
+ if (read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 1;
- if (_read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
+ if (read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
return 1;
- if (_read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
+ if (read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
return 1;
if ((MAJOR(dev->dev) == cmd->dev_types->device_mapper_major)) {
- if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
+ if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
goto_out;
if (_dm_uuid_has_prefix(sysbuf, "mpath-"))
@@ -394,11 +394,11 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
}
if ((MAJOR(dev->dev) == cmd->dev_types->md_major) &&
- _read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
+ read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
return 1;
if ((MAJOR(dev->dev) == cmd->dev_types->loop_major) &&
- _read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
+ read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
return 1;
out:
/* DEV_ID_TYPE_DEVNAME would be used for this dev. */
@@ -1190,7 +1190,7 @@ id_done:
if (!label_scan_open(du_devid->dev))
log_warn("Cannot open %s", dev_name(du_devid->dev));
- if (dev_is_partitioned(cmd->dev_types, du_devid->dev)) {
+ if (dev_is_partitioned(cmd, du_devid->dev)) {
/* Check if existing entry is whole device and new entry is a partition of it. */
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
if ((ret1 == 2) && (devt1 == du_devid->dev->dev))
diff --git a/lib/device/device_id.h b/lib/device/device_id.h
index 1167373d9..a1a53f253 100644
--- a/lib/device/device_id.h
+++ b/lib/device/device_id.h
@@ -52,4 +52,6 @@ void devices_file_exit(struct cmd_context *cmd);
void unlink_searched_devnames(struct cmd_context *cmd);
+int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize);
+
#endif
diff --git a/lib/filters/filter-composite.c b/lib/filters/filter-composite.c
index f4cbeefe8..46a6724f1 100644
--- a/lib/filters/filter-composite.c
+++ b/lib/filters/filter-composite.c
@@ -21,29 +21,24 @@
static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct dev_filter **filters;
- int ret;
+ int ret = 1;
+
+ dev_ext_enable(dev, external_device_info_source());
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
if (use_filter_name && strcmp((*filters)->name, use_filter_name))
continue;
ret = (*filters)->passes_filter(cmd, *filters, dev, use_filter_name);
- if (!ret)
- return 0; /* No 'stack': a filter, not an error. */
+ if (!ret) {
+ ret = 0; /* No 'stack': a filter, not an error. */
+ break;
+ }
}
- return 1;
-}
-
-static int _and_p_with_dev_ext_info(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
-{
- int r;
-
- dev_ext_enable(dev, external_device_info_source());
- r = _and_p(cmd, f, dev, use_filter_name);
dev_ext_disable(dev);
- return r;
+ return ret;
}
static void _composite_destroy(struct dev_filter *f)
@@ -72,7 +67,7 @@ static void _wipe(struct cmd_context *cmd, struct dev_filter *f, struct device *
}
}
-struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
+struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
{
struct dev_filter **filters_copy, *cft;
@@ -93,7 +88,7 @@ struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct d
return NULL;
}
- cft->passes_filter = use_dev_ext_info ? _and_p_with_dev_ext_info : _and_p;
+ cft->passes_filter = _and_p;
cft->destroy = _composite_destroy;
cft->wipe = _wipe;
cft->use_count = 0;
diff --git a/lib/filters/filter-md.c b/lib/filters/filter-md.c
index f72c52123..865fde1a2 100644
--- a/lib/filters/filter-md.c
+++ b/lib/filters/filter-md.c
@@ -98,7 +98,7 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
if (!md_filtering())
return 1;
- ret = dev_is_md_component(dev, NULL, cmd->use_full_md_check);
+ ret = dev_is_md_component(cmd, dev, NULL, cmd->use_full_md_check);
if (ret == -EAGAIN) {
/* let pass, call again after scan */
diff --git a/lib/filters/filter-mpath.c b/lib/filters/filter-mpath.c
index 471f0b4b9..ebd40a457 100644
--- a/lib/filters/filter-mpath.c
+++ b/lib/filters/filter-mpath.c
@@ -17,333 +17,17 @@
#include "lib/filters/filter.h"
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
-#ifdef UDEV_SYNC_SUPPORT
-#include <libudev.h>
-#include "lib/device/dev-ext-udev-constants.h"
-#endif
#ifdef __linux__
#include <dirent.h>
-#define MPATH_PREFIX "mpath-"
-
-struct mpath_priv {
- struct dm_pool *mem;
- struct dev_filter f;
- struct dev_types *dt;
- struct dm_hash_table *hash;
-};
-
-/*
- * given "/dev/foo" return "foo"
- */
-static const char *_get_sysfs_name(struct device *dev)
-{
- const char *name;
-
- if (!(name = strrchr(dev_name(dev), '/'))) {
- log_error("Cannot find '/' in device name.");
- return NULL;
- }
- name++;
-
- if (!*name) {
- log_error("Device name is not valid.");
- return NULL;
- }
-
- return name;
-}
-
-/*
- * given major:minor
- * readlink translates /sys/dev/block/major:minor to /sys/.../foo
- * from /sys/.../foo return "foo"
- */
-static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
- char *buf, size_t buf_size)
-{
- const char *name;
- char path[PATH_MAX];
- int size;
-
- if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
- (int) MAJOR(devno), (int) MINOR(devno)) < 0) {
- log_error("Sysfs path string is too long.");
- return NULL;
- }
-
- if ((size = readlink(path, buf, buf_size - 1)) < 0) {
- log_sys_error("readlink", path);
- return NULL;
- }
- buf[size] = '\0';
-
- if (!(name = strrchr(buf, '/'))) {
- log_error("Cannot find device name in sysfs path.");
- return NULL;
- }
- name++;
-
- return name;
-}
-
-static int _get_sysfs_string(const char *path, char *buffer, int max_size)
-{
- FILE *fp;
- int r = 0;
-
- if (!(fp = fopen(path, "r"))) {
- log_sys_error("fopen", path);
- return 0;
- }
-
- if (!fgets(buffer, max_size, fp))
- log_sys_error("fgets", path);
- else
- r = 1;
-
- if (fclose(fp))
- log_sys_error("fclose", path);
-
- return r;
-}
-
-static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
-{
- char path[PATH_MAX];
- char buffer[128];
-
- if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
- log_error("Sysfs path string is too long.");
- return 0;
- }
-
- buffer[0] = '\0';
-
- if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
- return_0;
-
- if (!strncmp(buffer, MPATH_PREFIX, 6))
- return 1;
-
- return 0;
-}
-
-static int _get_holder_name(const char *dir, char *name, int max_size)
-{
- struct dirent *d;
- DIR *dr;
- int r = 0;
-
- if (!(dr = opendir(dir))) {
- log_sys_error("opendir", dir);
- return 0;
- }
-
- *name = '\0';
- while ((d = readdir(dr))) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
- continue;
-
- /* There should be only one holder if it is multipath */
- if (*name) {
- r = 0;
- break;
- }
-
- strncpy(name, d->d_name, max_size);
- r = 1;
- }
-
- if (closedir(dr))
- log_sys_debug("closedir", dir);
-
- return r;
-}
-
-#ifdef UDEV_SYNC_SUPPORT
-static int _udev_dev_is_mpath_component(struct device *dev)
-{
- const char *value;
- struct dev_ext *ext;
-
- if (!(ext = dev_ext_get(dev)))
- return_0;
-
- value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
- if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
- return 1;
-
- value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
- if (value && !strcmp(value, "1"))
- return 1;
-
- return 0;
-}
-#else
-static int _udev_dev_is_mpath_component(struct device *dev)
-{
- return 0;
-}
-#endif
-
-static int _native_dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
-{
- struct mpath_priv *mp = (struct mpath_priv *) f->private;
- struct dev_types *dt = mp->dt;
- const char *part_name;
- const char *name; /* e.g. "sda" for "/dev/sda" */
- char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
- char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
- char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
- char holder_name[256]; /* e.g. "dm-1" */
- const char *sysfs_dir = dm_sysfs_dir();
- int dev_major = MAJOR(dev->dev);
- int dev_minor = MINOR(dev->dev);
- int dm_dev_major;
- int dm_dev_minor;
- struct stat info;
- dev_t primary_dev;
- long look;
-
- /* Limit this filter to SCSI or NVME devices */
- if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
- return 0;
-
- switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
-
- case 2: /* The dev is partition. */
- part_name = dev_name(dev); /* name of original dev for log_debug msg */
-
- /* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
- if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
- return_0;
-
- log_debug_devs("%s: Device is a partition, using primary "
- "device %s for mpath component detection",
- part_name, name);
- break;
-
- case 1: /* The dev is already a primary dev. Just continue with the dev. */
-
- /* gets "foo" for "/dev/foo" */
- if (!(name = _get_sysfs_name(dev)))
- return_0;
- break;
-
- default: /* 0, error. */
- log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
- return 0;
- }
-
- if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
- log_warn("Sysfs path to check mpath is too long.");
- return 0;
- }
-
- /* also will filter out partitions */
- if (stat(holders_path, &info))
- return 0;
-
- if (!S_ISDIR(info.st_mode)) {
- log_warn("Path %s is not a directory.", holders_path);
- return 0;
- }
-
- /*
- * If holders dir contains an entry such as "dm-1", then this sets
- * holder_name to "dm-1".
- *
- * If holders dir is empty, return 0 (this is generally where
- * devs that are not mpath components return.)
- */
- if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
- return 0;
-
- if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
- log_warn("dm device path to check mpath is too long.");
- return 0;
- }
-
- /*
- * stat "/dev/dm-1" which is the holder of the dev we're checking
- * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
- */
- if (stat(dm_dev_path, &info)) {
- log_debug("filter-mpath %s holder %s stat result %d",
- dev_name(dev), dm_dev_path, errno);
- return 0;
- }
- dm_dev_major = (int)MAJOR(info.st_rdev);
- dm_dev_minor = (int)MINOR(info.st_rdev);
-
- if (dm_dev_major != dt->device_mapper_major) {
- log_debug_devs("filter-mpath %s holder %s %d:%d does not have dm major",
- dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
- return 0;
- }
-
- /*
- * Save the result of checking that "/dev/dm-1" is an mpath device
- * to avoid repeating it for each path component.
- * The minor number of "/dev/dm-1" is added to the hash table with
- * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
- * and const value 1 meaning that dm minor 1 is not a multipath dev.
- */
- look = (long) dm_hash_lookup_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor));
- if (look > 0) {
- log_debug_devs("filter-mpath %s holder %s %u:%u already checked as %sbeing mpath.",
- dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
- return (look > 1) ? 1 : 0;
- }
-
- /*
- * Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
- * <holder_name> is a dm device with dm uuid prefix mpath-.
- * When true, <holder_name> will be something like "dm-1".
- *
- * (Is a hash table worth it to avoid reading one sysfs file?)
- */
- if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
- log_debug_devs("filter-mpath %s holder %s %u:%u ignore mpath component",
- dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
- (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
- return 1;
- }
-
- (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
-
- return 0;
-}
-
-static int _dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
-{
- if (dev->ext.src == DEV_EXT_NONE)
- return _native_dev_is_mpath_component(cmd, f, dev);
-
- if (dev->ext.src == DEV_EXT_UDEV)
- return _udev_dev_is_mpath_component(dev);
-
- log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
- "using external device info source %s", dev_ext_name(dev));
-
- return 0;
-}
-
-#define MSG_SKIPPING "%s: Skipping mpath component device"
-
static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
- if (_dev_is_mpath_component(cmd, f, dev) == 1) {
- if (dev->ext.src == DEV_EXT_NONE)
- log_debug_devs(MSG_SKIPPING, dev_name(dev));
- else
- log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
- dev_ext_name(dev), dev->ext.handle);
+ if (dev_is_mpath_component(cmd, dev)) {
+ log_debug_devs("%s: Skipping mpath component device", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_MPATH_COMPONENT;
return 0;
}
@@ -353,59 +37,33 @@ static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f
static void _destroy(struct dev_filter *f)
{
- struct mpath_priv *mp = (struct mpath_priv*) f->private;
-
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count);
-
- dm_hash_destroy(mp->hash);
- dm_pool_destroy(mp->mem);
}
struct dev_filter *mpath_filter_create(struct dev_types *dt)
{
+ struct dev_filter *f;
const char *sysfs_dir = dm_sysfs_dir();
- struct mpath_priv *mp;
- struct dm_pool *mem;
- struct dm_hash_table *hash;
if (!*sysfs_dir) {
log_verbose("No proc filesystem found: skipping multipath filter");
return NULL;
}
- if (!(hash = dm_hash_create(110))) {
- log_error("mpath hash table creation failed.");
+ if (!(f = zalloc(sizeof(*f)))) {
+ log_error("mpath filter allocation failed");
return NULL;
}
- if (!(mem = dm_pool_create("mpath", 256))) {
- log_error("mpath pool creation failed.");
- dm_hash_destroy(hash);
- return NULL;
- }
-
- if (!(mp = dm_pool_zalloc(mem, sizeof(*mp)))) {
- log_error("mpath filter allocation failed.");
- goto bad;
- }
-
- mp->f.passes_filter = _ignore_mpath_component;
- mp->f.destroy = _destroy;
- mp->f.use_count = 0;
- mp->f.private = mp;
- mp->f.name = "mpath";
- mp->dt = dt;
- mp->mem = mem;
- mp->hash = hash;
+ f->passes_filter = _ignore_mpath_component;
+ f->destroy = _destroy;
+ f->use_count = 0;
+ f->name = "mpath";
log_debug_devs("mpath filter initialised.");
- return &mp->f;
-bad:
- dm_pool_destroy(mem);
- dm_hash_destroy(hash);
- return NULL;
+ return f;
}
#else
diff --git a/lib/filters/filter-partitioned.c b/lib/filters/filter-partitioned.c
index c0b5554c5..642553ef2 100644
--- a/lib/filters/filter-partitioned.c
+++ b/lib/filters/filter-partitioned.c
@@ -22,7 +22,6 @@
static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
- struct dev_types *dt = (struct dev_types *) f->private;
int ret;
if (cmd->filter_nodata_only)
@@ -30,7 +29,7 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
dev->filtered_flags &= ~DEV_FILTERED_PARTITIONED;
- ret = dev_is_partitioned(dt, dev);
+ ret = dev_is_partitioned(cmd, dev);
if (ret == -EAGAIN) {
/* let pass, call again after scan */
@@ -72,7 +71,6 @@ struct dev_filter *partitioned_filter_create(struct dev_types *dt)
f->passes_filter = _passes_partitioned_filter;
f->destroy = _partitioned_filter_destroy;
f->use_count = 0;
- f->private = dt;
f->name = "partitioned";
log_debug_devs("Partitioned filter initialised.");
diff --git a/lib/filters/filter.h b/lib/filters/filter.h
index f9de65273..bff58c9a4 100644
--- a/lib/filters/filter.h
+++ b/lib/filters/filter.h
@@ -20,7 +20,7 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
-struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
+struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt);
diff --git a/lib/misc/lvm-wrappers.c b/lib/misc/lvm-wrappers.c
index c36e2cfc7..2e0cfd514 100644
--- a/lib/misc/lvm-wrappers.c
+++ b/lib/misc/lvm-wrappers.c
@@ -25,19 +25,29 @@ struct udev *_udev;
int udev_init_library_context(void)
{
if (_udev)
- udev_unref(_udev);
+ return 1;
+
+ if (getenv("DM_DISABLE_UDEV"))
+ return 0;
if (!(_udev = udev_new())) {
log_error("Failed to create udev library context.");
return 0;
}
+ if (!udev_is_running()) {
+ udev_unref(_udev);
+ _udev = NULL;
+ return 0;
+ }
+
return 1;
}
void udev_fin_library_context(void)
{
- udev_unref(_udev);
+ if (_udev)
+ udev_unref(_udev);
_udev = NULL;
}
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 490c9c73d..134697aa3 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -3228,6 +3228,11 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
_init_md_checks(cmd);
+ if (!dev_mpath_init(find_config_tree_str_allow_empty(cmd, devices_multipath_wwids_file_CFG, NULL))) {
+ ret = ECMD_FAILED;
+ goto_out;
+ }
+
if (!_cmd_no_meta_proc(cmd) && !_init_lvmlockd(cmd)) {
ret = ECMD_FAILED;
goto_out;
@@ -3248,6 +3253,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
out:
+ dev_mpath_exit();
hints_exit(cmd);
lvmcache_destroy(cmd, 1, 1);
label_scan_destroy(cmd);
@@ -3541,9 +3547,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
{
struct cmd_context *cmd;
- if (!udev_init_library_context())
- stack;
-
/*
* It's not necessary to use name mangling for LVM:
* - the character set used for LV names is subset of udev character set
@@ -3551,9 +3554,7 @@ struct cmd_context *init_lvm(unsigned set_connections,
*/
dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
- if (!(cmd = create_toolcontext(0, NULL, 1, threaded,
- set_connections, set_filters))) {
- udev_fin_library_context();
+ if (!(cmd = create_toolcontext(0, NULL, 1, threaded, set_connections, set_filters))) {
return_NULL;
}
@@ -3561,7 +3562,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
if (stored_errno()) {
destroy_toolcontext(cmd);
- udev_fin_library_context();
return_NULL;
}
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 464501ad5..40a93957c 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1193,16 +1193,6 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
log_debug("online_devs %s %s", dev_name(dev), dev->pvid);
- /*
- * This should already have been done by the filter, but make
- * another check directly with udev in case the filter was not
- * using udev and the native version didn't catch it.
- */
- if (udev_dev_is_mpath_component(dev)) {
- log_print("pvscan[%d] ignore multipath component %s.", getpid(), dev_name(dev));
- continue;
- }
-
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
if (!do_all)
log_print("pvscan[%d] ignore %s with no lvm info.", getpid(), dev_name(dev));
@@ -1257,7 +1247,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
if (pv->device_hint && !strncmp(pv->device_hint, "/dev/md", 7))
do_full_check = 1;
}
- if (do_full_check && dev_is_md_component(dev, NULL, 1)) {
+ if (do_full_check && dev_is_md_component(cmd, dev, NULL, 1)) {
log_print("pvscan[%d] ignore md component %s.", getpid(), dev_name(dev));
release_vg(vg);
continue;
2 years, 9 months
main - toolcontext: fix double free (core dumped) issue
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=db22a389cfb12eef77d...
Commit: db22a389cfb12eef77dfc2e1ce124ac83ed6c5a2
Parent: 66daedc6d27d07e4bcd43ee0286e21a69fdc33d9
Author: Heming Zhao <heming.zhao(a)suse.com>
AuthorDate: Tue Jul 13 03:01:00 2021 +0800
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Jul 12 14:10:21 2021 -0500
toolcontext: fix double free (core dumped) issue
How to trigger:
```
~ # export LVM_SYSTEM_DIR=_
~ # pvscan
No matching physical volumes found
double free or corruption (!prev)
Aborted (core dumped)
```
when LVM_SYSTEM_DIR is empty, _load_config_file() won't be called.
when LVM_SYSTEM_DIR is not empty, cfl->cft links into cmd->config_files
by _load_config_file()(a)lib/commands/toolcontext.c
core dumped code: _destroy_config()(a)lib/commands/toolcontext.c
```
/* CONFIG_FILE/CONFIG_MERGED_FILES */
if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
config_destroy(cft);
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE)))
config_destroy(cft); <=== first free the cft
dm_list_iterate_items(cfl, &cmd->config_files)
config_destroy(cfl->cft); <=== double free the cft
```
Fixes: c43f2f8ae08ed0555a300764c8644ea56f4f41e2
Signed-off-by: Heming Zhao <heming.zhao(a)suse.com>
---
lib/commands/toolcontext.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index b295a20ef..742bdd9c2 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -966,8 +966,13 @@ static void _destroy_config(struct cmd_context *cmd)
/* CONFIG_FILE/CONFIG_MERGED_FILES */
if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
config_destroy(cft);
- else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE)))
+ else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE))) {
+ dm_list_iterate_items(cfl, &cmd->config_files) {
+ if (cfl->cft == cft)
+ dm_list_del(&cfl->list);
+ }
config_destroy(cft);
+ }
dm_list_iterate_items(cfl, &cmd->config_files)
config_destroy(cfl->cft);
2 years, 9 months
main - skip indexing devices used by LVs in more commands
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=66daedc6d27d07e4bcd...
Commit: 66daedc6d27d07e4bcd43ee0286e21a69fdc33d9
Parent: 70c32d1e74b92f6055bcb688ed0e3bc8630f5489
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jul 7 16:59:56 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jul 9 13:59:31 2021 -0500
skip indexing devices used by LVs in more commands
expands commit d5a06f9a7df5a43b2e2311db62ff8d3011217d74
"pvscan: skip indexing devices used by LVs"
The dev cache index is expensive and slow, so limit it
to commands that are used to observe the state of lvm.
The index is only used to print warnings about incorrect
device use by active LVs, e.g. if an LV is using a
multipath component device instead of the multipath
device. Commands that continue to use the index and
print the warnings:
fullreport, lvmdiskscan, vgs, lvs, pvs,
vgdisplay, lvdisplay, pvdisplay,
vgscan, lvscan, pvscan (excluding --cache)
A couple other commands were borrowing the DEV_USED_FOR_LV
flag to just check if a device was actively in use by LVs.
These are converted to the new dev_is_used_by_active_lv().
---
lib/cache/lvmcache.c | 4 +-
lib/device/dev-cache.c | 4 +-
lib/device/dev-cache.h | 3 +-
lib/device/dev-type.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/device/dev-type.h | 3 ++
tools/command.c | 2 +-
tools/commands.h | 22 +++++-----
tools/lvmcmdline.c | 2 +
tools/lvmdevices.c | 5 ++-
tools/tools.h | 2 +
tools/vgimportclone.c | 4 +-
11 files changed, 146 insertions(+), 22 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index a798f5ab8..e15b6ce85 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -799,8 +799,8 @@ next:
same_id2 = !strcmp(idname2, device_id);
}
- has_lv1 = (dev1->flags & DEV_USED_FOR_LV) ? 1 : 0;
- has_lv2 = (dev2->flags & DEV_USED_FOR_LV) ? 1 : 0;
+ has_lv1 = dev_is_used_by_active_lv(cmd, dev1, NULL, NULL, NULL, NULL);
+ has_lv2 = dev_is_used_by_active_lv(cmd, dev2, NULL, NULL, NULL, NULL);
in_subsys1 = dev_subsystem_part_major(dt, dev1);
in_subsys2 = dev_subsystem_part_major(dt, dev2);
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index bb0d0f211..b1d477ebb 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -412,7 +412,7 @@ out:
return r;
}
-static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
+int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
{
char path[PATH_MAX];
@@ -533,7 +533,7 @@ static int _get_vgid_and_lvid_for_dev(struct device *dev)
char uuid[DM_UUID_LEN];
size_t uuid_len;
- if (!_get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
+ if (!get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
return_0;
uuid_len = strlen(uuid);
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index c3f5eddda..30ef1cdbe 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -68,13 +68,12 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
void dev_iter_destroy(struct dev_iter *iter);
struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter);
-void dev_reset_error_count(struct cmd_context *cmd);
-
void dev_cache_failed_path(struct device *dev, const char *path);
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt);
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value);
+int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
int setup_devices_file(struct cmd_context *cmd);
int setup_devices(struct cmd_context *cmd);
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 706061814..3c6dd1693 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -22,6 +22,7 @@
#include "lib/device/bcache.h"
#include "lib/label/label.h"
#include "lib/commands/toolcontext.h"
+#include "device_mapper/misc/dm-ioctl.h"
#ifdef BLKID_WIPING_SUPPORT
#include <blkid.h>
@@ -34,6 +35,7 @@
#include <libgen.h>
#include <ctype.h>
+#include <dirent.h>
/*
* An nvme device has major number 259 (BLKEXT), minor number <minor>,
@@ -77,6 +79,121 @@ int dev_is_lv(struct device *dev)
return ret;
}
+int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
+ char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid)
+{
+ char holders_path[PATH_MAX];
+ char dm_dev_path[PATH_MAX];
+ char dm_uuid[DM_UUID_LEN];
+ struct stat info;
+ DIR *d;
+ struct dirent *dirent;
+ char *holder_name;
+ int dm_dev_major, dm_dev_minor;
+ size_t lvm_prefix_len = sizeof(UUID_PREFIX) - 1;
+ size_t lvm_uuid_len = sizeof(UUID_PREFIX) - 1 + 2 * ID_LEN;
+ size_t uuid_len;
+ int used_count = 0;
+ char *used_name = NULL;
+ char *used_vgid = NULL;
+ char *used_lvid = NULL;
+
+ /*
+ * An LV using this device will be listed as a "holder" in the device's
+ * sysfs "holders" dir.
+ */
+
+ if (dm_snprintf(holders_path, sizeof(holders_path), "%sdev/block/%d:%d/holders/", dm_sysfs_dir(), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)) < 0) {
+ log_error("%s: dm_snprintf failed for path to holders directory.", dev_name(dev));
+ return 0;
+ }
+
+ if (!(d = opendir(holders_path)))
+ return 0;
+
+ while ((dirent = readdir(d))) {
+ if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name))
+ continue;
+
+ holder_name = dirent->d_name;
+
+ /*
+ * dirent->d_name is the dev name of the holder, e.g. "dm-1"
+ * from this name, create path "/dev/dm-1" to run stat on.
+ */
+
+ if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0)
+ continue;
+
+ /*
+ * stat "/dev/dm-1" which is the holder of the dev we're checking
+ * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
+ */
+ if (stat(dm_dev_path, &info))
+ continue;
+
+ dm_dev_major = (int)MAJOR(info.st_rdev);
+ dm_dev_minor = (int)MINOR(info.st_rdev);
+
+ if (dm_dev_major != cmd->dev_types->device_mapper_major)
+ continue;
+
+ /*
+ * if "dm-1" is a dm device, then check if it's an LVM LV
+ * by reading /sys/block/<holder_name>/dm/uuid and seeing
+ * if the uuid begins with LVM-
+ * UUID_PREFIX is "LVM-"
+ */
+
+ dm_uuid[0] = '\0';
+
+ if (!get_dm_uuid_from_sysfs(dm_uuid, sizeof(dm_uuid), dm_dev_major, dm_dev_minor))
+ continue;
+
+ if (!strncmp(dm_uuid, UUID_PREFIX, 4))
+ used_count++;
+
+ if (used_by_dm_name && !used_name)
+ used_name = dm_pool_strdup(cmd->mem, holder_name);
+
+ if (!used_by_vg_uuid && !used_by_lv_uuid)
+ continue;
+
+ /*
+ * UUID for LV is either "LVM-<vg_uuid><lv_uuid>" or
+ * "LVM-<vg_uuid><lv_uuid>-<suffix>", where vg_uuid and lv_uuid
+ * has length of ID_LEN and suffix len is not restricted (only
+ * restricted by whole DM UUID max len).
+ */
+
+ uuid_len = strlen(dm_uuid);
+
+ if (((uuid_len == lvm_uuid_len) ||
+ ((uuid_len > lvm_uuid_len) && (dm_uuid[lvm_uuid_len] == '-'))) &&
+ !strncmp(dm_uuid, UUID_PREFIX, lvm_prefix_len)) {
+
+ if (used_by_vg_uuid && !used_vgid)
+ used_vgid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len, ID_LEN);
+
+ if (used_by_lv_uuid && !used_lvid)
+ used_lvid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len + ID_LEN, ID_LEN);
+ }
+ }
+
+ if (used_by_lv_count)
+ *used_by_lv_count = used_count;
+ if (used_by_dm_name)
+ *used_by_dm_name = used_name;
+ if (used_by_vg_uuid)
+ *used_by_vg_uuid = used_vgid;
+ if (used_by_lv_uuid)
+ *used_by_lv_uuid = used_lvid;
+
+ if (used_count)
+ return 1;
+ return 0;
+}
+
struct dev_types *create_dev_types(const char *proc_dir,
const struct dm_config_node *cn)
{
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index d358520df..097be72cd 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -102,4 +102,7 @@ int dev_is_lv(struct device *dev);
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size);
+int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
+ char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid);
+
#endif
diff --git a/tools/command.c b/tools/command.c
index 7205969e1..b987e49b0 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -141,7 +141,7 @@ static inline int dumptype_arg(struct cmd_context *cmd __attribute__((unused)),
#define CAN_USE_ONE_SCAN 0x00002000
#define ALLOW_HINTS 0x00004000
#define ALLOW_EXPORTED 0x00008000
-
+#define CHECK_DEVS_USED 0x00010000
/* create foo_CMD enums for command def ID's in command-lines.in */
diff --git a/tools/commands.h b/tools/commands.h
index fa5359afe..a38d2b4f5 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -31,7 +31,7 @@ xx(formats,
xx(fullreport,
"Display full report",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(help,
"Display help for commands",
@@ -55,7 +55,7 @@ xx(lvcreate,
xx(lvdisplay,
"Display information about a logical volume",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
xx(lvextend,
"Add space to a logical volume",
@@ -75,7 +75,7 @@ xx(lvmdevices,
xx(lvmdiskscan,
"List devices that may be used as physical volumes",
- PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(lvmsadc,
"Collect activity data",
@@ -107,11 +107,11 @@ xx(lvresize,
xx(lvs,
"Display information about logical volumes",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
xx(lvscan,
"List all logical volumes in all volume groups",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CHECK_DEVS_USED)
xx(pvchange,
"Change attributes of physical volume(s)",
@@ -131,7 +131,7 @@ xx(pvdata,
xx(pvdisplay,
"Display various attributes of physical volume(s)",
- PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
@@ -149,11 +149,11 @@ xx(pvresize,
xx(pvs,
"Display information about physical volumes",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(pvscan,
"List all physical volumes",
- PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(segtypes,
"List available segment types",
@@ -197,7 +197,7 @@ xx(vgcreate,
xx(vgdisplay,
"Display volume group information",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgexport,
"Unregister volume group(s) from the system",
@@ -241,11 +241,11 @@ xx(vgrename,
xx(vgs,
"Display information about volume groups",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgscan,
"Search for all volume groups",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
xx(vgsplit,
"Move physical volumes into a new or existing volume group",
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index d97ff5720..490c9c73d 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2473,6 +2473,8 @@ static int _get_current_settings(struct cmd_context *cmd)
cmd->allow_mixed_block_sizes = find_config_tree_bool(cmd, devices_allow_mixed_block_sizes_CFG, NULL);
+ cmd->check_devs_used = (cmd->cname->flags & CHECK_DEVS_USED) ? 1 : 0;
+
/*
* enable_hints is set to 1 if any commands are using hints.
* use_hints is set to 1 if this command should use the hints.
diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c
index 5117277a0..87c39eec4 100644
--- a/tools/lvmdevices.c
+++ b/tools/lvmdevices.c
@@ -15,6 +15,7 @@
#include "tools.h"
#include "lib/cache/lvmcache.h"
#include "lib/device/device_id.h"
+#include "lib/device/dev-type.h"
static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *search_pvids, struct dm_list *found_devs)
{
@@ -389,7 +390,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* dev_cache_scan uses sysfs to check if an LV is using each dev
* and sets this flag is so.
*/
- if (dev->flags & DEV_USED_FOR_LV) {
+ if (dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", devname) == 'n') {
log_error("Device not removed.");
@@ -435,7 +436,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (du->devname && (du->devname[0] != '.')) {
if ((dev = dev_cache_get(cmd, du->devname, NULL)) &&
- (dev->flags & DEV_USED_FOR_LV)) {
+ dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", du->devname) == 'n') {
log_error("Device not removed.");
diff --git a/tools/tools.h b/tools/tools.h
index efbe1f44c..d4d3b9866 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -139,6 +139,8 @@ struct arg_value_group_list {
#define ALLOW_HINTS 0x00004000
/* Command can access exported vg. */
#define ALLOW_EXPORTED 0x00008000
+/* Command checks and reports warning if devs used by LV are incorrect. */
+#define CHECK_DEVS_USED 0x00010000
void usage(const char *name);
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index a47782771..55a2deb4d 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -61,14 +61,14 @@ static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
/*
* N.B. lvs_in_vg_activated() is not smart enough to distinguish
* between LVs that are active in the original VG vs the cloned VG
- * that's being imported, so check DEV_USED_FOR_LV.
+ * that's being imported, so check dev_is_used_by_active_lv.
*/
dm_list_iterate_items(pvl, &vg->pvs) {
if (is_missing_pv(pvl->pv) || !pvl->pv->dev) {
log_error("VG is missing a device.");
goto bad;
}
- if (pvl->pv->dev->flags & DEV_USED_FOR_LV) {
+ if (dev_is_used_by_active_lv(cmd, pvl->pv->dev, NULL, NULL, NULL, NULL)) {
log_error("Device %s has active LVs, deactivate first.", dev_name(pvl->pv->dev));
devs_used_for_lv++;
}
2 years, 9 months
main - man: vdoimport page
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=70c32d1e74b92f6055b...
Commit: 70c32d1e74b92f6055bcb688ed0e3bc8630f5489
Parent: ed48cb26a31e8e5a12d82d96d8bec6bfc4d5b218
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jul 9 20:50:40 2021 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jul 9 20:50:40 2021 +0200
man: vdoimport page
---
man/vdoimport.8_main | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/man/vdoimport.8_main b/man/vdoimport.8_main
new file mode 100644
index 000000000..1f329099c
--- /dev/null
+++ b/man/vdoimport.8_main
@@ -0,0 +1,92 @@
+.TH "FSADM" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
+.
+.SH "NAME"
+.
+vdoimport \(em utility to import VDO volumes into a new volume group.
+.
+.SH SYNOPSIS
+.
+.PD 0
+.ad l
+.TP 10
+.B vdoimport
+.RI [ options ]
+.IR device
+.
+.PD
+.
+.SH DESCRIPTION
+.
+vdoimport utility imports VDO volumes created and managed by
+.BR vdo (8)
+manager into
+.BR lvm2 (8)
+managed VDO LV. This is realized by moving VDO superblock by 2MiB
+and creating lvm2 metadata at the front of this device. The operation is not reversible,
+thus after conversion to lvm2 the access to VDO data is only possible with
+.BR lvm2 (8)
+commands,
+.BR vdo (8)
+manager no longer control such volume.
+.
+.SH OPTIONS
+.
+.TP
+.BR -f | --force
+Bypass some sanity checks.
+.
+.TP
+.BR -h | --help
+Display the help text.
+.
+.TP
+.BR -n | --name
+Specifies the name of converted VDO LV. When the name is not specified,
+some automatic name is selected. In case the converted VDO volume is
+already using LV a backend device, the name of this LV is used for VDO LV.
+In this case also the of volume group must stay same.
+.
+.TP
+.BR -v | --verbose
+Be more verbose.
+.
+.TP
+.BR -y | --yes
+Answer "yes" at any prompts.
+.
+.TP
+.BR --dry-run
+Print commands without running them.
+.
+.
+.SH DIAGNOSTICS
+.
+On successful completion, the status code is 0.
+A status code of 1 is used for failure.
+.
+.SH EXAMPLES
+.
+Convert VDO volume created by vdo manager into logical volume LV1 with within volume group VG1.
+.P
+#
+.B vdoimport --name VG1/LV1 /dev/mapper/vdo-volume
+.
+.SH ENVIRONMENT VARIABLES
+.
+.TP
+.B TMPDIR
+The temporary directory name for mount points. Defaults to "\fI/tmp\fP".
+.TP
+.B DM_DEV_DIR
+The device directory name.
+Defaults to "\fI/dev\fP" and must be an absolute path.
+.
+.SH SEE ALSO
+.
+.nh
+.ad l
+.BR lvm (8),
+.BR lvm.conf (5),
+.P
+.BR vdo (8),
+.BR vdo2lvm (8),
2 years, 9 months