Blame SOURCES/0006-filter-sysfs-skip-when-device-id-is-set.patch

b6fb8c
From f73be4480a5dd104a77e3ef84d7dcc80b834e593 Mon Sep 17 00:00:00 2001
b6fb8c
From: David Teigland <teigland@redhat.com>
b6fb8c
Date: Tue, 2 Nov 2021 15:42:26 -0500
38b7b2
Subject: [PATCH 06/54] filter-sysfs: skip when device id is set
b6fb8c
b6fb8c
When a device id is set for a device, using an idtype other
b6fb8c
than devname, it means that sysfs has been used with the device
b6fb8c
to match the device id.  So, checking for a sysfs entry for the
b6fb8c
device in filter-sysfs is redundant.  For any other cases not
b6fb8c
covered by this (e.g. devname ids), have filter-sysfs simply
b6fb8c
stat /sys/dev/block/major:minor to test if the device exists
b6fb8c
in sysfs.
b6fb8c
b6fb8c
The extensive processing done by filter-sysfs init is removed.
b6fb8c
It was taking an immense amount of time with many devices, e.g.
b6fb8c
. 1024 PVs in 520 VGs
b6fb8c
. 520 concurrent vgchange -ay <vgname> commands
b6fb8c
. vgchange scans only PVs in the named VG (based on pvs_online
b6fb8c
  files from a pending patch)
b6fb8c
b6fb8c
A large number of the vgchange commands were taking over 1 min,
b6fb8c
and nearly half of that time was used by filter-sysfs init.
b6fb8c
With this patch, the vgchange commands take about half the time.
b6fb8c
---
b6fb8c
 lib/commands/toolcontext.c |  24 ++-
b6fb8c
 lib/filters/filter-sysfs.c | 296 +++----------------------------------
b6fb8c
 2 files changed, 32 insertions(+), 288 deletions(-)
b6fb8c
b6fb8c
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
b6fb8c
index 1b7170de1..a0c78ddd6 100644
b6fb8c
--- a/lib/commands/toolcontext.c
b6fb8c
+++ b/lib/commands/toolcontext.c
b6fb8c
@@ -1143,19 +1143,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
b6fb8c
 	 * Update MAX_FILTERS definition above when adding new filters.
b6fb8c
 	 */
b6fb8c
 
b6fb8c
-	/*
b6fb8c
-	 * sysfs filter. Only available on 2.6 kernels.  Non-critical.
b6fb8c
-	 * Listed first because it's very efficient at eliminating
b6fb8c
-	 * unavailable devices.
b6fb8c
-	 *
b6fb8c
-	 * TODO: I suspect that using the lvm_type and device_id
b6fb8c
-	 * filters before this one may be more efficient.
b6fb8c
-	 */
b6fb8c
-	if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
b6fb8c
-		if ((filters[nr_filt] = sysfs_filter_create()))
b6fb8c
-			nr_filt++;
b6fb8c
-	}
b6fb8c
-
b6fb8c
 	/* internal filter used by command processing. */
b6fb8c
 	if (!(filters[nr_filt] = internal_filter_create())) {
b6fb8c
 		log_error("Failed to create internal device filter");
b6fb8c
@@ -1195,6 +1182,17 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
b6fb8c
 	}
b6fb8c
 	nr_filt++;
b6fb8c
 
b6fb8c
+	/*
b6fb8c
+	 * sysfs filter. Only available on 2.6 kernels.  Non-critical.
b6fb8c
+	 * Eliminates unavailable devices.
b6fb8c
+	 * TODO: this may be unnecessary now with device ids
b6fb8c
+	 * (currently not used for devs match to device id using syfs)
b6fb8c
+	 */
b6fb8c
+	if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
b6fb8c
+		if ((filters[nr_filt] = sysfs_filter_create()))
b6fb8c
+			nr_filt++;
b6fb8c
+	}
b6fb8c
+
b6fb8c
 	/* usable device filter. Required. */
b6fb8c
 	if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
b6fb8c
 		log_error("Failed to create usabled device filter");
b6fb8c
diff --git a/lib/filters/filter-sysfs.c b/lib/filters/filter-sysfs.c
b6fb8c
index 32ac324dd..672211057 100644
b6fb8c
--- a/lib/filters/filter-sysfs.c
b6fb8c
+++ b/lib/filters/filter-sysfs.c
b6fb8c
@@ -17,288 +17,49 @@
b6fb8c
 
b6fb8c
 #ifdef __linux__
b6fb8c
 
