summaryrefslogtreecommitdiff
path: root/lib/filters
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2018-05-03 17:12:07 -0500
committerDavid Teigland <teigland@redhat.com>2018-05-10 16:03:19 -0500
commit57bb46c5e7f8d6af1737af5ed1acae8abc37cded (patch)
tree60bf7f2050903efa5680f5234f8a16d2da2e6d72 /lib/filters
parent39ce38eb8868e367fa796ddb12b1020647d14c63 (diff)
downloadlvm2-57bb46c5e7f8d6af1737af5ed1acae8abc37cded.tar.gz
filter: use bcache for filter reads
Filters are still applied before any device reading or the label scan, but any filter checks that want to read the device are skipped and the device is flagged. After bcache is populated, but before lvm looks for devices (i.e. before label scan), the filters are reapplied to the devices that were flagged above. The filters will then find the data they need in bcache.
Diffstat (limited to 'lib/filters')
-rw-r--r--lib/filters/filter-composite.c9
-rw-r--r--lib/filters/filter-md.c39
-rw-r--r--lib/filters/filter-partitioned.c12
-rw-r--r--lib/filters/filter-persistent.c78
-rw-r--r--lib/filters/filter-signature.c12
-rw-r--r--lib/filters/filter-usable.c9
-rw-r--r--lib/filters/filter.h2
7 files changed, 122 insertions, 39 deletions
diff --git a/lib/filters/filter-composite.c b/lib/filters/filter-composite.c
index c63589640..f15ff1289 100644
--- a/lib/filters/filter-composite.c
+++ b/lib/filters/filter-composite.c
@@ -15,14 +15,19 @@
#include "lib.h"
#include "filter.h"
+#include "device.h"
static int _and_p(struct dev_filter *f, struct device *dev)
{
struct dev_filter **filters;
+ int ret;
- for (filters = (struct dev_filter **) f->private; *filters; ++filters)
- if (!(*filters)->passes_filter(*filters, dev))
+ for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
+ ret = (*filters)->passes_filter(*filters, dev);
+
+ if (!ret)
return 0; /* No 'stack': a filter, not an error. */
+ }
return 1;
}
diff --git a/lib/filters/filter-md.c b/lib/filters/filter-md.c
index 7fac50aae..bb8a7cf42 100644
--- a/lib/filters/filter-md.c
+++ b/lib/filters/filter-md.c
@@ -20,15 +20,21 @@
#define MSG_SKIPPING "%s: Skipping md component device"
-static int _ignore_md(struct dev_filter *f __attribute__((unused)),
- struct device *dev)
+static int _ignore_md(struct device *dev, int full)
{
int ret;
if (!md_filtering())
return 1;
- ret = dev_is_md(dev, NULL);
+ ret = dev_is_md(dev, NULL, full);
+
+ if (ret == -EAGAIN) {
+ /* let pass, call again after scan */
+ dev->flags |= DEV_FILTER_AFTER_SCAN;
+ log_debug_devs("filter md deferred %s", dev_name(dev));
+ return 1;
+ }
if (ret == 1) {
if (dev->ext.src == DEV_EXT_NONE)
@@ -48,6 +54,18 @@ static int _ignore_md(struct dev_filter *f __attribute__((unused)),
return 1;
}
+static int _ignore_md_lite(struct dev_filter *f __attribute__((unused)),
+ struct device *dev)
+{
+ return _ignore_md(dev, 0);
+}
+
+static int _ignore_md_full(struct dev_filter *f __attribute__((unused)),
+ struct device *dev)
+{
+ return _ignore_md(dev, 1);
+}
+
static void _destroy(struct dev_filter *f)
{
if (f->use_count)
@@ -56,7 +74,7 @@ static void _destroy(struct dev_filter *f)
dm_free(f);
}
-struct dev_filter *md_filter_create(struct dev_types *dt)
+struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt)
{
struct dev_filter *f;
@@ -65,7 +83,18 @@ struct dev_filter *md_filter_create(struct dev_types *dt)
return NULL;
}
- f->passes_filter = _ignore_md;
+ /*
+ * FIXME: for commands that want a full md check (pvcreate, vgcreate,
+ * vgextend), we do an extra read at the end of every device that the
+ * filter looks at. This isn't necessary; we only need to do the full
+ * md check on the PVs that these commands are trying to use.
+ */
+
+ if (cmd->use_full_md_check)
+ f->passes_filter = _ignore_md_full;
+ else
+ f->passes_filter = _ignore_md_lite;
+
f->destroy = _destroy;
f->use_count = 0;
f->private = dt;
diff --git a/lib/filters/filter-partitioned.c b/lib/filters/filter-partitioned.c
index f23fae60b..5e1c4e823 100644
--- a/lib/filters/filter-partitioned.c
+++ b/lib/filters/filter-partitioned.c
@@ -21,8 +21,18 @@
static int _passes_partitioned_filter(struct dev_filter *f, struct device *dev)
{
struct dev_types *dt = (struct dev_types *) f->private;
+ int ret;
- if (dev_is_partitioned(dt, dev)) {
+ ret = dev_is_partitioned(dt, dev);
+
+ if (ret == -EAGAIN) {
+ /* let pass, call again after scan */
+ log_debug_devs("filter partitioned deferred %s", dev_name(dev));
+ dev->flags |= DEV_FILTER_AFTER_SCAN;
+ return 1;
+ }
+
+ if (ret) {
if (dev->ext.src == DEV_EXT_NONE)
log_debug_devs(MSG_SKIPPING, dev_name(dev));
else
diff --git a/lib/filters/filter-persistent.c b/lib/filters/filter-persistent.c
index a4151c289..3fa57f191 100644
--- a/lib/filters/filter-persistent.c
+++ b/lib/filters/filter-persistent.c
@@ -27,6 +27,30 @@ struct pfilter {
};
/*
+ * The persistent filter is filter layer that sits above the other filters and
+ * caches the final result of those other filters. When a device is first
+ * checked against filters, it will not be in this cache, so this filter will
+ * pass the device down to the other filters to check it. The other filters
+ * will run and either include the device (good/pass) or exclude the device
+ * (bad/fail). That good or bad result propagates up through this filter which
+ * saves the result. The next time some code checks the filters against the
+ * device, this persistent/cache filter is checked first. This filter finds
+ * the previous result in its cache and returns it without reevaluating the
+ * other real filters.
+ *
+ * FIXME: a cache like this should not be needed. The fact it's needed is a
+ * symptom of code that should be fixed to not reevaluate filters multiple
+ * times. A device should be checked against the filter once, and then not
+ * need to be checked again. With scanning now controlled, we could probably
+ * do this.
+ *
+ * FIXME: "persistent" isn't a great name for this caching filter. This filter
+ * at one time saved its cache results to a file, which is how it got the name.
+ * That .cache file does not work well, causes problems, and is no longer used
+ * by default. The old code for it should be removed.
+ */
+
+/*
* The hash table holds one of these two states
* against each entry.
*/
@@ -264,27 +288,51 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
struct pfilter *pf = (struct pfilter *) f->private;
void *l = dm_hash_lookup(pf->devices, dev_name(dev));
struct dm_str_list *sl;
+ int pass = 1;
- /* Cached BAD? */
+ /* Cached bad, skip dev */
if (l == PF_BAD_DEVICE) {
- log_debug_devs("%s: Skipping (cached)", dev_name(dev));
+ log_debug_devs("%s: filter cache skipping (cached bad)", dev_name(dev));
return 0;
}
- /* Test dm devices every time, so cache them as GOOD. */
- if (MAJOR(dev->dev) == pf->dt->device_mapper_major) {
- if (!l)
- dm_list_iterate_items(sl, &dev->aliases)
- if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) {
- log_error("Failed to hash device to filter.");
- return 0;
- }
- return pf->real->passes_filter(pf->real, dev);
+ /* Cached good, use dev */
+ if (l == PF_GOOD_DEVICE) {
+ log_debug_devs("%s: filter cache using (cached good)", dev_name(dev));
+ return 1;
}
- /* Uncached */
+ /* Uncached, check filters and cache the result */
if (!l) {
- l = pf->real->passes_filter(pf->real, dev) ? PF_GOOD_DEVICE : PF_BAD_DEVICE;
+ dev->flags &= ~DEV_FILTER_AFTER_SCAN;
+
+ pass = pf->real->passes_filter(pf->real, dev);
+
+ if (!pass) {
+ /*
+ * A device that does not pass one filter is excluded
+ * even if the result of another filter is deferred,
+ * because the deferred result won't change the exclude.
+ */
+ l = PF_BAD_DEVICE;
+
+ } else if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
+ /*
+ * When the filter result is deferred, we let the device
+ * pass for now, but do not cache the result. We need to
+ * rerun the filters later. At that point the final result
+ * will be cached.
+ */
+ log_debug_devs("filter cache deferred %s", dev_name(dev));
+ dev->flags |= DEV_FILTER_AFTER_SCAN;
+ pass = 1;
+ goto out;
+
+ } else if (pass) {
+ l = PF_GOOD_DEVICE;
+ }
+
+ log_debug_devs("filter caching %s %s", pass ? "good" : "bad", dev_name(dev));
dm_list_iterate_items(sl, &dev->aliases)
if (!dm_hash_insert(pf->devices, sl->str, l)) {
@@ -292,8 +340,8 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
return 0;
}
}
-
- return (l == PF_BAD_DEVICE) ? 0 : 1;
+ out:
+ return pass;
}
static void _persistent_destroy(struct dev_filter *f)
diff --git a/lib/filters/filter-signature.c b/lib/filters/filter-signature.c
index b42647677..23b01e79c 100644
--- a/lib/filters/filter-signature.c
+++ b/lib/filters/filter-signature.c
@@ -26,14 +26,16 @@ static int _ignore_signature(struct dev_filter *f __attribute__((unused)),
char buf[BUFSIZE];
int ret = 0;
- if (!dev_open_readonly(dev)) {
- stack;
- return -1;
+ if (!scan_bcache) {
+ /* let pass, call again after scan */
+ log_debug_devs("filter signature deferred %s", dev_name(dev));
+ dev->flags |= DEV_FILTER_AFTER_SCAN;
+ return 1;
}
memset(buf, 0, BUFSIZE);
- if (!dev_read(dev, 0, BUFSIZE, DEV_IO_SIGNATURES, buf)) {
+ if (!dev_read_bytes(dev, 0, BUFSIZE, buf)) {
log_debug_devs("%s: Skipping: error in signature detection",
dev_name(dev));
ret = 0;
@@ -54,8 +56,6 @@ static int _ignore_signature(struct dev_filter *f __attribute__((unused)),
ret = 1;
out:
- dev_close(dev);
-
return ret;
}
diff --git a/lib/filters/filter-usable.c b/lib/filters/filter-usable.c
index 4ee2e9df8..2de2a0f2e 100644
--- a/lib/filters/filter-usable.c
+++ b/lib/filters/filter-usable.c
@@ -27,12 +27,6 @@ static int _native_check_pv_min_size(struct device *dev)
uint64_t size;
int ret = 0;
- /* Check it's accessible */
- if (!dev_open_readonly_quiet(dev)) {
- log_debug_devs("%s: Skipping: open failed", dev_name(dev));
- return 0;
- }
-
/* Check it's not too small */
if (!dev_get_size(dev, &size)) {
log_debug_devs("%s: Skipping: dev_get_size failed", dev_name(dev));
@@ -47,9 +41,6 @@ static int _native_check_pv_min_size(struct device *dev)
ret = 1;
out:
- if (!dev_close(dev))
- stack;
-
return ret;
}
diff --git a/lib/filters/filter.h b/lib/filters/filter.h
index 2f809dd91..624582738 100644
--- a/lib/filters/filter.h
+++ b/lib/filters/filter.h
@@ -23,7 +23,7 @@
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
-struct dev_filter *md_filter_create(struct dev_types *dt);
+struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt);
struct dev_filter *fwraid_filter_create(struct dev_types *dt);
struct dev_filter *mpath_filter_create(struct dev_types *dt);
struct dev_filter *partitioned_filter_create(struct dev_types *dt);