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:
parent
14f782c5a7
commit
e30bc9b179
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user