1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-03 17:50:03 +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/device/dev-type.h"
#include "lib/device/device_id.h"
#include "lib/datastruct/btree.h"
#include "lib/config/config.h"
#include "lib/commands/toolcontext.h"
#include "device_mapper/misc/dm-ioctl.h"
@ -37,8 +36,10 @@
#include <sys/file.h>
struct dev_iter {
struct btree_iter *current;
union radix_value *values;
struct dev_filter *filter;
unsigned nr_values;
unsigned pos;
};
struct dir_list {
@ -53,8 +54,8 @@ static struct {
struct dm_hash_table *lvid_index;
struct radix_tree *dm_uuids;
struct radix_tree *dm_devnos;
struct btree *sysfs_only_devices; /* see comments in _get_device_for_sysfs_dev_name_using_devno */
struct btree *devices;
struct radix_tree *sysfs_only_devices; /* see comments in _get_device_for_sysfs_dev_name_using_devno */
struct radix_tree *devices;
struct dm_regex *preferred_names_matcher;
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;
}
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 _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;
}
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.");
_free(dev);
return NULL;
@ -547,7 +563,7 @@ static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *dev
}
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.
* 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
* 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)))
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_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 = dev_by_devt;
@ -775,14 +791,12 @@ static int _insert_dev(const char *path, dev_t d)
*/
if (!dev_by_devt && !dev_by_path) {
log_debug_devs("Found dev %u:%u %s - new.", MAJOR(d), MINOR(d), path);
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 */
if (!(dev = _dev_create(d)))
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.");
_free(dev);
return 0;
@ -815,13 +829,13 @@ static int _insert_dev(const char *path, dev_t d)
MAJOR(d), MINOR(d), path,
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 */
if (!(dev = _dev_create(d)))
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.");
_free(dev);
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)
{
struct btree_iter *iter = btree_first(_cache.devices);
struct device *dev;
struct dev_iter *iter = dev_iter_create(NULL, 0);
struct device *dev = NULL;
int r = 1;
while (iter) {
dev = btree_get_data(iter);
while ((dev = dev_iter_get(NULL, iter)))
if (!_index_dev_by_vgid_and_lvid(cmd, dev))
r = 0;
iter = btree_next(iter);
}
return r;
}
@ -987,8 +996,8 @@ static int _dev_cache_iterate_sysfs_for_index(struct cmd_context *cmd, const cha
}
devno = MKDEV(major, minor);
if (!(dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devno)) &&
!(dev = (struct device *) btree_lookup(_cache.sysfs_only_devices, (uint32_t) devno))) {
if (!(dev = _dev_cache_get_dev_by_devno(_cache.devices, devno)) &&
!(dev = _dev_cache_get_dev_by_devno(_cache.sysfs_only_devices, devno))) {
if (!dm_device_get_name(major, minor, 1, devname, sizeof(devname)) ||
!(dev = _insert_sysfs_dev(devno, devname))) {
partial_failure = 1;
@ -1402,12 +1411,12 @@ int dev_cache_init(struct cmd_context *cmd)
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.");
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.");
goto bad;
}
@ -1496,6 +1505,12 @@ int dev_cache_exit(void)
if (_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));
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.
*/
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
@ -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
* 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) {
log_debug("Dropping aliases for %u:%u before adding new path %s.",
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 = (struct device *) btree_lookup(_cache.devices, (uint32_t) devt);
struct device *dev = _dev_cache_get_dev_by_devno(_cache.devices, devt);
if (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 btree_iter *iter = btree_first(_cache.devices);
struct dev_iter *iter = dev_iter_create(NULL, 0);
struct device *dev;
while (iter) {
dev = btree_get_data(iter);
while ((dev = dev_iter_get(NULL, iter)))
if (!memcmp(dev->pvid, pvid, ID_LEN))
return dev;
break;
iter = btree_next(iter);
}
dev_iter_destroy(iter);
return NULL;
return dev;
}
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));
if (!di) {
log_error("dev_iter allocation failed");
log_error("dev_iter allocation failed.");
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;
if (di->filter)
di->filter->use_count++;
@ -1819,28 +1839,23 @@ void dev_iter_destroy(struct dev_iter *iter)
{
if (iter->filter)
iter->filter->use_count--;
free(iter->values);
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 dev_filter *f;
struct device *d;
int ret;
while (iter->current) {
struct device *d = _iter_next(iter);
while (iter->pos < iter->nr_values) {
d = iter->values[iter->pos++].ptr;
ret = 1;
f = iter->filter;
if (f && !(d->flags & DEV_REGULAR))
if (f && cmd && !(d->flags & DEV_REGULAR))
ret = f->passes_filter(cmd, f, d, NULL);
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)
{
struct btree_iter *iter = btree_first(_cache.devices);
struct device *dev;
struct dev_iter *iter = dev_iter_create(NULL, 0);
bool ret = false;
while (iter) {
dev = btree_get_data(iter);
while ((dev = dev_iter_get(NULL, iter)))
if ((ret = dev_is_md_with_end_superblock(dt, dev)))
break;
if (dev_is_md_with_end_superblock(dt, dev))
return true;
dev_iter_destroy(iter);
iter = btree_next(iter);
}
return false;
return ret;
}
static int _setup_devices_list(struct cmd_context *cmd)