1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

devices: refresh device ids if the system changes

If the system changes, locate PVs that appear on different devices,
and update the device IDs in the devices file.  A system change is
detected by saving the DMI product_uuid or hostname in the devices
file, and comparing it to the current system value.  If a root PV
is restored or copied to a new system with different devices, then
the product_uuid or hostname should change, and trigger lvm to
locate PVIDs from system.devices on new devices.
This commit is contained in:
David Teigland 2023-09-13 12:28:47 -05:00
parent d06378373e
commit 88aa285a79
14 changed files with 1024 additions and 171 deletions

View File

@ -1646,7 +1646,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
* devices file. We then need to run label scan on these correct
* devices.
*/
device_ids_find_renamed_devs(cmd, &renamed_devs, NULL, 0);
device_ids_refresh(cmd, &renamed_devs, NULL, 0);
if (!dm_list_empty(&renamed_devs))
label_scan_devs(cmd, cmd->filter, &renamed_devs);

View File

@ -608,6 +608,50 @@ static int _init_system_id(struct cmd_context *cmd)
return 1;
}
static void _init_device_ids_refresh(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int check_product_uuid = 0;
int check_hostname = 0;
char path[PATH_MAX];
char uuid[128] = { 0 };
cmd->device_ids_check_product_uuid = 0;
cmd->device_ids_check_hostname = 0;
if (!find_config_tree_bool(cmd, devices_device_ids_refresh_CFG, NULL))
return;
if (!(cn = find_config_tree_array(cmd, devices_device_ids_refresh_checks_CFG, NULL)))
return;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING)
continue;
if (!strcmp(cv->v.str, "product_uuid"))
check_product_uuid = 1;
if (!strcmp(cv->v.str, "hostname"))
check_hostname = 1;
}
/* product_uuid is preferred */
if (check_product_uuid) {
const char *sysfs_dir = cmd->device_id_sysfs_dir ?: dm_sysfs_dir();
if (dm_snprintf(path, sizeof(path), "%sdevices/virtual/dmi/id/product_uuid", sysfs_dir) < 0)
return;
if (get_sysfs_value(path, uuid, sizeof(uuid), 0) && uuid[0])
cmd->product_uuid = dm_pool_strdup(cmd->libmem, uuid);;
if (cmd->product_uuid) {
cmd->device_ids_check_product_uuid = 1;
return;
}
}
if (check_hostname && cmd->hostname)
cmd->device_ids_check_hostname = 1;
}
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
@ -779,6 +823,8 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
_init_device_ids_refresh(cmd);
init_io_memory_size(find_config_tree_int(cmd, global_io_memory_size_CFG, NULL));
return 1;

View File

@ -120,6 +120,7 @@ struct cmd_context {
* Machine and system identification.
*/
const char *system_id;
const char *product_uuid;
const char *hostname;
const char *kernel_vsn;
@ -209,6 +210,9 @@ struct cmd_context {
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 */
unsigned device_ids_check_product_uuid:1;
unsigned device_ids_check_hostname:1;
unsigned device_ids_refresh_trigger:1;
/*
* Devices and filtering.

View File

@ -306,6 +306,22 @@ cfg(devices_search_for_devnames_CFG, "search_for_devnames", devices_CFG_SECTION,
"at other devices, but only those that are likely to have the PV.\n"
"If \"all\", lvm will look at all devices on the system.\n")
cfg(devices_device_ids_refresh_CFG, "device_ids_refresh", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 23), NULL, 0, NULL,
"Find PVs on new devices and update the device IDs in the devices file.\n"
"If PVs are restored or moved to a new system with new devices, but\n"
"an old system.devices remains with old device IDs, then search for\n"
"the PVIDs on new devices and update the device IDs in system.devices.\n"
"The original device IDs must also not be found on the new system.\n"
"See device_ids_refresh_check for conditions that trigger the refresh.\n")
cfg_array(devices_device_ids_refresh_checks_CFG, "device_ids_refresh_checks", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sproduct_uuid#Shostname", vsn(2, 3, 23), NULL, 0, NULL,
"Conditions that trigger device_ids_refresh to locate PVIDs on new devices.\n"
"product_uuid: refresh if /sys/devices/virtual/dmi/id/product_uuid does not\n"
"match the value saved in system.devices.\n"
"hostname: refresh if hostname does not match the value saved in system.devices.\n"
"(hostname is used if product_uuid is not available.)\n"
"Remove values from this list to prevent lvm from using them.\n")
cfg_array(devices_filter_CFG, "filter", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "#Sa|.*|", vsn(1, 0, 0), NULL, 0, NULL,
"Limit the block devices that are used by LVM commands.\n"
"This is a list of regular expressions used to accept or reject block\n"

View File

@ -41,7 +41,6 @@ static int _devices_fd = -1;
static int _using_devices_file;
static int _devices_file_locked;
static char _devices_lockfile[PATH_MAX];
static char _devices_file_systemid[PATH_MAX];
static char _devices_file_version[VERSION_LINE_MAX];
static const char *_searched_file = DEFAULT_RUN_DIR "/searched_devnames";
@ -96,6 +95,30 @@ static int _searched_devnames_exists(struct cmd_context *cmd)
return 0;
}
/*
* Check if the device_id saved in the VG metadata matches the actual device_id
* on the device used for the PV.
*/
int pv_device_id_is_stale(const struct physical_volume *pv)
{
struct dev_use *du;
if (!pv->vg || !pv->vg->cmd)
return 0;
if (!pv->device_id || !pv->device_id_type)
return 0;
if (!(du = get_du_for_dev(pv->vg->cmd, pv->dev)))
return 0;
if (!du->idname)
return 0;
if (du->idtype != idtype_from_str(pv->device_id_type))
return 1;
if (strcmp(du->idname, pv->device_id))
return 1;
return 0;
}
/*
* How the devices file and device IDs are used by an ordinary command:
*
@ -717,6 +740,82 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
return NULL;
}
static int device_id_system_read_preferred(struct cmd_context *cmd, struct device *dev,
uint16_t *new_idtype, const char **new_idname)
{
const char *idname = NULL;
uint16_t idtype;
if (MAJOR(dev->dev) == cmd->dev_types->device_mapper_major) {
if (dev_has_mpath_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_MPATH_UUID;
goto id_done;
}
if (_dev_has_crypt_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_CRYPT_UUID;
goto id_done;
}
if (_dev_has_lvmlv_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_LVMLV_UUID;
goto id_done;
}
}
/* TODO: kpartx partitions on loop devs. */
if (MAJOR(dev->dev) == cmd->dev_types->loop_major) {
idtype = DEV_ID_TYPE_LOOP_FILE;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
goto id_last;
}
if (MAJOR(dev->dev) == cmd->dev_types->md_major) {
idtype = DEV_ID_TYPE_MD_UUID;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
goto id_last;
}
if (MAJOR(dev->dev) == cmd->dev_types->drbd_major) {
/* TODO */
log_warn("Missing support for DRBD idtype");
goto id_last;
}
idtype = DEV_ID_TYPE_SYS_WWID;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_NAA;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_EUI;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_T10;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_SYS_SERIAL;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
id_last:
idtype = DEV_ID_TYPE_DEVNAME;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
return 0;
id_done:
*new_idtype = idtype;
*new_idname = idname;
return 1;
}
/*
* Check if this dev would use a stable idtype or if it
* would use DEV_ID_TYPE_DEVNAME.
@ -921,10 +1020,13 @@ int device_ids_read(struct cmd_context *cmd)
{
char line[PATH_MAX];
char buf[PATH_MAX];
char check_id[PATH_MAX];
char *idtype, *idname, *devname, *pvid, *part;
struct dev_use *du;
FILE *fp;
int line_error;
int product_uuid_found = 0;
int hostname_found = 0;
int ret = 1;
if (!cmd->enable_devices_file)
@ -953,16 +1055,39 @@ int device_ids_read(struct cmd_context *cmd)
if (line[0] == '#')
continue;
if (!strncmp(line, "SYSTEMID", 8)) {
_copy_idline_str(line, _devices_file_systemid, sizeof(_devices_file_systemid));
log_debug("read devices file systemid %s", _devices_file_systemid);
if ((!cmd->system_id && _devices_file_systemid[0]) ||
(cmd->system_id && strcmp(cmd->system_id, _devices_file_systemid))) {
log_warn("WARNING: devices file has unmatching system id %s vs local %s.",
_devices_file_systemid[0] ? _devices_file_systemid : "none", cmd->system_id ?: "none");
/* Old version wrote this but it's not used. */
if (!strncmp(line, "SYSTEMID", 8))
continue;
if (!strncmp(line, "HOSTNAME", 8)) {
if (!cmd->device_ids_check_hostname)
continue;
hostname_found = 1;
_copy_idline_str(line, check_id, sizeof(check_id));
log_debug("read devices file hostname %s", check_id);
if (cmd->hostname && strcmp(cmd->hostname, check_id)) {
log_debug("Devices file hostname %s vs local %s.",
check_id[0] ? check_id : "none", cmd->hostname ?: "none");
cmd->device_ids_refresh_trigger = 1;
}
continue;
}
if (!strncmp(line, "PRODUCT_UUID", 12)) {
if (!cmd->device_ids_check_product_uuid)
continue;
product_uuid_found = 1;
_copy_idline_str(line, check_id, sizeof(check_id));
log_debug("read devices file product_uuid %s", check_id);
if ((!cmd->product_uuid && check_id[0]) ||
(cmd->product_uuid && strcmp(cmd->product_uuid, check_id))) {
log_debug("Devices file product_uuid %s vs local %s.",
check_id[0] ? check_id : "none", cmd->product_uuid ?: "none");
cmd->device_ids_refresh_trigger = 1;
}
continue;
}
if (!strncmp(line, "VERSION", 7)) {
_copy_idline_str(line, _devices_file_version, sizeof(_devices_file_version));
log_debug("read devices file version %s", _devices_file_version);
@ -1028,6 +1153,12 @@ int device_ids_read(struct cmd_context *cmd)
if (fclose(fp))
stack;
if (!product_uuid_found && !hostname_found &&
(cmd->device_ids_check_product_uuid || cmd->device_ids_check_hostname)) {
cmd->device_ids_refresh_trigger = 1;
log_debug("Devices file refresh due to no product_uuid or hostname.");
}
return ret;
}
@ -1078,11 +1209,11 @@ int device_ids_write(struct cmd_context *cmd)
(!strncmp(cmd->name, "pvcreate", 8) || !strncmp(cmd->name, "vgcreate", 8))) {
/* If any PVs were seen during scan then don't create a new devices file. */
if (lvmcache_vg_info_count()) {
log_warn("Not creating system devices file due to existing VGs.");
log_print_unless_silent("Not creating system devices file due to existing VGs.");
free_dus(&cmd->use_devices);
return 1;
}
log_warn("Creating devices file %s", cmd->devices_file_path);
log_print_unless_silent("Creating devices file %s", cmd->devices_file_path);
cmd->enable_devices_file = 1;
}
@ -1132,15 +1263,10 @@ int device_ids_write(struct cmd_context *cmd)
fprintf(fp, "# LVM uses devices listed in this file.\n");
fprintf(fp, "# Created by LVM command %s pid %d at %s", cmd->name, getpid(), ctime(&t));
/*
* It's useful to ensure that this devices file is associated to a
* single system because this file can be used to control access to
* shared devices. If this file is copied/cloned to another system,
* that new system should not automatically gain access to the devices
* that the original system is using.
*/
if (cmd->system_id)
fprintf(fp, "SYSTEMID=%s\n", cmd->system_id);
if (cmd->product_uuid && cmd->device_ids_check_product_uuid)
fprintf(fp, "PRODUCT_UUID=%s\n", cmd->product_uuid);
if (cmd->hostname && cmd->device_ids_check_hostname)
fprintf(fp, "HOSTNAME=%s\n", cmd->hostname);
if (dm_snprintf(version_buf, VERSION_LINE_MAX, "VERSION=%u.%u.%u", DEVICES_FILE_MAJOR, DEVICES_FILE_MINOR, df_counter+1) < 0)
stack;
@ -1425,77 +1551,11 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
}
}
if (MAJOR(dev->dev) == cmd->dev_types->device_mapper_major) {
if (dev_has_mpath_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_MPATH_UUID;
goto id_done;
}
if (_dev_has_crypt_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_CRYPT_UUID;
goto id_done;
}
if (_dev_has_lvmlv_uuid(cmd, dev, &idname)) {
idtype = DEV_ID_TYPE_LVMLV_UUID;
goto id_done;
}
}
/* TODO: kpartx partitions on loop devs. */
if (MAJOR(dev->dev) == cmd->dev_types->loop_major) {
idtype = DEV_ID_TYPE_LOOP_FILE;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
goto id_last;
}
if (MAJOR(dev->dev) == cmd->dev_types->md_major) {
idtype = DEV_ID_TYPE_MD_UUID;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
goto id_last;
}
if (MAJOR(dev->dev) == cmd->dev_types->drbd_major) {
/* TODO */
log_warn("Missing support for DRBD idtype");
goto id_last;
}
/*
* No device-specific, existing, or user-specified idtypes,
* so use first available of sys_wwid, wwid_naa, wwid_eui,
* wwid_t10, sys_serial, devname.
*/
idtype = DEV_ID_TYPE_SYS_WWID;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_NAA;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_EUI;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_WWID_T10;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
idtype = DEV_ID_TYPE_SYS_SERIAL;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
id_last:
idtype = DEV_ID_TYPE_DEVNAME;
if ((idname = device_id_system_read(cmd, dev, idtype)))
goto id_done;
id_done:
if (!device_id_system_read_preferred(cmd, dev, &idtype, &idname))
return_0;
if (!idname)
return_0;
id_done:
/*
* Create a dev_id struct for the new idtype on dev->ids.
@ -2240,7 +2300,7 @@ static void _get_devs_with_serial_numbers(struct cmd_context *cmd, struct dm_lis
}
}
/* just copying the no-data filters in similar device_ids_find_renamed_devs */
/* just copying the no-data filters in similar device_ids_refresh */
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
@ -2300,7 +2360,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
if (!cmd->enable_devices_file)
return;
log_debug("validating devices file entries");
log_debug("Validating devices file entries");
/*
* Validate entries with proper device id types.
@ -2320,15 +2380,21 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
* scanned_devs are the devices that have been scanned,
* so they are the only devs we can verify PVID for.
*/
if (scanned_devs && !device_list_find_dev(scanned_devs, dev))
if (scanned_devs && !device_list_find_dev(scanned_devs, dev)) {
log_debug("Validate %s %s PVID %s on %s: not scanned",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".", dev_name(dev));
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)
if (dev->flags & DEV_SCAN_NOT_READ) {
log_debug("Validate %s %s PVID %s on %s: not read",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".", dev_name(dev));
continue;
}
/*
* du and dev may have been matched, but the dev could still
@ -2337,6 +2403,8 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
* probably wants to do something about it.
*/
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "persistent")) {
log_debug("Validate %s %s PVID %s on %s: filtered",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".", dev_name(dev));
log_warn("Devices file %s is excluded: %s.",
dev_name(dev), dev_filtered_reason(dev));
continue;
@ -2351,6 +2419,9 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
*/
if ((du->idtype == DEV_ID_TYPE_SYS_SERIAL) && du->pvid &&
memcmp(dev->pvid, du->pvid, ID_LEN)) {
log_debug("Validate %s %s PVID %s on %s: wrong PVID %s",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
dev_name(dev), dev->pvid);
log_debug("suspect device id serial %s for %s", du->idname, dev_name(dev));
if (!str_list_add(cmd->mem, &cmd->device_ids_check_serial, dm_pool_strdup(cmd->mem, du->idname)))
stack;
@ -2365,6 +2436,9 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
*/
if (dev->pvid[0]) {
if (!du->pvid || memcmp(dev->pvid, du->pvid, ID_LEN)) {
log_debug("Validate %s %s PVID %s on %s: wrong PVID %s",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
dev_name(dev), dev->pvid);
log_warn("Device %s has PVID %s (devices file %s)",
dev_name(dev), dev->pvid, du->pvid ?: "none");
if (!(tmpdup = strdup(dev->pvid)))
@ -2376,6 +2450,9 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
}
} else {
if (du->pvid && (du->pvid[0] != '.')) {
log_debug("Validate %s %s PVID %s on %s: wrong PVID %s",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
dev_name(dev), dev->pvid);
log_warn("Device %s has no PVID (devices file %s)",
dev_name(dev), du->pvid);
free(du->pvid);
@ -2385,6 +2462,10 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
}
}
log_debug("Validate %s %s PVID %s on %s: correct",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
dev_name(dev));
/*
* Avoid thrashing changes to the devices file during
* startup due to device names that are still being
@ -2482,7 +2563,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
devname = dev_name(dev);
log_print("Devices file PVID %s is now on %s.", du->pvid, devname);
log_debug("Devices file PVID %s is now on %s.", du->pvid, devname);
dup_devname1 = strdup(devname);
dup_devname2 = strdup(devname);
@ -2518,17 +2599,23 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
/*
* Each remaining du that's not matched to a dev (no du->dev set) is
* subject to device_ids_find_renamed_devs which will look for
* unmatched pvids on devs that have not been scanned yet.
* subject to device_ids_refresh which will look for unmatched pvids on
* devs that have not been scanned yet.
*/
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->idtype != DEV_ID_TYPE_DEVNAME)
/*
* Only search for devname type entries unless the refresh
* trigger is set due to a machine change, in which case
* we look for missing PVIDs on new devs with real idtypes.
*/
if ((du->idtype != DEV_ID_TYPE_DEVNAME) && !cmd->device_ids_refresh_trigger)
continue;
if (!du->pvid)
continue;
if (du->dev)
continue;
log_debug("Search needed to find device with PVID %s.", du->pvid);
log_debug("Search needed to locate PVID %s %s %s.",
du->pvid, idtype_to_str(du->idtype), du->idname ?: ".");
}
/*
@ -2624,7 +2711,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
/*
* Check for other problems for which we want to set *device_ids_invalid,
* even if we don't have a way to fix them right here. In particular,
* issues that may be fixed shortly by device_ids_find_renamed_devs.
* issues that may be fixed shortly by device_ids_refresh.
*
* The device_ids_invalid flag is only used to tell the caller not
* to write hints, which could be based on invalid device info.
@ -2650,7 +2737,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
if (update_file)
unlink_searched_devnames(cmd);
/* FIXME: for wrong devname cases, wait to write new until device_ids_find_renamed_devs? */
/* FIXME: for wrong devname cases, wait to write new until device_ids_refresh? */
/*
* try lock and device_ids_write(), the update is not required and will
@ -2957,7 +3044,7 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
* is using a non-system devices file?
*/
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list,
void device_ids_refresh(struct cmd_context *cmd, struct dm_list *dev_list,
int *search_count, int noupdate)
{
struct device *dev;
@ -2966,8 +3053,8 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
struct dev_iter *iter;
struct device_list *devl; /* holds struct device */
struct device_id_list *dil, *dil2; /* holds struct device + pvid */
struct dm_list search_pvids; /* list of device_id_list */
struct dm_list search_devs ; /* list of device_list */
struct dm_list search_list_pvids; /* list of device_id_list */
struct dm_list search_list_devs ; /* list of device_list */
const char *devname;
int update_file = 0;
int other_idtype = 0;
@ -2975,41 +3062,74 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
int no_pvid = 0;
int found = 0;
int not_found = 0;
int search_none;
int search_auto;
int search_mode_none;
int search_mode_auto;
int search_mode_all;
dm_list_init(&search_pvids);
dm_list_init(&search_devs);
dm_list_init(&search_list_pvids);
dm_list_init(&search_list_devs);
if (!cmd->enable_devices_file)
return;
search_none = !strcmp(cmd->search_for_devnames, "none");
search_auto = !strcmp(cmd->search_for_devnames, "auto");
if (cmd->device_ids_refresh_trigger) {
search_mode_all = 1;
search_mode_none = 0;
search_mode_auto = 0;
} else {
search_mode_all = !strcmp(cmd->search_for_devnames, "all");
search_mode_none = !strcmp(cmd->search_for_devnames, "none");
search_mode_auto = !strcmp(cmd->search_for_devnames, "auto");
}
/*
* Create search_list_pvids which is a list of PVIDs that
* we want to locate on some device.
*/
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->idtype != DEV_ID_TYPE_DEVNAME)
continue;
if (!du->pvid)
continue;
if (du->dev)
continue;
if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
/*
* When device_ids_refresh_trigger is set, it means
* that a PVID may be shifted to a new device even when
* the entry uses a stable id type, like wwid.
* Otherwise, we assume that only entries using the
* devname id type can move to new devices.
*/
if (!cmd->device_ids_refresh_trigger &&
(du->idtype != DEV_ID_TYPE_DEVNAME))
continue;
if (!search_none) {
memcpy(dil->pvid, du->pvid, ID_LEN);
dm_list_add(&search_pvids, &dil->list);
}
log_debug("Search for PVID %s.", du->pvid);
if (search_count)
(*search_count)++;
if (search_mode_none)
continue;
if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
continue;
memcpy(dil->pvid, du->pvid, ID_LEN);
dm_list_add(&search_list_pvids, &dil->list);
}
if (dm_list_empty(&search_pvids))
/* No unmatched PVIDs to search for, and no system id to update. */
if (dm_list_empty(&search_list_pvids) && !cmd->device_ids_refresh_trigger)
return;
log_debug("device ids refresh search_pvids %d trigger %d search all %d auto %d none %d",
dm_list_size(&search_list_pvids), cmd->device_ids_refresh_trigger,
search_mode_all, search_mode_auto, search_mode_none);
if (dm_list_empty(&search_list_pvids) && cmd->device_ids_refresh_trigger) {
update_file = 1;
goto out;
}
/*
* A previous command searched for devnames and found nothing, so it
* created the searched file to tell us not to bother. Without this, a
@ -3025,7 +3145,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* If hints are enabled, the hints invalidation could also remove the
* searched file.
*/
if (_searched_devnames_exists(cmd)) {
if (!cmd->device_ids_refresh_trigger && _searched_devnames_exists(cmd)) {
log_debug("Search for PVIDs skipped for %s", _searched_file);
return;
}
@ -3060,11 +3180,11 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
continue;
devl->dev = dev;
dm_list_add(&search_devs, &devl->list);
dm_list_add(&search_list_devs, &devl->list);
}
dev_iter_destroy(iter);
log_debug("Search for PVIDs reading labels on %d devs.", dm_list_size(&search_devs));
log_debug("Search for PVIDs reading labels on %d devs.", dm_list_size(&search_list_devs));
/*
* Read the dev to get the pvid, and run the filters that will use the
@ -3072,7 +3192,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* to modify the command's existing filter chain or the persistent
* filter values.
*/
dm_list_iterate_items(devl, &search_devs) {
dm_list_iterate_items(devl, &search_list_devs) {
int has_pvid;
dev = devl->dev;
@ -3081,7 +3201,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* themselves as alternatives to the missing ID_TYPE_DEVNAME
* entry. i.e. a ID_TYPE_DEVNAME entry would not appear on a
* device that has a wwid and would use ID_TYPE_SYS_WWID. So,
* if a dev in the search_devs list has a proper/stable device
* if a dev in the search_list_devs list has a proper/stable device
* id (e.g. wwid, serial, loop, mpath), then we don't need to
* read it to check for missing PVIDs.
*
@ -3097,7 +3217,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* user forces a devname id, then they should probably also
* set search_for_devnames=all.
*/
if (search_auto && _dev_has_stable_id(cmd, dev)) {
if (search_mode_auto && _dev_has_stable_id(cmd, dev)) {
other_idtype++;
continue;
}
@ -3134,12 +3254,12 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
goto next;
/*
* Check if the the PVID is one we are searching for.
* Loop below looks at search_pvid entries that have dil->dev set.
* This continues checking after all search_pvids entries have been
* Check if the the PVID returned from label_read is one we are looking for.
* The loop below looks at search_list_pvids entries that have dil->dev set.
* This loop continues checking after all search_list_pvids entries have been
* matched in order to check if the PVID is on duplicate devs.
*/
dm_list_iterate_items_safe(dil, dil2, &search_pvids) {
dm_list_iterate_items_safe(dil, dil2, &search_list_pvids) {
if (!memcmp(dil->pvid, dev->pvid, ID_LEN)) {
if (dil->dev) {
log_warn("WARNING: found PVID %s on multiple devices %s %s.",
@ -3164,15 +3284,16 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
/*
* The use_devices entries (repesenting the devices file) are
* updated for the new devices on which the PVs reside. The new
* correct devs are set as dil->dev on search_pvids entries.
* correct devs are set as dil->dev on search_list_pvids entries.
*
* The du/dev/id are set up and linked for the new devs.
*
* The command's full filter chain is updated for the new devs now that
* filter-deviceid will pass.
*/
dm_list_iterate_items(dil, &search_pvids) {
char *dup_devname1, *dup_devname2, *dup_devname3;
dm_list_iterate_items(dil, &search_list_pvids) {
char *new_idname, *new_idname2, *new_devname;
uint16_t new_idtype;
if (!dil->dev || dm_list_empty(&dil->dev->aliases)) {
not_found++;
@ -3187,37 +3308,50 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
/* shouldn't happen */
continue;
}
if (du->idtype != DEV_ID_TYPE_DEVNAME) {
/* shouldn't happen */
new_idtype = 0;
new_idname = NULL;
new_idname2 = NULL;
new_devname = NULL;
if (cmd->device_ids_refresh_trigger) {
if (!device_id_system_read_preferred(cmd, dev, &new_idtype, (const char **)&new_idname))
continue;
new_idname2 = strdup(new_idname);
new_devname = strdup(devname);
log_print_unless_silent("Devices file PVID %s has new device ID %s %s from %s.",
du->pvid ?: "", idtype_to_str(new_idtype), new_idname ?: "", devname);
} else {
/* Use the new device name as the new idname. */
new_idtype = DEV_ID_TYPE_DEVNAME;
new_idname = strdup(devname);
new_idname2 = strdup(devname);
new_devname = strdup(devname);
log_print_unless_silent("Found new device name %s for PVID %s.", devname, du->pvid ?: "");
}
dup_devname1 = strdup(devname);
dup_devname2 = strdup(devname);
dup_devname3 = strdup(devname);
id = zalloc(sizeof(struct dev_id));
if (!dup_devname1 || !dup_devname2 || !dup_devname3 || !id) {
free(dup_devname1);
free(dup_devname2);
free(dup_devname3);
if (!id || !new_devname || !new_idname || !new_idname2) {
free(id);
free(new_idname);
free(new_idname2);
free(new_devname);
stack;
continue;
}
if (!noupdate)
log_warn("Devices file PVID %s updating IDNAME to %s.", dev->pvid, devname);
free(du->idname);
free(du->devname);
free_dids(&dev->ids);
du->idname = dup_devname1;
du->devname = dup_devname2;
id->idtype = DEV_ID_TYPE_DEVNAME;
id->idname = dup_devname3;
id->dev = dev;
du->idtype = new_idtype;
du->idname = new_idname;
du->devname = new_devname;
du->dev = dev;
id->idtype = new_idtype;
id->idname = new_idname2;
id->dev = dev;
dev->id = id;
dev->flags |= DEV_MATCHED_USE_ID;
dm_list_add(&dev->ids, &id->list);
@ -3225,7 +3359,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
update_file = 1;
}
dm_list_iterate_items(dil, &search_pvids) {
dm_list_iterate_items(dil, &search_list_pvids) {
if (!dil->dev)
continue;
dev = dil->dev;
@ -3242,6 +3376,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
}
}
out:
/*
* try lock and device_ids_write(), the update is not required and will
* be done by a subsequent command if it's not done here.
@ -3259,11 +3394,11 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
}
/*
* The entries in search_pvids with a dev set are the new devs found
* The entries in search_list_pvids with a dev set are the new devs found
* for the PVIDs that we want to return to the caller in a device_list
* format.
*/
dm_list_iterate_items(dil, &search_pvids) {
dm_list_iterate_items(dil, &search_list_pvids) {
if (!dil->dev)
continue;
dev = dil->dev;
@ -3279,7 +3414,7 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
* pvids not found were from devices that are permanently detached.
* If a new PV appears, pvscan will run and do unlink_searched_file.
*/
if (not_found && !found)
if (!cmd->device_ids_refresh_trigger && not_found && !found)
_touch_searched_devnames(cmd);
}

View File

@ -36,7 +36,7 @@ void device_ids_match_device_list(struct cmd_context *cmd);
void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, int *device_ids_invalid, int noupdate);
int device_ids_version_unchanged(struct cmd_context *cmd);
void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs, int *update_needed, int noupdate);
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);
void device_ids_refresh(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);
const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_t idtype);
void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg, struct id *old_vg_id);
@ -72,4 +72,6 @@ int dev_read_vpd_wwids(struct cmd_context *cmd, struct device *dev);
int dev_read_sys_wwid(struct cmd_context *cmd, struct device *dev,
char *buf, int bufsize, struct dev_wwid **dw_out);
int pv_device_id_is_stale(const struct physical_volume *pv);
#endif

View File

@ -1092,11 +1092,12 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
if (cmd->enable_devices_list)
device_ids_match_device_list(cmd);
if (cmd->enable_devices_file && device_ids_use_devname(cmd)) {
if (cmd->enable_devices_file &&
(device_ids_use_devname(cmd) || cmd->device_ids_refresh_trigger)) {
relax_deviceid_filter = 1;
cmd->filter_deviceid_skip = 1;
/* PVIDs read from devs matched to devices file below instead. */
log_debug("Skipping device_id filtering due to devname ids.");
log_debug("Skipping device_id filtering");
}
/*

View File

@ -23,6 +23,7 @@
#include "lib/metadata/segtype.h"
#include "lib/cache/lvmcache.h"
#include "lib/device/device-types.h"
#include "lib/device/device_id.h"
#include "lib/datastruct/str_list.h"
#include "lib/locking/lvmlockd.h"
@ -3571,6 +3572,9 @@ static int _pvdeviceid_disp(struct dm_report *rh, struct dm_pool *mem,
if (!pv->device_id)
return _field_set_value(field, "", NULL);
if (pv->dev && pv_device_id_is_stale(pv))
return _field_set_value(field, "invalid", NULL);
if (!(repstr = pv_deviceid_dup(mem, pv))) {
log_error("Failed to allocate buffer.");
return 0;
@ -3589,6 +3593,9 @@ static int _pvdeviceidtype_disp(struct dm_report *rh, struct dm_pool *mem,
if (!pv->device_id_type)
return _field_set_value(field, "", NULL);
if (pv->dev && pv_device_id_is_stale(pv))
return _field_set_value(field, "invalid", NULL);
if (!(repstr = pv_deviceidtype_dup(mem, pv))) {
log_error("Failed to allocate buffer.");
return 0;

View File

@ -28,13 +28,13 @@ will scan devices outside the devices file to locate PVs on renamed
devices. A config setting search_for_devnames can be used to control the
scanning for renamed devname entries.
.P
Related to the devices file, the new command option --devices <devnames>
Related to the devices file, the command option --devices <devnames>
allows a list of devices to be specified for the command to use,
overriding the devices file. The listed devices act as a sort of devices
file in terms of limiting which devices lvm will see and use. Devices
that are not listed will appear to be missing to the lvm command.
.P
Multiple devices files can be kept \fI#DEFAULT_SYS_DIR#/devices\fP, which
Multiple devices files can be kept in \fI#DEFAULT_SYS_DIR#/devices\fP, which
allows lvm to be used with different sets of devices. For example, system
devices do not need to be exposed to a specific application, and the
application can use lvm on its own devices that are not exposed to the
@ -70,12 +70,20 @@ Possible device ID types are:
.br
.IP \[bu] 2
.B sys_wwid
uses the wwid reported by sysfs. This is the first choice for non-virtual
devices.
uses the wwid reported by the wwid sysfs file. This is the first choice.
.IP \[bu] 2
.B wwid_naa
uses the naa wwid decoded from the vpd_pg83 sysfs file.
.IP \[bu] 2
.B wwid_eui
uses the eui wwid decoded from the vpd_pg83 sysfs file.
.IP \[bu] 2
.B wwid_t10
uses the t10 wwid decoded from the vpd_pg83 sysfs file.
.IP \[bu] 2
.B sys_serial
uses the serial number reported by sysfs. This is the second choice for
non-virtual devices.
uses the serial number reported by the serial sysfs file or the vpd_pg80
file. A serial number is used if no wwid is available.
.IP \[bu] 2
.B mpath_uuid
is used for dm multipath devices, reported by sysfs.
@ -95,8 +103,24 @@ is used for loop devices, the backing file name repored by sysfs.
.B devname
the device name is used if no other type applies.
.P
The default choice for device ID type can be overridden using lvmdevices
--addev --deviceidtype <type>. If the specified type is available for the
device it will be used, otherwise the device will be added using the type
that would otherwise be chosen.
.SS Device ID refresh
.P
A machine identifier is saved in the devices file, and is used to detect
when the devices file has been created by a different machine. If the
devices file was created by a different machine, it indicates that PVs may
have been copied or restored onto new devices on a new machine. In this
case, lvm will search for the PVs listed in system.devices on new devices.
If found, the device IDs will be updated in system.devices for the
existing PVIDs (assuming the original device IDs are also no longer
found.)
.P
The machine identifier used in system.devices will be either the DMI
product_uuid from /sys/devices/virtual/dmi/id/product_uuid, or the
hostname from uname(2). See lvm.conf device_ids_refresh_checks to
configure this.

View File

@ -481,7 +481,7 @@ not grep "$dev1" "$DF"
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
not ls "$RUNDIR/lvm/pvs_online/$PVID3"
check lv_field $vg1/$lv1 lv_active "active"
lvs -qq -o active $vg1/$lv1 | grep active
# pvs updates the DF
pvs |tee out
grep "$dev1" out

View File

@ -0,0 +1,532 @@
#!/usr/bin/env bash
# Copyright (C) 2020-23 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='refresh device ids if system changes'
SKIP_WITH_LVMPOLLD=1
. lib/inittest
test -d /sys/block/ram0 && skip "Ramdisk already loaded"
test "$DM_DEV_DIR" = "/dev" || skip "Only works with /dev access -> make check LVM_TEST_DEVDIR=/dev"
# requires trailing / to match dm
SYS_DIR="$PWD/test/sys"
aux lvmconf "devices/use_devicesfile = 1" \
"devices/device_id_sysfs_dir = \"$SYS_DIR/\""
aux lvmconf 'devices/global_filter = [ "a|.*|" ]'
SERIAL1="S111"
SERIAL2="S222"
SERIAL3="S333"
SERIAL4="S444"
PRODUCT_UUID1="11111111-2222-3333-4444-555555555555"
PRODUCT_UUID2="11111111-2222-3333-4444-666666666666"
create_sysfs() {
mkdir -p "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device"
mkdir -p "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device"
mkdir -p "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device"
mkdir -p "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device"
echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
echo "$SERIAL3" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
echo "$SERIAL4" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
mkdir -p "$SYS_DIR/devices/virtual/dmi/id/"
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
}
remove_sysfs() {
rm -rf "$SYS_DIR"
}
cleanup_and_teardown()
{
remove_sysfs
rmmod brd
aux teardown
}
trap 'cleanup_and_teardown' EXIT
modprobe brd rd_nr=4 || skip
sleep 1
remove_sysfs
dev1="/dev/ram0"
dev2="/dev/ram1"
dev3="/dev/ram2"
dev4="/dev/ram3"
DFDIR="$LVM_SYSTEM_DIR/devices"
mkdir -p "$DFDIR" || true
DF="$DFDIR/system.devices"
ORIG="$DFDIR/orig.devices"
touch "$DF"
aux wipefs_a "$dev1"
aux wipefs_a "$dev2"
aux wipefs_a "$dev3"
aux wipefs_a "$dev4"
vgcreate $vg1 "$dev1"
eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev1")"
MAJOR1=$LVM2_PV_MAJOR
MINOR1=$LVM2_PV_MINOR
OPVID1=$LVM2_PV_UUID
PVID1=${OPVID1//-/}
vgcreate $vg2 "$dev2"
eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev2")"
MAJOR2=$LVM2_PV_MAJOR
MINOR2=$LVM2_PV_MINOR
OPVID2=$LVM2_PV_UUID
PVID2=${OPVID2//-/}
# just using pvcreate/pvs to get MAJOR MINOR
pvcreate "$dev3"
eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev3")"
MAJOR3=$LVM2_PV_MAJOR
MINOR3=$LVM2_PV_MINOR
pvcreate "$dev4"
eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev4")"
MAJOR4=$LVM2_PV_MAJOR
MINOR4=$LVM2_PV_MINOR
pvremove "$dev3"
pvremove "$dev4"
aux wipefs_a "$dev3"
aux wipefs_a "$dev4"
create_sysfs
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
cat "$DF"
grep $PRODUCT_UUID1 "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
pvs |tee out
grep "$dev1" out
grep "$dev2" out
not grep "$dev3" out
not grep "$dev4" out
# Prints the deviceid that's saved in metadata.
pvs -o uuid,deviceid "$dev1" | tee out
grep $OPVID1 out
grep $SERIAL1 out
# PV1 moves from dev1 to dev3 (and dev1 goes away)
# lvm does not find PV1 until the product_uuid changes which
# triggers the command to look at devs outside the DF.
# PV1 moves to new dev
dd if="$dev1" of="$dev3" bs=1M count=1
aux wipefs_a "$dev1"
rm "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
# PV1 not found
pvs |tee out
not grep "$dev1" out
grep "$dev2" out
not grep "$dev3" out
not grep "$dev4" out
# DF unchanged
grep $PRODUCT_UUID1 "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# product_uuid changes
echo "$PRODUCT_UUID2" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
# PV1 found on new dev
pvs |tee out
not grep "$dev1" out
grep "$dev2" out
grep "$dev3" out
not grep "$dev4" out
# DF updated replacing old dev with new dev
grep $PRODUCT_UUID2 "$DF"
not grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep "$dev3" "$DF"
not grep "$dev4" "$DF"
not grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# PV1 was originally written to dev1 but has not
# moved to dev3. The deviceid in the metadata is
# S111 from dev1, but the PV is now on dev3 which
# has deviceid S333. Since the deviceid of the dev
# doesn't match the deviceid savedin metadata,
# "invalid" is printed when displaying the outdated
# deviceid from the metadata.
pvs -o uuid,deviceid "$dev3" | tee out
grep $OPVID1 out
grep invalid out
# bring back dev1
echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
# No product_uuid so hostname is used
rm "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
grep HOSTNAME "$DF"
not grep PRODUCT_UUID "$DF"
pvs |tee out
not grep "$dev1" out
grep "$dev2" out
grep "$dev3" out
not grep "$dev4" out
not grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep "$dev3" "$DF"
not grep "$dev4" "$DF"
# PV1 moves from dev3 back to dev1
# lvm does not find PV1 until the hostname changes which
# triggers the command to look at devs outside the DF.
# PV1 moves to new dev
dd if="$dev3" of="$dev1" bs=1M count=1
aux wipefs_a "$dev3"
rm "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
# PV1 not found
pvs |tee out
not grep "$dev1" out
grep "$dev2" out
not grep "$dev3" out
not grep "$dev4" out
# we can't change the hostname to trigger lvm refresh,
# but removing the HOSTNAME line from system.devices
# will be a trigger.
sed -e "s|HOSTNAME=.||" "$DF" > tmpdf
cp tmpdf "$DF"
# PV1 found on new dev
pvs |tee out
grep "$dev1" out
grep "$dev2" out
not grep "$dev3" out
not grep "$dev4" out
# DF updated replacing old dev with new dev
not grep PRODUCT_UUID "$DF"
grep HOSTNAME "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# bring back dev3
echo "$SERIAL3" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
# DF has no PRODUCT_UUID or HOSTNAME, lvm command adds one
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
sed -e "s|HOSTNAME=.||" "$DF" > tmpdf
cp tmpdf "$DF"
sed -e "s|PRODUCT_UUID=.||" "$DF" > tmpdf
cp tmpdf "$DF"
not grep HOSTNAME "$DF"
not grep PRODUCT_UUID "$DF"
pvs
grep HOSTNAME "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# DF has PRODUCT_UUID but system only has hostname,
# and PV1 moves to different device
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
rm "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
# PV1 moves from dev1 to dev3
dd if="$dev1" of="$dev3" bs=1M count=1
aux wipefs_a "$dev1"
rm "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
pvs
grep HOSTNAME "$DF"
not grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep "$dev3" "$DF"
not grep "$dev4" "$DF"
not grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# bring back dev1
echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
# DF has HOSTNAME but system has product_uuid, lvm command updates it
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
grep HOSTNAME "$DF"
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
pvs
grep "$PRODUCT_UUID1" "$DF"
not grep HOSTNAME "$DF"
# DF has PRODUCT_UUID, system product_uuid changes, lvm command upates it
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
grep "$PRODUCT_UUID1" "$DF"
echo "$PRODUCT_UUID2" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
pvs
grep "$PRODUCT_UUID2" "$DF"
# PV1 moves from dev3 back to dev1
dd if="$dev3" of="$dev1" bs=1M count=1
aux wipefs_a "$dev3"
#
# pvscan --cache and vgchange -aay work when refresh is triggered and
# the device ids are wrong on the PVs that need to be autoactivated.
#
RUNDIR="/run"
test -d "$RUNDIR" || RUNDIR="/var/run"
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
_clear_online_files() {
# wait till udev is finished
aux udev_wait
rm -f "$PVS_ONLINE_DIR"/*
rm -f "$VGS_ONLINE_DIR"/*
rm -f "$PVS_LOOKUP_DIR"/*
}
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
rm "$DF"
vgimportdevices $vg1
vgimportdevices $vg2
grep "$PRODUCT_UUID1" "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
lvcreate -l1 -an -n $lv1 $vg1
lvcreate -l1 -an -n $lv1 $vg2
pvs -o+deviceid
# PV1 moves from dev1 to dev3
dd if="$dev1" of="$dev3" bs=1M count=1
aux wipefs_a "$dev1"
rm "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
_clear_online_files
# One PV in VG to autoactivate when system.devices has the wrong device ID
# PV1 is listed in system.devices as being from dev1 with SERIAL1,
# but PV1 is actually appearing from dev3 with SERIAL3. PRODUCT_UUID is
# wrong, so refresh is triggered and PV1 will be used from dev3.
echo "$PRODUCT_UUID2" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event "$dev3"
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/vgs_online/$vg1"
vgchange -aay --autoactivation event $vg1
# DF should be unchanged and have old info since the event based pvscan
# and vgchange are special/optimized for auto activation and don't update DF
grep "$PRODUCT_UUID1" "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# check that pvs will update DF PV1 to have SERIAL3
pvs
grep "$PRODUCT_UUID2" "$DF"
not grep "$dev1" "$DF"
grep "$dev2" "$DF"
grep "$dev3" "$DF"
not grep "$dev4" "$DF"
not grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# check that the vgchange aay above actually activated the LV
lvs -o active $vg1/$lv1 | grep active
vgchange -an $vg1
# bring back dev1
echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
# Two PVs in VG to autoactivate when system.devices has the wrong device ID
# PV1 moves from dev3 back to dev1
dd if="$dev3" of="$dev1" bs=1M count=1
aux wipefs_a "$dev3"
rm "$DF"
vgremove -ff $vg1
vgremove -ff $vg2
pvs
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
vgcreate $vg1 "$dev1" "$dev2"
vgimportdevices $vg1
lvcreate -l1 -n $lv1 $vg1 "$dev1"
lvcreate -l1 -n $lv2 $vg1 "$dev2"
lvcreate -l4 -i2 -n $lv3 $vg1 "$dev1" "$dev2"
vgchange -an $vg1
grep "$PRODUCT_UUID1" "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# PV1 moves from dev1 to dev3
dd if="$dev1" of="$dev3" bs=1M count=1
aux wipefs_a "$dev1"
rm "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
# PV2 moves from dev2 to dev4
dd if="$dev2" of="$dev4" bs=1M count=1
aux wipefs_a "$dev2"
rm "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
_clear_online_files
# Two PVs in VG to autoactivate when system.devices has the wrong device ID
# system.devices says PV1 has SERIAL1 and PV2 has SERIAL2, but the new
# system has PV1 on SERIAL3 and PV2 on SERIAL4.
# PRODUCT_UUID is wrong, so refresh finds PV1/PV2 on SERIAL3/SERIAL4
echo "$PRODUCT_UUID2" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event "$dev3"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event "$dev4"
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/vgs_online/$vg1"
ls "$RUNDIR/lvm/pvs_lookup/$vg1"
vgchange -aay --autoactivation event $vg1
# DF not yet updated by pvscan/vgchange
grep "$PRODUCT_UUID1" "$DF"
grep "$dev1" "$DF"
grep "$dev2" "$DF"
not grep "$dev3" "$DF"
not grep "$dev4" "$DF"
grep $SERIAL1 "$DF"
grep $SERIAL2 "$DF"
not grep $SERIAL3 "$DF"
not grep $SERIAL4 "$DF"
# check that lvmdevices will update DF
lvmdevices --update
grep "$PRODUCT_UUID2" "$DF"
not grep "$dev1" "$DF"
not grep "$dev2" "$DF"
grep "$dev3" "$DF"
grep "$dev4" "$DF"
not grep $SERIAL1 "$DF"
not grep $SERIAL2 "$DF"
grep $SERIAL3 "$DF"
grep $SERIAL4 "$DF"
# check that the vgchange actually activated LVs
lvs $vg1
lvs -o active $vg1/$lv1 | grep active
lvs -o active $vg1/$lv2 | grep active
lvs -o active $vg1/$lv3 | grep active
vgchange -an $vg1
vgremove -ff $vg1

View File

@ -81,11 +81,16 @@ wipe_all() {
wait_lvm_activate() {
local vgw=$1
local wait=0
rm status || true
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
# time for service to be started
sleep 1
while systemctl status lvm-activate-$vgw |tee status && test "$wait" -le 30; do
sleep .2
wait=$(( wait + 1 ))
done
cat status || true
}
# Test requires 3 devs
@ -179,10 +184,12 @@ udevadm trigger -c add "/sys/block/$BDEV3"
aux udev_wait
wait_lvm_activate $vg3
find "$RUNDIR/lvm"
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg3"
journalctl -u lvm-activate-$vg3 | tee out || true
grep "now active" out
check lv_field $vg3/$lv1 lv_active "active"
@ -455,3 +462,80 @@ check lv_field $vg10/$lv1 lv_active "active"
vgchange -an $vg10
vgremove -y $vg10
wipe_all
aux lvmconf 'devices/filter = [ "a|.*|" ]'
aux lvmconf 'devices/global_filter = [ "a|.*|" ]'
#
# system.devices contains different product_uuid and incorrect device IDs
#
SYS_DIR="$PWD/test/sys"
aux lvmconf "devices/use_devicesfile = 1" \
"devices/device_id_sysfs_dir = \"$SYS_DIR/\""
WWID1="naa.111"
WWID2="naa.222"
PRODUCT_UUID1="11111111-2222-3333-4444-555555555555"
PRODUCT_UUID2="11111111-2222-3333-4444-666666666666"
vgcreate $vg11 "$dev1"
lvcreate -l1 -an -n $lv1 $vg11 "$dev1"
eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev1")"
MAJOR1=$LVM2_PV_MAJOR
MINOR1=$LVM2_PV_MINOR
OPVID1=$LVM2_PV_UUID
PVID1=${OPVID1//-/}
mkdir -p "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device"
echo "$WWID1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid"
mkdir -p "$SYS_DIR/devices/virtual/dmi/id/"
echo "$PRODUCT_UUID1" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
vgimportdevices $vg11
grep $PRODUCT_UUID1 "$DF"
grep $PVID1 "$DF"
grep $WWID1 "$DF"
grep "$dev1" "$DF"
# change wwid for dev1 and product_uuid for host
echo "$WWID2" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid"
echo "$PRODUCT_UUID2" > "$SYS_DIR/devices/virtual/dmi/id/product_uuid"
_clear_online_files
udevadm trigger --settle -c add "/sys/block/$BDEV1"
wait_lvm_activate $vg11
ls "$RUNDIR/lvm/vgs_online/$vg11"
journalctl -u lvm-activate-$vg11 | tee out || true
grep "now active" out
# Run ordinary command that will refresh device ID in system.devices
pvs -o+uuid | tee out
grep "$dev1" out
grep "$OPVID1" out
# check new wwid for dev1 and new product_uuid for host
cat "$DF"
grep $PRODUCT_UUID2 "$DF"
not grep $PRODUCT_UUID1 "$DF"
grep $PVID1 "$DF"
grep $WWID2 "$DF"
not grep $WWID1 "$DF"
grep "$dev1" "$DF"
check lv_field $vg11/$lv1 lv_active "active"
vgchange -an $vg11
vgremove -y $vg11
rm -rf "$SYS_DIR"
wipe_all

View File

@ -283,7 +283,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
* Find and fix any devname entries that have moved to a
* renamed device.
*/
device_ids_find_renamed_devs(cmd, &found_devs, &search_count, 1);
device_ids_refresh(cmd, &found_devs, &search_count, 1);
if (search_count && !strcmp(cmd->search_for_devnames, "none"))
log_print("Not searching for missing devnames, search_for_devnames=\"none\".");

View File

@ -1441,18 +1441,20 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
* If a match fails here do not exclude it, that will be done below by
* passes_filter() which runs filter-deviceid. The
* relax_deviceid_filter case needs to be able to work around
* unmatching devs.
* unmatching devs, or unmatching product_uuid/hostname which means
* we can ignore the device ID and use any device with a PVID listed
* in system.devices.
*/
if (cmd->enable_devices_file) {
dm_list_iterate_items(devl, &pvscan_devs)
device_ids_match_dev(cmd, devl->dev);
}
if (cmd->enable_devices_list)
device_ids_match_device_list(cmd);
if (cmd->enable_devices_file && device_ids_use_devname(cmd)) {
if (cmd->enable_devices_file &&
(device_ids_use_devname(cmd) || cmd->device_ids_refresh_trigger)) {
relax_deviceid_filter = 1;
cmd->filter_deviceid_skip = 1;
}