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

vgchange -aay: improve unexpected command variations

For completeness and consistency, adjust the behavior
for some variations of:

  vgchange -aay --autoactivation event [vgname]

The current standard use is with a VG name arg, and the
command is only called when all pvs_online files exist.
This is the optimal case, in which only pvs_online devs
are read.  This remains the same.

Clean up behaviors for some other unexpected uses of the
command:

. With no VG name arg, the command activates any VGs
  that are complete according to pvs_online.  If no
  pvs_online files exist, it does nothing.

. If a VG name is used but no PVs online files exist for
  the VG, or the PVs online files are incomplete, then
  consider there could be a problem with the pvs_online
  files, and fall back to a full label scan prior to
  attempting the activation.
This commit is contained in:
David Teigland 2021-11-08 11:30:25 -06:00
parent 14b68ea313
commit 024ce50f06
6 changed files with 189 additions and 52 deletions

View File

@ -2164,7 +2164,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (devname[0]) {
log_debug("Found %s for %d:%d from sys", devname, major, minor);
log_debug("Found %s for %d:%d from sys dm", devname, major, minor);
return _strdup(devname);
}
return NULL;

View File

@ -134,8 +134,12 @@ int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
dm_list_add(pvs_online, &po->list);
}
if (closedir(dir))
log_sys_debug("closedir", PVS_ONLINE_DIR);
log_debug("PVs online found %d for %s", dm_list_size(pvs_online), vgname ?: "all");
return 1;
}
@ -355,6 +359,8 @@ int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
dm_list_add(pvs_online, &po->list);
}
log_debug("PVs online lookup found %d for %s", dm_list_size(pvs_online), vgname);
fclose(fp);
return 1;

View File

@ -1023,13 +1023,13 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
/*
* Use files under /run/lvm/, created by pvscan --cache autoactivation,
* to optimize device setup/scanning for a command that is run for a
* specific vg name. autoactivation happens during system startup
* when the hints file is not useful, so this uses the online files as
* an alternative.
*/
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
* to optimize device setup/scanning. autoactivation happens during
* system startup when the hints file is not useful, but he pvs_online
* files can provide a similar optimization to the hints file.
*/
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
int *found_none, int *found_all, int *found_incomplete)
{
struct dm_list pvs_online;
struct dm_list devs;
@ -1042,6 +1042,8 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
dm_list_init(&pvs_online);
dm_list_init(&devs);
log_debug_devs("Finding online devices to scan");
/* reads devices file, does not populate dev-cache */
if (!setup_devices_for_online_autoactivation(cmd))
return 0;
@ -1055,11 +1057,21 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
* info from the online files tell us which devices those PVs are
* located on.
*/
if (!get_pvs_lookup(&pvs_online, vgname)) {
if (!get_pvs_online(&pvs_online, vgname))
if (vgname) {
if (!get_pvs_lookup(&pvs_online, vgname)) {
if (!get_pvs_online(&pvs_online, vgname))
goto bad;
}
} else {
if (!get_pvs_online(&pvs_online, NULL))
goto bad;
}
if (dm_list_empty(&pvs_online)) {
*found_none = 1;
return 1;
}
/*
* For each po devno add a struct dev to dev-cache. This is a faster
* alternative to the usual dev_cache_scan() which looks at all
@ -1201,8 +1213,10 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
free_po_list(&pvs_online);
if (dm_list_empty(&devs))
if (dm_list_empty(&devs)) {
*found_none = 1;
return 1;
}
/*
* Scan devs to populate lvmcache info, which includes the mda info that's
@ -1220,13 +1234,17 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname)
* be able to fall back to a standard label scan if the online hints
* gave fewer PVs than listed in VG metadata.
*/
metadata_pv_count = lvmcache_pvsummary_count(vgname);
if (metadata_pv_count != dm_list_size(&devs)) {
log_debug("Incorrect PV list from online files %d metadata %d.",
dm_list_size(&devs), metadata_pv_count);
return 0;
if (vgname) {
metadata_pv_count = lvmcache_pvsummary_count(vgname);
if (metadata_pv_count > dm_list_size(&devs)) {
log_debug("Incomplete PV list from online files %d metadata %d.",
dm_list_size(&devs), metadata_pv_count);
*found_incomplete = 1;
return 1;
}
}
*found_all = 1;
return 1;
bad:
free_po_list(&pvs_online);

View File

@ -118,7 +118,9 @@ int label_scan_open_excl(struct device *dev);
int label_scan_open_rw(struct device *dev);
int label_scan_reopen_rw(struct device *dev);
int label_read_pvid(struct device *dev, int *has_pvid);
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname);
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
int *found_none, int *found_all, int *found_incomplete);
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);

View File

