From f9a6852eb85783cb7e239fc95c23c1f3f328f847 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 27 2022 14:22:21 +0000 Subject: import lvm2-2.03.16-3.el9 --- diff --git a/.gitignore b/.gitignore index c6abaac..8fdb939 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/lvm2-4a1f617.tgz +SOURCES/LVM2.2.03.16.tgz diff --git a/.lvm2.metadata b/.lvm2.metadata index 1de83ef..4d2ea90 100644 --- a/.lvm2.metadata +++ b/.lvm2.metadata @@ -1 +1 @@ -b87a5a886c6cceb6e38028f1ea20d5d1d6bd23a8 SOURCES/lvm2-4a1f617.tgz +a99cfcbcb2cf665824acde03775dccc9ef54a836 SOURCES/LVM2.2.03.16.tgz diff --git a/SOURCES/0001-devices-file-do-not-clear-PVID-of-unread-devices.patch b/SOURCES/0001-devices-file-do-not-clear-PVID-of-unread-devices.patch deleted file mode 100644 index 97029f3..0000000 --- a/SOURCES/0001-devices-file-do-not-clear-PVID-of-unread-devices.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 611c3f868699471c474e12280825242978c0bed8 Mon Sep 17 00:00:00 2001 -From: David Teigland -Date: Thu, 10 Feb 2022 14:00:25 -0600 -Subject: [PATCH] devices file: do not clear PVID of unread devices - -In a certain disconnected state, a block device is present on -the system, can be opened, reports a valid size, reports the -correct device id (wwid), and matches a devices file entry. -But, reading the device can still fail. In this case, -device_ids_validate() was misinterpreting the read error as -the device having no data/label on it (and no PVID). -The validate function would then clear the PVID from the -devices file entry for the device, thinking that it was -fixing the devices file (making it consistent with the on disk -state.) Fix this by not attempting to check and correct a -devices file entry that cannot be read. Also make this case -explicit in the hints validation code (which was doing the -right thing but indirectly.) ---- - lib/device/device.h | 1 + - lib/device/device_id.c | 14 ++++++++++++++ - lib/label/hints.c | 14 ++++++++++++++ - lib/label/label.c | 8 ++++++++ - 4 files changed, 37 insertions(+) - -diff --git a/lib/device/device.h b/lib/device/device.h -index 9e471a9b5..8c3a8c30e 100644 ---- a/lib/device/device.h -+++ b/lib/device/device.h -@@ -40,6 +40,7 @@ - #define DEV_IS_NVME 0x00040000 /* set if dev is nvme */ - #define DEV_MATCHED_USE_ID 0x00080000 /* matched an entry from cmd->use_devices */ - #define DEV_SCAN_FOUND_NOLABEL 0x00100000 /* label_scan read, passed filters, but no lvm label */ -+#define DEV_SCAN_NOT_READ 0x00200000 /* label_scan not able to read dev */ - - /* - * Support for external device info. -diff --git a/lib/device/device_id.c b/lib/device/device_id.c -index 4618247ba..003f10a96 100644 ---- a/lib/device/device_id.c -+++ b/lib/device/device_id.c -@@ -1746,6 +1746,13 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, - if (scanned_devs && !dev_in_device_list(dev, scanned_devs)) - continue; - -+ /* -+ * The matched device could not be read so we do not have -+ * the PVID from disk and cannot verify the devices file entry. -+ */ -+ if (dev->flags & DEV_SCAN_NOT_READ) -+ continue; -+ - /* - * du and dev may have been matched, but the dev could still - * have been excluded by other filters during label scan. -@@ -1828,6 +1835,13 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, - if (scanned_devs && !dev_in_device_list(dev, scanned_devs)) - continue; - -+ /* -+ * The matched device could not be read so we do not have -+ * the PVID from disk and cannot verify the devices file entry. -+ */ -+ if (dev->flags & DEV_SCAN_NOT_READ) -+ continue; -+ - if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "persistent")) { - log_warn("Devices file %s is excluded by filter: %s.", - dev_name(dev), dev_filtered_reason(dev)); -diff --git a/lib/label/hints.c b/lib/label/hints.c -index 93dfdd5c1..35ae7f5cc 100644 ---- a/lib/label/hints.c -+++ b/lib/label/hints.c -@@ -236,6 +236,7 @@ static int _touch_newhints(void) - return_0; - if (fclose(fp)) - stack; -+ log_debug("newhints created"); - return 1; - } - -@@ -506,6 +507,19 @@ int validate_hints(struct cmd_context *cmd, struct dm_list *hints) - if (!hint->chosen) - continue; - -+ /* -+ * label_scan was unable to read the dev so we don't know its pvid. -+ * Since we are unable to verify the hint is correct, it's possible -+ * that the PVID is actually found on a different device, so don't -+ * depend on hints. (This would also fail the following pvid check.) -+ */ -+ if (dev->flags & DEV_SCAN_NOT_READ) { -+ log_debug("Uncertain hint for unread device %d:%d %s", -+ major(hint->devt), minor(hint->devt), dev_name(dev)); -+ ret = 0; -+ continue; -+ } -+ - if (strcmp(dev->pvid, hint->pvid)) { - log_debug("Invalid hint device %d:%d %s pvid %s had hint pvid %s", - major(hint->devt), minor(hint->devt), dev_name(dev), -diff --git a/lib/label/label.c b/lib/label/label.c -index 5c77a6923..4f29d6208 100644 ---- a/lib/label/label.c -+++ b/lib/label/label.c -@@ -687,6 +687,8 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f, - - dm_list_iterate_items_safe(devl, devl2, devs) { - -+ devl->dev->flags &= ~DEV_SCAN_NOT_READ; -+ - /* - * If we prefetch more devs than blocks in the cache, then the - * cache will wait for earlier reads to complete, toss the -@@ -702,6 +704,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f, - log_debug_devs("Scan failed to open %s.", dev_name(devl->dev)); - dm_list_del(&devl->list); - dm_list_add(&reopen_devs, &devl->list); -+ devl->dev->flags |= DEV_SCAN_NOT_READ; - continue; - } - } -@@ -725,6 +728,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f, - log_debug_devs("Scan failed to read %s.", dev_name(devl->dev)); - scan_read_errors++; - scan_failed_count++; -+ devl->dev->flags |= DEV_SCAN_NOT_READ; - lvmcache_del_dev(devl->dev); - if (bb) - bcache_put(bb); -@@ -1389,6 +1393,10 @@ int label_scan(struct cmd_context *cmd) - * filter", and this result needs to be cleared (wiped) so that the - * complete set of filters (including those that require data) can be - * checked in _process_block, where headers have been read. -+ * -+ * FIXME: devs that are filtered with data in _process_block -+ * are not moved to the filtered_devs list like devs filtered -+ * here without data. Does that have any effect? - */ - log_debug_devs("Filtering devices to scan (nodata)"); - --- -2.34.1 - diff --git a/SOURCES/0001-devices-file-move-clean-up-after-command-is-run.patch b/SOURCES/0001-devices-file-move-clean-up-after-command-is-run.patch new file mode 100644 index 0000000..5e4a248 --- /dev/null +++ b/SOURCES/0001-devices-file-move-clean-up-after-command-is-run.patch @@ -0,0 +1,49 @@ +From 28a4df481fa47d0b71996a25ac08546c4bd094f8 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 27 May 2022 12:38:43 -0500 +Subject: [PATCH 1/7] devices file: move clean up after command is run + +devices_file_exit wasn't being called between lvm_shell +commands, so the file lock wouldn't be released. + +(cherry picked from commit 9dfa6f38793f6b5f7de2a4148ab2f7790e3c39da) +--- + lib/commands/toolcontext.c | 2 -- + tools/lvmcmdline.c | 1 + + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c +index 4cb81bf94..2666d7b42 100644 +--- a/lib/commands/toolcontext.c ++++ b/lib/commands/toolcontext.c +@@ -1905,7 +1905,6 @@ int refresh_toolcontext(struct cmd_context *cmd) + _destroy_segtypes(&cmd->segtypes); + _destroy_formats(cmd, &cmd->formats); + +- devices_file_exit(cmd); + if (!dev_cache_exit()) + stack; + _destroy_dev_types(cmd); +@@ -2034,7 +2033,6 @@ void destroy_toolcontext(struct cmd_context *cmd) + _destroy_segtypes(&cmd->segtypes); + _destroy_formats(cmd, &cmd->formats); + _destroy_filters(cmd); +- devices_file_exit(cmd); + dev_cache_exit(); + _destroy_dev_types(cmd); + _destroy_tags(cmd); +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index 1e3547ed7..b052d698f 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -3305,6 +3305,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) + hints_exit(cmd); + lvmcache_destroy(cmd, 1, 1); + label_scan_destroy(cmd); ++ devices_file_exit(cmd); + + if ((config_string_cft = remove_config_tree_by_source(cmd, CONFIG_STRING))) + dm_config_destroy(config_string_cft); +-- +2.34.3 + diff --git a/SOURCES/0002-devices-file-fail-if-devicesfile-filename-doesn-t-ex.patch b/SOURCES/0002-devices-file-fail-if-devicesfile-filename-doesn-t-ex.patch new file mode 100644 index 0000000..ed57cf2 --- /dev/null +++ b/SOURCES/0002-devices-file-fail-if-devicesfile-filename-doesn-t-ex.patch @@ -0,0 +1,55 @@ +From 9a79248fe21554e6cb99dd6ed044e7cbff18f777 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 27 May 2022 14:27:03 -0500 +Subject: [PATCH 2/7] devices file: fail if --devicesfile filename doesn't + exist + +A typo of the filename after --devicesfile should result in a +command error rather than the command falling back to using no +devices file at all. Exception is vgcreate|pvcreate which +create a new devices file if the file name doesn't exist. + +(cherry picked from commit bfe072e4388b530cbf5369be8a8f1305220198bf) +--- + lib/device/dev-cache.c | 9 +++++++++ + test/shell/devicesfile-basic.sh | 4 ++++ + 2 files changed, 13 insertions(+) + +diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c +index 3aaf6a2e5..ed9c726c9 100644 +--- a/lib/device/dev-cache.c ++++ b/lib/device/dev-cache.c +@@ -1863,6 +1863,15 @@ int setup_devices(struct cmd_context *cmd) + + file_exists = devices_file_exists(cmd); + ++ /* ++ * Fail if user specifies a file name that doesn't exist and ++ * the command is not creating a new devices file. ++ */ ++ if (!file_exists && !cmd->create_edit_devices_file && cmd->devicesfile && strlen(cmd->devicesfile)) { ++ log_error("Devices file not found: %s", cmd->devices_file_path); ++ return 0; ++ } ++ + /* + * Removing the devices file is another way of disabling the use of + * a devices file, unless the command creates the devices file. +diff --git a/test/shell/devicesfile-basic.sh b/test/shell/devicesfile-basic.sh +index 9c3455c76..77fe265a0 100644 +--- a/test/shell/devicesfile-basic.sh ++++ b/test/shell/devicesfile-basic.sh +@@ -104,6 +104,10 @@ not ls "$DFDIR/system.devices" + vgs --devicesfile test.devices $vg1 + not vgs --devicesfile test.devices $vg2 + ++# misspelled override name fails ++not vgs --devicesfile doesnotexist $vg1 ++not vgs --devicesfile doesnotexist $vg2 ++ + # devicesfile and devices cannot be used together + not vgs --devicesfile test.devices --devices "$dev1","$dev1" $vg1 + +-- +2.34.3 + diff --git a/SOURCES/0003-filter-mpath-handle-other-wwid-types-in-blacklist.patch b/SOURCES/0003-filter-mpath-handle-other-wwid-types-in-blacklist.patch new file mode 100644 index 0000000..7d3ca86 --- /dev/null +++ b/SOURCES/0003-filter-mpath-handle-other-wwid-types-in-blacklist.patch @@ -0,0 +1,54 @@ +From 1e78ed5a0d9a8296b42578cfc250a3a281a32878 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 6 Jun 2022 11:39:02 -0500 +Subject: [PATCH 3/7] filter-mpath: handle other wwid types in blacklist + +Fixes commit 494372b4eed0c8f6040e3357939eb7511ac25745 + "filter-mpath: use multipath blacklist" +to handle wwids with initial type digits 1 and 2 used +for t10 and eui ids. Originally recognized type 3 naa. + +(cherry picked from commit c302903dbab1d5fd05b344c654bed83c9ecb69f8) +--- + lib/device/dev-mpath.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c +index 270366ad7..846f6c8ba 100644 +--- a/lib/device/dev-mpath.c ++++ b/lib/device/dev-mpath.c +@@ -54,7 +54,7 @@ static void _read_blacklist_file(const char *path) + int section_black = 0; + int section_exceptions = 0; + int found_quote; +- int found_three; ++ int found_type; + int i, j; + + if (!(fp = fopen(path, "r"))) +@@ -114,7 +114,7 @@ static void _read_blacklist_file(const char *path) + + memset(wwid, 0, sizeof(wwid)); + found_quote = 0; +- found_three = 0; ++ found_type = 0; + j = 0; + + for (; i < MAX_WWID_LINE; i++) { +@@ -132,9 +132,10 @@ static void _read_blacklist_file(const char *path) + /* second quote is end of wwid */ + if ((line[i] == '"') && found_quote) + break; +- /* ignore first "3" in wwid */ +- if ((line[i] == '3') && !found_three) { +- found_three = 1; ++ /* exclude initial 3/2/1 for naa/eui/t10 */ ++ if (!j && !found_type && ++ ((line[i] == '3') || (line[i] == '2') || (line[i] == '1'))) { ++ found_type = 1; + continue; + } + +-- +2.34.3 + diff --git a/SOURCES/0004-filter-mpath-get-wwids-from-sysfs-vpd_pg83.patch b/SOURCES/0004-filter-mpath-get-wwids-from-sysfs-vpd_pg83.patch new file mode 100644 index 0000000..d2a09bc --- /dev/null +++ b/SOURCES/0004-filter-mpath-get-wwids-from-sysfs-vpd_pg83.patch @@ -0,0 +1,743 @@ +From 2966df2bcbbf553d86d0a608852dcc140df28fc0 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 6 Jun 2022 14:04:20 -0500 +Subject: [PATCH 4/7] filter-mpath: get wwids from sysfs vpd_pg83 + +to compare with wwids in /etc/multipath/wwids when +excluding multipath components. The wwid printed +from the sysfs wwid file may not be the wwid used +in multipath wwids. Save the wwids found for each +device on dev->wwids to avoid repeating reading +and parsing the sysfs files. + +(cherry picked from commit 3b0f9cec7e999c33f17714358d2b469bda6967d2) +--- + lib/Makefile.in | 1 + + lib/device/dev-cache.c | 18 ++++ + lib/device/dev-cache.h | 1 + + lib/device/dev-mpath.c | 232 ++++++++++++++++++++++++++++++++++------- + lib/device/device.h | 13 +++ + lib/device/device_id.c | 31 +++++- + lib/device/device_id.h | 2 + + lib/device/parse_vpd.c | 199 +++++++++++++++++++++++++++++++++++ + 8 files changed, 454 insertions(+), 43 deletions(-) + create mode 100644 lib/device/parse_vpd.c + +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 22b96134b..3ab5cb2f1 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -41,6 +41,7 @@ SOURCES =\ + device/dev-dasd.c \ + device/dev-lvm1-pool.c \ + device/online.c \ ++ device/parse_vpd.c \ + display/display.c \ + error/errseg.c \ + unknown/unknown.c \ +diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c +index ed9c726c9..193eb7585 100644 +--- a/lib/device/dev-cache.c ++++ b/lib/device/dev-cache.c +@@ -80,6 +80,7 @@ static void _dev_init(struct device *dev) + + dm_list_init(&dev->aliases); + dm_list_init(&dev->ids); ++ dm_list_init(&dev->wwids); + } + + void dev_destroy_file(struct device *dev) +@@ -383,6 +384,22 @@ out: + return 1; + } + ++int get_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen) ++{ ++ int ret; ++ int fd; ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return 0; ++ ret = read(fd, buf, buf_size); ++ close(fd); ++ if (ret <= 0) ++ return 0; ++ *retlen = ret; ++ return 1; ++} ++ + int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value) + { + FILE *fp; +@@ -1336,6 +1353,7 @@ int dev_cache_exit(void) + dm_hash_iterate(n, _cache.names) { + dev = (struct device *) dm_hash_get_data(_cache.names, n); + free_dids(&dev->ids); ++ free_wwids(&dev->wwids); + } + } + +diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h +index 46b1da72c..7ffe01152 100644 +--- a/lib/device/dev-cache.h ++++ b/lib/device/dev-cache.h +@@ -74,6 +74,7 @@ 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_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen); + int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor); + + int setup_devices_file(struct cmd_context *cmd); +diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c +index 846f6c8ba..27b0f41a6 100644 +--- a/lib/device/dev-mpath.c ++++ b/lib/device/dev-mpath.c +@@ -200,11 +200,12 @@ static void _read_wwid_exclusions(void) + log_debug("multipath config ignored %d wwids", rem_count); + } + +-static void _read_wwid_file(const char *config_wwids_file) ++static void _read_wwid_file(const char *config_wwids_file, int *entries) + { + FILE *fp; + char line[MAX_WWID_LINE]; + char *wwid, *p; ++ char typestr[2] = { 0 }; + int count = 0; + + if (config_wwids_file[0] != '/') { +@@ -226,8 +227,17 @@ static void _read_wwid_file(const char *config_wwids_file) + if (line[0] == '/') + wwid++; + +- /* skip the initial '3' */ +- wwid++; ++ ++ /* ++ * the initial character is the id type, ++ * 1 is t10, 2 is eui, 3 is naa, 8 is scsi name. ++ * wwids are stored in the hash table without the type charater. ++ * It seems that sometimes multipath does not include ++ * the type charater (seen with t10 scsi_debug devs). ++ */ ++ typestr[0] = *wwid; ++ if (typestr[0] == '1' || typestr[0] == '2' || typestr[0] == '3') ++ wwid++; + + if ((p = strchr(wwid, '/'))) + *p = '\0'; +@@ -240,6 +250,7 @@ static void _read_wwid_file(const char *config_wwids_file) + stack; + + log_debug("multipath wwids read %d from %s", count, config_wwids_file); ++ *entries = count; + } + + int dev_mpath_init(const char *config_wwids_file) +@@ -247,6 +258,7 @@ 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; ++ int entries = 0; + + dm_list_init(&_ignored); + dm_list_init(&_ignored_exceptions); +@@ -283,10 +295,16 @@ int dev_mpath_init(const char *config_wwids_file) + _wwid_hash_tab = wwid_tab; + + if (config_wwids_file) { +- _read_wwid_file(config_wwids_file); ++ _read_wwid_file(config_wwids_file, &entries); + _read_wwid_exclusions(); + } + ++ if (!entries) { ++ /* reading dev wwids is skipped with null wwid_hash_tab */ ++ dm_hash_destroy(_wwid_hash_tab); ++ _wwid_hash_tab = NULL; ++ } ++ + return 1; + } + +@@ -434,10 +452,10 @@ static int _dev_is_mpath_component_udev(struct device *dev) + + /* mpath_devno is major:minor of the dm multipath device currently using the component dev. */ + +-static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev, dev_t *mpath_devno) ++static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev, ++ int primary_result, dev_t primary_dev, dev_t *mpath_devno) + { + 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/" */ +@@ -451,25 +469,15 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device + 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)) +- return 0; +- +- switch (dev_get_primary_dev(dt, dev, &primary_dev)) { ++ switch (primary_result) { + + 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. */ +@@ -593,47 +601,189 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device + return is_mpath_component; + } + +-static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev) ++static int _read_sys_wwid(struct cmd_context *cmd, struct device *dev, ++ char *idbuf, int idbufsize) + { +- char sysbuf[PATH_MAX] = { 0 }; +- char *wwid; +- long look; ++ char idtmp[DEV_WWID_SIZE]; + +- if (!_wwid_hash_tab) ++ if (!read_sys_block(cmd, dev, "device/wwid", idbuf, idbufsize)) { ++ /* the wwid file is not under device for nvme devs */ ++ if (!read_sys_block(cmd, dev, "wwid", idbuf, idbufsize)) ++ return 0; ++ } ++ if (!idbuf[0]) + return 0; + +- if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf))) ++ /* in t10 id, replace series of spaces with one _ like multipath */ ++ if (!strncmp(idbuf, "t10.", 4) && strchr(idbuf, ' ')) { ++ if (idbufsize < DEV_WWID_SIZE) ++ return 0; ++ memcpy(idtmp, idbuf, DEV_WWID_SIZE); ++ memset(idbuf, 0, idbufsize); ++ format_t10_id((const unsigned char *)idtmp, DEV_WWID_SIZE, (unsigned char *)idbuf, idbufsize); ++ } ++ return 1; ++} ++ ++#define VPD_SIZE 4096 ++ ++static int _read_sys_vpd_wwids(struct cmd_context *cmd, struct device *dev, ++ struct dm_list *ids) ++{ ++ unsigned char vpd_data[VPD_SIZE] = { 0 }; ++ int vpd_datalen = 0; ++ ++ if (!read_sys_block_binary(cmd, dev, "device/vpd_pg83", (char *)vpd_data, VPD_SIZE, &vpd_datalen)) ++ return 0; ++ if (!vpd_datalen) + return 0; + +- if (!sysbuf[0]) ++ /* adds dev_wwid entry to dev->wwids for each id in vpd data */ ++ parse_vpd_ids(vpd_data, vpd_datalen, ids); ++ return 1; ++} ++ ++void free_wwids(struct dm_list *ids) ++{ ++ struct dev_wwid *dw, *safe; ++ ++ dm_list_iterate_items_safe(dw, safe, ids) { ++ dm_list_del(&dw->list); ++ free(dw); ++ } ++} ++ ++static int _wwid_type_num(char *id) ++{ ++ if (!strncmp(id, "naa.", 4)) ++ return 3; ++ else if (!strncmp(id, "eui.", 4)) ++ return 2; ++ else if (!strncmp(id, "t10.", 4)) ++ return 1; ++ else ++ return -1; ++} ++ ++/* ++ * TODO: if each of the different wwid types (naa/eui/t10) were ++ * represented by different DEV_ID_TYPE_FOO values, and used ++ * as device_id types, then we could drop struct dev_wwid and ++ * drop dev->wwids, and just use dev->ids for each of the ++ * different wwids found in vpd_pg83. This would also require ++ * the ability to handle both the original method of replacing ++ * every space in the id string with _ and the new/multipath ++ * format_t10_id replacing series of spaces with one _. ++ */ ++struct dev_wwid *add_wwid(char *id, int id_type, struct dm_list *ids) ++{ ++ struct dev_wwid *dw; ++ int len; ++ ++ if (!id_type) { ++ id_type = _wwid_type_num(id); ++ if (id_type == -1) ++ log_debug("unknown wwid type %s", id); ++ } ++ ++ if (!(dw = zalloc(sizeof(struct dev_wwid)))) ++ return NULL; ++ len = strlen(id); ++ if (len >= DEV_WWID_SIZE) ++ len = DEV_WWID_SIZE - 1; ++ memcpy(dw->id, id, len); ++ dw->type = id_type; ++ dm_list_add(ids, &dw->list); ++ return dw; ++} ++ ++/* ++ * we save ids with format: naa., eui., t10.. ++ * multipath wwids file uses format: 3, 2, 1. ++ * The values are saved in wwid_hash_tab without the type prefix. ++ */ ++ ++static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev, ++ int primary_result, dev_t primary_dev) ++{ ++ char idbuf[DEV_WWID_SIZE] = { 0 }; ++ struct dev_wwid *dw; ++ char *wwid; ++ ++ if (!_wwid_hash_tab) + return 0; + + /* +- * sysfs prints wwid as . +- * multipath wwid uses '3' +- * does "." always correspond to "3"? ++ * Check the primary device, not the partition. + */ +- if (!(wwid = strchr(sysbuf, '.'))) +- return 0; ++ if (primary_result == 2) { ++ if (!(dev = dev_cache_get_by_devt(cmd, primary_dev))) { ++ log_debug("dev_is_mpath_component %s no primary dev", dev_name(dev)); ++ 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)); ++ /* ++ * This function may be called multiple times for the same device, in ++ * particular if partitioned for each partition. ++ */ ++ if (!dm_list_empty(&dev->wwids)) ++ goto lookup; + +- if (look) { +- log_debug_devs("dev_is_mpath_component %s multipath wwid %s", dev_name(dev), wwid); +- return 1; ++ /* ++ * Get all the ids for the device from vpd_pg83 and check if any of ++ * those are in /etc/multipath/wwids. These ids should include the ++ * value printed from the sysfs wwid file. ++ */ ++ _read_sys_vpd_wwids(cmd, dev, &dev->wwids); ++ if (!dm_list_empty(&dev->wwids)) ++ goto lookup; ++ ++ /* ++ * This will read the sysfs wwid file, nvme devices in particular have ++ * a wwid file but not a vpd_pg83 file. ++ */ ++ if (_read_sys_wwid(cmd, dev, idbuf, sizeof(idbuf))) ++ add_wwid(idbuf, 0, &dev->wwids); ++ ++ lookup: ++ dm_list_iterate_items(dw, &dev->wwids) { ++ if (dw->type == 1 || dw->type == 2 || dw->type == 3) ++ wwid = &dw->id[4]; ++ else ++ wwid = dw->id; ++ ++ if (dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid))) { ++ log_debug_devs("dev_is_mpath_component %s %s in wwids file", dev_name(dev), dw->id); ++ return 1; ++ } + } ++ + return 0; + } + + int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *holder_devno) + { +- if (_dev_is_mpath_component_sysfs(cmd, dev, holder_devno) == 1) ++ struct dev_types *dt = cmd->dev_types; ++ int primary_result; ++ dev_t primary_dev; ++ ++ /* ++ * multipath only uses SCSI or NVME devices ++ */ ++ if (!major_is_scsi_device(dt, MAJOR(dev->dev)) && !dev_is_nvme(dt, dev)) ++ return 0; ++ ++ /* ++ * primary_result 2: dev is a partition, primary_dev is the whole device ++ * primary_result 1: dev is a whole device ++ */ ++ primary_result = dev_get_primary_dev(dt, dev, &primary_dev); ++ ++ if (_dev_is_mpath_component_sysfs(cmd, dev, primary_result, primary_dev, holder_devno) == 1) + goto found; + +- if (_dev_in_wwid_file(cmd, dev)) ++ if (_dev_in_wwid_file(cmd, dev, primary_result, primary_dev)) + goto found; + + if (external_device_info_source() == DEV_EXT_UDEV) { +@@ -641,6 +791,12 @@ int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *h + goto found; + } + ++ /* ++ * TODO: save the result of this function in dev->flags and use those ++ * flags on repeated calls to avoid repeating the work multiple times ++ * for the same device when there are partitions on the device. ++ */ ++ + return 0; + found: + return 1; +diff --git a/lib/device/device.h b/lib/device/device.h +index d0d670ec3..06440f44b 100644 +--- a/lib/device/device.h ++++ b/lib/device/device.h +@@ -59,6 +59,14 @@ struct dev_ext { + void *handle; + }; + ++#define DEV_WWID_SIZE 128 ++ ++struct dev_wwid { ++ struct dm_list list; ++ int type; ++ char id[DEV_WWID_SIZE]; ++}; ++ + #define DEV_ID_TYPE_SYS_WWID 0x0001 + #define DEV_ID_TYPE_SYS_SERIAL 0x0002 + #define DEV_ID_TYPE_MPATH_UUID 0x0003 +@@ -105,6 +113,7 @@ struct dev_use { + */ + struct device { + struct dm_list aliases; /* struct dm_str_list */ ++ struct dm_list wwids; /* struct dev_wwid, used for multipath component detection */ + struct dm_list ids; /* struct dev_id, different entries for different idtypes */ + struct dev_id *id; /* points to the the ids entry being used for this dev */ + dev_t dev; +@@ -206,5 +215,9 @@ void dev_destroy_file(struct device *dev); + + int dev_mpath_init(const char *config_wwids_file); + void dev_mpath_exit(void); ++struct dev_wwid *add_wwid(char *id, int id_type, struct dm_list *ids); ++void free_wwids(struct dm_list *ids); ++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); + + #endif +diff --git a/lib/device/device_id.c b/lib/device/device_id.c +index f1928347c..9dec9f884 100644 +--- a/lib/device/device_id.c ++++ b/lib/device/device_id.c +@@ -182,7 +182,9 @@ void free_dids(struct dm_list *ids) + } + } + +-int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize) ++static int _read_sys_block(struct cmd_context *cmd, struct device *dev, ++ const char *suffix, char *sysbuf, int sysbufsize, ++ int binary, int *retlen) + { + char path[PATH_MAX]; + dev_t devt = dev->dev; +@@ -196,11 +198,17 @@ int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suff + return 0; + } + +- get_sysfs_value(path, sysbuf, sysbufsize, 0); ++ if (binary) { ++ ret = get_sysfs_binary(path, sysbuf, sysbufsize, retlen); ++ if (ret && !*retlen) ++ ret = 0; ++ } else { ++ ret = get_sysfs_value(path, sysbuf, sysbufsize, 0); ++ if (ret && !sysbuf[0]) ++ ret = 0; ++ } + +- if (sysbuf[0]) { +- if (prim) +- log_debug("Using primary device_id for partition %s.", dev_name(dev)); ++ if (ret) { + sysbuf[sysbufsize - 1] = '\0'; + return 1; + } +@@ -220,6 +228,19 @@ int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suff + return 0; + } + ++int read_sys_block(struct cmd_context *cmd, struct device *dev, ++ const char *suffix, char *sysbuf, int sysbufsize) ++{ ++ return _read_sys_block(cmd, dev, suffix, sysbuf, sysbufsize, 0, NULL); ++} ++ ++int read_sys_block_binary(struct cmd_context *cmd, struct device *dev, ++ const char *suffix, char *sysbuf, int sysbufsize, ++ int *retlen) ++{ ++ return _read_sys_block(cmd, dev, suffix, sysbuf, sysbufsize, 1, retlen); ++} ++ + static int _dm_uuid_has_prefix(char *sysbuf, const char *prefix) + { + if (!strncmp(sysbuf, prefix, strlen(prefix))) +diff --git a/lib/device/device_id.h b/lib/device/device_id.h +index 94773a65e..9b9c9ce03 100644 +--- a/lib/device/device_id.h ++++ b/lib/device/device_id.h +@@ -58,6 +58,8 @@ 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); ++int read_sys_block_binary(struct cmd_context *cmd, struct device *dev, ++ const char *suffix, char *sysbuf, int sysbufsize, int *retlen); + + int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, const char **idname_out); + +diff --git a/lib/device/parse_vpd.c b/lib/device/parse_vpd.c +new file mode 100644 +index 000000000..4bafa7b9e +--- /dev/null ++++ b/lib/device/parse_vpd.c +@@ -0,0 +1,199 @@ ++/* ++ * Copyright (C) 2022 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" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Replace series of spaces with a single _. ++ */ ++int format_t10_id(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes) ++{ ++ int in_space = 0; ++ int retlen = 0; ++ int j = 0; ++ int i; ++ ++ for (i = 0; i < in_bytes; i++) { ++ if (!in[i]) ++ break; ++ if (j >= (out_bytes - 2)) ++ break; ++ /* skip leading spaces */ ++ if (!retlen && (in[i] == ' ')) ++ continue; ++ /* replace one or more spaces with _ */ ++ if (in[i] == ' ') { ++ in_space = 1; ++ continue; ++ } ++ /* spaces are finished so insert _ */ ++ if (in_space) { ++ out[j++] = '_'; ++ in_space = 0; ++ retlen++; ++ } ++ out[j++] = in[i]; ++ retlen++; ++ } ++ return retlen; ++} ++ ++static int _to_hex(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes) ++{ ++ int off = 0; ++ int num; ++ int i; ++ ++ for (i = 0; i < in_bytes; i++) { ++ num = sprintf((char *)out + off, "%02x", in[i]); ++ if (num < 0) ++ break; ++ off += num; ++ if (off + 2 >= out_bytes) ++ break; ++ } ++ return off; ++} ++ ++#define ID_BUFSIZE 1024 ++ ++/* ++ * based on linux kernel function ++ */ ++int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list *ids) ++{ ++ char id[ID_BUFSIZE]; ++ unsigned char tmp_str[ID_BUFSIZE]; ++ const unsigned char *d, *cur_id_str; ++ size_t id_len = ID_BUFSIZE; ++ int id_size = -1; ++ uint8_t cur_id_size = 0; ++ ++ memset(id, 0, ID_BUFSIZE); ++ for (d = vpd_data + 4; ++ d < vpd_data + vpd_datalen; ++ d += d[3] + 4) { ++ memset(tmp_str, 0, sizeof(tmp_str)); ++ ++ switch (d[1] & 0xf) { ++ case 0x1: ++ /* T10 Vendor ID */ ++ cur_id_size = d[3]; ++ if (cur_id_size + 4 > id_len) ++ cur_id_size = id_len - 4; ++ cur_id_str = d + 4; ++ format_t10_id(cur_id_str, cur_id_size, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "t10.%s", tmp_str); ++ if (id_size < 0) ++ break; ++ if (id_size >= ID_BUFSIZE) ++ id_size = ID_BUFSIZE - 1; ++ add_wwid(id, 1, ids); ++ break; ++ case 0x2: ++ /* EUI-64 */ ++ cur_id_size = d[3]; ++ cur_id_str = d + 4; ++ switch (cur_id_size) { ++ case 8: ++ _to_hex(cur_id_str, 8, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str); ++ break; ++ case 12: ++ _to_hex(cur_id_str, 12, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str); ++ break; ++ case 16: ++ _to_hex(cur_id_str, 16, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str); ++ break; ++ default: ++ break; ++ } ++ if (id_size < 0) ++ break; ++ if (id_size >= ID_BUFSIZE) ++ id_size = ID_BUFSIZE - 1; ++ add_wwid(id, 2, ids); ++ break; ++ case 0x3: ++ /* NAA */ ++ cur_id_size = d[3]; ++ cur_id_str = d + 4; ++ switch (cur_id_size) { ++ case 8: ++ _to_hex(cur_id_str, 8, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "naa.%s", tmp_str); ++ break; ++ case 16: ++ _to_hex(cur_id_str, 16, tmp_str, sizeof(tmp_str)); ++ id_size = snprintf(id, ID_BUFSIZE, "naa.%s", tmp_str); ++ break; ++ default: ++ break; ++ } ++ if (id_size < 0) ++ break; ++ if (id_size >= ID_BUFSIZE) ++ id_size = ID_BUFSIZE - 1; ++ add_wwid(id, 3, ids); ++ break; ++ case 0x8: ++ /* SCSI name string */ ++ cur_id_size = d[3]; ++ cur_id_str = d + 4; ++ if (cur_id_size >= id_len) ++ cur_id_size = id_len - 1; ++ memcpy(id, cur_id_str, cur_id_size); ++ id_size = cur_id_size; ++ ++ /* ++ * Not in the kernel version, copying multipath code, ++ * which checks if this string begins with naa or eui ++ * and if so does tolower() on the chars. ++ */ ++ if (!strncmp(id, "naa.", 4) || !strncmp(id, "eui.", 4)) { ++ int i; ++ for (i = 0; i < id_size; i++) ++ id[i] = tolower(id[i]); ++ } ++ add_wwid(id, 8, ids); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return id_size; ++} +-- +2.34.3 + diff --git a/SOURCES/0005-pvdisplay-restore-reportformat-option.patch b/SOURCES/0005-pvdisplay-restore-reportformat-option.patch new file mode 100644 index 0000000..b437a9c --- /dev/null +++ b/SOURCES/0005-pvdisplay-restore-reportformat-option.patch @@ -0,0 +1,36 @@ +From 3cfb00e5f7c720549100c5297be18600c9abf530 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 24 Jun 2022 10:40:54 -0500 +Subject: [PATCH 5/7] pvdisplay: restore --reportformat option + +Fixes commit b8f4ec846 "display: ignore --reportformat" +by restoring the --reportformat option to pvdisplay. +Adding -C to pvdisplay turns the command into a reporting +command (like pvs, vgs, lvs) in which --reportformat can +be useful. + +(cherry picked from commit db5277c97155632ce83e1125e348eda97c871968) +--- + tools/command-lines.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/command-lines.in b/tools/command-lines.in +index b64fd0dda..b6a03d158 100644 +--- a/tools/command-lines.in ++++ b/tools/command-lines.in +@@ -1593,10 +1593,10 @@ pvdisplay + OO: --aligned, --all, --binary, --colon, --columns, --configreport ConfigReport, + --foreign, --ignorelockingfailure, + --logonly, --maps, --noheadings, --nosuffix, --options String, +---readonly, --select String, --separator String, --shared, ++--readonly, --reportformat ReportFmt, --select String, --separator String, --shared, + --short, --sort String, --unbuffered, --units Units + OP: PV|Tag ... +-IO: --ignoreskippedcluster, --reportformat ReportFmt ++IO: --ignoreskippedcluster + ID: pvdisplay_general + + --- +-- +2.34.3 + diff --git a/SOURCES/0006-exit-with-error-when-devicesfile-name-doesn-t-exist.patch b/SOURCES/0006-exit-with-error-when-devicesfile-name-doesn-t-exist.patch new file mode 100644 index 0000000..273c939 --- /dev/null +++ b/SOURCES/0006-exit-with-error-when-devicesfile-name-doesn-t-exist.patch @@ -0,0 +1,247 @@ +From a369a7fd1fccf3c50103dd294b79055cc7c9d005 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 5 Jul 2022 17:08:00 -0500 +Subject: [PATCH 6/7] exit with error when --devicesfile name doesn't exist + +(cherry picked from commit 92b4fcf57f3c6d212d06b72b097e1a06e6efb84b) +--- + lib/cache/lvmcache.c | 3 ++- + lib/label/label.c | 4 ++-- + test/shell/devicesfile-basic.sh | 1 + + tools/pvcreate.c | 3 ++- + tools/pvremove.c | 3 ++- + tools/pvscan.c | 3 ++- + tools/toollib.c | 27 +++++++++++++++++++++------ + tools/vgcfgrestore.c | 5 ++++- + tools/vgcreate.c | 5 ++++- + tools/vgextend.c | 3 ++- + tools/vgmerge.c | 3 ++- + tools/vgsplit.c | 3 ++- + 12 files changed, 46 insertions(+), 17 deletions(-) + +diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c +index 22edcfd84..a1c4a61c8 100644 +--- a/lib/cache/lvmcache.c ++++ b/lib/cache/lvmcache.c +@@ -1612,7 +1612,8 @@ int lvmcache_label_scan(struct cmd_context *cmd) + * with infos/vginfos based on reading headers from + * each device, and a vg summary from each mda. + */ +- label_scan(cmd); ++ if (!label_scan(cmd)) ++ return_0; + + /* + * When devnames are used as device ids (which is dispreferred), +diff --git a/lib/label/label.c b/lib/label/label.c +index 711edb6f4..f845abb96 100644 +--- a/lib/label/label.c ++++ b/lib/label/label.c +@@ -801,7 +801,7 @@ static int _setup_bcache(void) + } + + if (!(scan_bcache = bcache_create(BCACHE_BLOCK_SIZE_IN_SECTORS, cache_blocks, ioe))) { +- log_error("Failed to create bcache with %d cache blocks.", cache_blocks); ++ log_error("Failed to set up io layer with %d blocks.", cache_blocks); + return 0; + } + +@@ -1292,7 +1292,7 @@ int label_scan(struct cmd_context *cmd) + * data to invalidate.) + */ + if (!(iter = dev_iter_create(NULL, 0))) { +- log_error("Scanning failed to get devices."); ++ log_error("Failed to get device list."); + return 0; + } + while ((dev = dev_iter_get(cmd, iter))) { +diff --git a/test/shell/devicesfile-basic.sh b/test/shell/devicesfile-basic.sh +index 77fe265a0..715c579b3 100644 +--- a/test/shell/devicesfile-basic.sh ++++ b/test/shell/devicesfile-basic.sh +@@ -107,6 +107,7 @@ not vgs --devicesfile test.devices $vg2 + # misspelled override name fails + not vgs --devicesfile doesnotexist $vg1 + not vgs --devicesfile doesnotexist $vg2 ++not vgs --devicesfile doesnotexist + + # devicesfile and devices cannot be used together + not vgs --devicesfile test.devices --devices "$dev1","$dev1" $vg1 +diff --git a/tools/pvcreate.c b/tools/pvcreate.c +index 71eb060a3..a1ef0e9e1 100644 +--- a/tools/pvcreate.c ++++ b/tools/pvcreate.c +@@ -144,7 +144,8 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv) + + cmd->create_edit_devices_file = 1; + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_ECMD_FAILED; + + if (!(handle = init_processing_handle(cmd, NULL))) { + log_error("Failed to initialize processing handle."); +diff --git a/tools/pvremove.c b/tools/pvremove.c +index 2dfdbd016..5c39ee0c7 100644 +--- a/tools/pvremove.c ++++ b/tools/pvremove.c +@@ -45,7 +45,8 @@ int pvremove(struct cmd_context *cmd, int argc, char **argv) + + clear_hint_file(cmd); + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_ECMD_FAILED; + + /* When forcibly clearing a PV we don't care about a VG lock. */ + if (pp.force == DONT_PROMPT_OVERRIDE) +diff --git a/tools/pvscan.c b/tools/pvscan.c +index 1e47d754a..72c3279c3 100644 +--- a/tools/pvscan.c ++++ b/tools/pvscan.c +@@ -1407,7 +1407,8 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv, + * which we want 'pvscan --cache' to do, and that uses + * info from lvmcache, e.g. duplicate pv info. + */ +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_0; + + cmd->pvscan_recreate_hints = 0; + cmd->use_hints = 0; +diff --git a/tools/toollib.c b/tools/toollib.c +index d77092d89..544791808 100644 +--- a/tools/toollib.c ++++ b/tools/toollib.c +@@ -1655,7 +1655,10 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv, + + log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LABEL); + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) { ++ ret_max = ECMD_FAILED; ++ goto_out; ++ } + + if (argc) { + for (; opt < argc; opt++) { +@@ -2435,8 +2438,13 @@ int process_each_vg(struct cmd_context *cmd, + * Scan all devices to populate lvmcache with initial + * list of PVs and VGs. + */ +- if (!(read_flags & PROCESS_SKIP_SCAN)) +- lvmcache_label_scan(cmd); ++ if (!(read_flags & PROCESS_SKIP_SCAN)) { ++ if (!lvmcache_label_scan(cmd)) { ++ ret_max = ECMD_FAILED; ++ goto_out; ++ } ++ } ++ + + /* + * A list of all VGs on the system is needed when: +@@ -3987,7 +3995,10 @@ int process_each_lv(struct cmd_context *cmd, + * Scan all devices to populate lvmcache with initial + * list of PVs and VGs. + */ +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) { ++ ret_max = ECMD_FAILED; ++ goto_out; ++ } + + /* + * A list of all VGs on the system is needed when: +@@ -4623,8 +4634,12 @@ int process_each_pv(struct cmd_context *cmd, + goto_out; + } + +- if (!(read_flags & PROCESS_SKIP_SCAN)) +- lvmcache_label_scan(cmd); ++ if (!(read_flags & PROCESS_SKIP_SCAN)) { ++ if (!lvmcache_label_scan(cmd)) { ++ ret_max = ECMD_FAILED; ++ goto_out; ++ } ++ } + + if (!lvmcache_get_vgnameids(cmd, &all_vgnameids, only_this_vgname, 1)) { + ret_max = ret; +diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c +index e49313d14..9fcba89d4 100644 +--- a/tools/vgcfgrestore.c ++++ b/tools/vgcfgrestore.c +@@ -132,7 +132,10 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv) + + clear_hint_file(cmd); + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) { ++ unlock_vg(cmd, NULL, vg_name); ++ return_ECMD_FAILED; ++ } + + cmd->handles_unknown_segments = 1; + +diff --git a/tools/vgcreate.c b/tools/vgcreate.c +index dde3f1eac..14608777f 100644 +--- a/tools/vgcreate.c ++++ b/tools/vgcreate.c +@@ -84,7 +84,10 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) + + cmd->create_edit_devices_file = 1; + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) { ++ unlock_vg(cmd, NULL, vp_new.vg_name); ++ return_ECMD_FAILED; ++ } + + if (lvmcache_vginfo_from_vgname(vp_new.vg_name, NULL)) { + unlock_vg(cmd, NULL, vp_new.vg_name); +diff --git a/tools/vgextend.c b/tools/vgextend.c +index 0856b4c78..fecd6bdd5 100644 +--- a/tools/vgextend.c ++++ b/tools/vgextend.c +@@ -160,7 +160,8 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) + + cmd->edit_devices_file = 1; + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_ECMD_FAILED; + + if (!(handle = init_processing_handle(cmd, NULL))) { + log_error("Failed to initialize processing handle."); +diff --git a/tools/vgmerge.c b/tools/vgmerge.c +index 08615cd62..4ed4a8f0b 100644 +--- a/tools/vgmerge.c ++++ b/tools/vgmerge.c +@@ -72,7 +72,8 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, + return ECMD_FAILED; + } + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_ECMD_FAILED; + + if (strcmp(vg_name_to, vg_name_from) > 0) + lock_vg_from_first = 1; +diff --git a/tools/vgsplit.c b/tools/vgsplit.c +index 5f113b363..c7f4b8af4 100644 +--- a/tools/vgsplit.c ++++ b/tools/vgsplit.c +@@ -559,7 +559,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) + return ECMD_FAILED; + } + +- lvmcache_label_scan(cmd); ++ if (!lvmcache_label_scan(cmd)) ++ return_ECMD_FAILED; + + if (!(vginfo_to = lvmcache_vginfo_from_vgname(vg_name_to, NULL))) { + if (!validate_name(vg_name_to)) { +-- +2.34.3 + diff --git a/SOURCES/0007-make-generate.patch b/SOURCES/0007-make-generate.patch new file mode 100644 index 0000000..3e51442 --- /dev/null +++ b/SOURCES/0007-make-generate.patch @@ -0,0 +1,43 @@ +From a8588f39219a2794fad562b38e6dc63aee791f82 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 11 Jul 2022 01:02:22 +0200 +Subject: [PATCH 7/7] make: generate + +(cherry picked from commit c0f8e6675c62332263acdc7c3c2f61eca20bd60f) +--- + man/pvdisplay.8_pregen | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/man/pvdisplay.8_pregen b/man/pvdisplay.8_pregen +index 23d41b29b..e7767d0c4 100644 +--- a/man/pvdisplay.8_pregen ++++ b/man/pvdisplay.8_pregen +@@ -61,6 +61,8 @@ and more, using a more compact and configurable output format. + .br + [ \fB--readonly\fP ] + .br ++[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ] ++.br + [ \fB--separator\fP \fIString\fP ] + .br + [ \fB--shared\fP ] +@@ -320,6 +322,16 @@ device-mapper kernel driver, so this option is unable to report whether + or not LVs are actually in use. + . + .HP ++\fB--reportformat\fP \fBbasic\fP|\fBjson\fP ++.br ++Overrides current output format for reports which is defined globally by ++the report/output_format setting in \fBlvm.conf\fP(5). ++\fBbasic\fP is the original format with columns and rows. ++If there is more than one report per command, each report is prefixed ++with the report name for identification. \fBjson\fP produces report ++output in JSON format. See \fBlvmreport\fP(7) for more information. ++. ++.HP + \fB-S\fP|\fB--select\fP \fIString\fP + .br + Select objects for processing and reporting based on specified criteria. +-- +2.34.3 + diff --git a/SOURCES/0008-apply-multipath_component_detection-0-to-duplicate-P.patch b/SOURCES/0008-apply-multipath_component_detection-0-to-duplicate-P.patch new file mode 100644 index 0000000..6070b2c --- /dev/null +++ b/SOURCES/0008-apply-multipath_component_detection-0-to-duplicate-P.patch @@ -0,0 +1,55 @@ +From 2a31250c445911eb07057f077a17e3a281ac0049 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 25 Jul 2022 13:50:43 -0500 +Subject: [PATCH] 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.) + +(cherry picked from commit 99ce09ae778c2cc4aa2611e425bba5287b8b9513) +--- + 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 a1c4a61c8..00916885c 100644 +--- a/lib/cache/lvmcache.c ++++ b/lib/cache/lvmcache.c +@@ -652,6 +652,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 +-- +2.37.1 + diff --git a/SOURCES/0009-lvmdbusd-Correct-conditional-for-lvm-child-process-r.patch b/SOURCES/0009-lvmdbusd-Correct-conditional-for-lvm-child-process-r.patch new file mode 100644 index 0000000..e32528a --- /dev/null +++ b/SOURCES/0009-lvmdbusd-Correct-conditional-for-lvm-child-process-r.patch @@ -0,0 +1,30 @@ +From f7277061859740712b67ef6b229c2fc07482ef16 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 15:51:14 -0500 +Subject: [PATCH 1/9] lvmdbusd: Correct conditional for lvm child process + running + +Poll returns None when process is running, else exit value. If poll returns +0 we will fail to exit the select loop. + +(cherry picked from commit 37733cd4eb5116db371ac1ae6e971e3c336c3ddb) +--- + daemons/lvmdbusd/lvm_shell_proxy.py.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in +index 7816daa8b..78fe1e422 100644 +--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in ++++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in +@@ -75,7 +75,7 @@ class LVMShellProxy(object): + stderr += read_decoded(self.lvm_shell.stderr) + + # Check to see if the lvm process died on us +- if self.lvm_shell.poll(): ++ if self.lvm_shell.poll() is not None: + raise Exception(self.lvm_shell.returncode, "%s" % stderr) + + if stdout.endswith(SHELL_PROMPT): +-- +2.37.1 + diff --git a/SOURCES/0010-lvmdbusd-Simplify-child-process-env.patch b/SOURCES/0010-lvmdbusd-Simplify-child-process-env.patch new file mode 100644 index 0000000..09ee5fd --- /dev/null +++ b/SOURCES/0010-lvmdbusd-Simplify-child-process-env.patch @@ -0,0 +1,30 @@ +From ece4c18a42af8fde41f55fd43e8cc0ca34ab2f7d Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 15:52:20 -0500 +Subject: [PATCH 2/9] lvmdbusd: Simplify child process env + +We don't need to duplicate the entire env from the parent, supply only what +is needed. + +(cherry picked from commit 58c6c9e9aa8d6aa6d3be14a04ec0f4257b61495e) +--- + daemons/lvmdbusd/lvm_shell_proxy.py.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in +index 78fe1e422..10719c67e 100644 +--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in ++++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in +@@ -135,7 +135,8 @@ class LVMShellProxy(object): + self.report_stream = os.fdopen(self.report_fd, 'rb', 0) + + # Setup the environment for using our own socket for reporting +- local_env = copy.deepcopy(os.environ) ++ local_env = {} ++ local_env["LC_ALL"] = "C" + local_env["LVM_REPORT_FD"] = "32" + local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd" + +-- +2.37.1 + diff --git a/SOURCES/0011-lvmdbusd-re-work-lvm-shell-main.patch b/SOURCES/0011-lvmdbusd-re-work-lvm-shell-main.patch new file mode 100644 index 0000000..ad1cc42 --- /dev/null +++ b/SOURCES/0011-lvmdbusd-re-work-lvm-shell-main.patch @@ -0,0 +1,73 @@ +From 6d0ad276260c902dba66df73beac1bafc3f4c254 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 15:58:15 -0500 +Subject: [PATCH 3/9] lvmdbusd: re-work lvm shell main + +Add an optional single argument "bisect" to use with git bisect for +automation. Normal case is no arguments when running stand-alone. + +(cherry picked from commit b3407b16c1c7b5bff01e3bde4e0f62a2608682f8) +--- + daemons/lvmdbusd/lvm_shell_proxy.py.in | 46 ++++++++++++++++---------- + 1 file changed, 28 insertions(+), 18 deletions(-) + +diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in +index 10719c67e..40639442c 100644 +--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in ++++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in +@@ -238,24 +238,34 @@ class LVMShellProxy(object): + + + if __name__ == "__main__": +- shell = LVMShellProxy() +- in_line = "start" ++ print("USING LVM BINARY: %s " % LVM_CMD) ++ + try: +- while in_line: +- in_line = input("lvm> ") +- if in_line: +- start = time.time() +- ret, out, err = shell.call_lvm(in_line.split()) +- end = time.time() +- +- print(("RC: %d" % ret)) +- print(("OUT:\n%s" % out)) +- print(("ERR:\n%s" % err)) +- +- print("Command = %f seconds" % (end - start)) +- except KeyboardInterrupt: +- pass +- except EOFError: +- pass ++ if len(sys.argv) > 1 and sys.argv[1] == "bisect": ++ shell = LVMShellProxy() ++ shell.exit_shell() ++ else: ++ shell = LVMShellProxy() ++ in_line = "start" ++ try: ++ while in_line: ++ in_line = input("lvm> ") ++ if in_line: ++ start = time.time() ++ ret, out, err = shell.call_lvm(in_line.split()) ++ end = time.time() ++ ++ print(("RC: %d" % ret)) ++ print(("OUT:\n%s" % out)) ++ print(("ERR:\n%s" % err)) ++ ++ print("Command = %f seconds" % (end - start)) ++ except KeyboardInterrupt: ++ pass ++ except EOFError: ++ pass + except Exception: + traceback.print_exc(file=sys.stdout) ++ sys.exit(1) ++ ++ sys.exit(0) +-- +2.37.1 + diff --git a/SOURCES/0012-lvmdbusd-Add-debug-output-for-which-lvm-binary-is-us.patch b/SOURCES/0012-lvmdbusd-Add-debug-output-for-which-lvm-binary-is-us.patch new file mode 100644 index 0000000..ba9c433 --- /dev/null +++ b/SOURCES/0012-lvmdbusd-Add-debug-output-for-which-lvm-binary-is-us.patch @@ -0,0 +1,26 @@ +From a9ca83b880c19a72d6e00e13b6a638fb11630819 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 15:59:11 -0500 +Subject: [PATCH 4/9] lvmdbusd: Add debug output for which lvm binary is used + +(cherry picked from commit 51d9b686c08d963c61898d407d15abf39f129d72) +--- + daemons/lvmdbusd/main.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/daemons/lvmdbusd/main.py b/daemons/lvmdbusd/main.py +index b0a82d492..1e717ef69 100644 +--- a/daemons/lvmdbusd/main.py ++++ b/daemons/lvmdbusd/main.py +@@ -127,6 +127,8 @@ def main(): + log_error("You cannot specify --lvmshell and --nojson") + sys.exit(1) + ++ log_debug("Using lvm binary: %s" % cfg.LVM_CMD) ++ + # We will dynamically add interfaces which support vdo if it + # exists. + cfg.vdo_support = supports_vdo() +-- +2.37.1 + diff --git a/SOURCES/0013-lvmdbusd-Change-unit-test-vdo-minimum-size.patch b/SOURCES/0013-lvmdbusd-Change-unit-test-vdo-minimum-size.patch new file mode 100644 index 0000000..5252f4e --- /dev/null +++ b/SOURCES/0013-lvmdbusd-Change-unit-test-vdo-minimum-size.patch @@ -0,0 +1,73 @@ +From aa5ec0804d151e5951c4516c3bc08d37e2494349 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 16:03:27 -0500 +Subject: [PATCH 5/9] lvmdbusd: Change unit test vdo minimum size + +(cherry picked from commit 47c61907b4adbdead50f5bb5ac95c0f5d0fe263e) +--- + test/dbus/lvmdbustest.py | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py +index 6d692223f..3eef77fd7 100755 +--- a/test/dbus/lvmdbustest.py ++++ b/test/dbus/lvmdbustest.py +@@ -23,6 +23,9 @@ import os + + g_tmo = 0 + ++# Approx. min size ++VDO_MIN_SIZE = mib(8192) ++ + # Prefix on created objects to enable easier clean-up + g_prefix = os.getenv('PREFIX', '') + +@@ -1155,7 +1158,7 @@ class TestDbusService(unittest.TestCase): + return + + # This may not pass +- for i in [48, 64, 128]: ++ for i in [64, 128]: + yes = self._test_expired_timer(i) + if yes: + break +@@ -1907,8 +1910,8 @@ class TestDbusService(unittest.TestCase): + vdo_pool_object_path = self.handle_return( + vg_proxy.VgVdo.CreateVdoPoolandLv( + pool_name, lv_name, +- dbus.UInt64(mib(4096)), # Appears to be minimum size +- dbus.UInt64(mib(8192)), ++ dbus.UInt64(VDO_MIN_SIZE), ++ dbus.UInt64(VDO_MIN_SIZE * 2), + dbus.Int32(g_tmo), + EOD)) + +@@ -1950,7 +1953,7 @@ class TestDbusService(unittest.TestCase): + vg_proxy = self._vg_create(vg_prefix="vdo_conv_") + lv = self._test_lv_create( + vg_proxy.Vg.LvCreate, +- (dbus.String(pool_name), dbus.UInt64(mib(4096)), ++ (dbus.String(pool_name), dbus.UInt64(VDO_MIN_SIZE), + dbus.Array([], signature='(ott)'), dbus.Int32(g_tmo), + EOD), vg_proxy.Vg, LV_BASE_INT) + lv_obj_path = self._lookup("%s/%s" % (vg_proxy.Vg.Name, pool_name)) +@@ -1959,7 +1962,7 @@ class TestDbusService(unittest.TestCase): + vdo_pool_path = self.handle_return( + vg_proxy.VgVdo.CreateVdoPool( + dbus.ObjectPath(lv.object_path), lv_name, +- dbus.UInt64(mib(8192)), ++ dbus.UInt64(VDO_MIN_SIZE), + dbus.Int32(g_tmo), + EOD)) + +@@ -2083,6 +2086,7 @@ if __name__ == '__main__': + std_err_print('\n*** Testing only lvm shell mode ***\n') + + for g_tmo in [0, 15]: ++ std_err_print('Testing TMO=%d\n' % g_tmo) + if mode == 0: + if set_execution(False, r): + r.register_result(unittest.main(exit=False)) +-- +2.37.1 + diff --git a/SOURCES/0014-lvmdbusd-Fix-env-variable-LVM_DBUSD_TEST_MODE.patch b/SOURCES/0014-lvmdbusd-Fix-env-variable-LVM_DBUSD_TEST_MODE.patch new file mode 100644 index 0000000..7af9d4d --- /dev/null +++ b/SOURCES/0014-lvmdbusd-Fix-env-variable-LVM_DBUSD_TEST_MODE.patch @@ -0,0 +1,54 @@ +From d978fe593b3c75d4b5b66d743b4f5c3632861559 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Wed, 25 May 2022 16:21:14 -0500 +Subject: [PATCH 6/9] lvmdbusd: Fix env variable LVM_DBUSD_TEST_MODE + +Make it more logical. + +(cherry picked from commit b3d7aff6a3a8fd55790f61b9b0b33d599841030b) +--- + test/dbus/lvmdbustest.py | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py +index 3eef77fd7..d876a1748 100755 +--- a/test/dbus/lvmdbustest.py ++++ b/test/dbus/lvmdbustest.py +@@ -40,9 +40,10 @@ pv_device_list = os.getenv('LVM_DBUSD_PV_DEVICE_LIST', None) + + # Default is to test all modes + # 0 == Only test fork & exec mode +-# 1 == Test both fork & exec & lvm shell mode (default) ++# 1 == Only test lvm shell mode ++# 2 == Test both fork & exec & lvm shell mode (default) + # Other == Test just lvm shell mode +-test_shell = os.getenv('LVM_DBUSD_TEST_MODE', 1) ++test_shell = os.getenv('LVM_DBUSD_TEST_MODE', 2) + + # LVM binary to use + LVM_EXECUTABLE = os.getenv('LVM_BINARY', '/usr/sbin/lvm') +@@ -2081,16 +2082,19 @@ if __name__ == '__main__': + if mode == 0: + std_err_print('\n*** Testing only lvm fork & exec test mode ***\n') + elif mode == 1: ++ std_err_print('\n*** Testing only lvm shell mode ***\n') ++ elif mode == 2: + std_err_print('\n*** Testing fork & exec & lvm shell mode ***\n') + else: +- std_err_print('\n*** Testing only lvm shell mode ***\n') ++ std_err_print("Unsupported \"LVM_DBUSD_TEST_MODE\"=%d, [0-2] valid" % mode) ++ sys.exit(1) + + for g_tmo in [0, 15]: + std_err_print('Testing TMO=%d\n' % g_tmo) + if mode == 0: + if set_execution(False, r): + r.register_result(unittest.main(exit=False)) +- elif mode == 2: ++ elif mode == 1: + if set_execution(True, r): + r.register_result(unittest.main(exit=False)) + else: +-- +2.37.1 + diff --git a/SOURCES/0015-lvmdbusd-Remove-the-use-of-sub-shell-for-lvm-shell.patch b/SOURCES/0015-lvmdbusd-Remove-the-use-of-sub-shell-for-lvm-shell.patch new file mode 100644 index 0000000..1eb4144 --- /dev/null +++ b/SOURCES/0015-lvmdbusd-Remove-the-use-of-sub-shell-for-lvm-shell.patch @@ -0,0 +1,62 @@ +From 8e724393079784edbf779678df6937dd838c4149 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Thu, 26 May 2022 10:44:02 -0500 +Subject: [PATCH 7/9] lvmdbusd: Remove the use of sub shell for lvm shell + +This reduces the number of processes and improves security. + +(cherry picked from commit 7a2090655d3ab5abde83b981594ed527e2a7f1f7) +--- + daemons/lvmdbusd/lvm_shell_proxy.py.in | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in +index 40639442c..1a5051a92 100644 +--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in ++++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in +@@ -129,31 +129,29 @@ class LVMShellProxy(object): + except FileExistsError: + pass + +- # We have to open non-blocking as the other side isn't open until +- # we actually fork the process. ++ # Open the fifo for use to read and for lvm child process to write to. + self.report_fd = os.open(tmp_file, os.O_NONBLOCK) + self.report_stream = os.fdopen(self.report_fd, 'rb', 0) ++ lvm_fd = os.open(tmp_file, os.O_WRONLY) + +- # Setup the environment for using our own socket for reporting +- local_env = {} +- local_env["LC_ALL"] = "C" +- local_env["LVM_REPORT_FD"] = "32" +- local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd" +- +- # Disable the abort logic if lvm logs too much, which easily happens +- # when utilizing the lvm shell. +- local_env["LVM_LOG_FILE_MAX_LINES"] = "0" ++ # Set up the environment for using our own socket for reporting and disable the abort ++ # logic if lvm logs too much, which easily happens when utilizing the lvm shell. ++ local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd", ++ "LVM_LOG_FILE_MAX_LINES": "0"} + + # run the lvm shell + self.lvm_shell = subprocess.Popen( +- [LVM_CMD + " 32>%s" % tmp_file], ++ [LVM_CMD], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env, +- stderr=subprocess.PIPE, close_fds=True, shell=True) ++ stderr=subprocess.PIPE, close_fds=True, pass_fds=(lvm_fd,), shell=False) + + try: + make_non_block(self.lvm_shell.stdout) + make_non_block(self.lvm_shell.stderr) + ++ # Close our copy of the lvm_fd, child process is open in its process space ++ os.close(lvm_fd) ++ + # wait for the first prompt + errors = self._read_until_prompt(no_output=True)[2] + if errors and len(errors): +-- +2.37.1 + diff --git a/SOURCES/0016-lvmdbusd-Job-prop.-Get-GetAll-exec.-immediately.patch b/SOURCES/0016-lvmdbusd-Job-prop.-Get-GetAll-exec.-immediately.patch new file mode 100644 index 0000000..270d741 --- /dev/null +++ b/SOURCES/0016-lvmdbusd-Job-prop.-Get-GetAll-exec.-immediately.patch @@ -0,0 +1,42 @@ +From 70714b7fbe4d6f1ee943614cc26a990f20e35450 Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Mon, 6 Jun 2022 09:51:54 -0500 +Subject: [PATCH 8/9] lvmdbusd: Job prop. Get/GetAll exec. immediately + +This allows API user the ability to check on the status of a long running +job without blocking in the request queue. + +(cherry picked from commit eee89a941eb4e63865356cfe9e513c24cfa8e0f9) +--- + daemons/lvmdbusd/job.py | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/daemons/lvmdbusd/job.py b/daemons/lvmdbusd/job.py +index 988b1147a..7629cafc7 100644 +--- a/daemons/lvmdbusd/job.py ++++ b/daemons/lvmdbusd/job.py +@@ -226,3 +226,21 @@ class Job(AutomatedProperties): + def Uuid(self): + import uuid + return uuid.uuid1() ++ ++ # Override the property "getters" implementation for the job interface, so a user can query a job while the queue ++ # is processing items. Originally all the property get methods were this way, but we changed this in ++ # e53454d6de07de56736303dd2157c3859f6fa848 ++ ++ # Properties ++ # noinspection PyUnusedLocal ++ @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, ++ in_signature='ss', out_signature='v') ++ def Get(self, interface_name, property_name): ++ # Note: If we get an exception in this handler we won't know about it, ++ # only the side effect of no returned value! ++ return AutomatedProperties._get_prop(self, interface_name, property_name) ++ ++ @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, ++ in_signature='s', out_signature='a{sv}') ++ def GetAll(self, interface_name): ++ return AutomatedProperties._get_all_prop(self, interface_name) +-- +2.37.1 + diff --git a/SOURCES/0017-lvmdbusd-Don-t-require-lvm-prompt-for-shell.patch b/SOURCES/0017-lvmdbusd-Don-t-require-lvm-prompt-for-shell.patch new file mode 100644 index 0000000..2429858 --- /dev/null +++ b/SOURCES/0017-lvmdbusd-Don-t-require-lvm-prompt-for-shell.patch @@ -0,0 +1,174 @@ +From a3c2dcc3726261d6463ea35102d86863d698021b Mon Sep 17 00:00:00 2001 +From: Tony Asleson +Date: Mon, 6 Jun 2022 09:56:32 -0500 +Subject: [PATCH 9/9] lvmdbusd: Don't require "lvm> " prompt for shell + +Depending on how lvm is compiled, it may not present the "lvm> " prompt +when using the lvm shell. Don't require it to be present. + +Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2090391 +(cherry picked from commit 691494268502ddb20da2a14568984c0fa4f29f50) +--- + daemons/lvmdbusd/lvm_shell_proxy.py.in | 83 +++++++++++++------------- + 1 file changed, 43 insertions(+), 40 deletions(-) + +diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in +index 1a5051a92..e106ca36f 100644 +--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in ++++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in +@@ -19,7 +19,6 @@ import sys + import tempfile + import time + import select +-import copy + + try: + import simplejson as json +@@ -31,8 +30,6 @@ from lvmdbusd.cfg import LVM_CMD + from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\ + read_decoded + +-SHELL_PROMPT = "lvm> " +- + + def _quote_arg(arg): + if len(shlex.split(arg)) > 1: +@@ -43,10 +40,11 @@ def _quote_arg(arg): + + class LVMShellProxy(object): + +- # Read until we get prompt back and a result +- # @param: no_output Caller expects no output to report FD +- # Returns stdout, report, stderr (report is JSON!) +- def _read_until_prompt(self, no_output=False): ++ # Read REPORT FD until we have a complete and valid JSON record or give ++ # up trying to get one. ++ # ++ # Returns stdout, report (JSON), stderr ++ def _read_response(self): + stdout = "" + report = "" + stderr = "" +@@ -58,6 +56,7 @@ class LVMShellProxy(object): + # Try reading from all FDs to prevent one from filling up and causing + # a hang. Keep reading until we get the prompt back and the report + # FD does not contain valid JSON ++ + while keep_reading: + try: + rd_fd = [ +@@ -78,32 +77,33 @@ class LVMShellProxy(object): + if self.lvm_shell.poll() is not None: + raise Exception(self.lvm_shell.returncode, "%s" % stderr) + +- if stdout.endswith(SHELL_PROMPT): +- if no_output: +- keep_reading = False +- else: +- cur_report_len = len(report) +- if cur_report_len != 0: +- # Only bother to parse if we have more data +- if prev_report_len != cur_report_len: +- prev_report_len = cur_report_len +- # Parse the JSON if it's good we are done, +- # if not we will try to read some more. +- try: +- report_json = json.loads(report) +- keep_reading = False +- except ValueError: +- pass +- +- if keep_reading: +- extra_passes -= 1 +- if extra_passes <= 0: +- if len(report): +- raise ValueError("Invalid json: %s" % +- report) +- else: +- raise ValueError( +- "lvm returned no JSON output!") ++ cur_report_len = len(report) ++ if cur_report_len != 0: ++ # Only bother to parse if we have more data and the last 2 characters match expected ++ # complete JSON, prevents excessive JSON parsing attempts ++ if prev_report_len != cur_report_len and report[-2:] == "}\n": ++ prev_report_len = cur_report_len ++ ++ # Parse the JSON if it's good we are done, ++ # if not we will try to read some more. ++ try: ++ report_json = json.loads(report) ++ keep_reading = False ++ except ValueError: ++ pass ++ ++ # As long as lvm is spewing something on one of the FDs we will ++ # keep trying. If we get a few timeouts with no activity, and ++ # we don't have valid JSON, we will raise an error. ++ if len(ready) == 0 and keep_reading: ++ extra_passes -= 1 ++ if extra_passes <= 0: ++ if len(report): ++ raise ValueError("Invalid json: %s" % ++ report) ++ else: ++ raise ValueError( ++ "lvm returned no JSON output!") + + except IOError as ioe: + log_debug(str(ioe)) +@@ -118,7 +118,6 @@ class LVMShellProxy(object): + self.lvm_shell.stdin.flush() + + def __init__(self): +- + # Create a temp directory + tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_") + tmp_file = "%s/lvmdbus_report" % (tmp_dir) +@@ -139,6 +138,11 @@ class LVMShellProxy(object): + local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd", + "LVM_LOG_FILE_MAX_LINES": "0"} + ++ # If any env variables contain LVM we will propagate them too ++ for k, v in os.environ.items(): ++ if "LVM" in k: ++ local_env[k] = v ++ + # run the lvm shell + self.lvm_shell = subprocess.Popen( + [LVM_CMD], +@@ -152,10 +156,9 @@ class LVMShellProxy(object): + # Close our copy of the lvm_fd, child process is open in its process space + os.close(lvm_fd) + +- # wait for the first prompt +- errors = self._read_until_prompt(no_output=True)[2] +- if errors and len(errors): +- raise RuntimeError(errors) ++ # Assume we are ready as we may not get the lvm prompt message depending on ++ # if we are using readline or editline. ++ + except: + raise + finally: +@@ -169,7 +172,7 @@ class LVMShellProxy(object): + self._write_cmd('lastlog\n') + + # read everything from the STDOUT to the next prompt +- stdout, report_json, stderr = self._read_until_prompt() ++ stdout, report_json, stderr = self._read_response() + if 'log' in report_json: + error_msg = "" + # Walk the entire log array and build an error string +@@ -203,7 +206,7 @@ class LVMShellProxy(object): + self._write_cmd(cmd) + + # read everything from the STDOUT to the next prompt +- stdout, report_json, stderr = self._read_until_prompt() ++ stdout, report_json, stderr = self._read_response() + + # Parse the report to see what happened + if 'log' in report_json: +-- +2.37.1 + diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index 2f12831..491af12 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -1,4 +1,4 @@ -%global device_mapper_version 1.02.183 +%global device_mapper_version 1.02.185 %global enable_cache 1 %global enable_cluster 1 @@ -44,7 +44,7 @@ %global configure_cluster --with-cluster=internal %endif -%global from_snapshot 1 +%global from_snapshot 0 %if 0%{?from_snapshot} %global commit 4a1f6173d29a7d7ecab14a9313000aa5f81170d0 %global shortcommit %(c=%{commit}; echo ${c:0:7}) @@ -58,12 +58,12 @@ Name: lvm2 %if 0%{?rhel} Epoch: %{rhel} %endif -Version: 2.03.14 +Version: 2.03.16 %if 0%{?from_snapshot} #Release: 0.1.20211115git%{shortcommit}%{?dist}%{?rel_suffix} Release: 4%{?dist} %else -Release: 1%{?dist} +Release: 3%{?dist} %endif License: GPLv2 URL: http://sourceware.org/lvm2 @@ -72,7 +72,25 @@ Source0: lvm2-%{shortcommit}.tgz %else Source0: ftp://sourceware.org/pub/lvm2/releases/LVM2.%{version}.tgz %endif -Patch1: 0001-devices-file-do-not-clear-PVID-of-unread-devices.patch +Patch1: 0001-devices-file-move-clean-up-after-command-is-run.patch +Patch2: 0002-devices-file-fail-if-devicesfile-filename-doesn-t-ex.patch +Patch3: 0003-filter-mpath-handle-other-wwid-types-in-blacklist.patch +Patch4: 0004-filter-mpath-get-wwids-from-sysfs-vpd_pg83.patch +Patch5: 0005-pvdisplay-restore-reportformat-option.patch +Patch6: 0006-exit-with-error-when-devicesfile-name-doesn-t-exist.patch +Patch7: 0007-make-generate.patch +# BZ 2109351: +Patch8: 0008-apply-multipath_component_detection-0-to-duplicate-P.patch +# BZ 2090391: +Patch9: 0009-lvmdbusd-Correct-conditional-for-lvm-child-process-r.patch +Patch10: 0010-lvmdbusd-Simplify-child-process-env.patch +Patch11: 0011-lvmdbusd-re-work-lvm-shell-main.patch +Patch12: 0012-lvmdbusd-Add-debug-output-for-which-lvm-binary-is-us.patch +Patch13: 0013-lvmdbusd-Change-unit-test-vdo-minimum-size.patch +Patch14: 0014-lvmdbusd-Fix-env-variable-LVM_DBUSD_TEST_MODE.patch +Patch15: 0015-lvmdbusd-Remove-the-use-of-sub-shell-for-lvm-shell.patch +Patch16: 0016-lvmdbusd-Job-prop.-Get-GetAll-exec.-immediately.patch +Patch17: 0017-lvmdbusd-Don-t-require-lvm-prompt-for-shell.patch BuildRequires: make BuildRequires: gcc @@ -134,6 +152,22 @@ or more physical volumes and creating one or more logical volumes %setup -q -n LVM2.%{version} %endif %patch1 -p1 -b .backup1 +%patch2 -p1 -b .backup2 +%patch3 -p1 -b .backup3 +%patch4 -p1 -b .backup4 +%patch5 -p1 -b .backup5 +%patch6 -p1 -b .backup6 +%patch7 -p1 -b .backup7 +%patch8 -p1 -b .backup8 +%patch9 -p1 -b .backup9 +%patch10 -p1 -b .backup10 +%patch11 -p1 -b .backup11 +%patch12 -p1 -b .backup12 +%patch13 -p1 -b .backup13 +%patch14 -p1 -b .backup14 +%patch15 -p1 -b .backup15 +%patch16 -p1 -b .backup16 +%patch17 -p1 -b .backup17 %build %global _default_pid_dir /run @@ -704,6 +738,19 @@ An extensive functional testsuite for LVM2. %endif %changelog +* Fri Jul 29 2022 Marian Csontos - 2.03.16-3 +- Fix effect of setting multipath_component_detection to 0. +- Fix lvmdbusd using lvm shell with editline. + +* Thu Jul 14 2022 Marian Csontos - 2.03.16-2 +- Exit with error when --devicesfile used does not exist. +- Restore --reportformat option in pvdisplay. +- Improve multipath backlist option handling. + +* Wed May 18 2022 Marian Csontos - 2.03.16-1 +- Update to upstream version 2.03.16. +- See WHATS_NEW and WHATS_NEW_DM for more information. + * Tue Feb 15 2022 Marian Csontos - 2.03.14-4 - Remove service based autoactivation. - New lvmautoactivation(7) man page.