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

device_mapper: refactor code to lvm library

Move the code around caching active dm device devno, name and uuid
from device_mapper/libdm-iface to dev_cache file - as libdm layer
cares about 'decoding' ioctl data from kernel and caching for use by
lvm stays within lvm.

Introduce:
dev_cache_update_dm_devs
dev_cache_get_dm_dev_by_devno
dev_cache_get_dm_dev_by_uuid

Use radix_tree for searching.
This commit is contained in:
Zdenek Kabelac 2024-06-02 23:10:05 +02:00
parent 14f782c5a7
commit e30bc9b179
6 changed files with 116 additions and 147 deletions

View File

@ -175,8 +175,7 @@ struct dm_names {
struct dm_active_device {
struct dm_list list;
uint32_t major;
uint32_t minor;
dev_t devno;
char *name; /* device name */
uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
@ -230,16 +229,6 @@ struct dm_names *dm_task_get_names(struct dm_task *dmt);
#define DM_DEVICE_LIST_HAS_UUID 2
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features);
/*
* -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
* 0: uuid not present
* 1: listed and dm_active_device will be set for not NULL pointer
*/
int dm_device_list_find_by_uuid(const struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev);
int dm_device_list_find_by_dev(const struct dm_list *devs_list,
uint32_t major, uint32_t minor,
const char **name, const char **uuid);
/* Release all associated memory with list of active DM devices */
void dm_device_list_destroy(struct dm_list **devs_list);

View File

@ -782,46 +782,17 @@ static int _check_has_event_nr(void) {
return _has_event_nr;
}
struct dm_device_list {
struct dm_list list;
unsigned count;
unsigned features;
struct dm_hash_table *uuids;
/* As last element (sized according to count), pointers to individual dm_devs */
struct dm_active_device *sorted[]; /* For bsearch() devs sorted by device node */
};
/*
* Comparing 2 dev nodes by its minor.
*
* TODO: enhance if DM would ever use multiple major:minor...
*/
static int _dm_dev_compare(const void *p1, const void *p2)
{
int m1 = (*(struct dm_active_device **)p1)->minor;
int m2 = (*(struct dm_active_device **)p2)->minor;
if (m1 > m2)
return 1;
if (m1 < m2)
return -1;
return 0;
}
int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
unsigned *devs_features)
{
struct dm_names *names, *names1;
struct dm_active_device *dm_dev, *dm_new_dev;
struct dm_device_list *devs;
struct dm_list *devs;
unsigned next = 0;
uint32_t *event_nr;
char *uuid_ptr;
size_t len;
int cnt = 0;
unsigned index = 0;
*devs_list = 0;
*devs_features = 0;
@ -839,12 +810,10 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
/* buffer for devs + sorted ptrs + dm_devs + aligned strings */
if (!(devs = malloc(sizeof(*devs) + cnt * (2 * sizeof(void*) + sizeof(*dm_dev)) +
(!cnt ? 0 : (char*)names1 - (char*)names + 256))))
(cnt ? (char*)names1 - (char*)names + 256 : 0))))
return_0;
dm_list_init(&devs->list);
devs->count = cnt;
devs->uuids = NULL;
dm_list_init(devs);
if (!cnt) {
/* nothing in the list -> mark all features present */
@ -858,9 +827,7 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
do {
names = (struct dm_names *)((char *) names + next);
devs->sorted[index++] = dm_dev;
dm_dev->major = MAJOR(names->dev);
dm_dev->minor = MINOR(names->dev);
dm_dev->devno = (dev_t) names->dev;
dm_dev->name = (char*)(dm_dev + 1);
dm_dev->event_nr = 0;
dm_dev->uuid = NULL;
@ -870,11 +837,6 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
if (_check_has_event_nr()) {
/* Hash for UUIDs with some more bits to reduce colision count */
if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
free(devs);
return_0;
}
*devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
event_nr = _align_ptr(names->name + len);
@ -887,97 +849,25 @@ int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
len = strlen(uuid_ptr) + 1;
dm_new_dev = _align_ptr((char*)dm_new_dev + len);
memcpy(dm_dev->uuid, uuid_ptr, len);
if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
return_0; // FIXME
#if 0
log_debug("Active %s (%s) %u:%u event:%u",
dm_dev->name, dm_dev->uuid,
dm_dev->major, dm_dev->minor, dm_dev->event_nr);
#endif
}
}
dm_list_add(&devs->list, &dm_dev->list);
dm_list_add(devs, &dm_dev->list);
dm_dev = dm_new_dev;
next = names->next;
} while (next);
out:
*devs_list = (struct dm_list *)devs;
/* sort by minors */
qsort(devs->sorted, devs->count, sizeof(void*), _dm_dev_compare);
#if 0
for (int i = 0; i < index; ++i) /* check order */
log_debug("DM devices: minor=%d name=%s uuid=%s",
devs->sorted[i]->minor, devs->sorted[i]->name,
devs->sorted[i]->uuid);
#endif
*devs_list = devs;
return 1;
}
int dm_device_list_find_by_uuid(const struct dm_list *devs_list, const char *uuid,
const struct dm_active_device **dev)
{
const struct dm_device_list *devs = (const struct dm_device_list *) devs_list;
const struct dm_active_device *dm_dev;
if (devs->uuids &&
(dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
if (dev)
*dev = dm_dev;
return 1;
}
return 0;
}
/*
* Find DM device in devs array for given major:minor.
* ATM assuming all DM devices use the single known major.
*
* NOTE:
* When major:minor is found, the 'name' and 'uuid' pointers
* are return as const string pointing to devs structure.
* Once the dm_device_list structure is destroyed
* those pointers become invalid!
*/
int dm_device_list_find_by_dev(const struct dm_list *devs_list,
uint32_t major, uint32_t minor,
const char **name, const char **uuid)
{
const struct dm_device_list *devs = (const struct dm_device_list *) devs_list;
const struct dm_active_device search = { .major = major, .minor = minor };
const struct dm_active_device *findme[] = { &search };
const struct dm_active_device **dm_dev_found;
const char *fname = NULL, *fuuid = NULL;
int ret = 0;
/* Prefer bsearch O(logN) over linear list scanning O(N) */
if ((dm_dev_found = bsearch(findme, devs->sorted, devs->count, sizeof(void*),
_dm_dev_compare))) {
fname = (*dm_dev_found)->name;
fuuid = (*dm_dev_found)->uuid ? : ""; /* Device without UUID */
ret = 1;
}
if (name)
*name = fname;
if (uuid)
*uuid = fuuid;
return ret;
}
void dm_device_list_destroy(struct dm_list **devs_list)
{
struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
if (devs) {
if (devs->uuids)
dm_hash_destroy(devs->uuids);
free(devs);
*devs_list = NULL;
}

View File

@ -886,12 +886,13 @@ int device_get_uuid(struct cmd_context *cmd, int major, int minor,
{
struct dm_task *dmt;
struct dm_info info;
const struct dm_active_device *dm_dev;
const char *uuid;
int r = 0;
if (cmd->cache_dm_devs) {
if (dm_device_list_find_by_dev(cmd->cache_dm_devs, major, minor, NULL, &uuid)) {
dm_strncpy(uuid_buf, uuid, uuid_buf_size);
if ((dm_dev = dev_cache_get_dm_dev_by_devno(cmd, MKDEV(major, minor)))) {
dm_strncpy(uuid_buf, dm_dev->uuid, uuid_buf_size);
return 1;
}
uuid_buf[0] = 0;
@ -1066,8 +1067,8 @@ int dev_manager_info(struct cmd_context *cmd,
dm_strncpy(old_style_dlid, dlid, sizeof(old_style_dlid));
if (cmd->cache_dm_devs &&
!dm_device_list_find_by_uuid(cmd->cache_dm_devs, dlid, NULL) &&
!dm_device_list_find_by_uuid(cmd->cache_dm_devs, old_style_dlid, NULL)) {
!dev_cache_get_dm_dev_by_uuid(cmd, dlid) &&
!dev_cache_get_dm_dev_by_uuid(cmd, old_style_dlid)) {
log_debug("Cached as inactive %s.", name);
if (dminfo)
memset(dminfo, 0, sizeof(*dminfo));
@ -2431,7 +2432,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
{
char *dlid, *name;
struct dm_info info, info2;
const struct dm_active_device *dev;
const struct dm_active_device *dm_dev;
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
return_0;
@ -2440,14 +2441,14 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
if (dm->cmd->cache_dm_devs) {
if (!dm_device_list_find_by_uuid(dm->cmd->cache_dm_devs, dlid, &dev)) {
if (!(dm_dev = dev_cache_get_dm_dev_by_uuid(dm->cmd, dlid))) {
log_debug("Cached as not present %s.", name);
return 1;
}
info = (struct dm_info) {
.exists = 1,
.major = dev->major,
.minor = dev->minor,
.major = MAJOR(dm_dev->devno),
.minor = MINOR(dm_dev->devno),
};
log_debug("Cached as present %s %s (%d:%d).",
name, dlid, info.major, info.minor);

View File

@ -14,6 +14,7 @@
*/
#include "base/memory/zalloc.h"
#include "base/data-struct/radix-tree.h"
#include "lib/misc/lib.h"
#include "lib/device/dev-type.h"
#include "lib/device/device_id.h"
@ -23,6 +24,7 @@
#include "device_mapper/misc/dm-ioctl.h"
#include "lib/activate/activate.h"
#include "lib/misc/lvm-string.h"
#include "lib/mm/xlate.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
@ -49,6 +51,8 @@ static struct {
struct dm_hash_table *names;
struct dm_hash_table *vgid_index;
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 dm_regex *preferred_names_matcher;
@ -454,6 +458,15 @@ out:
return r;
}
/* Change bit ordering for devno to generate more compact bTree */
static inline uint32_t _shuffle_devno(dev_t d)
{
return cpu_to_be32(d);
//return (d & 0xff) << 24 | (d & 0xff00) << 8 | (d & 0xff0000) >> 8 | (d & 0xff000000) >> 24;
//return (d & 0xff000000) >> 24 | (d & 0xffff00) | ((d & 0xff) << 24);
//return (uint32_t) d;
}
static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx, const char *key)
{
struct dm_list *list;
@ -1303,6 +1316,77 @@ out:
return r;
}
int dev_cache_update_dm_devs(struct cmd_context *cmd)
{
struct dm_active_device *dm_dev;
unsigned devs_features;
uint32_t d;
dm_device_list_destroy(&cmd->cache_dm_devs);
if (_cache.dm_devnos) {
radix_tree_destroy(_cache.dm_devnos);
_cache.dm_devnos = NULL;
}
if (_cache.dm_uuids) {
radix_tree_destroy(_cache.dm_uuids);
_cache.dm_uuids = NULL;
}
if (!get_device_list(NULL, &cmd->cache_dm_devs, &devs_features))
return 1;
if (!(devs_features & DM_DEVICE_LIST_HAS_UUID)) {
/* Cache unusable with older kernels without UUIDs in LIST */
dm_device_list_destroy(&cmd->cache_dm_devs);
return 1;
}
if (!(_cache.dm_devnos = radix_tree_create(NULL, NULL)) ||
!(_cache.dm_uuids = radix_tree_create(NULL, NULL))) {
return_0; // FIXME
}
/* Insert every active DM device into radix trees */
dm_list_iterate_items(dm_dev, cmd->cache_dm_devs) {
d = _shuffle_devno(dm_dev->devno);
if (!radix_tree_insert_ptr(_cache.dm_devnos, &d, sizeof(d), dm_dev))
return_0;
if (!radix_tree_insert_ptr(_cache.dm_uuids, dm_dev->uuid, strlen(dm_dev->uuid), dm_dev))
return_0;
}
//radix_tree_dump(_cache.dm_devnos, stdout);
//radix_tree_dump(_cache.dm_uuids, stdout);
return 1;
}
/* Find active DM device in devs array for given major:minor */
const struct dm_active_device *
dev_cache_get_dm_dev_by_devno(struct cmd_context *cmd, dev_t devno)
{
uint32_t d = _shuffle_devno(devno);
if (!_cache.dm_devnos)
return NULL;
return radix_tree_lookup_ptr(_cache.dm_devnos, &d, sizeof(d));
}
/* Find active DM device in devs array for given DM UUID */
const struct dm_active_device *
dev_cache_get_dm_dev_by_uuid(struct cmd_context *cmd, const char *dm_uuid)
{
if (!_cache.dm_uuids)
return NULL;
return radix_tree_lookup_ptr(_cache.dm_uuids, dm_uuid, strlen(dm_uuid));
}
int dev_cache_init(struct cmd_context *cmd)
{
_cache.names = NULL;
@ -1406,6 +1490,12 @@ int dev_cache_exit(void)
if (_cache.lvid_index)
dm_hash_destroy(_cache.lvid_index);
if (_cache.dm_devnos)
radix_tree_destroy(_cache.dm_devnos);
if (_cache.dm_uuids)
radix_tree_destroy(_cache.dm_uuids);
memset(&_cache, 0, sizeof(_cache));
return (!num_open);

View File

@ -37,6 +37,12 @@ struct dev_filter {
struct dm_list *dev_cache_get_dev_list_for_vgid(const char *vgid);
struct dm_list *dev_cache_get_dev_list_for_lvid(const char *lvid);
int dev_cache_update_dm_devs(struct cmd_context *cmd);
const struct dm_active_device *
dev_cache_get_dm_dev_by_devno(struct cmd_context *cmd, dev_t devno);
const struct dm_active_device *
dev_cache_get_dm_dev_by_uuid(struct cmd_context *cmd, const char *dm_uuid);
/*
* The global device cache.
*/

View File

@ -1259,7 +1259,6 @@ int label_scan(struct cmd_context *cmd)
uint64_t max_metadata_size_bytes;
int using_hints;
int create_hints = 0; /* NEWHINTS_NONE */
unsigned devs_features = 0;
log_debug_devs("Finding devices to scan");
@ -1271,14 +1270,10 @@ int label_scan(struct cmd_context *cmd)
if (!label_scan_setup_bcache())
return_0;
/* Initialize device_list cache early so
/* Initialize dm device cache early so
* 'Hints' file processing can also use it */
dm_device_list_destroy(&cmd->cache_dm_devs);
if (get_device_list(NULL, &cmd->cache_dm_devs, &devs_features))
if (!(devs_features & DM_DEVICE_LIST_HAS_UUID))
/* Using older kernels without UUIDs in LIST,
* -> cannot use cache */
dm_device_list_destroy(&cmd->cache_dm_devs);
if (!dev_cache_update_dm_devs(cmd))
return_0;
/*
* Creates a list of available devices, does not open or read any,
@ -1673,7 +1668,6 @@ void label_scan_invalidate_lvs(struct cmd_context *cmd, struct dm_list *lvs)
struct dm_active_device *dm_dev;
struct device *dev;
struct lv_list *lvl;
dev_t devt;
/*
* This is only needed when the command sees PVs stacked on LVs which
@ -1688,8 +1682,7 @@ void label_scan_invalidate_lvs(struct cmd_context *cmd, struct dm_list *lvs)
dm_list_iterate_items(dm_dev, cmd->cache_dm_devs)
if (dm_dev->uuid &&
strncmp(dm_dev->uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) == 0) {
devt = MKDEV(dm_dev->major, dm_dev->minor);
if ((dev = dev_cache_get_by_devt(cmd, devt)))
if ((dev = dev_cache_get_by_devt(cmd, dm_dev->devno)))
label_scan_invalidate(dev);
}
} else