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

scanning: improve filtering control

Filtering in label_scan was controlled indirectly by
the fact that bcache was not yet set up when label_scan
first ran.  The result is that filters that needed data
would not run and would return -EAGAIN, which would
result in the dev flag FILTER_AFTER_SCAN being set.
After the dev header was read for checking the label,
filters would be rechecked because of FILTER_AFTER_SCAN.
All filters would be checked this time because bcache
was now set up, and the filters needing data would
largely use data already scanned for reading the label.
This design worked but is hard to adjust for future
cases where bcache is already set up.

Replace this method (based on setting up bcache, or not)
with a new cmd flag filter_nodata_only.  When this flag
is set filters that need data will not run.  This allows
the same label_scan behavior when bcache has been set up.
There are no expected changes in behavior.
This commit is contained in:
David Teigland 2020-10-20 15:10:08 -05:00
parent c74ccd5201
commit 2c9bb67604

View File

@ -362,34 +362,33 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
uint64_t sector = 0; uint64_t sector = 0;
int is_duplicate = 0; int is_duplicate = 0;
int ret = 0; int ret = 0;
int pass;
dev->flags &= ~DEV_SCAN_FOUND_LABEL; dev->flags &= ~DEV_SCAN_FOUND_LABEL;
/* /*
* The device may have signatures that exclude it from being processed. * The device may have signatures that exclude it from being processed,
* If filters were applied before bcache data was available, some * even if it might look like a PV. Now that the device has been read
* filters may have deferred their check until the point where bcache * and data is available in bcache for it, recheck filters, including
* data had been read (here). They set this flag to indicate that the * those that use data. The device needs to be excluded before it
* filters should be retested now that data from the device is ready. * begins to be processed as a PV.
*/ */
if (f && (dev->flags & DEV_FILTER_AFTER_SCAN)) { if (f) {
dev->flags &= ~DEV_FILTER_AFTER_SCAN; if (!f->passes_filter(cmd, f, dev, NULL)) {
/*
* If this device was previously scanned (not common)
* and if it passed filters at that point, lvmcache
* info may have been saved for it. Now the same
* device is being scanned again, and it may fail
* filters this time. If the caller did not clear
* lvmcache info for this dev before rescanning, do
* that now. It's unlikely this is actually needed.
*/
if (dev->pvid[0]) {
log_print("Clear pvid and info for filtered dev %s", dev_name(dev));
lvmcache_del_dev(dev);
memset(dev->pvid, 0, sizeof(dev->pvid));
}
log_debug_devs("Scan filtering %s", dev_name(dev));
pass = f->passes_filter(cmd, f, dev, NULL);
if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
/* Shouldn't happen */
dev->flags &= ~DEV_FILTER_OUT_SCAN;
log_debug_devs("Scan filter should not be deferred %s", dev_name(dev));
pass = 1;
}
if (!pass) {
log_very_verbose("%s: Not processing filtered", dev_name(dev));
dev->flags |= DEV_FILTER_OUT_SCAN;
*is_lvm_device = 0; *is_lvm_device = 0;
goto_out; goto_out;
} }
@ -414,7 +413,12 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
log_very_verbose("%s: No lvm label detected", dev_name(dev)); log_very_verbose("%s: No lvm label detected", dev_name(dev));
lvmcache_del_dev(dev); /* FIXME: if this is needed, fix it. */ /* See comment above */
if (dev->pvid[0]) {
log_print("Clear pvid and info for no lvm header %s", dev_name(dev));
lvmcache_del_dev(dev);
memset(dev->pvid, 0, sizeof(dev->pvid));
}
*is_lvm_device = 0; *is_lvm_device = 0;
goto out; goto out;
@ -1009,6 +1013,7 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
int label_scan(struct cmd_context *cmd) int label_scan(struct cmd_context *cmd)
{ {
struct dm_list all_devs; struct dm_list all_devs;
struct dm_list filtered_devs;
struct dm_list scan_devs; struct dm_list scan_devs;
struct dm_list hints_list; struct dm_list hints_list;
struct dev_iter *iter; struct dev_iter *iter;
@ -1021,9 +1026,15 @@ int label_scan(struct cmd_context *cmd)
log_debug_devs("Finding devices to scan"); log_debug_devs("Finding devices to scan");
dm_list_init(&all_devs); dm_list_init(&all_devs);
dm_list_init(&filtered_devs);
dm_list_init(&scan_devs); dm_list_init(&scan_devs);
dm_list_init(&hints_list); dm_list_init(&hints_list);
if (!scan_bcache) {
if (!_setup_bcache())
return_0;
}
/* /*
* dev_cache_scan() creates a list of devices on the system * dev_cache_scan() creates a list of devices on the system
* (saved in in dev-cache) which we can iterate through to * (saved in in dev-cache) which we can iterate through to
@ -1047,29 +1058,15 @@ int label_scan(struct cmd_context *cmd)
} }
/* /*
* Set up the iterator that is needed to step through each device in * Create a list of all devices in dev-cache (all found on the system.)
* dev cache. * Do not apply filters and do not read any (the filter arg is NULL).
* Invalidate bcache data for all devs (there will usually be no bcache
* data to invalidate.)
*/ */
if (!(iter = dev_iter_create(cmd->filter, 0))) { if (!(iter = dev_iter_create(NULL, 0))) {
log_error("Scanning failed to get devices."); log_error("Scanning failed to get devices.");
return 0; return 0;
} }
log_debug_devs("Filtering devices to scan");
/*
* Iterate through all devices in dev cache and apply filters
* to exclude devs that we do not need to scan. Those devs
* that pass the filters are returned by the iterator and
* saved in a list of devs that we will proceed to scan to
* check if they are LVM devs. IOW this loop is the
* application of filters (those that do not require reading
* the devs) to the list of all devices. It does that because
* the 'cmd->filter' is used above when setting up the iterator.
* Unfortunately, it's not obvious that this is what's happening
* here. filters that require reading the device are not applied
* here, but in process_block(), see DEV_FILTER_AFTER_SCAN.
*/
while ((dev = dev_iter_get(cmd, iter))) { while ((dev = dev_iter_get(cmd, iter))) {
if (!(devl = zalloc(sizeof(*devl)))) if (!(devl = zalloc(sizeof(*devl))))
continue; continue;
@ -1078,16 +1075,43 @@ int label_scan(struct cmd_context *cmd)
/* /*
* label_scan should not generally be called a second time, * label_scan should not generally be called a second time,
* so this will usually not be true. * so this will usually do nothing.
*/ */
label_scan_invalidate(dev); label_scan_invalidate(dev);
}; };
dev_iter_destroy(iter); dev_iter_destroy(iter);
if (!scan_bcache) { /*
if (!_setup_bcache()) * Exclude devices that fail nodata filters. (Those filters that can be
return 0; * checked without reading data from the device.)
*
* The result of checking nodata filters is saved by the "persistent
* filter", and this result needs to be cleared (wiped) so that the
* complete set of filters (including those that require data) can be
* checked in _process_block, where headers have been read.
*/
log_debug_devs("Filtering devices to scan (nodata)");
cmd->filter_nodata_only = 1;
dm_list_iterate_items_safe(devl, devl2, &all_devs) {
dev = devl->dev;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, NULL)) {
dm_list_del(&devl->list);
dm_list_add(&filtered_devs, &devl->list);
if (dev->pvid[0]) {
log_print("Clear pvid and info for filtered dev %s", dev_name(dev));
lvmcache_del_dev(dev);
memset(dev->pvid, 0, sizeof(dev->pvid));
}
}
} }
cmd->filter_nodata_only = 0;
dm_list_iterate_items(devl, &all_devs)
cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
dm_list_iterate_items(devl, &filtered_devs)
cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
/* /*
* In some common cases we can avoid scanning all devices * In some common cases we can avoid scanning all devices
@ -1110,8 +1134,6 @@ int label_scan(struct cmd_context *cmd)
} else } else
using_hints = 1; using_hints = 1;
log_debug("Will scan %d devices skip %d", dm_list_size(&scan_devs), dm_list_size(&all_devs));
/* /*
* If the total number of devices exceeds the soft open file * If the total number of devices exceeds the soft open file
* limit, then increase the soft limit to the hard/max limit * limit, then increase the soft limit to the hard/max limit