1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-01 21:44:22 +03:00

Compare commits

...

3 Commits

Author SHA1 Message Date
David Teigland
1068c5c15e pvscan: recognize "pci" as a common symlink component in filters
In case the filter strings don't include "/dev/disk", and only
include "pci".
2023-01-27 16:51:21 -06:00
David Teigland
a2392655a9 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 b2d80db12e13
"pvscan: use alternate device names from DEVLINKS to check filter"
2023-01-27 16:51:21 -06:00
David Teigland
f4d285a3cb 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>.
2023-01-27 16:51:17 -06:00
6 changed files with 107 additions and 68 deletions

View File

@@ -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 */
@@ -207,6 +208,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.

View File

@@ -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) {
@@ -179,7 +182,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;
@@ -250,3 +253,48 @@ 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;
if (strstr(fname, "pci-"))
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);
}

View File

@@ -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 */

View File

@@ -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)) {

View File

@@ -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;
@@ -910,30 +867,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 +1483,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 &&
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);
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.",

View File

@@ -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;