main - tests: update test to handle different status
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0fed9b097120648301f...
Commit: 0fed9b097120648301faa586970a47b8b4d629ff
Parent: 8e9410594b3113386a667df400b2c229c745cb6a
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Nov 4 17:00:48 2022 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Nov 8 11:10:21 2022 +0100
tests: update test to handle different status
Since now we change deduplication with V4 table line change,
the modification tends to be faster and we can capture for a few ms
also 'status' about opening or closing deduplication index.
Use 'grep -E' to handle both words.
---
test/shell/lvchange-vdo.sh | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/test/shell/lvchange-vdo.sh b/test/shell/lvchange-vdo.sh
index 7cc44d6bc..b11edf35c 100644
--- a/test/shell/lvchange-vdo.sh
+++ b/test/shell/lvchange-vdo.sh
@@ -40,13 +40,14 @@ check grep_dmsetup status $vg-vdopool-vpool " online online "
# dedulication_ARG
lvchange --deduplication n $vg/vdopool
-check grep_dmsetup status $vg-vdopool-vpool " offline online "
+check grep_dmsetup status $vg-vdopool-vpool -E " offline|closed online "
+
lvchange --deduplication y $vg/vdopool
-check grep_dmsetup status $vg-vdopool-vpool " online online "
+check grep_dmsetup status $vg-vdopool-vpool -E " online|opening online "
lvchange --compression n --deduplication n $vg/vdopool
-check grep_dmsetup status $vg-vdopool-vpool " offline offline "
+check grep_dmsetup status $vg-vdopool-vpool -E " offline|closed offline "
# --vdosettings needs inactive LV
not lvchange --vdosettings 'ack_threads=8' $vg/vdopool
1 year, 5 months
main - vdo: enhance detection of virtual size
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8e9410594b3113386a6...
Commit: 8e9410594b3113386a667df400b2c229c745cb6a
Parent: 218c7d44b5ac64b6c38dfd40885a22008b5cec81
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Nov 5 23:10:36 2022 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Nov 8 11:10:21 2022 +0100
vdo: enhance detection of virtual size
Improve detection of VDO virtual size - so it's not reading VDO
metadata when VDO device is already active and instead we reuse
existing table line for knowing existing metadata size.
NOTE: if there is ever going to be added support for reduction
of VDO virtual size - this method will need to be reworked to
allow size difference only within 'extent_size' alignment.
---
device_mapper/libdm-deptree.c | 44 ++++++++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 13 deletions(-)
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
index 02a56c8e3..39af7b1d4 100644
--- a/device_mapper/libdm-deptree.c
+++ b/device_mapper/libdm-deptree.c
@@ -2850,7 +2850,7 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
return 1;
}
-static int _vdo_emit_segment_line(struct dm_task *dmt,
+static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
struct load_segment *seg,
char *params, size_t paramsize)
{
@@ -2858,6 +2858,10 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
char data[DM_FORMAT_DEV_BUFSIZE];
char data_dev[128]; // for /dev/dm-XXXX
uint64_t logical_blocks;
+ struct dm_task *vdo_dmt;
+ uint64_t start, length = 0;
+ char *type = NULL;
+ char *vdo_params = NULL;
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
return_0;
@@ -2867,18 +2871,32 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
return 0;
}
- if (dm_vdo_parse_logical_size(data_dev, &logical_blocks)) {
- logical_blocks *= 8;
- if (seg->size != logical_blocks) {
- if (seg->size > logical_blocks) {
- log_error("Virtual size of VDO volume is smaller then expected (" FMTu64 " > " FMTu64 ").",
- seg->size, logical_blocks);
- return 1;
- }
- log_debug_activation("Increasing VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
- seg->size, logical_blocks);
- seg->size = logical_blocks;
+ /*
+ * If there is already running VDO target, read 'existing' virtual size out of table line
+ * and avoid reading it them from VDO metadata device
+ *
+ * NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recongnize 'right' size.
+ * However if there would be supported also reduction, this check would need to check range.
+ */
+ if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
+ if (dm_task_set_major(vdo_dmt, major) &&
+ dm_task_set_minor(vdo_dmt, minor) &&
+ dm_task_run(vdo_dmt)) {
+ (void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
+ if (!type || strcmp(type, "vdo"))
+ length = 0;
}
+
+ dm_task_destroy(vdo_dmt);
+ }
+
+ if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
+ length = logical_blocks * 8;
+
+ if (seg->size < length) {
+ log_debug_activation("Correcting VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
+ seg->size, length);
+ seg->size = length;
}
if (seg->vdo_version < 4) {
@@ -2980,7 +2998,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
break;
case SEG_VDO:
- if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
+ if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
return_0;
break;
case SEG_CRYPT:
1 year, 5 months
main - vdo: replace errors with debug
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=218c7d44b5ac64b6c38...
Commit: 218c7d44b5ac64b6c38dfd40885a22008b5cec81
Parent: c98617c593a84e32ff8ee32ecf2382d4e1369c16
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Nov 4 16:27:56 2022 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Nov 8 11:07:20 2022 +0100
vdo: replace errors with debug
As we actully use reading of VDO metadata only as extra 'information' source,
and not error command - switch to 'log_debug()' severity with messages
out of parser code.
---
device_mapper/vdo/vdo_reader.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/device_mapper/vdo/vdo_reader.c b/device_mapper/vdo/vdo_reader.c
index b765af042..4f91f8011 100644
--- a/device_mapper/vdo/vdo_reader.c
+++ b/device_mapper/vdo/vdo_reader.c
@@ -188,19 +188,19 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
*logical_blocks = 0;
if ((fh = open(vdo_path, O_RDONLY)) == -1) {
- log_sys_error("Failed to open VDO backend %s", vdo_path);
+ log_sys_debug("Failed to open VDO backend %s.", vdo_path);
goto err;
}
if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
if (errno != ENOTTY) {
- log_sys_error("ioctl", vdo_path);
+ log_sys_debug("ioctl", vdo_path);
goto err;
}
/* lets retry for file sizes */
if (fstat(fh, &st) < 0) {
- log_sys_error("fstat", vdo_path);
+ log_sys_debug("fstat", vdo_path);
goto err;
}
@@ -208,12 +208,12 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
}
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
- log_sys_error("read", vdo_path);
+ log_sys_debug("read", vdo_path);
goto err;
}
if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
- log_sys_error("mismatch header", vdo_path);
+ log_debug_activation("Found mismatching VDO magic header in %s.", vdo_path);
goto err;
}
@@ -221,7 +221,7 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
_vdo_decode_header(&h);
if (h.version.major_version != 5) {
- log_error("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
+ log_debug_activation("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
goto err;
}
@@ -231,17 +231,17 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
regpos = vg.regions[VDO_DATA_REGION].start_block * 4096;
if ((regpos + sizeof(buffer)) > size) {
- log_error("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
+ log_debug_activation("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
goto err;
}
if ((l = lseek(fh, regpos, SEEK_SET)) < 0) {
- log_sys_error("lseek", vdo_path);
+ log_sys_debug("lseek", vdo_path);
goto err;
}
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
- log_sys_error("read error", vdo_path);
+ log_sys_debug("read", vdo_path);
goto err;
}
@@ -250,7 +250,7 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
_vdo_decode_version(&vn);
if (vn.major_version > 41) {
- log_error("Unknown VDO component version %u.", vn.major_version); // should be 41!
+ log_debug_activation("Unknown VDO component version %u.", vn.major_version); // should be 41!
goto err;
}
@@ -258,16 +258,16 @@ bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
_vdo_decode_pvc(&pvc);
if (pvc.nonce != vg.nonce) {
- log_error("Mismatching VDO nonce " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
+ log_debug_activation("VDO metadata has mismatching VDO nonces " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
goto err;
}
#if 0
- log_debug("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
- log_debug("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
- log_debug("SlabSize " FMTu64 ".", pvc.config.slab_size);
- log_debug("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
- log_debug("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
+ log_debug_activation("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
+ log_debug_activation("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
+ log_debug_activation("SlabSize " FMTu64 ".", pvc.config.slab_size);
+ log_debug_activation("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
+ log_debug_activation("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
#endif
*logical_blocks = pvc.config.logical_blocks;
1 year, 5 months
main - devices: factor common list functions
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c98617c593a84e32ff8...
Commit: c98617c593a84e32ff8ee32ecf2382d4e1369c16
Parent: 761b922178c8522fd9abb207ba31bd27f9fa9dc4
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Nov 7 11:38:46 2022 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Nov 7 11:38:46 2022 -0600
devices: factor common list functions
which were duplicated in various places
---
lib/Makefile.in | 1 +
lib/cache/lvmcache.c | 48 ++++++++---------------------
lib/cache/lvmcache.h | 2 --
lib/device/dev_util.c | 66 ++++++++++++++++++++++++++++++++++++++++
lib/device/device.h | 12 ++++++++
lib/device/device_id.c | 17 ++---------
lib/metadata/metadata-exported.h | 6 ----
tools/pvscan.c | 2 +-
tools/toollib.c | 34 +++------------------
tools/vgimportclone.c | 15 ++-------
10 files changed, 102 insertions(+), 101 deletions(-)
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 3380b28fb..50c7a1fd2 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -43,6 +43,7 @@ SOURCES =\
device/filesystem.c \
device/online.c \
device/parse_vpd.c \
+ device/dev_util.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 1aa699c83..1ae63b3fc 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -144,28 +144,6 @@ int lvmcache_found_duplicate_vgnames(void)
return _found_duplicate_vgnames;
}
-static struct device_list *_get_devl_in_device_list(struct device *dev, struct dm_list *head)
-{
- struct device_list *devl;
-
- dm_list_iterate_items(devl, head) {
- if (devl->dev == dev)
- return devl;
- }
- return NULL;
-}
-
-int dev_in_device_list(struct device *dev, struct dm_list *head)
-{
- struct device_list *devl;
-
- dm_list_iterate_items(devl, head) {
- if (devl->dev == dev)
- return 1;
- }
- return 0;
-}
-
bool lvmcache_has_duplicate_devs(void)
{
if (dm_list_empty(&_unused_duplicates) && dm_list_empty(&_initial_duplicates))
@@ -192,11 +170,11 @@ void lvmcache_del_dev_from_duplicates(struct device *dev)
{
struct device_list *devl;
- if ((devl = _get_devl_in_device_list(dev, &_initial_duplicates))) {
+ if ((devl = device_list_find_dev(&_initial_duplicates, dev))) {
log_debug_cache("delete dev from initial duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
- if ((devl = _get_devl_in_device_list(dev, &_unused_duplicates))) {
+ if ((devl = device_list_find_dev(&_unused_duplicates, dev))) {
log_debug_cache("delete dev from unused duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
@@ -605,7 +583,7 @@ int vg_has_duplicate_pvs(struct volume_group *vg)
bool lvmcache_dev_is_unused_duplicate(struct device *dev)
{
- return dev_in_device_list(dev, &_unused_duplicates) ? true : false;
+ return device_list_find_dev(&_unused_duplicates, dev) ? true : false;
}
static void _warn_unused_duplicates(struct cmd_context *cmd)
@@ -934,7 +912,7 @@ next:
}
/* Remove dev_mpath from altdevs. */
- if ((devl = _get_devl_in_device_list(dev_mpath, &altdevs)))
+ if ((devl = device_list_find_dev(&altdevs, dev_mpath)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
@@ -1001,7 +979,7 @@ next:
}
/* Remove dev_md from altdevs. */
- if ((devl = _get_devl_in_device_list(dev_md, &altdevs)))
+ if ((devl = device_list_find_dev(&altdevs, dev_md)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
@@ -1029,7 +1007,7 @@ next:
}
/* Remove dev_md from altdevs. */
- if ((devl = _get_devl_in_device_list(dev_md, &altdevs)))
+ if ((devl = device_list_find_dev(&altdevs, dev_md)))
dm_list_del(&devl->list);
}
@@ -1107,8 +1085,8 @@ next:
if (dev1 == dev2)
continue;
- prev_unchosen1 = dev_in_device_list(dev1, &_unused_duplicates);
- prev_unchosen2 = dev_in_device_list(dev2, &_unused_duplicates);
+ prev_unchosen1 = device_list_find_dev(&_unused_duplicates, dev1) ? 1 :0;
+ prev_unchosen2 = device_list_find_dev(&_unused_duplicates, dev2) ? 1 :0;
if (!prev_unchosen1 && !prev_unchosen2) {
/*
@@ -1118,8 +1096,8 @@ next:
* want the same duplicate preference to be preserved
* in each instance of lvmcache for a single command.
*/
- prev_unchosen1 = dev_in_device_list(dev1, &_prev_unused_duplicate_devs);
- prev_unchosen2 = dev_in_device_list(dev2, &_prev_unused_duplicate_devs);
+ prev_unchosen1 = device_list_find_dev(&_prev_unused_duplicate_devs, dev1) ? 1 :0;
+ prev_unchosen2 = device_list_find_dev(&_prev_unused_duplicate_devs, dev2) ? 1 : 0;
}
dev1_major = MAJOR(dev1->dev);
@@ -1296,7 +1274,7 @@ next:
if (!info) {
log_debug_cache("PV %s with duplicates will use %s.", pvid, dev_name(dev1));
- if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
+ if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@@ -1315,7 +1293,7 @@ next:
* for the current lvmcache device to drop.
*/
- if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
+ if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@@ -2530,7 +2508,7 @@ struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *lab
memcpy(dev->pvid, pvid, ID_LEN);
/* shouldn't happen */
- if (dev_in_device_list(dev, &_initial_duplicates))
+ if (device_list_find_dev(&_initial_duplicates, dev))
log_debug_cache("Initial duplicate already in list %s", dev_name(dev));
else {
/*
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 934246274..7dde3cda3 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -186,8 +186,6 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, const char *pvid_ar
uint64_t lvmcache_max_metadata_size(void);
void lvmcache_save_metadata_size(uint64_t val);
-int dev_in_device_list(struct device *dev, struct dm_list *head);
-
bool lvmcache_has_bad_metadata(struct device *dev);
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);
diff --git a/lib/device/dev_util.c b/lib/device/dev_util.c
new file mode 100644
index 000000000..2302df462
--- /dev/null
+++ b/lib/device/dev_util.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 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/device/device.h"
+
+int device_id_list_remove(struct dm_list *list, struct device *dev)
+{
+ struct device_id_list *dil;
+
+ dm_list_iterate_items(dil, list) {
+ if (dil->dev == dev) {
+ dm_list_del(&dil->list);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+struct device_id_list *device_id_list_find_dev(struct dm_list *list, struct device *dev)
+{
+ struct device_id_list *dil;
+
+ dm_list_iterate_items(dil, list) {
+ if (dil->dev == dev)
+ return dil;
+ }
+ return NULL;
+}
+
+int device_list_remove(struct dm_list *list, struct device *dev)
+{
+ struct device_list *devl;
+
+ dm_list_iterate_items(devl, list) {
+ if (devl->dev == dev) {
+ dm_list_del(&devl->list);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+struct device_list *device_list_find_dev(struct dm_list *list, struct device *dev)
+{
+ struct device_list *devl;
+
+ dm_list_iterate_items(devl, list) {
+ if (devl->dev == dev)
+ return devl;
+ }
+ return NULL;
+}
+
diff --git a/lib/device/device.h b/lib/device/device.h
index a047158d8..446104218 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -179,6 +179,12 @@ struct device_list {
struct device *dev;
};
+struct device_id_list {
+ struct dm_list list;
+ struct device *dev;
+ char pvid[ID_LEN + 1];
+};
+
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
@@ -235,4 +241,10 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
int format_t10_id(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes);
int parse_vpd_serial(const unsigned char *in, char *out, int outsize);
+/* dev_util */
+int device_id_list_remove(struct dm_list *devices, struct device *dev);
+struct device_id_list *device_id_list_find_dev(struct dm_list *devices, struct device *dev);
+int device_list_remove(struct dm_list *devices, struct device *dev);
+struct device_list *device_list_find_dev(struct dm_list *devices, struct device *dev);
+
#endif
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index 599e357be..aae875776 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -2208,7 +2208,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
* scanned_devs are the devices that have been scanned,
* so they are the only devs we can verify PVID for.
*/
- if (scanned_devs && !dev_in_device_list(dev, scanned_devs))
+ if (scanned_devs && !device_list_find_dev(scanned_devs, dev))
continue;
/*
@@ -2310,7 +2310,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
* scanned_devs are the devices that have been scanned,
* so they are the only devs we can verify PVID for.
*/
- if (scanned_devs && !dev_in_device_list(dev, scanned_devs))
+ if (scanned_devs && !device_list_find_dev(scanned_devs, dev))
continue;
/*
@@ -2462,17 +2462,6 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
}
}
-static struct device_id_list *_device_id_list_find_dev(struct dm_list *list, struct device *dev)
-{
- struct device_id_list *dil;
-
- dm_list_iterate_items(dil, list) {
- if (dil->dev == dev)
- return dil;
- }
- return NULL;
-}
-
/*
* Validate entries with suspect sys_serial values. A sys_serial du (devices
* file entry) matched a device with the same serial number, but the PVID did
@@ -2612,7 +2601,7 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
du->idname, du->pvid, dev_name(dev));
/* update file if this dev pairing is new or different */
- if (!(dil = _device_id_list_find_dev(&prev_devs, dev)))
+ if (!(dil = device_id_list_find_dev(&prev_devs, dev)))
update_file = 1;
else if (memcmp(dil->pvid, du->pvid, ID_LEN))
update_file = 1;
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 04f32cace..c7eaa5233 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -590,12 +590,6 @@ struct vgnameid_list {
const char *vgid;
};
-struct device_id_list {
- struct dm_list list;
- struct device *dev;
- char pvid[ID_LEN + 1];
-};
-
#define PV_PE_START_CALC ((uint64_t) -1) /* Calculate pe_start value */
/*
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 1c58e4a5b..96935a43b 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -703,7 +703,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* devices used by the VG we read.
*/
dm_list_iterate_items(pvl, &vg->pvs) {
- if (dev_in_device_list(pvl->pv->dev, &devs))
+ if (device_list_find_dev(&devs, pvl->pv->dev))
continue;
log_error_pvscan(cmd, "activation for VG %s found different devices.", vgname);
ret = ECMD_FAILED;
diff --git a/tools/toollib.c b/tools/toollib.c
index 5305e811b..ae6f311ba 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -4133,32 +4133,6 @@ static int _get_arg_devices(struct cmd_context *cmd,
return ret_max;
}
-static int _device_list_remove(struct dm_list *devices, struct device *dev)
-{
- struct device_id_list *dil;
-
- dm_list_iterate_items(dil, devices) {
- if (dil->dev == dev) {
- dm_list_del(&dil->list);
- return 1;
- }
- }
-
- return 0;
-}
-
-static struct device_id_list *_device_list_find_dev(struct dm_list *devices, struct device *dev)
-{
- struct device_id_list *dil;
-
- dm_list_iterate_items(dil, devices) {
- if (dil->dev == dev)
- return dil;
- }
-
- return NULL;
-}
-
/* Process devices that are not PVs. */
static int _process_other_devices(struct cmd_context *cmd,
@@ -4263,8 +4237,8 @@ static int _process_duplicate_pvs(struct cmd_context *cmd,
dm_list_iterate_items(devl, &unused_duplicate_devs) {
/* Duplicates are displayed if -a is used or the dev is named as an arg. */
- if ((dil = _device_list_find_dev(arg_devices, devl->dev)))
- _device_list_remove(arg_devices, devl->dev);
+ if ((dil = device_id_list_find_dev(arg_devices, devl->dev)))
+ device_id_list_remove(arg_devices, devl->dev);
if (!process_other_devices && !dil)
continue;
@@ -4384,8 +4358,8 @@ static int _process_pvs_in_vg(struct cmd_context *cmd,
/* Remove each arg_devices entry as it is processed. */
if (arg_devices && !dm_list_empty(arg_devices)) {
- if ((dil = _device_list_find_dev(arg_devices, pv->dev)))
- _device_list_remove(arg_devices, dil->dev);
+ if ((dil = device_id_list_find_dev(arg_devices, pv->dev)))
+ device_id_list_remove(arg_devices, dil->dev);
}
if (!process_pv && dil)
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index 9e426c942..60ef20762 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -25,17 +25,6 @@ struct vgimportclone_params {
unsigned import_vg:1;
};
-static struct device_list *_get_device_list(struct dm_list *list, struct device *dev)
-{
- struct device_list *devl;
-
- dm_list_iterate_items(devl, list) {
- if (devl->dev == dev)
- return devl;
- }
- return NULL;
-}
-
static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
struct vgimportclone_params *vp)
{
@@ -82,7 +71,7 @@ static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
*/
dm_list_iterate_items(pvl, &vg->pvs) {
- if ((devl = _get_device_list(&vp->new_devs, pvl->pv->dev))) {
+ if ((devl = device_list_find_dev(&vp->new_devs, pvl->pv->dev))) {
dm_list_del(&devl->list);
dm_list_add(&tmp_devs, &devl->list);
} else {
@@ -192,7 +181,7 @@ static int _get_other_devs(struct cmd_context *cmd, struct dm_list *new_devs, st
return_0;
while ((dev = dev_iter_get(cmd, iter))) {
- if (_get_device_list(new_devs, dev))
+ if (device_list_find_dev(new_devs, dev))
continue;
if (!(devl = zalloc(sizeof(*devl)))) {
r = 0;
1 year, 5 months
main - device_id: handle duplicate serial numbers
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=761b922178c8522fd9a...
Commit: 761b922178c8522fd9abb207ba31bd27f9fa9dc4
Parent: bdab36cf3f059e597371bb504646f4dfb7a89f50
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Oct 31 16:14:01 2022 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Nov 7 08:56:02 2022 -0600
device_id: handle duplicate serial numbers
Handle multiple devices using the same serial number as
their device id. After matching devices to devices file
entries, if there is a discrepency between the ondisk PVID
and the devices file PVID, then rematch devices to
devices file entries using PVID, looking at all disks
on the system with the same serial number.
---
lib/cache/lvmcache.c | 16 +
lib/commands/toolcontext.h | 1 +
lib/device/device.h | 5 +
lib/device/device_id.c | 377 +++++++++++++++++++
lib/device/device_id.h | 1 +
test/shell/devicesfile-serial.sh | 777 +++++++++++++++++++++++++++++++++++++++
tools/lvmdevices.c | 10 +-
7 files changed, 1185 insertions(+), 2 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 2cb904fd4..1aa699c83 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1634,6 +1634,22 @@ int lvmcache_label_scan(struct cmd_context *cmd)
if (!label_scan(cmd))
return_0;
+ /*
+ * device_ids_validate() found devices using a sys_serial device id
+ * which had a PVID on disk that did not match the PVID in the devices
+ * file. Serial numbers may not always be unique, so any device with
+ * the same serial number is found and searched for the correct PVID.
+ * If the PVID is found on a device that has not been scanned, then
+ * it needs to be scanned so it can be used.
+ */
+ if (!dm_list_empty(&cmd->device_ids_check_serial)) {
+ struct dm_list scan_devs;
+ dm_list_init(&scan_devs);
+ device_ids_check_serial(cmd, &scan_devs, NULL, 0);
+ if (!dm_list_empty(&scan_devs))
+ label_scan_devs(cmd, cmd->filter, &scan_devs);
+ }
+
/*
* When devnames are used as device ids (which is dispreferred),
* changing/unstable devnames can lead to entries in the devices file
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 32bfda57a..7f5fd12fc 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -215,6 +215,7 @@ struct cmd_context {
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */
+ struct dm_list device_ids_check_serial;
const char *devicesfile; /* from --devicesfile option */
struct dm_list deviceslist; /* from --devices option, struct dm_str_list */
diff --git a/lib/device/device.h b/lib/device/device.h
index 519754e41..a047158d8 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -118,6 +118,11 @@ struct dev_use {
char *pvid;
};
+struct dev_use_list {
+ struct dm_list list;
+ struct dev_use *du;
+};
+
/*
* All devices in LVM will be represented by one of these.
* pointer comparisons are valid.
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index 15b34a158..599e357be 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -22,6 +22,8 @@
#include "lib/metadata/metadata.h"
#include "lib/format_text/layout.h"
#include "lib/cache/lvmcache.h"
+#include "lib/datastruct/str_list.h"
+#include "lib/metadata/metadata-exported.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -752,6 +754,35 @@ const char *dev_idname_for_metadata(struct cmd_context *cmd, struct device *dev)
return dev->id->idname;
}
+static const char *_dev_idname(struct device *dev, uint16_t idtype)
+{
+ struct dev_id *id;
+
+ dm_list_iterate_items(id, &dev->ids) {
+ if (id->idtype != idtype)
+ continue;
+ if (!id->idname)
+ continue;
+ return id->idname;
+ }
+ return NULL;
+}
+
+static int _dev_has_id(struct device *dev, uint16_t idtype, const char *idname)
+{
+ struct dev_id *id;
+
+ dm_list_iterate_items(id, &dev->ids) {
+ if (id->idtype != idtype)
+ continue;
+ if (!id->idname)
+ continue;
+ if (!strcmp(idname, id->idname))
+ return 1;
+ }
+ return 0;
+}
+
static void _copy_idline_str(char *src, char *dst, int len)
{
char *s, *d = dst;
@@ -2077,6 +2108,62 @@ void device_ids_match(struct cmd_context *cmd)
}
}
+static void _get_devs_with_serial_numbers(struct cmd_context *cmd, struct dm_list *serial_str_list, struct dm_list *devs)
+{
+ struct dev_iter *iter;
+ struct device *dev;
+ struct device_list *devl;
+ struct dev_id *id;
+ const char *idname;
+
+ if (!(iter = dev_iter_create(NULL, 0)))
+ return;
+ while ((dev = dev_iter_get(cmd, iter))) {
+ /* if serial has already been read for this dev then use it */
+ dm_list_iterate_items(id, &dev->ids) {
+ if (id->idtype == DEV_ID_TYPE_SYS_SERIAL) {
+ if (str_list_match_item(serial_str_list, id->idname)) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ goto next_dev;
+ devl->dev = dev;
+ dm_list_add(devs, &devl->list);
+ }
+ goto next_dev;
+ }
+ }
+
+ /* just copying the no-data filters in similar device_ids_find_renamed_devs */
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
+ continue;
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
+ continue;
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "usable"))
+ continue;
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "mpath"))
+ continue;
+
+ if ((idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_SERIAL))) {
+ if (str_list_match_item(serial_str_list, idname)) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ goto next_dev;
+ if (!(id = zalloc(sizeof(struct dev_id))))
+ goto next_dev;
+ id->idtype = DEV_ID_TYPE_SYS_SERIAL;
+ id->idname = (char *)idname;
+ id->dev = dev;
+ dm_list_add(&dev->ids, &id->list);
+ devl->dev = dev;
+ dm_list_add(devs, &devl->list);
+ } else {
+ free((char *)idname);
+ }
+ }
+ next_dev:
+ continue;
+ }
+ dev_iter_destroy(iter);
+}
+
/*
* This is called after devices are scanned to compare what was found on disks
* vs what's in the devices file. The devices file could be outdated and need
@@ -2145,6 +2232,19 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
checked++;
+ /*
+ * If the PVID doesn't match, don't assume that the serial
+ * number is correct, since serial numbers may not be unique.
+ * Search for the PVID on other devs in device_ids_check_serial.
+ */
+ if ((du->idtype == DEV_ID_TYPE_SYS_SERIAL) &&
+ (!du->pvid || memcmp(dev->pvid, du->pvid, ID_LEN))) {
+ log_debug("suspect device id serial %s for %s", du->idname, dev_name(dev));
+ str_list_add(cmd->mem, &cmd->device_ids_check_serial, dm_pool_strdup(cmd->mem, du->idname));
+ *device_ids_invalid = 1;
+ continue;
+ }
+
/*
* If the du pvid from the devices file does not match the
* pvid read from disk, replace the du pvid with the pvid from
@@ -2362,6 +2462,282 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
}
}
+static struct device_id_list *_device_id_list_find_dev(struct dm_list *list, struct device *dev)
+{
+ struct device_id_list *dil;
+
+ dm_list_iterate_items(dil, list) {
+ if (dil->dev == dev)
+ return dil;
+ }
+ return NULL;
+}
+
+/*
+ * Validate entries with suspect sys_serial values. A sys_serial du (devices
+ * file entry) matched a device with the same serial number, but the PVID did
+ * not match. Check if multiple devices have the same serial number, and if so
+ * pair the devs to the du's based on PVID. This requires searching all devs
+ * for the given serial number, and then reading the PVID from all those devs.
+ * This may involve reading labels from devs outside the devices file.
+ * (This could also be done for duplicate wwids if needed.)
+ */
+void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
+ int *update_needed, int noupdate)
+{
+ struct dm_list dus_check; /* dev_use_list */
+ struct dm_list devs_check; /* device_list */
+ struct dm_list prev_devs; /* device_id_list */
+ struct dev_use_list *dul;
+ struct device_list *devl, *devl2;
+ struct device_id_list *dil;
+ struct device *dev;
+ struct dev_use *du;
+ char *tmpdup;
+ int update_file = 0;
+ int has_pvid;
+ int found;
+ int count;
+
+ dm_list_init(&dus_check);
+ dm_list_init(&devs_check);
+ dm_list_init(&prev_devs);
+
+ /*
+ * Create list of du's with a suspect serial number. These du's will
+ * be rematched to a device using pvid. The device_ids_check_serial
+ * list was created by device_ids_validate() when it found that the
+ * PVID on the dev did not match the PVID in the du that was paired
+ * with the dev.
+ */
+ dm_list_iterate_items(du, &cmd->use_devices) {
+ if (du->dev && (du->idtype == DEV_ID_TYPE_SYS_SERIAL) &&
+ str_list_match_item(&cmd->device_ids_check_serial, du->idname)) {
+ if (!(dul = dm_pool_zalloc(cmd->mem, sizeof(*dul))))
+ continue;
+ dul->du = du;
+ dm_list_add(&dus_check, &dul->list);
+ }
+ }
+
+ /*
+ * Create list of devs on the system with suspect serial numbers.
+ * Read the serial number of each dev in dev cache, and return
+ * devs that match the suspect serial numbers.
+ */
+ log_debug("Finding all devs with suspect serial numbers.");
+ _get_devs_with_serial_numbers(cmd, &cmd->device_ids_check_serial, &devs_check);
+
+ /*
+ * Read the PVID from any devs_check entries that have not been scanned
+ * yet (this is where some devs outside the devices file may be read.)
+ * If the dev has no PVID or is excluded by filters, then there's no
+ * point in trying to match it to one of the dus_check entries.
+ */
+ log_debug("Reading and filtering %d devs with suspect serial numbers.", dm_list_size(&devs_check));
+ dm_list_iterate_items_safe(devl, devl2, &devs_check) {
+ const char *idname;
+ if (!(idname = _dev_idname(devl->dev, DEV_ID_TYPE_SYS_SERIAL))) {
+ log_debug("serial missing for %s", dev_name(devl->dev));
+ continue;
+ }
+ if (devl->dev->flags & DEV_SCAN_FOUND_LABEL) {
+ log_debug("serial %s pvid %s %s", idname, devl->dev->pvid, dev_name(devl->dev));
+ continue;
+ }
+ if (devl->dev->flags & DEV_SCAN_FOUND_NOLABEL) {
+ log_debug("serial %s nolabel %s", idname, dev_name(devl->dev));
+ continue;
+ }
+
+ dev = devl->dev;
+ has_pvid = 0;
+
+ label_read_pvid(dev, &has_pvid);
+ if (!has_pvid) {
+ log_debug("serial %s no pvid %s", idname, dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ continue;
+ }
+
+ /* data-based filters use data read by label_read_pvid */
+ if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "partitioned") ||
+ !cmd->filter->passes_filter(cmd, cmd->filter, dev, "signature") ||
+ !cmd->filter->passes_filter(cmd, cmd->filter, dev, "md") ||
+ !cmd->filter->passes_filter(cmd, cmd->filter, dev, "fwraid")) {
+ log_debug("serial %s pvid %s filtered %s", idname, devl->dev->pvid, dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ }
+ }
+
+ log_debug("Checking %d PVs with suspect serial numbers.", dm_list_size(&devs_check));
+
+ /*
+ * Unpair du's and dev's that were matched using suspect serial numbers
+ * so that things can be matched again using PVID. If current pairings
+ * are correct they will just be matched again. Save the previous
+ * pairings so that we can detect when a wrong pairing was corrected.
+ */
+ dm_list_iterate_items(dul, &dus_check) {
+ if (!dul->du->dev)
+ continue;
+ /* save previously matched devs so they can be dropped from
+ lvmcache at the end if they are no longer used */
+ if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
+ continue;
+ du = dul->du;
+ dil->dev = du->dev;
+ memcpy(dil->pvid, du->pvid, ID_LEN);
+ dm_list_add(&prev_devs, &dil->list);
+ du->dev->flags &= ~DEV_MATCHED_USE_ID;
+ du->dev = NULL;
+ }
+
+ /*
+ * Match du to a dev based on PVID.
+ */
+ dm_list_iterate_items(dul, &dus_check) {
+ log_debug("Matching suspect serial device id %s PVID %s prev %s",
+ dul->du->idname, dul->du->pvid, dul->du->devname);
+ found = 0;
+ dm_list_iterate_items(devl, &devs_check) {
+ if (!memcmp(dul->du->pvid, devl->dev->pvid, ID_LEN)) {
+ /* pair dev and du */
+ du = dul->du;
+ dev = devl->dev;
+ du->dev = dev;
+ dev->flags |= DEV_MATCHED_USE_ID;
+
+ log_debug("Match suspect serial device id %s PVID %s to %s",
+ du->idname, du->pvid, dev_name(dev));
+
+ /* update file if this dev pairing is new or different */
+ if (!(dil = _device_id_list_find_dev(&prev_devs, dev)))
+ update_file = 1;
+ else if (memcmp(dil->pvid, du->pvid, ID_LEN))
+ update_file = 1;
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ log_debug("Match PVID failed in %d devs checked.", dm_list_size(&devs_check));
+ }
+
+ /*
+ * Handle du's with suspect serial numbers that did not have a match
+ * based on PVID in the previous loop. If the du matches a device
+ * based on the serial number, and there is only one instance of that
+ * serial number on the system, then assume that the PVID in the
+ * devices file is outdated and pair the du and dev, and update the
+ * PVID in the devices file. (This is what's done for du and dev with
+ * matching wwid but unmatching PVID.)
+ */
+ dm_list_iterate_items(dul, &dus_check) {
+ du = dul->du;
+
+ /* matched in previous loop using pvid */
+ if (du->dev)
+ continue;
+
+ log_debug("Matching suspect serial device id %s unmatched PVID %s prev %s",
+ du->idname, du->pvid, du->devname);
+ dev = NULL;
+ count = 0;
+ /* count the number of devs using this serial number */
+ dm_list_iterate_items(devl, &devs_check) {
+ if (_dev_has_id(devl->dev, DEV_ID_TYPE_SYS_SERIAL, du->idname)) {
+ dev = devl->dev;
+ count++;
+ }
+ if (count > 1)
+ break;
+ }
+ if (count != 1) {
+ log_warn("No device matches devices file PVID %s with duplicate serial number %s previously %s.",
+ du->pvid, du->idname, du->devname);
+ continue;
+ }
+
+ log_warn("Device %s with serial number %s has PVID %s (devices file %s)",
+ dev_name(dev), du->idname, dev->pvid, du->pvid ?: "none");
+ if (!(tmpdup = strdup(dev->pvid)))
+ continue;
+ free(du->pvid);
+ du->pvid = tmpdup;
+ du->dev = dev;
+ dev->flags |= DEV_MATCHED_USE_ID;
+ update_file = 1;
+ }
+
+ /*
+ * label_scan() was done based on the original du/dev matches, so if
+ * there were some changes made to the du/dev matches above, then we
+ * may need to correct the results of the label_scan:
+ *
+ * . if some devices were scanned in label_scan, but those devs are no
+ * longer matched to any du, then we need to clear the scanned info
+ * from those devs from lvmcache.
+ *
+ * . if some devices were not scanned in label_scan, but those devs are
+ * now matched to a du, then we need to run label_scan on those devs to
+ * populate lvmcache with info from them (the caller does this.)
+ */
+
+ /*
+ * Find devs that were previously matched to a du but now are not.
+ * Clear the filter state and lvmcache info for them.
+ */
+ dm_list_iterate_items(dil, &prev_devs) {
+ if (!get_du_for_dev(cmd, dil->dev)) {
+ log_debug("Drop incorrectly matched serial %s", dev_name(dil->dev));
+ cmd->filter->wipe(cmd, cmd->filter, dil->dev, NULL);
+ lvmcache_del_dev(dil->dev);
+ }
+ }
+
+ /*
+ * Find devs that are now matched to a du but were not previously
+ * scanned by label_scan (DEV_SCAN_FOUND_LABEL). The caller will
+ * call label_scan on the devs returned in the list.
+ */
+ dm_list_iterate_items(dul, &dus_check) {
+ if (!(dev = dul->du->dev))
+ continue;
+ if (!(dev->flags & DEV_SCAN_FOUND_LABEL)) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ continue;
+ devl->dev = dev;
+ dm_list_add(scan_devs, &devl->list);
+ }
+ }
+
+ /*
+ * Look for dus_check entries that were originally matched to a dev
+ * but now are not. Warn about these like device_ids_match() would.
+ */
+ dm_list_iterate_items(dul, &dus_check) {
+ if (!dul->du->dev) {
+ du = dul->du;
+ log_warn("Devices file %s %s PVID %s not found.",
+ idtype_to_str(du->idtype),
+ du->idname ?: "none",
+ du->pvid ?: "none");
+ if (du->devname) {
+ free(du->devname);
+ du->devname = NULL;
+ update_file = 1;
+ }
+ }
+ }
+
+ if (update_file && update_needed)
+ *update_needed = 1;
+
+ if (update_file && !noupdate)
+ _device_ids_update_try(cmd);
+}
+
/*
* Devices with IDNAME=devname that are mistakenly included by filter-deviceid
* due to a devname change are fully scanned and added to lvmcache.
@@ -2903,6 +3279,7 @@ void unlock_devices_file(struct cmd_context *cmd)
void devices_file_init(struct cmd_context *cmd)
{
dm_list_init(&cmd->use_devices);
+ dm_list_init(&cmd->device_ids_check_serial);
}
void devices_file_exit(struct cmd_context *cmd)
diff --git a/lib/device/device_id.h b/lib/device/device_id.h
index 700176bb5..bc9292fea 100644
--- a/lib/device/device_id.h
+++ b/lib/device/device_id.h
@@ -35,6 +35,7 @@ int device_ids_match_dev(struct cmd_context *cmd, struct device *dev);
void device_ids_match_device_list(struct cmd_context *cmd);
void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, int *device_ids_invalid, int noupdate);
int device_ids_version_unchanged(struct cmd_context *cmd);
+void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs, int *update_needed, int noupdate);
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);
const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_t idtype);
void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg, struct id *old_vg_id);
diff --git a/test/shell/devicesfile-serial.sh b/test/shell/devicesfile-serial.sh
new file mode 100644
index 000000000..b7bfce29e
--- /dev/null
+++ b/test/shell/devicesfile-serial.sh
@@ -0,0 +1,777 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='device id wwid from vpd_pg83'
+
+. lib/inittest
+
+test "$DM_DEV_DIR" = "/dev" || skip "Only works with /dev access -> make check LVM_TEST_DEVDIR=/dev"
+
+aux lvmconf 'devices/use_devicesfile = 1'
+# requires trailing / to match dm
+aux lvmconf 'devices/device_id_sysfs_dir = "/test/sys/"'
+SYS_DIR="/test/sys"
+
+
+# The string format of the serial numbers
+# encoded in the pg80 files
+SERIAL1=003dd33a331c183c2300e1d883604609
+SERIAL2=003dd33a441c183c2300e1d883604609
+SERIAL3=003dd33a551c183c2300e1d883604609
+SERIAL4=003dd33a661c183c2300e1d883604609
+
+create_base() {
+ mkdir -p $SYS_DIR/dev/block
+ mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+ mkdir -p $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device
+ mkdir -p $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device
+ mkdir -p $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device
+
+ # Create four different pg80 serial numbers that
+ # can be assigned to devs
+
+ echo -n "0080 0020 3030 3364 6433 3361 3333 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_1
+
+ echo -n "0080 0020 3030 3364 6433 3361 3434 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_2
+
+ echo -n "0080 0020 3030 3364 6433 3361 3535 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_3
+
+ echo -n "0080 0020 3030 3364 6433 3361 3636 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_4
+}
+
+remove_base() {
+ rm -rf $SYS_DIR
+}
+
+modprobe brd
+sleep 2
+remove_base
+
+dev1=/dev/ram0
+dev2=/dev/ram1
+dev3=/dev/ram2
+dev4=/dev/ram3
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+ORIG="$DFDIR/orig.devices"
+touch $DF
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+vgcreate $vg1 "$dev1"
+MAJOR1=`pvs "$dev1" --noheading -o major | tr -d - | awk '{print $1}'`
+MINOR1=`pvs "$dev1" --noheading -o minor | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+vgcreate $vg2 "$dev2"
+MAJOR2=`pvs "$dev2" --noheading -o major | tr -d - | awk '{print $1}'`
+MINOR2=`pvs "$dev2" --noheading -o minor | tr -d - | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+vgcreate $vg3 "$dev3"
+MAJOR3=`pvs "$dev3" --noheading -o major | tr -d - | awk '{print $1}'`
+MINOR3=`pvs "$dev3" --noheading -o minor | tr -d - | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+vgcreate $vg4 "$dev4"
+MAJOR4=`pvs "$dev4" --noheading -o major | tr -d - | awk '{print $1}'`
+MINOR4=`pvs "$dev4" --noheading -o minor | tr -d - | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+create_base
+
+
+# get serial number from pg80
+cp pg80_1 $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg80
+cp pg80_2 $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/vpd_pg80
+cp pg80_3 $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/vpd_pg80
+cp pg80_4 $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/vpd_pg80
+
+rm $DF
+lvmdevices --adddev "$dev1"
+grep $SERIAL1 $DF
+lvmdevices --adddev "$dev2"
+grep $SERIAL2 $DF
+lvmdevices --adddev "$dev3"
+grep $SERIAL3 $DF
+lvmdevices --adddev "$dev4"
+grep $SERIAL4 $DF
+cat $DF
+cp $DF $ORIG
+pvs
+# run command to update metadata so deviceids are written to metadata
+vgchange --addtag x $vg1
+vgchange --addtag x $vg2
+vgchange --addtag x $vg3
+vgchange --addtag x $vg4
+pvs -o uuid,deviceidtype,deviceid "$dev1" |tee out
+grep $OPVID1 out
+grep sys_serial out
+grep $SERIAL1 out
+pvs -o uuid,deviceidtype,deviceid "$dev2" |tee out
+grep $OPVID2 out
+grep sys_serial out
+grep $SERIAL2 out
+
+# get serial number from device/serial
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg80
+rm $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/vpd_pg80
+rm $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/vpd_pg80
+rm $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/vpd_pg80
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL2 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL3 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL4 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+pvcreate $dev1
+pvcreate $dev2
+pvcreate $dev3
+pvcreate $dev4
+grep $SERIAL1 $DF
+grep $SERIAL2 $DF
+grep $SERIAL3 $DF
+grep $SERIAL4 $DF
+
+# all pvs have the same serial number
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+vgcreate $vg3 $dev3
+vgcreate $vg4 $dev4
+cp $DF $ORIG
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID2 $DF |tee out
+grep $SERIAL1 out
+grep $dev2 out
+grep $PVID3 $DF |tee out
+grep $SERIAL1 out
+grep $dev3 out
+grep $PVID4 $DF |tee out
+grep $SERIAL1 out
+grep $dev4 out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep $dev1 out
+grep $dev2 out
+grep $dev3 out
+grep $dev4 out
+grep $OPVID1 out
+grep $OPVID2 out
+grep $OPVID3 out
+grep $OPVID4 out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $vg4 out
+grep sys_serial out
+grep $SERIAL1 out
+
+pvs -o+uuid,deviceid $dev1 |tee out
+grep $OPVID1 out
+grep $SERIAL1 out
+grep $vg1 out
+
+pvs -o+uuid,deviceid $dev2 |tee out
+grep $OPVID2 out
+grep $SERIAL1 out
+grep $vg2 out
+
+pvs -o+uuid,deviceid $dev3 |tee out
+grep $OPVID3 out
+grep $SERIAL1 out
+grep $vg3 out
+
+pvs -o+uuid,deviceid $dev4 |tee out
+grep $OPVID4 out
+grep $SERIAL1 out
+grep $vg4 out
+
+
+# all pvs have the same serial number, df devnames are stale
+# edit DF to make devnames stale
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev2|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev3|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev3|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $dev4 out |tee out4
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $OPVID4 out4
+grep $SERIAL1 out1
+grep $SERIAL1 out2
+grep $SERIAL1 out3
+grep $SERIAL1 out4
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID2 $DF |tee out
+grep $SERIAL1 out
+grep $dev2 out
+grep $PVID3 $DF |tee out
+grep $SERIAL1 out
+grep $dev3 out
+grep $PVID4 $DF |tee out
+grep $SERIAL1 out
+grep $dev4 out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev2"|tee out2
+pvs -o+uuid,deviceid "$dev3"|tee out3
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $OPVID4 out4
+
+# all pvs have the same serial number,
+# dev1 and dev2 have devnames swapped,
+# dev3 has stale PVID in the DF.
+# lvm fixes the stale devnames but does not fix the stale PVID
+# because of the duplicate serial numbers, so dev3 is not found
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|PVID=$PVID4|PVID=4SqT4onBxSiv4dot0GRDPtrWqOlrOPH1|" tmp2 > "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+not grep $dev4 out
+not grep $OPVID4 out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+
+not pvs "$dev4"
+
+# dev1&2 have same serial, dev3&4 have same serial
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL2 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL2 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+vgcreate $vg3 $dev3
+vgcreate $vg4 $dev4
+cp $DF $ORIG
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID2 $DF |tee out
+grep $SERIAL1 out
+grep $dev2 out
+grep $PVID3 $DF |tee out
+grep $SERIAL2 out
+grep $dev3 out
+grep $PVID4 $DF |tee out
+grep $SERIAL2 out
+grep $dev4 out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep $dev1 out
+grep $dev2 out
+grep $dev3 out
+grep $dev4 out
+grep $OPVID1 out
+grep $OPVID2 out
+grep $OPVID3 out
+grep $OPVID4 out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $vg4 out
+grep sys_serial out
+grep $SERIAL1 out
+grep $SERIAL2 out
+
+pvs -o+uuid,deviceid $dev1 |tee out
+grep $OPVID1 out
+grep $SERIAL1 out
+grep $vg1 out
+
+pvs -o+uuid,deviceid $dev2 |tee out
+grep $OPVID2 out
+grep $SERIAL1 out
+grep $vg2 out
+
+pvs -o+uuid,deviceid $dev3 |tee out
+grep $OPVID3 out
+grep $SERIAL2 out
+grep $vg3 out
+
+pvs -o+uuid,deviceid $dev4 |tee out
+grep $OPVID4 out
+grep $SERIAL2 out
+grep $vg4 out
+
+# dev1&2 have serial1 and dev3&4 have serial2, swap devnames
+# edit DF to make devnames stale
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev3|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev3|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev2|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev2|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $dev4 out |tee out4
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $OPVID4 out4
+grep $SERIAL1 out1
+grep $SERIAL1 out2
+grep $SERIAL2 out3
+grep $SERIAL2 out4
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID2 $DF |tee out
+grep $SERIAL1 out
+grep $dev2 out
+grep $PVID3 $DF |tee out
+grep $SERIAL2 out
+grep $dev3 out
+grep $PVID4 $DF |tee out
+grep $SERIAL2 out
+grep $dev4 out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev2"|tee out2
+pvs -o+uuid,deviceid "$dev3"|tee out3
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep $OPVID1 out1
+grep $SERIAL1 out1
+grep $OPVID2 out2
+grep $SERIAL1 out2
+grep $OPVID3 out3
+grep $SERIAL2 out3
+grep $OPVID4 out4
+grep $SERIAL2 out4
+
+
+# all devs have same serial, dev1&4 are pvs, dev2&3 are not pvs
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg4 $dev4
+cp $DF $ORIG
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID4 $DF |tee out
+grep $SERIAL1 out
+grep $dev4 out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep $dev1 out
+grep $dev4 out
+grep $OPVID1 out
+grep $OPVID4 out
+grep $vg1 out
+grep $vg4 out
+grep sys_serial out
+grep $SERIAL1 out
+
+pvs -o+uuid,deviceid $dev1 |tee out
+grep $OPVID1 out
+grep $SERIAL1 out
+grep $vg1 out
+
+not pvs -o+uuid,deviceid $dev2
+not pvs -o+uuid,deviceid $dev3
+
+pvs -o+uuid,deviceid $dev4 |tee out
+grep $OPVID4 out
+grep $SERIAL1 out
+grep $vg4 out
+
+# edit DF to make devnames stale
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" orig > tmp1
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev3|" tmp1 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev4 out |tee out4
+grep $OPVID1 out1
+grep $OPVID4 out4
+grep $SERIAL1 out1
+grep $SERIAL1 out4
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID4 $DF |tee out
+grep $SERIAL1 out
+grep $dev4 out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep $OPVID1 out1
+grep $SERIAL1 out1
+grep $OPVID4 out4
+grep $SERIAL1 out4
+
+# one pv with serial, three other non-pvs with same serial
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg2 $dev2
+cp $DF $ORIG
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+
+grep $PVID2 $DF |tee out
+grep $SERIAL1 out
+grep $dev2 out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep $dev2 out
+grep sys_serial out
+grep $SERIAL1 out
+not grep $dev1 out
+not grep $dev3 out
+not grep $dev4 out
+
+# edit DF to make devname stale
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev3|" orig > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev2 out
+grep $OPVID2 out
+grep $SERIAL1 out
+grep $dev2 "$DF"
+
+# different serial numbers, stale pvid and devname in df,
+# lvm corrects pvid in df because serial number is unique
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL2 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL3 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL4 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+vgcreate $vg3 $dev3
+vgcreate $vg4 $dev4
+cp $DF $ORIG
+grep $SERIAL1 $DF
+grep $SERIAL2 $DF
+grep $SERIAL3 $DF
+grep $SERIAL4 $DF
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+pvs -o+uuid,deviceid
+
+cp $ORIG orig
+sed -e "s|PVID=$PVID1|PVID=bad14onBxSiv4dot0GRDPtrWqOlr1bad|" orig > tmp1
+sed -e "s|PVID=$PVID3|PVID=bad24onBxSiv4dot0GRDPtrWqOlr2bad|" tmp1 > tmp2
+sed -e "s|DEVNAME=$dev1|DEVNAME=.|" tmp2 > "$DF"
+cat $DF
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $dev4 out |tee out4
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $OPVID4 out4
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep $vg4 out4
+grep $SERIAL1 out1
+grep $SERIAL2 out2
+grep $SERIAL3 out3
+grep $SERIAL4 out4
+
+grep $PVID1 $DF |tee out
+grep $SERIAL1 out
+grep $dev1 out
+grep $PVID2 $DF |tee out
+grep $SERIAL2 out
+grep $dev2 out
+grep $PVID3 $DF |tee out
+grep $SERIAL3 out
+grep $dev3 out
+grep $PVID4 $DF |tee out
+grep $SERIAL4 out
+grep $dev4 out
+
+# duplicate serial on two pvs, two pvs with devname type, all devnames stale
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo "" > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo "" > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+vgcreate $vg3 $dev3
+vgcreate $vg4 $dev4
+cp $DF $ORIG
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+OPVID4=`pvs "$dev4" --noheading -o uuid | awk '{print $1}'`
+cat $DF
+
+pvs -o+uuid,deviceid
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev3|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev3|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev2|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev2|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat $DF
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $dev4 out |tee out4
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $OPVID4 out4
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep $vg4 out4
+grep $SERIAL1 out1
+grep $SERIAL1 out2
+
+cat $DF
+grep $PVID1 $DF |tee out1
+grep $PVID2 $DF |tee out2
+grep $PVID3 $DF |tee out3
+grep $PVID4 $DF |tee out4
+grep $dev1 out1
+grep $SERIAL1 out1
+grep $dev2 out2
+grep $SERIAL1 out2
+grep $dev3 out3
+grep $dev4 out4
+
+# two pvs with duplicate serial and stale devname, one pv with unique serial and stale pvid
+
+aux wipefs_a $dev1
+aux wipefs_a $dev2
+aux wipefs_a $dev3
+aux wipefs_a $dev4
+
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial
+echo $SERIAL3 > $SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial
+echo $SERIAL1 > $SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial
+
+rm $DF
+touch $DF
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+vgcreate $vg3 $dev3
+cp $DF $ORIG
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+cat $DF
+
+pvs -o+uuid,deviceid
+
+cp $ORIG orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev4|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|PVID=$dev3|PVID=bad14onBxSiv4dot0GRDPtrWqOlr1bad|" tmp2 > $DF
+cat $DF
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $dev3 out |tee out3
+grep $OPVID1 out1
+grep $OPVID2 out2
+grep $OPVID3 out3
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep $SERIAL1 out1
+grep $SERIAL1 out2
+grep $SERIAL3 out3
+
+cat $DF
+grep $PVID1 $DF |tee out1
+grep $PVID2 $DF |tee out2
+grep $PVID3 $DF |tee out3
+grep $dev1 out1
+grep $SERIAL1 out1
+grep $dev2 out2
+grep $SERIAL1 out2
+grep $dev3 out3
+grep $SERIAL3 out3
+
+remove_base
+rmmod brd
+
diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c
index 5d9c0c7b7..e58ab4490 100644
--- a/tools/lvmdevices.c
+++ b/tools/lvmdevices.c
@@ -124,6 +124,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
{
struct dm_list search_pvids;
struct dm_list found_devs;
+ struct dm_list scan_devs;
struct device_id_list *dil;
struct device_list *devl;
struct device *dev;
@@ -132,6 +133,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
dm_list_init(&search_pvids);
dm_list_init(&found_devs);
+ dm_list_init(&scan_devs);
if (!setup_devices_file(cmd))
return ECMD_FAILED;
@@ -186,6 +188,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
int update_set = arg_is_set(cmd, update_ARG);
int search_count = 0;
int update_needed = 0;
+ int serial_update_needed = 0;
int invalid = 0;
unlink_searched_devnames(cmd);
@@ -273,6 +276,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
}
}
+ if (!dm_list_empty(&cmd->device_ids_check_serial))
+ device_ids_check_serial(cmd, &scan_devs, &serial_update_needed, 1);
+
/*
* Find and fix any devname entries that have moved to a
* renamed device.
@@ -288,7 +294,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
}
if (arg_is_set(cmd, update_ARG)) {
- if (update_needed || !dm_list_empty(&found_devs)) {
+ if (update_needed || serial_update_needed || !dm_list_empty(&found_devs)) {
if (!device_ids_write(cmd))
goto_bad;
log_print("Updated devices file to version %s", devices_file_version());
@@ -301,7 +307,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* needs updates, i.e. running --update would make
* changes.
*/
- if (update_needed) {
+ if (update_needed || serial_update_needed) {
log_error("Updates needed for devices file.");
goto bad;
}
1 year, 5 months
main - device_id: look for serial number in other locations
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=bdab36cf3f059e59737...
Commit: bdab36cf3f059e597371bb504646f4dfb7a89f50
Parent: 36a923926c2c27c1a8a5ac262387d2a4d3e620f8
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Oct 24 16:23:36 2022 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Nov 7 08:56:02 2022 -0600
device_id: look for serial number in other locations
Only /sys/dev/block/major:minor/device/serial was read to find
a disk serial number, but a serial number seems to be reported
more often in other locations, so check these also:
/sys/dev/block/major:minor/device/vpd_pg80
/sys/class/block/vda/serial (for virtio disks only)
---
lib/device/device.h | 1 +
lib/device/device_id.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--
lib/device/parse_vpd.c | 40 ++++++++++++++++++++++++++++++
3 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/lib/device/device.h b/lib/device/device.h
index ca46490ce..519754e41 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -228,5 +228,6 @@ int dev_mpath_init(const char *config_wwids_file);
void dev_mpath_exit(void);
int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list *ids);
int format_t10_id(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes);
+int parse_vpd_serial(const unsigned char *in, char *out, int outsize);
#endif
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index bd9b3c4bf..15b34a158 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -454,6 +454,67 @@ int dev_read_sys_wwid(struct cmd_context *cmd, struct device *dev,
return 1;
}
+static int _dev_read_sys_serial(struct cmd_context *cmd, struct device *dev,
+ char *buf, int bufsize)
+{
+ unsigned char vpd_data[VPD_SIZE] = { 0 };
+ const char *devname;
+ int vpd_datalen = 0;
+
+ /*
+ * Look in
+ * /sys/dev/block/major:minor/device/serial
+ * /sys/dev/block/major:minor/device/vpd_pg80
+ * /sys/class/block/vda/serial
+ * (Only virtio disks /dev/vdx are known to use /sys/class/block/vdx/serial.)
+ */
+
+ read_sys_block(cmd, dev, "device/serial", buf, bufsize);
+ if (buf[0])
+ return 1;
+
+ if (read_sys_block_binary(cmd, dev, "device/vpd_pg80", (char *)vpd_data, VPD_SIZE, &vpd_datalen) && vpd_datalen) {
+ parse_vpd_serial(vpd_data, buf, bufsize);
+ if (buf[0])
+ return 1;
+ }
+
+ devname = dev_name(dev);
+ if (!strncmp(devname, "/dev/vd", 7)) {
+ char path[PATH_MAX];
+ char vdx[8] = { 0 };
+ const char *sysfs_dir;
+ const char *base;
+ int i, j = 0, ret;
+
+ /* /dev/vda to vda */
+ base = basename(devname);
+
+ /* vda1 to vda */
+ for (i = 0; i < strlen(base); i++) {
+ if (isdigit(base[i]))
+ break;
+ vdx[j] = base[i];
+ j++;
+ }
+
+ sysfs_dir = cmd->device_id_sysfs_dir ?: dm_sysfs_dir();
+
+ if (dm_snprintf(path, sizeof(path), "%s/class/block/%s/serial", sysfs_dir, vdx) < 0)
+ return 0;
+
+ ret = get_sysfs_value(path, buf, bufsize, 0);
+ if (ret && !buf[0])
+ ret = 0;
+ if (ret) {
+ buf[bufsize - 1] = '\0';
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_t idtype)
{
char sysbuf[PATH_MAX] = { 0 };
@@ -471,8 +532,9 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
sysbuf[0] = '\0';
}
- else if (idtype == DEV_ID_TYPE_SYS_SERIAL)
- read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
+ else if (idtype == DEV_ID_TYPE_SYS_SERIAL) {
+ _dev_read_sys_serial(cmd, dev, sysbuf, sizeof(sysbuf));
+ }
else if (idtype == DEV_ID_TYPE_MPATH_UUID) {
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
diff --git a/lib/device/parse_vpd.c b/lib/device/parse_vpd.c
index 99e8c0ec2..23b0c6efa 100644
--- a/lib/device/parse_vpd.c
+++ b/lib/device/parse_vpd.c
@@ -211,3 +211,43 @@ int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list
return id_size;
}
+
+int parse_vpd_serial(const unsigned char *in, char *out, int outsize)
+{
+ uint8_t len_buf[2] __attribute__((aligned(8))) = { 0 };;
+ size_t len;
+
+ /* parsing code from multipath tools */
+ /* ignore in[0] and in[1] */
+ /* len is in[2] and in[3] */
+ /* serial begins at in[4] */
+
+ len_buf[0] = in[2];
+ len_buf[1] = in[3];
+ len = len_buf[0] << 8 | len_buf[1];
+
+ if (outsize == 0)
+ return 0;
+
+ if (len > DEV_WWID_SIZE)
+ len = DEV_WWID_SIZE;
+ /*
+ * Strip leading and trailing whitespace
+ */
+ while (len > 0 && in[len + 3] == ' ')
+ --len;
+ while (len > 0 && in[4] == ' ') {
+ ++in;
+ --len;
+ }
+
+ if (len >= outsize)
+ len = outsize - 1;
+
+ if (len > 0) {
+ memcpy(out, in + 4, len);
+ out[len] = '\0';
+ }
+ return len;
+}
+
1 year, 5 months
rhel-8.7.0 - apply multipath_component_detection=0 to duplicate PV handling
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=377ed7d9bac948e1be9...
Commit: 377ed7d9bac948e1be97e78aa9f9e525e9af470d
Parent: 73b9a2805ca2f2c70f6f631b405f8fea3f72f23b
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jul 25 13:50:43 2022 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Nov 2 12:20:07 2022 -0500
apply multipath_component_detection=0 to duplicate PV handling
multipath_component_detection=0 has always applied to the filter-based
component detection. Also apply this setting to the duplicate-PV
handling which also eliminates multipath components (based on duplicate
PVs having the same wwid.)
---
lib/cache/lvmcache.c | 3 +++
test/shell/duplicate-pvs-multipath.sh | 10 +++++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 61a2fee6d..04e9f0605 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -640,6 +640,9 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
*dev_mpath = NULL;
+ if (!find_config_tree_bool(cmd, devices_multipath_component_detection_CFG, NULL))
+ return 0;
+
/* This function only makes sense with more than one dev. */
if ((info && dm_list_empty(altdevs)) || (!info && (dm_list_size(altdevs) == 1))) {
log_debug("Skip multipath component checks with single device for PVID %s", pvid);
diff --git a/test/shell/duplicate-pvs-multipath.sh b/test/shell/duplicate-pvs-multipath.sh
index 59c15b0d4..bc98d2d5a 100644
--- a/test/shell/duplicate-pvs-multipath.sh
+++ b/test/shell/duplicate-pvs-multipath.sh
@@ -24,9 +24,13 @@ modprobe --dry-run scsi_debug || skip
multipath -l || skip
multipath -l | grep scsi_debug && skip
-# Turn off multipath_component_detection so that the duplicate
-# resolution of mpath components is used.
-aux lvmconf 'devices/multipath_component_detection = 0'
+# FIXME: setting multipath_component_detection=0 now also disables
+# the wwid-based mpath component detection, so this test will need
+# to find another way to disable only the filter-mpath code (using
+# sysfs and multipath/wwids) while keeping the code enabled that
+# eliminates duplicates based on their matching wwids which this
+# tries to test.
+
# Prevent wwids from being used for filtering.
aux lvmconf 'devices/multipath_wwids_file = "/dev/null"'
# Need to use /dev/mapper/mpath
1 year, 5 months
main - device_mapper: vdo V4 avoid messaging
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=36a923926c2c27c1a8a...
Commit: 36a923926c2c27c1a8a5ac262387d2a4d3e620f8
Parent: 2e79b005c2013fb03d8a48a3cfd8e70a982dd65b
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 27 23:58:42 2022 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Nov 2 13:59:34 2022 +0100
device_mapper: vdo V4 avoid messaging
With V4 format build table line with compression and
deduplication and skip sending any messages to set up
these parameters.
---
device_mapper/libdm-deptree.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
index 0445e1b4b..02a56c8e3 100644
--- a/device_mapper/libdm-deptree.c
+++ b/device_mapper/libdm-deptree.c
@@ -2894,12 +2894,15 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name);
} else {
- EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u ",
+ EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
+ "deduplication %s compression %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
- seg->vdo_params.block_map_era_length);
+ seg->vdo_params.block_map_era_length,
+ seg->vdo_params.use_deduplication ? "on" : "off",
+ seg->vdo_params.use_compression ? "on" : "off");
}
EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
@@ -4376,7 +4379,8 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
seg->vdo_name = vdo_pool_name;
seg->vdo_data_size = data_size;
- node->props.send_messages = 2;
+ if (seg->vdo_version < 4)
+ node->props.send_messages = 2;
return 1;
}
1 year, 5 months
main - dev_manager: accept misalined vdo pools.
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=2e79b005c2013fb03d8...
Commit: 2e79b005c2013fb03d8a48a3cfd8e70a982dd65b
Parent: 829ab017082eaad253ebd28ad7d7ae7f3936dbcb
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Oct 26 14:38:29 2022 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Nov 2 13:59:34 2022 +0100
dev_manager: accept misalined vdo pools.
Since lvm2 may create VDO pool virtual size aligned only on extent size
while VDO itself is just 4K aligned - we need to support such misalign.
---
lib/activate/dev_manager.c | 8 +++++---
lib/metadata/vdo_manip.c | 10 ++--------
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 5fec52a2a..cafb94ad5 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -277,7 +277,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
int dmtask;
int with_flush; /* TODO: arg for _info_run */
void *target = NULL;
- uint64_t target_start, target_length, start, length, length_crop = 0;
+ uint64_t target_start, target_length, start, extent_size, length, length_crop = 0;
char *target_name, *target_params;
const char *devname;
@@ -306,8 +306,8 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
/* Query status only for active device */
if (seg_status && dminfo->exists) {
- start = length = seg_status->seg->lv->vg->extent_size;
- start *= seg_status->seg->le;
+ extent_size = length = seg_status->seg->lv->vg->extent_size;
+ start = extent_size * seg_status->seg->le;
length *= _seg_len(seg_status->seg);
/* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */
@@ -328,6 +328,8 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
if ((start == target_start) &&
((length == target_length) ||
+ ((lv_is_vdo_pool(seg_status->seg->lv)) && /* should fit within extent size */
+ (length < target_length) && ((length + extent_size) > target_length)) ||
(length_crop && (length_crop == target_length))))
break; /* Keep target_params when matching segment is found */
diff --git a/lib/metadata/vdo_manip.c b/lib/metadata/vdo_manip.c
index 779883d03..0181dc6d5 100644
--- a/lib/metadata/vdo_manip.c
+++ b/lib/metadata/vdo_manip.c
@@ -263,7 +263,6 @@ static int _format_vdo_pool_data_lv(struct logical_volume *data_lv,
return 0;
}
-reformat:
if (*logical_size) {
logical_size_aligned = 0;
if (dm_snprintf(buf_args[args], sizeof(buf_args[0]), "--logical-size=" FMTu64 "K",
@@ -374,13 +373,8 @@ reformat:
// align obtained size to extent size
logical_size_aligned = *logical_size / data_lv->vg->extent_size * data_lv->vg->extent_size;
if (*logical_size != logical_size_aligned) {
- *logical_size = logical_size_aligned;
- argv[1] = (char*) "--force";
- args = 2;
- reformating = 1;
- log_verbose("Reformating VDO to align virtual size %s by extent size.",
- display_size(data_lv->vg->cmd, *logical_size));
- goto reformat;
+ log_debug("Using bigger VDO virtual size unaligned on extent size by %s.",
+ display_size(data_lv->vg->cmd, *logical_size - logical_size_aligned));
}
}
1 year, 5 months
main - device_mapper: add parser for vdo metadata
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=829ab017082eaad253e...
Commit: 829ab017082eaad253ebd28ad7d7ae7f3936dbcb
Parent: 17baeb65a913fb1793d0142b20087b10a7f88e37
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Oct 26 14:33:09 2022 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Nov 2 13:59:34 2022 +0100
device_mapper: add parser for vdo metadata
Add very simplistic parser of vdo metadata to be able to obtain
logical_blocks stored within vdo metadata - as lvm2 may
submit smaller value due to internal aligment rules.
To avoid creation of mismatching table line - use this number
instead the one provided by lvm2.
---
device_mapper/Makefile | 3 +-
device_mapper/libdm-deptree.c | 15 +++
device_mapper/vdo/target.h | 2 +
device_mapper/vdo/vdo_reader.c | 279 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 298 insertions(+), 1 deletion(-)
diff --git a/device_mapper/Makefile b/device_mapper/Makefile
index d3b791eb5..a322235cb 100644
--- a/device_mapper/Makefile
+++ b/device_mapper/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
@@ -29,6 +29,7 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \
device_mapper/vdo/status.c \
+ device_mapper/vdo/vdo_reader.c \
device_mapper/vdo/vdo_target.c
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a
diff --git a/device_mapper/libdm-deptree.c b/device_mapper/libdm-deptree.c
index 2d382037c..0445e1b4b 100644
--- a/device_mapper/libdm-deptree.c
+++ b/device_mapper/libdm-deptree.c
@@ -2857,6 +2857,7 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
int pos = 0;
char data[DM_FORMAT_DEV_BUFSIZE];
char data_dev[128]; // for /dev/dm-XXXX
+ uint64_t logical_blocks;
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
return_0;
@@ -2866,6 +2867,20 @@ static int _vdo_emit_segment_line(struct dm_task *dmt,
return 0;
}
+ if (dm_vdo_parse_logical_size(data_dev, &logical_blocks)) {
+ logical_blocks *= 8;
+ if (seg->size != logical_blocks) {
+ if (seg->size > logical_blocks) {
+ log_error("Virtual size of VDO volume is smaller then expected (" FMTu64 " > " FMTu64 ").",
+ seg->size, logical_blocks);
+ return 1;
+ }
+ log_debug_activation("Increasing VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
+ seg->size, logical_blocks);
+ seg->size = logical_blocks;
+ }
+ }
+
if (seg->vdo_version < 4) {
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
data_dev,
diff --git a/device_mapper/vdo/target.h b/device_mapper/vdo/target.h
index 60c5bff56..bd21bb5d7 100644
--- a/device_mapper/vdo/target.h
+++ b/device_mapper/vdo/target.h
@@ -108,6 +108,8 @@ struct dm_vdo_target_params {
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size);
+bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
+
//----------------------------------------------------------------
#endif
diff --git a/device_mapper/vdo/vdo_reader.c b/device_mapper/vdo/vdo_reader.c
new file mode 100644
index 000000000..b765af042
--- /dev/null
+++ b/device_mapper/vdo/vdo_reader.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2022 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * 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
+ */
+
+/*
+ * Based on VDO sources: https://github.com/dm-vdo/vdo
+ *
+ * Simplified parser of VDO superblock to obtain basic VDO parameteers
+ *
+ * TODO: maybe switch to some library in the future
+ */
+
+//#define _GNU_SOURCE 1
+//#define _LARGEFILE64_SOURCE 1
+
+#include "device_mapper/misc/dmlib.h"
+
+#include "target.h"
+
+#include "lib/mm/xlate.h"
+//#include "linux/byteorder/big_endian.h"
+//#include "linux/byteorder/little_endian.h"
+//#define le32_to_cpu __le32_to_cpu
+//#define le64_to_cpu __le64_to_cpu
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fs.h> /* For block ioctl definitions */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+typedef unsigned char uuid_t[16];
+
+#define __packed __attribute__((packed))
+
+static const char _MAGIC_NUMBER[] = "dmvdo001";
+#define MAGIC_NUMBER_SIZE (sizeof(_MAGIC_NUMBER) - 1)
+
+struct vdo_version_number {
+ uint32_t major_version;
+ uint32_t minor_version;
+} __packed;
+
+/*
+ * The registry of component ids for use in headers
+ */
+enum {
+ SUPER_BLOCK = 0,
+ FIXED_LAYOUT = 1,
+ RECOVERY_JOURNAL = 2,
+ SLAB_DEPOT = 3,
+ BLOCK_MAP = 4,
+ GEOMETRY_BLOCK = 5,
+}; /* ComponentID */
+
+struct vdo_header {
+ uint32_t id; /* The component this is a header for */
+ struct vdo_version_number version; /* The version of the data format */
+ size_t size; /* The size of the data following this header */
+} __packed;
+
+struct vdo_geometry_block {
+ char magic_number[MAGIC_NUMBER_SIZE];
+ struct vdo_header header;
+ uint32_t checksum;
+} __packed;
+
+struct vdo_config {
+ uint64_t logical_blocks; /* number of logical blocks */
+ uint64_t physical_blocks; /* number of physical blocks */
+ uint64_t slab_size; /* number of blocks in a slab */
+ uint64_t recovery_journal_size; /* number of recovery journal blocks */
+ uint64_t slab_journal_blocks; /* number of slab journal blocks */
+} __packed;
+
+struct vdo_component_41_0 {
+ uint32_t state;
+ uint64_t complete_recoveries;
+ uint64_t read_only_recoveries;
+ struct vdo_config config; /* packed */
+ uint64_t nonce;
+} __packed;
+
+enum vdo_volume_region_id {
+ VDO_INDEX_REGION = 0,
+ VDO_DATA_REGION = 1,
+ VDO_VOLUME_REGION_COUNT,
+};
+
+struct vdo_volume_region {
+ /* The ID of the region */
+ enum vdo_volume_region_id id;
+ /*
+ * The absolute starting offset on the device. The region continues
+ * until the next region begins.
+ */
+ uint64_t start_block;
+} __packed;
+
+struct vdo_index_config {
+ uint32_t mem;
+ uint32_t unused;
+ uint8_t sparse;
+} __packed;
+
+struct vdo_volume_geometry {
+ uint32_t release_version;
+ uint64_t nonce;
+ uuid_t uuid;
+ uint64_t bio_offset;
+ struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
+ struct vdo_index_config index_config;
+} __packed;
+
+/* Decoding mostly only some used stucture members */
+
+static void _vdo_decode_version(struct vdo_version_number *v)
+{
+ v->major_version = le32_to_cpu(v->major_version);
+ v->minor_version = le32_to_cpu(v->minor_version);
+}
+
+static void _vdo_decode_header(struct vdo_header *h)
+{
+ h->id = le32_to_cpu(h->id);
+ _vdo_decode_version(&h->version);
+ h->size = le64_to_cpu(h->size);
+}
+
+static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
+{
+ vr->id = le32_to_cpu(vr->id);
+ vr->start_block = le32_to_cpu(vr->start_block);
+}
+
+static void _vdo_decode_volume_geometry(struct vdo_volume_geometry *vg)
+{
+ vg->release_version = le64_to_cpu(vg->release_version);
+ vg->nonce = le64_to_cpu(vg->nonce);
+ _vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
+}
+
+static void _vdo_decode_config(struct vdo_config *vc)
+{
+ vc->logical_blocks = le64_to_cpu(vc->logical_blocks);
+ vc->physical_blocks = le64_to_cpu(vc->physical_blocks);
+ vc->slab_size = le64_to_cpu(vc->slab_size);
+ vc->recovery_journal_size = le64_to_cpu(vc->recovery_journal_size);
+ vc->slab_journal_blocks = le64_to_cpu(vc->slab_journal_blocks);
+}
+
+static void _vdo_decode_pvc(struct vdo_component_41_0 *pvc)
+{
+ _vdo_decode_config(&pvc->config);
+ pvc->nonce = le64_to_cpu(pvc->nonce);
+}
+
+bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
+{
+ char buffer[4096];
+ int fh, n;
+ bool r = false;
+ off_t l;
+ struct stat st;
+ uint64_t size;
+ uint64_t regpos;
+
+ struct vdo_header h;
+ struct vdo_version_number vn;
+ struct vdo_volume_geometry vg;
+ struct vdo_component_41_0 pvc;
+
+ *logical_blocks = 0;
+ if ((fh = open(vdo_path, O_RDONLY)) == -1) {
+ log_sys_error("Failed to open VDO backend %s", vdo_path);
+ goto err;
+ }
+
+ if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
+ if (errno != ENOTTY) {
+ log_sys_error("ioctl", vdo_path);
+ goto err;
+ }
+
+ /* lets retry for file sizes */
+ if (fstat(fh, &st) < 0) {
+ log_sys_error("fstat", vdo_path);
+ goto err;
+ }
+
+ size = st.st_size;
+ }
+
+ if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
+ log_sys_error("read", vdo_path);
+ goto err;
+ }
+
+ if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
+ log_sys_error("mismatch header", vdo_path);
+ goto err;
+ }
+
+ memcpy(&h, buffer + MAGIC_NUMBER_SIZE, sizeof(h));
+ _vdo_decode_header(&h);
+
+ if (h.version.major_version != 5) {
+ log_error("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
+ goto err;
+ }
+
+ memcpy(&vg, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg));
+ _vdo_decode_volume_geometry(&vg);
+
+ regpos = vg.regions[VDO_DATA_REGION].start_block * 4096;
+
+ if ((regpos + sizeof(buffer)) > size) {
+ log_error("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
+ goto err;
+ }
+
+ if ((l = lseek(fh, regpos, SEEK_SET)) < 0) {
+ log_sys_error("lseek", vdo_path);
+ goto err;
+ }
+
+ if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
+ log_sys_error("read error", vdo_path);
+ goto err;
+ }
+
+
+ memcpy(&vn, buffer + sizeof(struct vdo_geometry_block), sizeof(vn));
+ _vdo_decode_version(&vn);
+
+ if (vn.major_version > 41) {
+ log_error("Unknown VDO component version %u.", vn.major_version); // should be 41!
+ goto err;
+ }
+
+ memcpy(&pvc, buffer + sizeof(struct vdo_geometry_block) + sizeof(vn), sizeof(pvc));
+ _vdo_decode_pvc(&pvc);
+
+ if (pvc.nonce != vg.nonce) {
+ log_error("Mismatching VDO nonce " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
+ goto err;
+ }
+
+#if 0
+ log_debug("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
+ log_debug("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
+ log_debug("SlabSize " FMTu64 ".", pvc.config.slab_size);
+ log_debug("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
+ log_debug("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
+#endif
+
+ *logical_blocks = pvc.config.logical_blocks;
+ r = true;
+err:
+ (void) close(fh);
+
+ return r;
+}
1 year, 5 months