main - pvscan: recognize "pci" as a common symlink component in filters
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=6d14144d311fb347e42...
Commit: 6d14144d311fb347e4225ad6a48d4900b39445c4
Parent: c9fdc828ff0504bc2e57f65862bc382f7663a8a2
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 27 16:46:03 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jan 31 15:30:35 2023 -0600
pvscan: recognize "pci" as a common symlink component in filters
In case the filter strings don't include "/dev/disk", and only
include "pci".
---
lib/filters/filter-regex.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/filters/filter-regex.c b/lib/filters/filter-regex.c
index 40dc8aa1b..ecc32914b 100644
--- a/lib/filters/filter-regex.c
+++ b/lib/filters/filter-regex.c
@@ -284,6 +284,8 @@ static int _filter_contains_symlink(struct cmd_context *cmd, int filter_cfg)
return 1;
if (strstr(fname, "wwn-"))
return 1;
+ if (strstr(fname, "pci-"))
+ return 1;
}
}
1 month, 3 weeks
main - vgchange autoactivation: skip regex filter containing symlinks
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c9fdc828ff0504bc2e5...
Commit: c9fdc828ff0504bc2e57f65862bc382f7663a8a2
Parent: 17a3585cbb55d9a15ced9775a18b50c53a50ee8e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jan 27 15:56:06 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jan 31 15:30:35 2023 -0600
vgchange autoactivation: skip regex filter containing symlinks
"vgchange -aay --autoactivation event" is called by our udev rule.
When the udev rule runs, symlinks for devices may not all be created
yet. If the regex filter contains symlinks, it won't work correctly.
This command uses devices that already passed through pvscan. Since
pvscan applies the regex filter correctly, this command inherits the
filtering from pvscan and can skip the regex filter itself.
See the previous commit
"pvscan: use alternate device names from DEVLINKS to check filter"
---
lib/commands/toolcontext.h | 1 +
lib/filters/filter-regex.c | 46 +++++++++++++++++++++++++++++++++++++++++++
lib/filters/filter.h | 2 ++
lib/label/label.c | 17 ++++++++++++++++
tools/pvscan.c | 49 +++-------------------------------------------
tools/vgchange.c | 1 +
6 files changed, 70 insertions(+), 46 deletions(-)
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 4069b6116..b5c1d8a90 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -194,6 +194,7 @@ struct cmd_context {
unsigned create_edit_devices_file:1; /* command expects to create and/or edit devices file */
unsigned edit_devices_file:1; /* command expects to edit devices file */
unsigned filter_deviceid_skip:1; /* don't use filter-deviceid */
+ unsigned filter_regex_skip:1; /* don't use filter-regex */
unsigned filter_regex_with_devices_file:1; /* use filter-regex even when devices file is enabled */
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
diff --git a/lib/filters/filter-regex.c b/lib/filters/filter-regex.c
index d9ed0104c..40dc8aa1b 100644
--- a/lib/filters/filter-regex.c
+++ b/lib/filters/filter-regex.c
@@ -161,6 +161,9 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
if (cmd->enable_devices_list)
return 1;
+ if (cmd->filter_regex_skip)
+ return 1;
+
if (cmd->enable_devices_file && !cmd->filter_regex_with_devices_file) {
/* can't warn in create_filter because enable_devices_file is set later */
if (rf->config_filter && !rf->warned_filter) {
@@ -250,3 +253,46 @@ struct dev_filter *regex_filter_create(const struct dm_config_value *patterns, i
dm_pool_destroy(mem);
return NULL;
}
+
+static int _filter_contains_symlink(struct cmd_context *cmd, int filter_cfg)
+{
+ const struct dm_config_node *cn;
+ const struct dm_config_value *cv;
+ const char *fname;
+
+ if ((cn = find_config_tree_array(cmd, filter_cfg, NULL))) {
+ for (cv = cn->v; cv; cv = cv->next) {
+ if (cv->type != DM_CFG_STRING)
+ continue;
+ if (!cv->v.str)
+ continue;
+
+ fname = cv->v.str;
+
+ if (fname[0] != 'a')
+ continue;
+
+ if (strstr(fname, "/dev/disk/"))
+ return 1;
+ if (strstr(fname, "/dev/mapper/"))
+ return 1;
+
+ /* In case /dev/disk/by was omitted */
+ if (strstr(fname, "lvm-pv-uuid"))
+ return 1;
+ if (strstr(fname, "dm-uuid"))
+ return 1;
+ if (strstr(fname, "wwn-"))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int regex_filter_contains_symlink(struct cmd_context *cmd)
+{
+ return _filter_contains_symlink(cmd, devices_filter_CFG) ||
+ _filter_contains_symlink(cmd, devices_global_filter_CFG);
+}
+
diff --git a/lib/filters/filter.h b/lib/filters/filter.h
index 4cdfa2c9b..0678e5e11 100644
--- a/lib/filters/filter.h
+++ b/lib/filters/filter.h
@@ -64,4 +64,6 @@ struct dev_filter *usable_filter_create(struct cmd_context *cmd, struct dev_type
#define DEV_FILTERED_DEVICES_LIST 0x00001000
#define DEV_FILTERED_IS_LV 0x00002000
+int regex_filter_contains_symlink(struct cmd_context *cmd);
+
#endif /* _LVM_FILTER_H */
diff --git a/lib/label/label.c b/lib/label/label.c
index f845abb96..42d7b6709 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -27,6 +27,7 @@
#include "lib/format_text/layout.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
+#include "lib/filters/filter.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -1099,6 +1100,20 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
log_debug("Skipping device_id filtering due to devname ids.");
}
+ /*
+ * See corresponding code in pvscan. This function is used during
+ * startup autoactivation when udev has not created all symlinks, so
+ * regex filter containing symlinks doesn't work. pvscan has code
+ * to properly check devs against the filter using DEVLINKS. The
+ * pvscan will only create pvs_online files for devs that pass the
+ * filter. We get devs from the pvs_online files, so we inherit the
+ * regex filtering from pvscan and don't have to do it ourself.
+ */
+ if (!cmd->enable_devices_file &&
+ !cmd->enable_devices_list &&
+ regex_filter_contains_symlink(cmd))
+ cmd->filter_regex_skip = 1;
+
cmd->filter_nodata_only = 1;
dm_list_iterate_items_safe(devl, devl2, &devs) {
@@ -1179,6 +1194,8 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
if (relax_deviceid_filter)
cmd->filter_deviceid_skip = 0;
+ cmd->filter_regex_skip = 0;
+
free_po_list(&pvs_online);
if (dm_list_empty(&devs)) {
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 71485610b..8f60b2522 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -803,49 +803,6 @@ out:
return ret;
}
-/*
- * The optimization in which only the pvscan arg devname is added to dev-cache
- * does not work if there's an lvm.conf filter containing symlinks to the dev
- * like /dev/disk/by-id/lvm-pv-uuid-xyz entries. A full dev_cache_scan will
- * associate the symlinks with the system dev name passed to pvscan, which lets
- * filter-regex match the devname with the symlink name in the filter.
- */
-static int _filter_uses_symlinks(struct cmd_context *cmd, int filter_cfg)
-{
- const struct dm_config_node *cn;
- const struct dm_config_value *cv;
- const char *fname;
-
- if ((cn = find_config_tree_array(cmd, filter_cfg, NULL))) {
- for (cv = cn->v; cv; cv = cv->next) {
- if (cv->type != DM_CFG_STRING)
- continue;
- if (!cv->v.str)
- continue;
-
- fname = cv->v.str;
-
- if (fname[0] != 'a')
- continue;
-
- if (strstr(fname, "/dev/disk/"))
- return 1;
- if (strstr(fname, "/dev/mapper/"))
- return 1;
-
- /* In case /dev/disk/by was omitted */
- if (strstr(fname, "lvm-pv-uuid"))
- return 1;
- if (strstr(fname, "dm-uuid"))
- return 1;
- if (strstr(fname, "wwn-"))
- return 1;
- }
- }
-
- return 0;
-}
-
struct pvscan_arg {
struct dm_list list;
const char *devname;
@@ -1544,9 +1501,9 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
* be usable by that symlink name yet.
*/
if ((dm_list_size(&pvscan_devs) == 1) &&
- !cmd->enable_devices_file && !cmd->enable_devices_list &&
- (_filter_uses_symlinks(cmd, devices_filter_CFG) ||
- _filter_uses_symlinks(cmd, devices_global_filter_CFG))) {
+ !cmd->enable_devices_file &&
+ !cmd->enable_devices_list &&
+ regex_filter_contains_symlink(cmd)) {
char *env_str;
struct dm_list *env_aliases;
devl = dm_list_item(dm_list_first(&pvscan_devs), struct device_list);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 09ade96a6..7d1bbd70a 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -16,6 +16,7 @@
#include "tools.h"
#include "lib/device/device_id.h"
#include "lib/label/hints.h"
+#include "lib/filters/filter.h"
struct vgchange_params {
int lock_start_count;
1 month, 3 weeks
main - pvscan: use alternate device names from DEVLINKS to check filter
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=17a3585cbb55d9a15ce...
Commit: 17a3585cbb55d9a15ced9775a18b50c53a50ee8e
Parent: d9f8acb65a78c20ac806efaeb7a1e39208e1a443
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 19 17:37:31 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jan 31 15:30:35 2023 -0600
pvscan: use alternate device names from DEVLINKS to check filter
pvscan --cache <dev> is called by our udev rule at a time when all
the symlinks for <dev> may not be created yet (by other udev rules.)
The regex filter in lvm.conf may refer to <dev> using a symlink name
that hasn't yet been created, which would cause <dev> to not match
the filter regex. The DEVLINKS env var, set by udev, contains all
the symlink names for <dev> that have been or will be created.
So, we add all these symlink names to dev->aliases, as if we had
found them in /dev. This allows <dev> to be recognized by a regex
filter containing a symlink for <dev>.
---
lib/commands/toolcontext.h | 1 +
lib/filters/filter-regex.c | 2 +-
man/lvmautoactivation.7_main | 13 ++++++++++
tools/pvscan.c | 60 ++++++++++++++++++++++++++------------------
4 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 7f5fd12fc..4069b6116 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -207,6 +207,7 @@ struct cmd_context {
unsigned udevoutput:1;
unsigned online_vg_file_removed:1;
unsigned disable_dm_devs:1; /* temporarily disable use of dm devs cache */
+ unsigned filter_regex_set_preferred_name_disable:1; /* prevent dev_set_preferred_name */
/*
* Devices and filtering.
diff --git a/lib/filters/filter-regex.c b/lib/filters/filter-regex.c
index 05c5b3f2d..d9ed0104c 100644
--- a/lib/filters/filter-regex.c
+++ b/lib/filters/filter-regex.c
@@ -179,7 +179,7 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
if (m >= 0) {
if (dm_bit(rf->accept, m)) {
- if (!first)
+ if (!first && !cmd->filter_regex_set_preferred_name_disable)
dev_set_preferred_name(sl, dev);
return 1;
diff --git a/man/lvmautoactivation.7_main b/man/lvmautoactivation.7_main
index 808ea0d9f..0f7734557 100644
--- a/man/lvmautoactivation.7_main
+++ b/man/lvmautoactivation.7_main
@@ -184,6 +184,19 @@ system from booting. A custom systemd service could be written to run
autoactivation during system startup, in which case disabling event
autoactivation may be useful.
.
+.SS lvm.conf filter
+.P
+Device symlinks from /dev/disk/ can be used in the lvm.conf filter to
+guard against changes in kernel device names. The /dev/disk/by-path/ or
+/dev/disk/by-id/ prefixes should be included in the filter names; these
+prefixes help lvm detect that symlink names are used. Filters containing
+symlinks require special matching by commands run in the lvm udev rule.
+.P
+Common symlinks, e.g. beginning with wwn-, scsi-, pci-, or lvm-pv-uuid-,
+are recommended. Uncommon or custom symlinks created by custom udev rules
+may be less reliable. If a custom udev rule creates symlinks used in the
+lvm filter, then the udev rule should be started prior to the lvm rule.
+.
.SH EXAMPLES
.P
VG "vg" contains two PVs:
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 773862227..71485610b 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -910,30 +910,6 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
struct pvscan_arg *arg;
struct device_list *devl;
- /*
- * If no devices file is used, and lvm.conf filter is set to
- * accept /dev/disk/by-id/lvm-pv-uuid-xyz or another symlink,
- * but pvscan --cache is passed devname or major:minor, so
- * pvscan needs to match its arg device to the filter symlink.
- * setup_dev_in_dev_cache() adds /dev/sda2 to dev-cache which
- * does not match a symlink to /dev/sda2, so we need a full
- * dev_cache_scan that will associate all symlinks to sda2,
- * which allows filter-regex to work. This case could be
- * optimized if needed by adding dev-cache entries for each
- * filter "a" entry (filter symlink patterns would still need
- * a full dev_cache_scan.)
- * (When no devices file is used and 69-dm-lvm.rules is
- * used which calls pvscan directly, symlinks may not
- * have been created by other rules when pvscan runs, so
- * the full dev_cache_scan may still not find them.)
- */
- if (!cmd->enable_devices_file && !cmd->enable_devices_list &&
- (_filter_uses_symlinks(cmd, devices_filter_CFG) ||
- _filter_uses_symlinks(cmd, devices_global_filter_CFG))) {
- log_print_pvscan(cmd, "finding all devices for filter symlinks.");
- dev_cache_scan(cmd);
- }
-
/* pass NULL filter when getting devs from dev-cache, filtering is done separately */
/* in common usage, no dev will be found for a devno */
@@ -1550,6 +1526,42 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
cmd->filter_nodata_only = 1;
+ /*
+ * Hack to handle regex filter that contains a symlink name for dev arg.
+ * pvscan --cache <dev> is called by our udev rule at a time when the
+ * symlinks for <dev> may not all be created yet (by other udev rules.)
+ * The regex filter in lvm.conf may refer to <dev> using a symlink name,
+ * so we need to know all the symlinks for <dev> in order for the filter
+ * to work correctly. Scanning /dev with dev_cache_scan() would usually
+ * find all the symlink names for <dev>, adding them to dev->aliases,
+ * which would let the filter work, but all symlinks aren't created yet.
+ * But, the DEVLINKS env var, set by udev, contains all the symlink
+ * names for <dev> that have been or *will be* created. So, we add all
+ * these symlink names to dev->aliases, as if we had found them in /dev.
+ * This allows <dev> to be recognized by a regex filter containing a
+ * symlink for <dev>. We have to tell filter-regex to not set the
+ * preferred name for <dev> to a symlink name since the <dev> may not
+ * be usable by that symlink name yet.
+ */
+ if ((dm_list_size(&pvscan_devs) == 1) &&
+ !cmd->enable_devices_file && !cmd->enable_devices_list &&
+ (_filter_uses_symlinks(cmd, devices_filter_CFG) ||
+ _filter_uses_symlinks(cmd, devices_global_filter_CFG))) {
+ char *env_str;
+ struct dm_list *env_aliases;
+ devl = dm_list_item(dm_list_first(&pvscan_devs), struct device_list);
+ if ((env_str = getenv("DEVLINKS"))) {
+ log_debug("Finding symlink names from DEVLINKS for filter regex.");
+ log_debug("DEVLINKS %s", env_str);
+ env_aliases = str_to_str_list(cmd->mem, env_str, " ", 0);
+ dm_list_splice(&devl->dev->aliases, env_aliases);
+ } else {
+ log_debug("Finding symlink names from /dev for filter regex.");
+ dev_cache_scan(cmd);
+ }
+ cmd->filter_regex_set_preferred_name_disable = 1;
+ }
+
dm_list_iterate_items_safe(devl, devl2, &pvscan_devs) {
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print_pvscan(cmd, "%s excluded: %s.",
1 month, 3 weeks
main - lvresize: fail early if crypt device is missing
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d9f8acb65a78c20ac80...
Commit: d9f8acb65a78c20ac806efaeb7a1e39208e1a443
Parent: 5374a44c57127cdd832a675545c1d2bbf0b3751a
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jan 30 17:12:11 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Mon Jan 30 17:12:11 2023 -0600
lvresize: fail early if crypt device is missing
If extending an LV with crypto_LUKS on it, and the crypt device
is missing, then fail the command before extending the LV.
---
lib/device/filesystem.c | 15 ++++++++++++++-
lib/device/filesystem.h | 2 ++
lib/metadata/lv_manip.c | 4 ++++
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c
index db507bdda..c9cc7c553 100644
--- a/lib/device/filesystem.c
+++ b/lib/device/filesystem.c
@@ -94,6 +94,19 @@ static int _get_crypt_path(dev_t lv_devt, char *lv_path, char *crypt_path)
return ret;
}
+int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path)
+{
+ char crypt_path[PATH_MAX];
+ struct stat st_lv;
+
+ if (stat(lv_path, &st_lv) < 0) {
+ log_error("Failed to get LV path %s", lv_path);
+ return 0;
+ }
+
+ return _get_crypt_path(st_lv.st_rdev, lv_path, crypt_path);
+}
+
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
struct fs_info *fsi, int include_mount)
{
@@ -149,7 +162,7 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
memset(&info, 0, sizeof(info));
- log_print("File system found on crypt device %s on LV %s.",
+ log_print("Checking crypt device %s on LV %s.",
crypt_path, display_lvname(lv));
if ((fd = open(crypt_path, O_RDONLY)) < 0) {
diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h
index 77eac34d0..cbc7b5352 100644
--- a/lib/device/filesystem.h
+++ b/lib/device/filesystem.h
@@ -50,4 +50,6 @@ int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, stru
uint64_t newsize_bytes_fs);
int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype);
+int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path);
+
#endif
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index fa6393a48..2a4e0e88a 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6939,6 +6939,10 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
log_error("File system not found for --resizefs or --fs options.");
goto out;
}
+ if (!strcmp(fstype, "crypto_LUKS") && !lv_crypt_is_active(cmd, lv_path)) {
+ log_error("LUKS dm-crypt device must be active for fs resize.");
+ goto out;
+ }
/* FS utils will fail if LVs were renamed while mounted. */
if (fs_mount_state_is_misnamed(cmd, lv_top, lv_path, fstype))
goto_out;
1 month, 3 weeks
rhel-9.2.0 - build: Fix make rpm with VERSION_DM without dash
by Marian Csontos
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=611b768134fe39ddfb2...
Commit: 611b768134fe39ddfb2eec99eb5417e7e001d8cd
Parent: 0441d340e752427d0d355a85e5e5e465e911a102
Author: Marian Csontos <mcsontos(a)redhat.com>
AuthorDate: Wed Jun 15 11:53:51 2022 +0200
Committer: Marian Csontos <mcsontos(a)redhat.com>
CommitterDate: Fri Jan 27 12:36:24 2023 +0100
build: Fix make rpm with VERSION_DM without dash
When building RPM from a branch based on a release tag the expected -git
suffix is missing breaking the script producing error like following one:
error: line 215: Unterminated rich dependency: (2021-53.ge36b180a6.el9: Requires: device-mapper-devel >= 1.02.181 (2021-53.ge36b180a6.el9
(cherry picked from commit e60d7ce8e748cb6d51552879c162d01aafa17160)
---
Makefile.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.in b/Makefile.in
index 1d5aff482..91b21b78c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -110,7 +110,7 @@ rpm: dist
$(LN_S) -f $(abs_top_srcdir)/spec/build.inc $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_srcdir)/spec/macros.inc $(rpmbuilddir)/SOURCES
$(LN_S) -f $(abs_top_srcdir)/spec/packages.inc $(rpmbuilddir)/SOURCES
- DM_VER=$$(cut -d- -f1 $(top_srcdir)/VERSION_DM);\
+ DM_VER=$$(cut -d' ' -f1 $(top_srcdir)/VERSION_DM | cut -d- -f1);\
GIT_VER=$$(cd $(top_srcdir); git describe | cut -d- --output-delimiter=. -f2,3 || echo 0);\
$(SED) -e "s,\(device_mapper_version\) [0-9.]*$$,\1 $$DM_VER," \
-e "s,^\(Version:[^0-9%]*\)[0-9.]*$$,\1 $(LVM_VER)," \
2 months
main - lvresize: fail early if mounted LV was renamed
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=5374a44c57127cdd832...
Commit: 5374a44c57127cdd832a675545c1d2bbf0b3751a
Parent: 8adfcddc35be16ac1d1a00a169ec89a7f12d69af
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 26 14:00:00 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Jan 26 14:02:20 2023 -0600
lvresize: fail early if mounted LV was renamed
If a mounted LV is renamed, then fs resizing utilities will fail,
so detect this condition and fail the command before any changes
are made.
---
lib/device/filesystem.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
lib/device/filesystem.h | 2 +
lib/metadata/lv_manip.c | 3 ++
test/shell/lvresize-fs.sh | 11 +++++
4 files changed, 126 insertions(+)
diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c
index b4c43a626..db507bdda 100644
--- a/lib/device/filesystem.c
+++ b/lib/device/filesystem.c
@@ -214,6 +214,116 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
return ret;
}
+int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype)
+{
+ FILE *fp;
+ char proc_line[PATH_MAX];
+ char proc_fstype[FSTYPE_MAX];
+ char proc_devpath[1024];
+ char proc_mntpath[1024];
+ char lv_mapper_path[1024];
+ char mntent_mount_dir[1024];
+ char *dm_name;
+ struct stat st_lv;
+ struct stat stme;
+ FILE *fme = NULL;
+ struct mntent *me;
+ int renamed = 0;
+ int found_dir = 0;
+ int found_dev = 0;
+ int dev_match, dir_match;
+
+ if (stat(lv_path, &st_lv) < 0) {
+ log_error("Failed to get LV path %s", lv_path);
+ return 0;
+ }
+
+ /*
+ * If LVs have been renamed while their file systems were mounted, then
+ * inconsistencies appear in the device path and mount point info
+ * provided by getmntent and /proc/mounts. If there's any
+ * inconsistency or duplication of info for the LV name or the mount
+ * point, then give up and don't try fs resize which is likely to fail
+ * due to kernel problems where mounts reference old device names
+ * causing fs resizing tools to fail.
+ */
+
+ if (!(fme = setmntent("/etc/mtab", "r")))
+ return_0;
+
+ while ((me = getmntent(fme))) {
+ if (strcmp(me->mnt_type, fstype))
+ continue;
+ if (me->mnt_dir[0] != '/')
+ continue;
+ if (me->mnt_fsname[0] != '/')
+ continue;
+ if (stat(me->mnt_dir, &stme) < 0)
+ continue;
+ if (stme.st_dev != st_lv.st_rdev)
+ continue;
+ strncpy(mntent_mount_dir, me->mnt_dir, PATH_MAX-1);
+ }
+ endmntent(fme);
+
+ if (!(dm_name = dm_build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
+ return_0;
+
+ if ((dm_snprintf(lv_mapper_path, 1024, "%s/%s", dm_dir(), dm_name) < 0))
+ return_0;
+
+ if (!(fp = fopen("/proc/mounts", "r")))
+ return_0;
+
+ while (fgets(proc_line, sizeof(proc_line), fp)) {
+ if (proc_line[0] != '/')
+ continue;
+ if (sscanf(proc_line, "%s %s %s", proc_devpath, proc_mntpath, proc_fstype) != 3)
+ continue;
+ if (strcmp(fstype, proc_fstype))
+ continue;
+
+ dir_match = !strcmp(mntent_mount_dir, proc_mntpath);
+ dev_match = !strcmp(lv_mapper_path, proc_devpath);
+
+ if (dir_match)
+ found_dir++;
+ if (dev_match)
+ found_dev++;
+
+ if (dir_match != dev_match) {
+ log_error("LV %s mounted at %s may have been renamed (from %s).",
+ lv_mapper_path, proc_mntpath, proc_devpath);
+ renamed = 1;
+ }
+ }
+
+ if (fclose(fp))
+ stack;
+
+ /*
+ * Don't try resizing if:
+ * - different device names apppear for the mount point
+ * (LVs probably renamed while mounted), or
+ * - the mount point for the LV appears multiple times, or
+ * - the LV device is listed for multiple mounts.
+ */
+ if (renamed) {
+ log_error("File system resizing not supported: fs utilities do not support renamed devices.");
+ return 1;
+ }
+ /* These two are likely detected as renamed, but include checks in case. */
+ if (found_dir > 1) {
+ log_error("File system resizing not supported: %s appears more than once in /proc/mounts.", mntent_mount_dir);
+ return 1;
+ }
+ if (found_dev > 1) {
+ log_error("File system resizing not supported: %s appears more than once in /proc/mounts.", lv_mapper_path);
+ return 1;
+ }
+ return 0;
+}
+
#define FS_CMD_MAX_ARGS 16
int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h
index fd1af0416..77eac34d0 100644
--- a/lib/device/filesystem.h
+++ b/lib/device/filesystem.h
@@ -48,4 +48,6 @@ int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct
uint64_t newsize_bytes, char *fsmode);
int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes_fs);
+
+int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype);
#endif
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index cfb118f11..fa6393a48 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6939,6 +6939,9 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
log_error("File system not found for --resizefs or --fs options.");
goto out;
}
+ /* FS utils will fail if LVs were renamed while mounted. */
+ if (fs_mount_state_is_misnamed(cmd, lv_top, lv_path, fstype))
+ goto_out;
}
/*
diff --git a/test/shell/lvresize-fs.sh b/test/shell/lvresize-fs.sh
index 0be6911a0..f437652d6 100644
--- a/test/shell/lvresize-fs.sh
+++ b/test/shell/lvresize-fs.sh
@@ -262,6 +262,17 @@ umount "$mount_dir"
lvchange -an $vg/$lv
lvremove $vg/$lv
+# lvextend|lvreduce, ext4, active, mounted, --fs resize, renamed LV
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+lvrename $vg/$lv $vg/$lv2
+not lvextend --fs resize -L+32M $vg/$lv2
+not lvreduce --fs resize -L-32M $vg/$lv2
+umount "$mount_dir"
+lvchange -an $vg/$lv2
+lvremove $vg/$lv2
+
#
# lvextend, xfs
2 months
rhel-9.2.0 - lvmdbusd: Add command_log_selection to command line
by Marian Csontos
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0441d340e752427d0d3...
Commit: 0441d340e752427d0d355a85e5e5e465e911a102
Parent: 4e34edd6e4e52328dd77b6a55aeadd9b0454c743
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Nov 29 10:04:17 2022 -0600
Committer: Marian Csontos <mcsontos(a)redhat.com>
CommitterDate: Thu Jan 26 16:54:56 2023 +0100
lvmdbusd: Add command_log_selection to command line
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2145114
(cherry picked from commit e63b0c7262f50ab43fcde1c50b6d880acab68407)
---
daemons/lvmdbusd/cmdhandler.py | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/daemons/lvmdbusd/cmdhandler.py b/daemons/lvmdbusd/cmdhandler.py
index 0c7bd8528..9a76db4c9 100644
--- a/daemons/lvmdbusd/cmdhandler.py
+++ b/daemons/lvmdbusd/cmdhandler.py
@@ -17,7 +17,7 @@ import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
- make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option
+ make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -121,6 +121,9 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
+ # Ensure we get an error message when we fork & exec the lvm command line
+ command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
+
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
@@ -167,7 +170,17 @@ def call_lvm(command, debug=False, line_cb=None,
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
- return process.returncode, stdout_text, stderr_text
+ try:
+ report_json = json.loads(stdout_text)
+ except json.decoder.JSONDecodeError:
+ # Some lvm commands don't return json even though we are asking for it to do so.
+ return process.returncode, stdout_text, stderr_text
+
+ error_msg = get_error_msg(report_json)
+ if error_msg:
+ stderr_text += error_msg
+
+ return process.returncode, report_json, stderr_text
else:
if cfg.run.value == 0:
raise SystemExit
@@ -619,20 +632,8 @@ def lvm_full_report_json():
rc, out, err = call(cmd)
# When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5:
- # If the 'call' implementation is lvmshell, the out is a dictionary as lvmshell has to
- # parse the output to get the exit value. When doing fork & exec, out is a string
- # representing the JSON. TODO: Make this consistent between implementations.
- if cfg.SHELL_IN_USE:
- assert(type(out) == dict)
- return out
- else:
- try:
- return json.loads(out)
- except json.decoder.JSONDecodeError as joe:
- log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
- (str(joe), out))
- raise LvmBug("'fullreport' returned invalid JSON")
-
+ assert(type(out) == dict)
+ return out
raise LvmBug("'fullreport' exited with code '%d'" % rc)
2 months
rhel-9.2.0 - lvmdbusd: Move get_error_msg to utils
by Marian Csontos
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4e34edd6e4e52328dd7...
Commit: 4e34edd6e4e52328dd77b6a55aeadd9b0454c743
Parent: 8f7b4456ad93c3907a82fd03d0feceb9785e3bfc
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Tue Nov 29 10:00:39 2022 -0600
Committer: Marian Csontos <mcsontos(a)redhat.com>
CommitterDate: Thu Jan 26 16:54:50 2023 +0100
lvmdbusd: Move get_error_msg to utils
Moving this so we can re-use outside of lvm_shell_proxy.
(cherry picked from commit 8f60c494515ddccb20e4afb804edb6b9599e65c0)
---
daemons/lvmdbusd/lvm_shell_proxy.py.in | 23 +++--------------------
daemons/lvmdbusd/utils.py | 17 +++++++++++++++++
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/daemons/lvmdbusd/lvm_shell_proxy.py.in b/daemons/lvmdbusd/lvm_shell_proxy.py.in
index ac6d51e65..37d73218b 100755
--- a/daemons/lvmdbusd/lvm_shell_proxy.py.in
+++ b/daemons/lvmdbusd/lvm_shell_proxy.py.in
@@ -28,7 +28,7 @@ except ImportError:
import lvmdbusd.cfg as cfg
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
- read_decoded, extract_stack_trace, LvmBug
+ read_decoded, extract_stack_trace, LvmBug, get_error_msg
SHELL_PROMPT = "lvm> "
@@ -191,24 +191,7 @@ class LVMShellProxy(object):
def get_last_log(self):
self._write_cmd('lastlog\n')
report_json = self._read_response()[1]
- return LVMShellProxy.get_error_msg(report_json)
-
- @staticmethod
- def get_error_msg(report_json):
- # Get the error message from the returned JSON
- if 'log' in report_json:
- error_msg = ""
- # Walk the entire log array and build an error string
- for log_entry in report_json['log']:
- if log_entry['log_type'] == "error":
- if error_msg:
- error_msg += ', ' + log_entry['log_message']
- else:
- error_msg = log_entry['log_message']
-
- return error_msg
-
- return None
+ return get_error_msg(report_json)
def call_lvm(self, argv, debug=False):
rc = 1
@@ -245,7 +228,7 @@ class LVMShellProxy(object):
# report json too.
error_msg = self.get_last_log()
if error_msg is None:
- error_msg = LVMShellProxy.get_error_msg(report_json)
+ error_msg = get_error_msg(report_json)
if error_msg is None:
error_msg = 'No error reason provided! (missing "log" section)'
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 5aecb1fff..0b81591b2 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -859,3 +859,20 @@ class LvmDebugData:
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
+
+
+def get_error_msg(report_json):
+ # Get the error message from the returned JSON
+ if 'log' in report_json:
+ error_msg = ""
+ # Walk the entire log array and build an error string
+ for log_entry in report_json['log']:
+ if log_entry['log_type'] == "error":
+ if error_msg:
+ error_msg += ', ' + log_entry['log_message']
+ else:
+ error_msg = log_entry['log_message']
+
+ return error_msg
+
+ return None
2 months
rhel-9.2.0 - vgimportclone: fix importing PV without metadata
by Marian Csontos
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8f7b4456ad93c3907a8...
Commit: 8f7b4456ad93c3907a82fd03d0feceb9785e3bfc
Parent: db067b9054d87ada6aa133394e65e3af9d75fc08
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jan 5 14:28:31 2023 -0600
Committer: Marian Csontos <mcsontos(a)redhat.com>
CommitterDate: Thu Jan 26 16:51:12 2023 +0100
vgimportclone: fix importing PV without metadata
If one of the PVs in the VG does not hold metadata, then the
command would fail, thinking that PV was from a different VG.
Also add missing free on that error path.
(cherry picked from commit c4b898a53eec39bc28b5451e7fde87945303a644)
---
tools/vgimportclone.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index 60ef20762..93fa3b18d 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -203,7 +203,7 @@ int vgimportclone(struct cmd_context *cmd, int argc, char **argv)
struct device *dev;
struct device_list *devl;
struct dm_list other_devs;
- struct volume_group *vg, *error_vg;
+ struct volume_group *vg, *error_vg = NULL;
const char *vgname;
char base_vgname[NAME_LEN] = { 0 };
char tmp_vgname[NAME_LEN] = { 0 };
@@ -322,7 +322,7 @@ int vgimportclone(struct cmd_context *cmd, int argc, char **argv)
goto out;
}
- if (!(vgname = lvmcache_vgname_from_info(info))) {
+ if (!(vgname = lvmcache_vgname_from_info(info)) || is_orphan_vg(vgname)) {
/* The PV may not have metadata, this will be resolved in
the process_each_vg/vg_read at the end. */
continue;
@@ -503,6 +503,8 @@ retry_name:
}
ret = ECMD_PROCESSED;
out:
+ if (error_vg)
+ release_vg(error_vg);
unlock_devices_file(cmd);
return ret;
}
2 months
main - Revert "lvresize: enable crypt resizing with --force"
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8adfcddc35be16ac1d1...
Commit: 8adfcddc35be16ac1d1a00a169ec89a7f12d69af
Parent: 49c650423a17197c66b1c839a0274db8fba9a7d9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jan 25 09:30:05 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jan 25 10:10:57 2023 -0600
Revert "lvresize: enable crypt resizing with --force"
It looks like force was not being used to enable crypt resize,
but rather to force an inconsistency between LV and crypt
sizes, so this is either not needed or force in this case
should have some other meaning.
This reverts commit ed808a9b548ca59221d512bfb7ae581e8367fe50.
---
lib/metadata/lv_manip.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index f06b08254..cfb118f11 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6417,13 +6417,9 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv,
goto out;
}
if (!strcmp(lp->fsopt, "checksize")) {
- if (!lp->force) {
- log_error("crypt reduce is required (see --resizefs or cryptsetup resize.)");
- ret = 0;
- goto out;
- }
- /* This is only because it has been allowed in the past. */
- log_print("Forcing cryptsetup resize (--resizefs preferred.)");
+ log_error("crypt reduce is required (see --resizefs or cryptsetup resize.)");
+ ret = 0;
+ goto out;
}
if (test_mode()) {
ret = 1;
2 months