@ -19,62 +19,136 @@ _clear_online_files() {
aux prepare_devs 4
# Because mapping devno to devname gets dm name from sysfs
aux lvmconf 'devices/scan = "/dev"'
base1=$(basename $dev1)
base2=$(basename $dev2)
base3=$(basename $dev3)
base4=$(basename $dev4)
aux extend_filter "a|/dev/mapper/$base1|"
aux extend_filter "a|/dev/mapper/$base2|"
aux extend_filter "a|/dev/mapper/$base3|"
aux extend_filter "a|/dev/mapper/$base4|"
vgcreate $vg1 "$dev1" "$dev2"
vgcreate $vg2 "$dev3"
pvcreate "$dev4"
lvcreate -l1 -n $lv1 -an $vg1
lvcreate -l1 -n $lv2 -an $vg1
lvcreate -l1 -n $lv1 -an $vg2
# With no pv online files, vgchange that uses online files
# will find no PVs to activate from.
# Expected use, with vg name and all online files exist for vgchange.
_clear_online_files
not vgchange -aay --autoactivation event $vg1
not vgchange -aay --autoactivation event $vg2
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
# incomplete vg will not be activated
pvscan --cache "$dev1"
pvscan --cache "$dev2"
vgchange -aay --autoactivation event $vg1
# VG foo is incomplete
check lv_field $vg1/$lv1 lv_active ""
# complete vg is activated
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev3"
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
pvscan --cache "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
vgchange -an $vg1
vgchange -an $vg2
# the same tests but using command options matching udev rule
# Count io to check the pvs_online optimization
# is working to limit scanning.
vgchange -an
_clear_online_files
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
vgchange -aay --autoactivation event $vg1
# VG foo is incomplete
pvscan --cache "$dev1"
pvscan --cache "$dev2"
strace -e io_submit vgchange -aay --autoactivation event $vg1 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 4
rm trace.out
strace -e io_submit pvscan --cache "$dev3" 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 1
rm trace.out
strace -e io_submit vgchange -aay --autoactivation event $vg2 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 2
rm trace.out
# non-standard usage: no VG name arg, vgchange will only used pvs_online files
vgchange -an
_clear_online_files
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg1/$lv2 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev1"
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg1/$lv2 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev2"
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev3"
vgchange -aay --autoactivation event
check lv_field $vg2/$lv1 lv_active "active"
# non-standard usage: include VG name arg, but missing or incomplete pvs_online files
vgchange -an
_clear_online_files
# all missing pvs_online, vgchange falls back to full label scan
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
vgchange -an
_clear_online_files
# incomplete pvs_online, vgchange falls back to full label scan
pvscan --cache "$dev1"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
vgchange -an
_clear_online_files
# incomplete pvs_online, pvs_online from different vg,
# no pvs_online found for vg arg so vgchange falls back to full label scan
pvscan --cache "$dev3"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
vgchange -an
_clear_online_files
# same tests but using command options matching udev rule
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev3"
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
vgchange -an $vg1
vgchange -an $vg2

View File

@ -879,7 +879,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
}
if (arg_is_set(cmd, autoactivation_ARG)) {
int found_none = 0, found_all = 0, found_incomplete = 0;
int skip_command = 0;
if (!_check_autoactivation(cmd, &vp, &skip_command))
return ECMD_FAILED;
if (skip_command)
@ -889,14 +891,49 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
* Special label scan optimized for autoactivation
* that is based on info read from /run/lvm/ files
* created by pvscan --cache during autoactivation.
* (Add an option to disable this optimization?)
* Add an option to disable this optimization? e.g.
* "online_skip" in --autoactivation / auto_activation_settings
*
* In some cases it might be useful to strictly follow
* the online files, and not fall back to a standard
* label scan when no pvs or incomplete pvs are found
* from the online files. Add option for that? e.g.
* "online_only" in --autoactivation / auto_activation_settings
*
* Generally the way that vgchange -aay --autoactivation event
* is currently used, it will not be called until pvscan --cache
* has found the VG is complete, so it will not generally be
* following the paths that fall back to standard label_scan.
*
* TODO: Like pvscan_aa_quick, this could do lock_vol(vgname)
* before label_scan_vg_online, then set cmd->can_use_one_scan=1
* to avoid rescanning in _vg_read called by process_each_vg.
*/
get_single_vgname_cmd_arg(cmd, NULL, &vgname);
if (vgname) {
if (!label_scan_vg_online(cmd, vgname))
log_debug("Standard label_scan required in place of online scan.");
else
if (!label_scan_vg_online(cmd, vgname, &found_none, &found_all, &found_incomplete)) {
log_print("PVs online error%s%s, using all devices.", vgname ? " for VG " : "", vgname ?: "");
} else {
if (!vgname) {
/* Not expected usage, activate any VGs that are complete based on pvs_online. */
flags |= PROCESS_SKIP_SCAN;
} else if (found_all) {
/* The expected and optimal usage, only online PVs are read. */
flags |= PROCESS_SKIP_SCAN;
/*
} else if (online_only) {
log_print("PVs online %s.", found_none ? "not found" : "incomplete");
return vgname ? ECMD_FAILED : ECMD_PROCESSED;
*/
} else if (found_none) {
/* Not expected usage, use full label_scan in process_each */
log_print("PVs online not found for VG %s, using all devices.", vgname);
} else if (found_incomplete) {
/* Not expected usage, use full label_scan in process_each */
log_print("PVs online incomplete for VG %s, using all devicess.", vgname);
} else {
/* Shouldn't happen */
log_print("PVs online unknown for VG %s, using all devices.", vgname);
}
}
}