b6fb8c
-#include <sys/sysmacros.h>
b6fb8c
-#include <dirent.h>
b6fb8c
-
b6fb8c
-static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
b6fb8c
-				unsigned *sysfs_depth)
b6fb8c
+static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
b6fb8c
 {
b6fb8c
+	char path[PATH_MAX];
b6fb8c
+	const char *sysfs_dir;
b6fb8c
 	struct stat info;
b6fb8c
-	unsigned i;
b6fb8c
-	static const struct dir_class {
b6fb8c
-		const char path[32];
b6fb8c
-		int depth;
b6fb8c
-	} classes[] = {
b6fb8c
-		/*
b6fb8c
-		 * unified classification directory for all kernel subsystems
b6fb8c
-		 *
b6fb8c
-		 * /sys/subsystem/block/devices
b6fb8c
-		 * |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
b6fb8c
-		 * |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
b6fb8c
-		 *  `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
b6fb8c
-		 *
b6fb8c
-		 */
b6fb8c
-		{ "subsystem/block/devices", 0 },
b6fb8c
-
b6fb8c
-		/*
b6fb8c
-		 * block subsystem as a class
b6fb8c
-		 *
b6fb8c
-		 * /sys/class/block
b6fb8c
-		 * |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
b6fb8c
-		 * |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
b6fb8c
-		 *  `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
b6fb8c
-		 *
b6fb8c
-		 */
b6fb8c
-		{ "class/block", 0 },
b6fb8c
-
b6fb8c
-		/*
b6fb8c
-		 * old block subsystem layout with nested directories
b6fb8c
-		 *
b6fb8c
-		 * /sys/block/
b6fb8c
-		 * |-- sda
b6fb8c
-		 * |   |-- capability
b6fb8c
-		 * |   |-- dev
b6fb8c
-		 * ...
b6fb8c
-		 * |   |-- sda1
b6fb8c
-		 * |   |   |-- dev
b6fb8c
-		 * ...
b6fb8c
-		 * |
b6fb8c
-		 * `-- sr0
b6fb8c
-		 *     |-- capability
b6fb8c
-		 *     |-- dev
b6fb8c
-		 * ...
b6fb8c
-		 *
b6fb8c
-		 */
b6fb8c
-
b6fb8c
-		{ "block", 1 }
b6fb8c
-	};
b6fb8c
-
b6fb8c
-	for (i = 0; i < DM_ARRAY_SIZE(classes); ++i)
b6fb8c
-		if ((dm_snprintf(path, len, "%s%s", sysfs_dir, classes[i].path) >= 0) &&
b6fb8c
-		    (stat(path, &info) == 0)) {
b6fb8c
-			*sysfs_depth = classes[i].depth;
b6fb8c
-			return 1;
b6fb8c
-		}
b6fb8c
-
b6fb8c
-	return 0;
b6fb8c
-}
b6fb8c
-
b6fb8c
-/*----------------------------------------------------------------
b6fb8c
- * We need to store a set of dev_t.
b6fb8c
- *--------------------------------------------------------------*/
b6fb8c
-struct entry {
b6fb8c
-	struct entry *next;
b6fb8c
-	dev_t dev;
b6fb8c
-};
b6fb8c
-
b6fb8c
-#define SET_BUCKETS 64
b6fb8c
-struct dev_set {
b6fb8c
-	struct dm_pool *mem;
b6fb8c
-	const char *sys_block;
b6fb8c
-	unsigned sysfs_depth;
b6fb8c
-	int initialised;
b6fb8c
-	struct entry *slots[SET_BUCKETS];
b6fb8c
-};
b6fb8c
-
b6fb8c
-static struct dev_set *_dev_set_create(struct dm_pool *mem,
b6fb8c
-				       const char *sys_block,
b6fb8c
-				       unsigned sysfs_depth)
b6fb8c
-{
b6fb8c
-	struct dev_set *ds;
b6fb8c
-
b6fb8c
-	if (!(ds = dm_pool_zalloc(mem, sizeof(*ds))))
b6fb8c
-		return NULL;
b6fb8c
-
b6fb8c
-	ds->mem = mem;
b6fb8c
-	if (!(ds->sys_block = dm_pool_strdup(mem, sys_block)))
b6fb8c
-		return NULL;
b6fb8c
-
b6fb8c
-	ds->sysfs_depth = sysfs_depth;
b6fb8c
-	ds->initialised = 0;
b6fb8c
-
b6fb8c
-	return ds;
b6fb8c
-}
b6fb8c
-
b6fb8c
-static unsigned _hash_dev(dev_t dev)
b6fb8c
-{
b6fb8c
-	return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
b6fb8c
-}
b6fb8c
 
