1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-18 10:04:20 +03:00

lvmdevices: new output and options for check and update

- add new comparison between old and new entries, and use this
  as the basis for new dedicated output for check and update
- add new --refresh option to search for missing PVIDs on all
  devices, and possibly update the device ID
- internally, only use the term "refresh" for cases where a
  new device ID may be found and assigned for a missing PVID
This commit is contained in:
David Teigland 2023-10-27 17:39:32 -05:00
parent a5628cf782
commit 37773c1055
8 changed files with 681 additions and 84 deletions

14
lib/cache/lvmcache.c vendored
View File

@ -1643,7 +1643,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
* need to be scanned to find the new device for the PVIDs.
* device_ids_validate() will update the devices file to correct
* some info, but to locate new devices for PVIDs, it defers
* to device_ids_refresh() which involves label scanning.
* to device_ids_search() which involves label scanning.
*
* device_ids_refresh_trigger is set by device_ids_read() when
* it sees that the local machine doesn't match the machine
@ -1652,17 +1652,17 @@ int lvmcache_label_scan(struct cmd_context *cmd)
* This also means that all devs on the system need to be
* scanned to find the new devices for the PVIDs.
*
* When device_ids_refresh() locates the correct devices
* When device_ids_search() locates the correct devices
* for the PVs in the devices file, it returns those new
* devices in the refresh_devs list. Those devs need to
* be passed to label_scan to populate lvmcache info.
*/
if (cmd->device_ids_invalid || cmd->device_ids_refresh_trigger) {
struct dm_list refresh_devs;
dm_list_init(&refresh_devs);
device_ids_refresh(cmd, &refresh_devs, NULL, 0, NULL);
if (!dm_list_empty(&refresh_devs))
label_scan_devs(cmd, cmd->filter, &refresh_devs);
struct dm_list new_devs;
dm_list_init(&new_devs);
device_ids_search(cmd, &new_devs, 0, 0, NULL);
if (!dm_list_empty(&new_devs))
label_scan_devs(cmd, cmd->filter, &new_devs);
}
/*

View File

@ -2277,7 +2277,7 @@ void device_ids_match(struct cmd_context *cmd)
/*
* Next match entries with IDTYPE=devname, which is only
* based on matching devname, so somewhat likely to be wrong
* and need correcting in device_ids_validate/device_ids_refresh.
* and need correcting in device_ids_validate/device_ids_search.
*/
dm_list_iterate_items(du, &cmd->use_devices) {
@ -2386,7 +2386,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_refresh */
/* just copying the no-data filters in similar device_ids_search */
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
@ -2705,7 +2705,7 @@ 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_refresh which will look for unmatched pvids on
* subject to device_ids_search which will look for unmatched pvids on
* devs that have not been scanned yet.
*/
dm_list_iterate_items(du, &cmd->use_devices) {
@ -2818,7 +2818,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
* Set invalid if an entry using IDNAME=devname has not
* been matched to a device. It's possible that the device
* with the PVID has a new name, different from the IDNAME
* value. device_ids_refresh needs to search system devs
* value. device_ids_search needs to search system devs
* for the PVID. The same applies when the IDNAME field
* has no value.
*/
@ -2851,7 +2851,7 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
if (update_file && update_needed)
*update_needed = 1;
/* FIXME: for wrong devname cases, wait to write new until device_ids_refresh? */
/* FIXME: for wrong devname cases, wait to write new until device_ids_search? */
/*
* try lock and device_ids_write(), the update is not required and will
@ -3180,8 +3180,8 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
* is using a non-system devices file?
*/
void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
int *search_count, int noupdate, int *update_needed)
void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
int all_ids, int noupdate, int *update_needed)
{
struct device *dev;
struct dev_use *du;
@ -3193,9 +3193,6 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
struct dm_list search_list_devs ; /* list of device_list */
const char *devname;
int update_file = 0;
int other_idtype = 0;
int other_pvid = 0;
int no_pvid = 0;
int found = 0;
int not_found = 0;
int search_mode_none;
@ -3208,7 +3205,24 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
if (!cmd->enable_devices_file)
return;
if (cmd->device_ids_refresh_trigger) {
/*
* When the product_uuid/hostname change (refresh_trigger is set), or
* when --refresh is included with lvmdevices --check|--update (all_ids
* is set), this function expands from correcting renamed IDTYPE=devname
* entries to looking for missing PVIDs with any IDTYPE, and assigning new
* IDTYPE/IDNAME values for a PVID entry if it's found elsewhere.
* (e.g. a PVID that has moved to a device with a new wwid.) We require
* the --refresh option with update|check because otherwise a PVID may
* be picked up from an old cloned/snapshotted device, and lvm would
* begin using that old clone rather than the actual PV.
*
* Note: refresh_trigger=1 means that product_uuid/hostname has changed,
* which means that the devices file should be updated with that new
* value, even if no device ids need updates themselves.
* With --refresh (all_ids=1), an update may not be needed at all.
*/
if (cmd->device_ids_refresh_trigger || all_ids) {
search_mode_all = 1;
search_mode_none = 0;
search_mode_auto = 0;
@ -3229,21 +3243,18 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
continue;
/*
* 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.
* When device_ids_refresh_trigger/all_ids is set, it means
* that a PVID may be relocated to a new device, even when the
* entry and/or device have a stable id type, like wwid.
* Ordinarily, we assume that only entries using the devname
* id type will need to be located on new devices.
*/
if (!cmd->device_ids_refresh_trigger &&
if (!cmd->device_ids_refresh_trigger && !all_ids &&
(du->idtype != DEV_ID_TYPE_DEVNAME))
continue;
log_debug("Search for PVID %s.", du->pvid);
if (search_count)
(*search_count)++;
if (search_mode_none)
continue;
@ -3257,8 +3268,8 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
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,
log_debug("Search for PVIDs %d trigger %d all_ids %d search all %d auto %d none %d",
dm_list_size(&search_list_pvids), cmd->device_ids_refresh_trigger, all_ids,
search_mode_all, search_mode_auto, search_mode_none);
if (dm_list_empty(&search_list_pvids) && cmd->device_ids_refresh_trigger) {
@ -3281,7 +3292,7 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
* If hints are enabled, the hints invalidation could also remove the
* searched file.
*/
if (!cmd->device_ids_refresh_trigger && _searched_devnames_exists(cmd)) {
if (!cmd->device_ids_refresh_trigger && !all_ids && _searched_devnames_exists(cmd)) {
log_debug("Search for PVIDs skipped for %s", _searched_file);
return;
}
@ -3333,12 +3344,12 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
dev = devl->dev;
/*
* We only need to check devs that would use ID_TYPE_DEVNAME
* 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_list_devs list has a proper/stable device
* id (e.g. wwid, serial, loop, mpath), then we don't need to
* As an optimization for locating new devs for IDTYPE=devname
* entries, we can just check devs that would also use
* ID_TYPE_DEVNAME themselves. i.e. a ID_TYPE_DEVNAME entry
* would not appear on a device that has a wwid. So, if a
* dev in search_list_devs 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.
*
* search_for_devnames="all" means we should search every
@ -3355,7 +3366,6 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
*/
if (search_mode_auto && _dev_has_stable_id(cmd, dev)) {
log_debug("Search for PVIDs skip %s (stable id)", dev_name(dev));
other_idtype++;
continue;
}
@ -3368,15 +3378,11 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
* Sets has_pvid=1 if the dev has an lvm PVID.
* This loop may look at and skip many non-LVM devices.
*/
if (!label_read_pvid(dev, &has_pvid)) {
no_pvid++;
if (!label_read_pvid(dev, &has_pvid))
continue;
}
if (!has_pvid) {
no_pvid++;
if (!has_pvid)
continue;
}
/*
* These filters will use the block of data from bcache that
@ -3407,19 +3413,15 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
log_warn("WARNING: use lvmdevices to select a device for PVID %s.", dil->pvid);
dm_list_del(&dil->list);
} else {
log_debug("Devices file PVID %s found on %s.", dil->pvid, dev_name(dev));
log_debug("Search for PVID %s found on %s.", dil->pvid, dev_name(dev));
dil->dev = dev;
}
} else {
other_pvid++;
}
}
next:
label_scan_invalidate(dev);
}
log_debug("Search for PVIDs other_pvid %d no_pvid %d other_idtype %d.", other_pvid, no_pvid, other_idtype);
/*
* The use_devices entries (repesenting the devices file) are
* updated for the new devices on which the PVs reside. The new
@ -3453,7 +3455,7 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
new_idname2 = NULL;
new_devname = NULL;
if (cmd->device_ids_refresh_trigger) {
if (cmd->device_ids_refresh_trigger || all_ids) {
if (!device_id_system_read_preferred(cmd, dev, &new_idtype, (const char **)&new_idname))
continue;
new_idname2 = strdup(new_idname);
@ -3548,7 +3550,7 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
continue;
devl->dev = dev;
dm_list_add(refresh_devs, &devl->list);
dm_list_add(new_devs, &devl->list);
}
/*
@ -3556,7 +3558,7 @@ void device_ids_refresh(struct cmd_context *cmd, struct dm_list *refresh_devs,
* pvids not found were from devices that are permanently detached.
* If a new PV appears, pvscan will run and do unlink_searched_file.
*/
if (!cmd->device_ids_refresh_trigger && not_found && !found)
if (!cmd->device_ids_refresh_trigger && !all_ids && not_found && !found)
_touch_searched_devnames(cmd);
}

View File

@ -37,8 +37,8 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
int noupdate, int *update_needed);
void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
int noupdate, int *update_needed);
void device_ids_refresh(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count,
int noupdate, int *update_needed);
void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
int all_ids, int noupdate, int *update_needed);
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);
int device_ids_version_unchanged(struct cmd_context *cmd);

View File

@ -222,6 +222,227 @@ not grep "$WWID1" out
grep "IDNAME=$dev3" out
grep "DEVNAME=$dev3" out
#
# lvmdevices --check|--update
#
DEVNAME_NONE=/dev/sdxyz
PVID_NONE=aaaaaa
WWID_NONE=naa.56789
rm $DF
lvmdevices --adddev "$dev1"
lvmdevices --adddev "$dev2"
lvmdevices --adddev "$dev3"
lvmdevices --adddev "$dev4"
cat $DF
cp "$DF" orig
# 1. lvmdevices --check|--update : devs with wwid
# 1.a change pvid and devname
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > tmp1
sed -e "s|PVID=$PVID1|PVID=$PVID_NONE|" tmp1 > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID1 out
grep DEVNAME=$dev1 out
grep "old $DEVNAME_NONE" out
grep "old $PVID_NONE" out
lvmdevices --update
grep PVID=$PVID1 "$DF" |tee out
grep DEVNAME=$dev1 out
lvmdevices --check
# 1.b change devname
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID1 out
grep DEVNAME=$dev1 out
grep "old $DEVNAME_NONE" out
lvmdevices --update
grep PVID=$PVID1 "$DF" |tee out
grep DEVNAME=$dev1 out
lvmdevices --check
# 1.c change pvid
sed -e "s|PVID=$PVID1|PVID=$PVID_NONE|" orig > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID1 out
grep DEVNAME=$dev1 out
grep "old $PVID_NONE" out
lvmdevices --update
grep PVID=$PVID1 "$DF" |tee out
grep DEVNAME=$dev1 out
lvmdevices --check
# 2. lvmdevices --check|--update : devs with only devname
# 2.a change idname and devname
sed -e "s|IDNAME=$dev3|IDNAME=$DEVNAME_NONE|" orig > tmp1
sed -e "s|DEVNAME=$dev3|DEVNAME=$DEVNAME_NONE|" tmp1 > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID3 out |tee out1
grep IDNAME=$dev3 out1
grep DEVNAME=$dev3 out1
grep "old $DEVNAME_NONE" out1
lvmdevices --update
grep PVID=$PVID3 "$DF" |tee out
grep IDNAME=$dev3 out
grep DEVNAME=$dev3 out
lvmdevices --check
# 2.b change devname
sed -e "s|DEVNAME=$dev3|DEVNAME=$DEVNAME_NONE|" orig > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID3 out |tee out1
grep IDNAME=$dev3 out1
grep DEVNAME=$dev3 out1
grep "old $DEVNAME_NONE" out1
lvmdevices --update
grep PVID=$PVID3 "$DF" |tee out
grep IDNAME=$dev3 out
grep DEVNAME=$dev3 out
lvmdevices --check
# 2.c change idname
sed -e "s|IDNAME=$dev3|IDNAME=$DEVNAME_NONE|" orig > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID3 out |tee out1
grep IDNAME=$dev3 out1
grep DEVNAME=$dev3 out1
grep "old $DEVNAME_NONE" out1
lvmdevices --update
grep PVID=$PVID3 "$DF" |tee out
grep IDNAME=$dev3 out
grep DEVNAME=$dev3 out
lvmdevices --check
# 3. lvmdevices --check|--update --refresh devs with IDTYPE=sys_wwid
# 3.a.i change idtype and idname and devname (wwid to serial)
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > tmp1
sed -e "s|IDTYPE=sys_wwid IDNAME=$WWID1|IDTYPE=sys_serial IDNAME=S123|" tmp1 > "$DF"
cat "$DF"
# this command succeeds since no update is detected, the dev is simply not found
lvmdevices --check |tee out
grep 'device not found' out
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
grep "old sys_serial" out1
grep "old S123" out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
# 3.a.ii change idtype and idname and devname (wwid to devname)
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > tmp1
sed -e "s|IDTYPE=sys_wwid IDNAME=$WWID1|IDTYPE=devname IDNAME=$DEVNAME_NONE|" tmp1 > "$DF"
cat "$DF"
# the command without --refresh thinks the update should be just to the devname
not lvmdevices --check |tee out
grep PVID=$PVID1 out | tee out1
grep DEVNAME=$dev1 out1
grep IDNAME=$dev1 out1
grep IDTYPE=devname out1
# the command with --refresh sees the update should use sys_wwid
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out | tee out1
grep DEVNAME=$dev1 out1
grep IDNAME=$WWID1 out1
grep IDTYPE=sys_wwid out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
# 3.b change idtype and idname
sed -e "s|IDTYPE=sys_wwid IDNAME=$WWID1|IDTYPE=sys_serial IDNAME=S123|" orig > "$DF"
cat "$DF"
# this command succeeds since no update is detected, the dev is simply not found
lvmdevices --check |tee out
grep 'device not found' out
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
grep "old sys_serial" out1
grep "old S123" out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
# 3.c change idname and devname
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > tmp1
sed -e "s|IDNAME=$WWID1|IDNAME=$WWID_NONE|" tmp1 > "$DF"
cat "$DF"
# this command succeeds since no update is detected, the dev is simply not found
lvmdevices --check |tee out
grep 'device not found' out
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
grep "old $WWID_NONE" out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
# 3.d change idname
sed -e "s|IDNAME=$WWID1|IDNAME=$WWID_NONE|" orig > "$DF"
cat "$DF"
# this command succeeds since no update is detected, the dev is simply not found
lvmdevices --check |tee out
grep 'device not found' out
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
grep "old $WWID_NONE" out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
# 3.e change devname
sed -e "s|DEVNAME=$dev1|DEVNAME=$DEVNAME_NONE|" orig > "$DF"
cat "$DF"
not lvmdevices --check |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep "old $DEVNAME_NONE" out1
not lvmdevices --check --refresh |tee out
grep PVID=$PVID1 out |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --update --refresh
grep PVID=$PVID1 "$DF" |tee out1
grep DEVNAME=$dev1 out1
grep IDTYPE=sys_wwid out1
grep IDNAME=$WWID1 out1
lvmdevices --check
vgchange -an $vg1
lvremove -y $vg1

View File

@ -466,11 +466,10 @@ grep $did1 $DF
rm $DF
sed "s/$did1/baddid/" "$DF.orig" |tee $DF
# FIXME: lvmdevices --check needs fixed output
#lvmdevices --check 2>&1|tee out
#grep $dev1 out
#grep baddid out
#not grep $dev2 out
lvmdevices --check 2>&1|tee out
grep $dev1 out
grep baddid out
not grep $dev2 out
lvmdevices 2>&1|tee out
grep $pvid1 out
@ -499,8 +498,7 @@ d1=$(basename $dev1)
d3=$(basename $dev3)
sed "s/$d1/$d3/" "$DF.orig" |tee $DF
not lvmdevices --check 2>&1 |tee out
# FIXME: define fixed check output
#grep $dev1 out
grep $dev1 out
lvmdevices --update
@ -522,9 +520,8 @@ sed "s/$d2/$d1/" "${DF}_1" |tee ${DF}_2
sed "s/tmp/$d2/" "${DF}_2" |tee $DF
rm ${DF}_1 ${DF}_2
not lvmdevices --check 2>&1 |tee out
# FIXME: define fixed check output
#grep $dev1 out
#grep $dev2 out
grep $dev1 out
grep $dev2 out
lvmdevices --update
@ -544,8 +541,7 @@ d1=$(basename $dev1)
d3=$(basename $dev3)
sed "s/$d1/$d3/" "$DF.orig" |tee $DF
not lvmdevices --check 2>&1 |tee out
# FIXME: define fixed check output
#grep $dev1 out
grep $dev1 out
pvs -o+uuid,deviceid | grep $vg |tee out
grep $dev1 out |tee out1

View File

@ -668,6 +668,19 @@ arg(readonly_ARG, '\0', "readonly", 0, 0, 0,
"or not LVs are actually in use.\n")
arg(refresh_ARG, '\0', "refresh", 0, 0, 0,
"#lvmdevices\n"
"Search for missing PVs on new devices, and update the devices file\n"
"with new device IDs for the PVs if they are found on new devices.\n"
"This is useful if PVs have been moved to new devices with new WWIDs,\n"
"for example. The device ID type and name may both change for a PV.\n"
"WARNING: if a PV is detached from the system, but a device containing a\n"
"clone or snapshot of that PV is present, then refresh would replace the\n"
"correct device ID with the clone/snapshot device ID, and lvm would begin\n"
"using the wrong device for the PV. Use deldev/adddev to safely change\n"
"a PV device ID in this scenario.\n"
"#vgchange\n"
"#lvchange\n"
"#vgmknodes\n"
"If the LV is active, reload its metadata.\n"
"This is not necessary in normal operation, but may be useful\n"
"if something has gone wrong, or if some form of manual LV\n"

View File

@ -1448,10 +1448,11 @@ DESC: Print devices in the devices file.
lvmdevices --check
ID: lvmdevices_check
OO: --refresh
DESC: Check the devices file and report incorrect values.
lvmdevices --update
OO: --delnotfound
OO: --delnotfound, --refresh
ID: lvmdevices_update
DESC: Update the devices file to fix incorrect values.

View File

@ -120,6 +120,361 @@ static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *sear
}
}
static char *_part_str(struct dev_use *du)
{
static char _part_str_buf[64];
if (du->part)
snprintf(_part_str_buf, 63, " PART=%d", du->part);
else
_part_str_buf[0] = '\0';
return _part_str_buf;
}
static void _print_check(struct cmd_context *cmd)
{
struct dm_list use_old;
struct dm_list use_new;
struct dm_list done_old;
struct dm_list done_new;
struct dev_use *du_old, *du_new;
int pvid_same;
int idname_same;
int idtype_same;
int devname_same;
char *part;
dm_list_init(&use_old);
dm_list_init(&use_new);
dm_list_init(&done_old);
dm_list_init(&done_new);
dm_list_splice(&use_new, &cmd->use_devices);
device_ids_read(cmd);
dm_list_splice(&use_old, &cmd->use_devices);
dm_list_init(&cmd->use_devices);
/*
* Check entries with proper id types.
*/
restart1:
dm_list_iterate_items(du_old, &use_old) {
if (du_old->idtype == DEV_ID_TYPE_DEVNAME)
continue;
dm_list_iterate_items(du_new, &use_new) {
if (du_new->idtype == DEV_ID_TYPE_DEVNAME)
continue;
if (du_old->idtype != du_new->idtype)
continue;
if (!du_old->idname || !du_new->idname)
continue;
if (du_old->part != du_new->part)
continue;
if (!strcmp(du_old->idname, du_new->idname)) {
part = _part_str(du_old);
/*
* Old and new entries match based on device id.
* Possible differences between old and new:
* DEVNAME mismatch can be common.
* PVID mismatch is not common, but can
* happen from something like dd of one
* PV to another.
*/
if (!du_new->dev) {
/* We can't know the new pvid and devname without a device. */
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: device not found",
idtype_to_str(du_old->idtype),
du_old->idname,
du_old->devname ?: "none",
du_old->pvid ?: "none",
part);
goto next1;
}
pvid_same = (du_old->pvid && du_new->pvid && !strcmp(du_old->pvid, du_new->pvid));
devname_same = (du_old->devname && du_new->devname && !strcmp(du_old->devname, du_new->devname));
if (pvid_same && devname_same) {
log_verbose("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: no change",
idtype_to_str(du_new->idtype),
du_new->idname,
du_new->devname ?: "none",
du_new->pvid ?: "none",
part);
} else if (!pvid_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s (old %s) PVID=%s (old %s)%s: update",
idtype_to_str(du_new->idtype),
du_new->idname,
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid ?: "none",
du_old->pvid ?: "none",
part);
} else if (pvid_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname,
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid ?: "none",
part);
} else if (!pvid_same && devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s (old %s)%s: update",
idtype_to_str(du_new->idtype),
du_new->idname,
du_new->devname ?: "none",
du_new->pvid ?: "none",
du_old->pvid ?: "none",
part);
}
next1:
dm_list_del(&du_old->list);
dm_list_del(&du_new->list);
dm_list_add(&done_old, &du_old->list);
dm_list_add(&done_new, &du_new->list);
goto restart1;
}
}
}
/*
* Check entries with devname id type.
*/
restart2:
dm_list_iterate_items(du_old, &use_old) {
if (du_old->idtype != DEV_ID_TYPE_DEVNAME)
continue;
dm_list_iterate_items(du_new, &use_new) {
if (du_new->idtype != DEV_ID_TYPE_DEVNAME)
continue;
if (!du_old->pvid || !du_new->pvid)
continue;
if (du_old->part != du_new->part)
continue;
if (!memcmp(du_old->pvid, du_new->pvid, strlen(du_old->pvid))) {
part = _part_str(du_old);
/*
* Old and new entries match based on PVID.
* IDNAME and DEVNAME might not match.
*/
if (!du_new->dev) {
/* We can't know the new idname and devname without a device. */
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: device not found",
idtype_to_str(du_old->idtype),
du_old->idname ?: "none",
du_old->devname ?: "none",
du_old->pvid,
part);
goto next2;
}
idname_same = (du_old->idname && du_new->idname && !strcmp(du_old->idname, du_new->idname));
devname_same = (du_old->devname && du_new->devname && !strcmp(du_old->devname, du_new->devname));
if (idname_same && devname_same) {
log_verbose("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: no change",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
} else if (!idname_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s (old %s) DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
} else if (idname_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
} else if (!idname_same && devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s (old %s) DEVNAME=%s PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
}
next2:
dm_list_del(&du_old->list);
dm_list_del(&du_new->list);
dm_list_add(&done_old, &du_old->list);
dm_list_add(&done_new, &du_new->list);
goto restart2;
}
}
}
/*
* Check entries with new IDTYPE (refresh can do this)
* Compare PVIDs.
*/
restart3:
dm_list_iterate_items(du_old, &use_old) {
dm_list_iterate_items(du_new, &use_new) {
if (!du_old->pvid || !du_new->pvid)
continue;
if (du_old->part != du_new->part)
continue;
if (!memcmp(du_old->pvid, du_new->pvid, strlen(du_old->pvid))) {
part = _part_str(du_old);
/*
* Old and new entries match based on PVID.
* IDTYPE, IDNAME, DEVNAME might not match.
*/
if (!du_new->dev) {
/* could this happen? */
log_print_unless_silent("IDTYPE=%s (%s) IDNAME=%s (%s) DEVNAME=%s (%s) PVID=%s%s: device not found",
idtype_to_str(du_new->idtype),
idtype_to_str(du_old->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
goto next3;
}
idtype_same = (du_old->idtype == du_new->idtype);
idname_same = (du_old->idname && du_new->idname && !strcmp(du_old->idname, du_new->idname));
devname_same = (du_old->devname && du_new->devname && !strcmp(du_old->devname, du_new->devname));
if (idtype_same && idname_same && devname_same) {
/* this case will probably be caught earlier */
log_verbose("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: no change",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
} else if (!idtype_same && !idname_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s (old %s) IDNAME=%s (old %s) DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
idtype_to_str(du_old->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
} else if (!idtype_same && !idname_same && devname_same) {
log_print_unless_silent("IDTYPE=%s (old %s) IDNAME=%s (old %s) DEVNAME=%s PVID=%s%s: update",
idtype_to_str(du_new->idtype),
idtype_to_str(du_old->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
} else if (idtype_same && !idname_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s (old %s) DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
} else if (idtype_same && !idname_same && devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s (old %s) DEVNAME=%s PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_old->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
} else if (idtype_same && idname_same && !devname_same) {
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s (old %s) PVID=%s%s: update",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_new->devname ?: "none",
du_old->devname ?: "none",
du_new->pvid,
part);
}
next3:
dm_list_del(&du_old->list);
dm_list_del(&du_new->list);
dm_list_add(&done_old, &du_old->list);
dm_list_add(&done_new, &du_new->list);
goto restart3;
}
}
}
/*
* Entries remaining on old/new lists can't be directly
* correlated by loops above, to print field-specific
* changes. So, just print remaining old entries as
* being removed and remaing new entries as being added.
*/
dm_list_iterate_items(du_old, &use_old) {
part = _part_str(du_old);
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: old entry",
idtype_to_str(du_old->idtype),
du_old->idname ?: "none",
du_old->devname ?: "none",
du_old->pvid,
part);
}
dm_list_iterate_items(du_new, &use_new) {
part = _part_str(du_new);
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: new entry",
idtype_to_str(du_new->idtype),
du_new->idname ?: "none",
du_new->devname ?: "none",
du_new->pvid,
part);
}
/* Restore cmd->use_devices list */
dm_list_splice(&cmd->use_devices, &use_new);
dm_list_splice(&cmd->use_devices, &done_new);
}
int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
{
struct dm_list search_pvids;
@ -186,7 +541,6 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (arg_is_set(cmd, check_ARG) || arg_is_set(cmd, update_ARG)) {
int update_set = arg_is_set(cmd, update_ARG);
int search_count = 0;
int update_needed = 0;
unlink_searched_devnames(cmd);
@ -248,11 +602,17 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (!dev_is_mpath_component(cmd, dev, &mpath_devno))
continue;
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: remove multipath component",
idtype_to_str(du->idtype),
du->idname ?: "none",
du->devname ?: "none",
du->pvid ?: "none",
_part_str(du));
update_needed = 1;
if (update_set) {
log_print("Removing multipath component %s.", dev_name(du->dev));
if (update_set)
dm_list_del(&du->list);
}
if (!(mpath_dev = dev_cache_get_by_devt(cmd, mpath_devno)))
continue;
@ -264,8 +624,8 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (!device_id_add(cmd, mpath_dev, dev->pvid, NULL, NULL, 0))
stack;
} else {
log_print("Missing multipath device %s for multipath component %s.",
dev_name(mpath_dev), dev_name(du->dev));
log_print_unless_silent("Missing multipath device %s for multipath component %s.",
dev_name(mpath_dev), dev_name(du->dev));
}
}
}
@ -276,10 +636,15 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
}
/*
* Find and fix any devname entries that have moved to a
* renamed device.
* Find devname entries that have moved to a renamed device.
* If --refresh is set, then also look for missing PVIDs on
* devices with new device ids of any type, e.g. a PVID that's
* moved to a new WWID.
*/
device_ids_refresh(cmd, &found_devs, &search_count, 1, &update_needed);
cmd->search_for_devnames = "all";
device_ids_search(cmd, &found_devs, arg_is_set(cmd, refresh_ARG), 1, &update_needed);
_print_check(cmd);
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->dev)
@ -289,11 +654,15 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
if (arg_is_set(cmd, delnotfound_ARG)) {
dm_list_iterate_items_safe(du, du2, &cmd->use_devices) {
if (!du->dev) {
log_print("Deleting IDTYPE=%s IDNAME=%s PVID=%s",
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".");
log_print_unless_silent("IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s: delete",
idtype_to_str(du->idtype),
du->idname ?: "none",
du->devname ?: "none",
du->pvid ?: "none",
_part_str(du));
dm_list_del(&du->list);
free_du(du);
update_needed++;
update_needed = 1;
}
}
}
@ -553,18 +922,13 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
/* If no options, print use_devices list */
dm_list_iterate_items(du, &cmd->use_devices) {
char part_buf[64] = { 0 };
if (du->part)
snprintf(part_buf, 63, " PART=%d", du->part);
log_print("Device %s IDTYPE=%s IDNAME=%s DEVNAME=%s PVID=%s%s",
du->dev ? dev_name(du->dev) : "none",
du->idtype ? idtype_to_str(du->idtype) : "none",
du->idname ? du->idname : "none",
du->devname ? du->devname : "none",
du->pvid ? (char *)du->pvid : "none",
part_buf);
_part_str(du));
}
out: