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

dev-cache: replace btree with radix_tree usage

Instead of less efficient 'btree' switch dev_cache to use
radix_tree, that is generating more efficient tree mapping.

Some direct use of btree iteration replace with our dev_iter code.
This commit is contained in:
Zdenek Kabelac 2024-06-19 13:09:45 +02:00
parent 4b126fd953
commit e0537559c6

View File

@ -18,7 +18,6 @@
#include "lib/misc/lib.h" #include "lib/misc/lib.h"
#include "lib/device/dev-type.h" #include "lib/device/dev-type.h"
#include "lib/device/device_id.h" #include "lib/device/device_id.h"
#include "lib/datastruct/btree.h"
#include "lib/config/config.h" #include "lib/config/config.h"
#include "lib/commands/toolcontext.h" #include "lib/commands/toolcontext.h"
#include "device_mapper/misc/dm-ioctl.h" #include "device_mapper/misc/dm-ioctl.h"
@ -37,8 +36,10 @@
#include <sys/file.h> #include <sys/file.h>
struct dev_iter { struct dev_iter {
struct btree_iter *current; union radix_value *values;
struct dev_filter *filter; struct dev_filter *filter;
unsigned nr_values;
unsigned pos;
}; };
struct dir_list { struct dir_list {
@ -53,8 +54,8 @@ static struct {
struct dm_hash_table *lvid_index; struct dm_hash_table *lvid_index;
struct radix_tree *dm_uuids; struct radix_tree *dm_uuids;
struct radix_tree *dm_devnos; struct radix_tree *dm_devnos;
struct btree *sysfs_only_devices; /* see comments in _get_device_for_sysfs_dev_name_using_devno */ struct radix_tree *sysfs_only_devices; /* see comments in _get_device_for_sysfs_dev_name_using_devno */
struct btree *devices; struct radix_tree *devices;
struct dm_regex *preferred_names_matcher; struct dm_regex *preferred_names_matcher;
const char *dev_dir; const char *dev_dir;
@ -489,6 +490,21 @@ static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx,
return list; return list;
} }
static bool _dev_cache_insert_devno(struct radix_tree *rt, dev_t devno, void *dev)
{
union radix_value v = { .ptr = dev };
uint32_t key = _shuffle_devno(devno);
return radix_tree_insert(rt, &key, sizeof(key), v);
}
static struct device *_dev_cache_get_dev_by_devno(struct radix_tree *rt, dev_t devno)
{
uint32_t key = _shuffle_devno(devno);
return radix_tree_lookup_ptr(rt, &key, sizeof(key));
}
static struct device *_insert_sysfs_dev(dev_t devno, const char *devname) static struct device *_insert_sysfs_dev(dev_t devno, const char *devname)
{ {
static struct device _fake_dev = { .flags = DEV_USED_FOR_LV }; static struct device _fake_dev = { .flags = DEV_USED_FOR_LV };
@ -516,7 +532,7 @@ static struct device *_insert_sysfs_dev(dev_t devno, const char *devname)
return_NULL; return_NULL;
} }
if (!btree_insert(_cache.sysfs_only_devices, (uint32_t) devno, dev)) { if (!_dev_cache_insert_devno(_cache.sysfs_only_devices, devno, dev)) {
log_error("Couldn't add device to binary tree of sysfs-only devices in dev cache."); log_error("Couldn't add device to binary tree of sysfs-only devices in dev cache.");
_free(dev); _free(dev);
return NULL; return NULL;
@ -547,7 +563,7 @@ static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *dev
} }
devno = MKDEV(major, minor); devno = MKDEV(major, minor);
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devno))) { if (!(dev = _dev_cache_get_dev_by_devno(_cache.devices, devno))) {
/* /*
* If we get here, it means the device is referenced in sysfs, but it's not yet in /dev. * If we get here, it means the device is referenced in sysfs, but it's not yet in /dev.
* This may happen in some rare cases right after LVs get created - we sync with udev * This may happen in some rare cases right after LVs get created - we sync with udev
@ -559,7 +575,7 @@ static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *dev
* where different directory for dev nodes is used (e.g. our test suite). So track * where different directory for dev nodes is used (e.g. our test suite). So track
* such devices in _cache.sysfs_only_devices hash for the vgid/lvid check to work still. * such devices in _cache.sysfs_only_devices hash for the vgid/lvid check to work still.
*/ */
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) devno)) && if (!(dev = _dev_cache_get_dev_by_devno(_cache.sysfs_only_devices, devno)) &&
!(dev = _insert_sysfs_dev(devno, devname))) !(dev = _insert_sysfs_dev(devno, devname)))
return_NULL; return_NULL;
} }
@ -757,7 +773,7 @@ static int _insert_dev(const char *path, dev_t d)
struct device *dev_by_devt; struct device *dev_by_devt;
struct device *dev_by_path; struct device *dev_by_path;
dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) d); dev_by_devt = _dev_cache_get_dev_by_devno(_cache.devices, d);
dev_by_path = (struct device *) dm_hash_lookup(_cache.names, path); dev_by_path = (struct device *) dm_hash_lookup(_cache.names, path);
dev = dev_by_devt; dev = dev_by_devt;
@ -775,14 +791,12 @@ static int _insert_dev(const char *path, dev_t d)
*/ */
if (!dev_by_devt && !dev_by_path) { if (!dev_by_devt && !dev_by_path) {
log_debug_devs("Found dev %u:%u %s - new.", MAJOR(d), MINOR(d), path); log_debug_devs("Found dev %u:%u %s - new.", MAJOR(d), MINOR(d), path);
if (!(dev = _dev_cache_get_dev_by_devno(_cache.sysfs_only_devices, d)))
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) d))) {
/* create new device */ /* create new device */
if (!(dev = _dev_create(d))) if (!(dev = _dev_create(d)))
return_0; return_0;
}
if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) { if (!(_dev_cache_insert_devno(_cache.devices, d, dev))) {
log_error("Couldn't insert device into binary tree."); log_error("Couldn't insert device into binary tree.");
_free(dev); _free(dev);
return 0; return 0;
@ -815,13 +829,13 @@ static int _insert_dev(const char *path, dev_t d)
MAJOR(d), MINOR(d), path, MAJOR(d), MINOR(d), path,
MAJOR(dev_by_path->dev), MINOR(dev_by_path->dev)); MAJOR(dev_by_path->dev), MINOR(dev_by_path->dev));
if (!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) d))) { if (!(dev = _dev_cache_get_dev_by_devno(_cache.sysfs_only_devices, d))) {
/* create new device */ /* create new device */
if (!(dev = _dev_create(d))) if (!(dev = _dev_create(d)))
return_0; return_0;
} }
if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) { if (!(_dev_cache_insert_devno(_cache.devices, d, dev))) {
log_error("Couldn't insert device into binary tree."); log_error("Couldn't insert device into binary tree.");
_free(dev); _free(dev);
return 0; return 0;
@ -942,19 +956,14 @@ static int _insert_dir(const char *dir)
static int _dev_cache_iterate_devs_for_index(struct cmd_context *cmd) static int _dev_cache_iterate_devs_for_index(struct cmd_context *cmd)
{ {
struct btree_iter *iter = btree_first(_cache.devices); struct dev_iter *iter = dev_iter_create(NULL, 0);
struct device *dev; struct device *dev = NULL;
int r = 1; int r = 1;
while (iter) { while ((dev = dev_iter_get(NULL, iter)))
dev = btree_get_data(iter);
if (!_index_dev_by_vgid_and_lvid(cmd, dev)) if (!_index_dev_by_vgid_and_lvid(cmd, dev))
r = 0; r = 0;
iter = btree_next(iter);
}
return r; return r;
} }
@ -987,8 +996,8 @@ static int _dev_cache_iterate_sysfs_for_index(struct cmd_context *cmd, const cha
} }
devno = MKDEV(major, minor); devno = MKDEV(major, minor);
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devno)) && if (!(dev = _dev_cache_get_dev_by_devno(_cache.devices, devno)) &&
!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) devno))) { !(dev = _dev_cache_get_dev_by_devno(_cache.sysfs_only_devices, devno))) {
if (!dm_device_get_name(major, minor, 1, devname, sizeof(devname)) || if (!dm_device_get_name(major, minor, 1, devname, sizeof(devname)) ||
!(dev = _insert_sysfs_dev(devno, devname))) { !(dev = _insert_sysfs_dev(devno, devname))) {
partial_failure = 1; partial_failure = 1;
@ -1402,12 +1411,12 @@ int dev_cache_init(struct cmd_context *cmd)
return_0; return_0;
} }
if (!(_cache.devices = btree_create(_cache.mem))) { if (!(_cache.devices = radix_tree_create(NULL, NULL))) {
log_error("Couldn't create binary tree for dev-cache."); log_error("Couldn't create binary tree for dev-cache.");
goto bad; goto bad;
} }
if (!(_cache.sysfs_only_devices = btree_create(_cache.mem))) { if (!(_cache.sysfs_only_devices = radix_tree_create(NULL, NULL))) {
log_error("Couldn't create binary tree for sysfs-only devices in dev cache."); log_error("Couldn't create binary tree for sysfs-only devices in dev cache.");
goto bad; goto bad;
} }
@ -1496,6 +1505,12 @@ int dev_cache_exit(void)
if (_cache.dm_uuids) if (_cache.dm_uuids)
radix_tree_destroy(_cache.dm_uuids); radix_tree_destroy(_cache.dm_uuids);
if (_cache.devices)
radix_tree_destroy(_cache.devices);
if (_cache.sysfs_only_devices)
radix_tree_destroy(_cache.sysfs_only_devices);
memset(&_cache, 0, sizeof(_cache)); memset(&_cache, 0, sizeof(_cache));
return (!num_open); return (!num_open);
@ -1627,7 +1642,7 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
* Remove incorrect info and then add new dev-cache entry. * Remove incorrect info and then add new dev-cache entry.
*/ */
if (dev && (st.st_rdev != dev->dev)) { if (dev && (st.st_rdev != dev->dev)) {
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev); struct device *dev_by_devt = _dev_cache_get_dev_by_devno(_cache.devices, st.st_rdev);
/* /*
* lvm commands create this condition when they * lvm commands create this condition when they
@ -1713,7 +1728,8 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
* Without dropping the aliases, it's plausible that lvm commands * Without dropping the aliases, it's plausible that lvm commands
* could end up using the wrong dm device. * could end up using the wrong dm device.
*/ */
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev); struct device *dev_by_devt = _dev_cache_get_dev_by_devno(_cache.devices, st.st_rdev);
if (dev_by_devt) { if (dev_by_devt) {
log_debug("Dropping aliases for %u:%u before adding new path %s.", log_debug("Dropping aliases for %u:%u before adding new path %s.",
MAJOR(st.st_rdev), MINOR(st.st_rdev), name); MAJOR(st.st_rdev), MINOR(st.st_rdev), name);
@ -1773,7 +1789,7 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt) struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt)
{ {
struct device *dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devt); struct device *dev = _dev_cache_get_dev_by_devno(_cache.devices, devt);
if (dev) if (dev)
return dev; return dev;
@ -1783,19 +1799,16 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt)
struct device *dev_cache_get_by_pvid(struct cmd_context *cmd, const char *pvid) struct device *dev_cache_get_by_pvid(struct cmd_context *cmd, const char *pvid)
{ {
struct btree_iter *iter = btree_first(_cache.devices); struct dev_iter *iter = dev_iter_create(NULL, 0);
struct device *dev; struct device *dev;
while (iter) { while ((dev = dev_iter_get(NULL, iter)))
dev = btree_get_data(iter);
if (!memcmp(dev->pvid, pvid, ID_LEN)) if (!memcmp(dev->pvid, pvid, ID_LEN))
break;
dev_iter_destroy(iter);
return dev; return dev;
iter = btree_next(iter);
}
return NULL;
} }
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused) struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
@ -1803,11 +1816,18 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
struct dev_iter *di = malloc(sizeof(*di)); struct dev_iter *di = malloc(sizeof(*di));
if (!di) { if (!di) {
log_error("dev_iter allocation failed"); log_error("dev_iter allocation failed.");
return NULL; return NULL;
} }
di->current = btree_first(_cache.devices); if (!radix_tree_values(_cache.devices, NULL, 0,
&di->values, &di->nr_values)) {
log_error("dev_iter values allocation failed.");
free(di);
return NULL;
}
di->pos = 0;
di->filter = f; di->filter = f;
if (di->filter) if (di->filter)
di->filter->use_count++; di->filter->use_count++;
@ -1819,28 +1839,23 @@ void dev_iter_destroy(struct dev_iter *iter)
{ {
if (iter->filter) if (iter->filter)
iter->filter->use_count--; iter->filter->use_count--;
free(iter->values);
free(iter); free(iter);
} }
static struct device *_iter_next(struct dev_iter *iter)
{
struct device *d = btree_get_data(iter->current);
iter->current = btree_next(iter->current);
return d;
}
struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter) struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter)
{ {
struct dev_filter *f; struct dev_filter *f;
struct device *d;
int ret; int ret;
while (iter->current) { while (iter->pos < iter->nr_values) {
struct device *d = _iter_next(iter); d = iter->values[iter->pos++].ptr;
ret = 1; ret = 1;
f = iter->filter; f = iter->filter;
if (f && !(d->flags & DEV_REGULAR)) if (f && cmd && !(d->flags & DEV_REGULAR))
ret = f->passes_filter(cmd, f, d, NULL); ret = f->passes_filter(cmd, f, d, NULL);
if (!f || (d->flags & DEV_REGULAR) || ret) if (!f || (d->flags & DEV_REGULAR) || ret)
@ -1865,19 +1880,17 @@ const char *dev_name(const struct device *dev)
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt) bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
{ {
struct btree_iter *iter = btree_first(_cache.devices);
struct device *dev; struct device *dev;
struct dev_iter *iter = dev_iter_create(NULL, 0);
bool ret = false;
while (iter) { while ((dev = dev_iter_get(NULL, iter)))
dev = btree_get_data(iter); if ((ret = dev_is_md_with_end_superblock(dt, dev)))
break;
if (dev_is_md_with_end_superblock(dt, dev)) dev_iter_destroy(iter);
return true;
iter = btree_next(iter); return ret;
}
return false;
} }
static int _setup_devices_list(struct cmd_context *cmd) static int _setup_devices_list(struct cmd_context *cmd)