diff --git a/device_mapper/all.h b/device_mapper/all.h index 663abe870..cdd3b4a77 100644 --- a/device_mapper/all.h +++ b/device_mapper/all.h @@ -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); diff --git a/device_mapper/ioctl/libdm-iface.c b/device_mapper/ioctl/libdm-iface.c index 170e9c931..b240669c3 100644 --- a/device_mapper/ioctl/libdm-iface.c +++ b/device_mapper/ioctl/libdm-iface.c @@ -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; } diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index e9054a929..31ceae45d 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -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); diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index cd0c902c5..a78bcfc62 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -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 @@ -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); diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h index e6d0364ff..8f9dd86bd 100644 --- a/lib/device/dev-cache.h +++ b/lib/device/dev-cache.h @@ -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. */ diff --git a/lib/label/label.c b/lib/label/label.c index 38ae43caa..b4fcff8b0 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -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