b6fb8c
-/*
b6fb8c
- * Doesn't check that the set already contains dev.
b6fb8c
- */
b6fb8c
-static int _set_insert(struct dev_set *ds, dev_t dev)
b6fb8c
-{
b6fb8c
-	struct entry *e;
b6fb8c
-	unsigned h = _hash_dev(dev);
b6fb8c
-
b6fb8c
-	if (!(e = dm_pool_alloc(ds->mem, sizeof(*e))))
b6fb8c
-		return 0;
b6fb8c
-
b6fb8c
-	e->next = ds->slots[h];
b6fb8c
-	e->dev = dev;
b6fb8c
-	ds->slots[h] = e;
b6fb8c
-
b6fb8c
-	return 1;
b6fb8c
-}
b6fb8c
+	dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
b6fb8c
 
b6fb8c
-static int _set_lookup(struct dev_set *ds, dev_t dev)
b6fb8c
-{
b6fb8c
-	unsigned h = _hash_dev(dev);
b6fb8c
-	struct entry *e;
b6fb8c
+	/*
b6fb8c
+	 * Any kind of device id other than devname has been set
b6fb8c
+	 * using sysfs so we know that sysfs info exists for dev.
b6fb8c
+	 */
b6fb8c
+	if (dev->id && dev->id->idtype && (dev->id->idtype != DEV_ID_TYPE_DEVNAME))
b6fb8c
+		return 1;
b6fb8c
 
b6fb8c
-	for (e = ds->slots[h]; e; e = e->next)
b6fb8c
-		if (e->dev == dev)
b6fb8c
+	sysfs_dir = dm_sysfs_dir();
b6fb8c
+	if (sysfs_dir && *sysfs_dir) {
b6fb8c
+		if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
b6fb8c
+				sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
b6fb8c
+			log_debug("failed to create sysfs path");
b6fb8c
 			return 1;
b6fb8c
-
b6fb8c
-	return 0;
b6fb8c
-}
b6fb8c
-
b6fb8c
-/*----------------------------------------------------------------
b6fb8c
- * filter methods
b6fb8c
- *--------------------------------------------------------------*/
b6fb8c
-static int _parse_dev(const char *file, FILE *fp, dev_t *result)
b6fb8c
-{
b6fb8c
-	unsigned major, minor;
b6fb8c
-	char buffer[64];
b6fb8c
-
b6fb8c
-	if (!fgets(buffer, sizeof(buffer), fp)) {
b6fb8c
-		log_error("Empty sysfs device file: %s", file);
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
b6fb8c
-		log_error("Incorrect format for sysfs device file: %s.", file);
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	*result = makedev(major, minor);
b6fb8c
-	return 1;
b6fb8c
-}
b6fb8c
-
b6fb8c
-static int _read_dev(const char *file, dev_t *result)
b6fb8c
-{
b6fb8c
-	int r;
b6fb8c
-	FILE *fp;
b6fb8c
-
b6fb8c
-	if (!(fp = fopen(file, "r"))) {
b6fb8c
-		log_sys_error("fopen", file);
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	r = _parse_dev(file, fp, result);
b6fb8c
-
b6fb8c
-	if (fclose(fp))
b6fb8c
-		log_sys_error("fclose", file);
b6fb8c
-
b6fb8c
-	return r;
b6fb8c
-}
b6fb8c
-
b6fb8c
-/*
b6fb8c
- * Recurse through sysfs directories, inserting any devs found.
b6fb8c
- */
b6fb8c
-static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth)
b6fb8c
-{
b6fb8c
-	struct dirent *d;
b6fb8c
-	DIR *dr;
b6fb8c
-	struct stat info;
b6fb8c
-	char path[PATH_MAX];
b6fb8c
-	char file[PATH_MAX];
b6fb8c
-	dev_t dev = { 0 };
b6fb8c
-	int r = 1;
b6fb8c
-
b6fb8c
-	if (!(dr = opendir(dir))) {
b6fb8c
-		log_sys_error("opendir", dir);
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	while ((d = readdir(dr))) {
b6fb8c
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
b6fb8c
-			continue;
b6fb8c
-
b6fb8c
-		if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
b6fb8c
-				 d->d_name) < 0) {
b6fb8c
-			log_warn("WARNING: sysfs path name too long: %s in %s.",
b6fb8c
-				 d->d_name, dir);
b6fb8c
-			continue;
b6fb8c
 		}
b6fb8c
 
b6fb8c
-		/* devices have a "dev" file */
b6fb8c
-		if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) {
b6fb8c
-			log_warn("WARNING: sysfs path name too long: %s in %s.",
b6fb8c
-				 d->d_name, dir);
b6fb8c
-			continue;
b6fb8c
-		}
b6fb8c
-
b6fb8c
-		if (!stat(file, &info)) {
b6fb8c
-			/* recurse if we found a device and expect subdirs */
b6fb8c
-			if (sysfs_depth)
b6fb8c
-				_read_devs(ds, path, sysfs_depth - 1);
b6fb8c
-
b6fb8c
-			/* add the device we have found */
b6fb8c
-			if (_read_dev(file, &dev))
b6fb8c
-				_set_insert(ds, dev);
b6fb8c
+		if (lstat(path, &info)) {
b6fb8c
+			log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
b6fb8c
+			dev->filtered_flags |= DEV_FILTERED_SYSFS;
b6fb8c
+			return 0;
b6fb8c
 		}
b6fb8c
 	}
b6fb8c
 
b6fb8c
-	if (closedir(dr))
b6fb8c
-		log_sys_debug("closedir", dir);
b6fb8c
-
b6fb8c
-	return r;
b6fb8c
-}
b6fb8c
-
b6fb8c
-static int _init_devs(struct dev_set *ds)
b6fb8c
-{
b6fb8c
-	if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) {
b6fb8c
-		ds->initialised = -1;
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	ds->initialised = 1;
b6fb8c
-
b6fb8c
-	return 1;
b6fb8c
-}
b6fb8c
-
b6fb8c
-
b6fb8c
-static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
b6fb8c
-{
b6fb8c
-	struct dev_set *ds = (struct dev_set *) f->private;
b6fb8c
-
b6fb8c
-	dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
b6fb8c
-
b6fb8c
-	if (!ds->initialised)
b6fb8c
-		_init_devs(ds);
b6fb8c
-
b6fb8c
-	/* Pass through if initialisation failed */
b6fb8c
-	if (ds->initialised != 1)
b6fb8c
-		return 1;
b6fb8c
-
b6fb8c
-	if (!_set_lookup(ds, dev->dev)) {
b6fb8c
-		log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
b6fb8c
-		dev->filtered_flags |= DEV_FILTERED_SYSFS;
b6fb8c
-		return 0;
b6fb8c
-	}
b6fb8c
-
b6fb8c
 	return 1;
b6fb8c
 }
b6fb8c
 
b6fb8c
 static void _destroy(struct dev_filter *f)
b6fb8c
 {
b6fb8c
-	struct dev_set *ds = (struct dev_set *) f->private;
b6fb8c
-
b6fb8c
 	if (f->use_count)
b6fb8c
 		log_error(INTERNAL_ERROR "Destroying sysfs filter while in use %u times.", f->use_count);
b6fb8c
-
b6fb8c
-	dm_pool_destroy(ds->mem);
b6fb8c
+	free(f);
b6fb8c
 }
b6fb8c
 
b6fb8c
 struct dev_filter *sysfs_filter_create(void)
b6fb8c
 {
b6fb8c
 	const char *sysfs_dir = dm_sysfs_dir();
b6fb8c
-	char sys_block[PATH_MAX];
b6fb8c
-	unsigned sysfs_depth;
b6fb8c
-	struct dm_pool *mem;
b6fb8c
-	struct dev_set *ds;
b6fb8c
 	struct dev_filter *f;
b6fb8c
 
b6fb8c
 	if (!*sysfs_dir) {
b6fb8c
@@ -306,26 +67,12 @@ struct dev_filter *sysfs_filter_create(void)
b6fb8c
 		return NULL;
b6fb8c
 	}
b6fb8c
 
b6fb8c
-	if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
b6fb8c
-		return NULL;
b6fb8c
-
b6fb8c
-	if (!(mem = dm_pool_create("sysfs", 256))) {
b6fb8c
-		log_error("sysfs pool creation failed");
b6fb8c
-		return NULL;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) {
b6fb8c
-		log_error("sysfs dev_set creation failed");
b6fb8c
-		goto bad;
b6fb8c
-	}
b6fb8c
-
b6fb8c
-	if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
b6fb8c
+	if (!(f = zalloc(sizeof(*f))))
b6fb8c
 		goto_bad;
b6fb8c
 
b6fb8c
 	f->passes_filter = _accept_p;
b6fb8c
 	f->destroy = _destroy;
b6fb8c
 	f->use_count = 0;
b6fb8c
-	f->private = ds;
b6fb8c
 	f->name = "sysfs";
b6fb8c
 
b6fb8c
 	log_debug_devs("Sysfs filter initialised.");
b6fb8c
@@ -333,7 +80,6 @@ struct dev_filter *sysfs_filter_create(void)
b6fb8c
 	return f;
b6fb8c
 
b6fb8c
  bad:
b6fb8c
-	dm_pool_destroy(mem);
b6fb8c
 	return NULL;
b6fb8c
 }
b6fb8c
 
b6fb8c
-- 
38b7b2
2.34.3
b6fb8c