mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
dev-cache: switch use of btree to radix_tree
Use radix_tree instead of not so well efficient btree code. This change allows to use more efficient 'radix_tree_iterate()', so just easily visit every stored value within the tree. To allow simple transtion, still provide 'dev_iter()' functionality so not every code needs immediate rewrite and can use the old iteration (with extra allocated memory for every tree value)
This commit is contained in:
parent
6e6d4c62b3
commit
b5245d3bcc
@ -14,10 +14,10 @@
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "lib/datastruct/btree.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
@ -35,8 +35,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 {
|
||||
@ -49,8 +51,8 @@ static struct {
|
||||
struct dm_hash_table *names;
|
||||
struct dm_hash_table *vgid_index;
|
||||
struct dm_hash_table *lvid_index;
|
||||
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;
|
||||
|
||||
@ -476,6 +478,31 @@ static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx,
|
||||
return list;
|
||||
}
|
||||
|
||||
void dev_cache_iterate(struct radix_tree_iterator *it)
|
||||
{
|
||||
radix_tree_iterate(_cache.devices, NULL, 0, it);
|
||||
}
|
||||
|
||||
static uint32_t _shuffle_devno(dev_t d)
|
||||
{
|
||||
return (d & 0xff000000) >> 24 | (d & 0xffff00) | ((d & 0xff) << 24);
|
||||
}
|
||||
|
||||
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_lookup_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 };
|
||||
@ -503,7 +530,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;
|
||||
@ -534,7 +561,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_lookup_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
|
||||
@ -546,7 +573,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_lookup_devno(_cache.sysfs_only_devices, devno)) &&
|
||||
!(dev = _insert_sysfs_dev(devno, devname)))
|
||||
return_NULL;
|
||||
}
|
||||
@ -744,7 +771,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_lookup_devno(_cache.devices, d);
|
||||
dev_by_path = (struct device *) dm_hash_lookup(_cache.names, path);
|
||||
dev = dev_by_devt;
|
||||
|
||||
@ -762,14 +789,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_lookup_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;
|
||||
@ -802,13 +827,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_lookup_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;
|
||||
@ -927,22 +952,40 @@ static int _insert_dir(const char *dir)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Sharing 'struct visitor' for several radix tree iterators
|
||||
* and just adding/using members as needed. */
|
||||
struct visitor {
|
||||
struct radix_tree_iterator it;
|
||||
struct cmd_context *cmd;
|
||||
struct dev_types *dt;
|
||||
struct device *dev;
|
||||
const char *pvid;
|
||||
unsigned found;
|
||||
};
|
||||
|
||||
static bool _visit_dev_cache_iterate_devs_for_index(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
|
||||
if (!_index_dev_by_vgid_and_lvid(vt->cmd, dev))
|
||||
vt->found = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int _dev_cache_iterate_devs_for_index(struct cmd_context *cmd)
|
||||
{
|
||||
struct btree_iter *iter = btree_first(_cache.devices);
|
||||
struct device *dev;
|
||||
int r = 1;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_dev_cache_iterate_devs_for_index,
|
||||
.cmd = cmd,
|
||||
};
|
||||
|
||||
while (iter) {
|
||||
dev = btree_get_data(iter);
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
if (!_index_dev_by_vgid_and_lvid(cmd, dev))
|
||||
r = 0;
|
||||
|
||||
iter = btree_next(iter);
|
||||
}
|
||||
|
||||
return r;
|
||||
return !vt.found;
|
||||
}
|
||||
|
||||
static int _dev_cache_iterate_sysfs_for_index(struct cmd_context *cmd, const char *path)
|
||||
@ -974,8 +1017,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_lookup_devno(_cache.devices, devno)) &&
|
||||
!(dev = _dev_cache_lookup_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;
|
||||
@ -1318,12 +1361,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;
|
||||
}
|
||||
@ -1406,6 +1449,12 @@ int dev_cache_exit(void)
|
||||
if (_cache.lvid_index)
|
||||
dm_hash_destroy(_cache.lvid_index);
|
||||
|
||||
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);
|
||||
@ -1537,7 +1586,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_lookup_devno(_cache.devices, st.st_rdev);
|
||||
|
||||
/*
|
||||
* lvm commands create this condition when they
|
||||
@ -1623,7 +1672,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_lookup_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);
|
||||
@ -1683,7 +1733,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_lookup_devno(_cache.devices, devt);
|
||||
|
||||
if (dev)
|
||||
return dev;
|
||||
@ -1691,21 +1741,32 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool _visit_dev_cache_get_by_devt(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
|
||||
if (memcmp(dev->pvid, vt->pvid, ID_LEN))
|
||||
return true;
|
||||
|
||||
vt->dev = dev;
|
||||
|
||||
return false; /* found -> stop iterator */
|
||||
}
|
||||
|
||||
struct device *dev_cache_get_by_pvid(struct cmd_context *cmd, const char *pvid)
|
||||
{
|
||||
struct btree_iter *iter = btree_first(_cache.devices);
|
||||
struct device *dev;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_dev_cache_get_by_devt,
|
||||
.cmd = cmd,
|
||||
.pvid = pvid,
|
||||
};
|
||||
|
||||
while (iter) {
|
||||
dev = btree_get_data(iter);
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
if (!memcmp(dev->pvid, pvid, ID_LEN))
|
||||
return dev;
|
||||
|
||||
iter = btree_next(iter);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return vt.dev;
|
||||
}
|
||||
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
|
||||
@ -1713,11 +1774,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++;
|
||||
@ -1729,23 +1797,18 @@ 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;
|
||||
@ -1773,21 +1836,31 @@ const char *dev_name(const struct device *dev)
|
||||
return unknown_device_name();
|
||||
}
|
||||
|
||||
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
|
||||
static bool _dev_cache_has_md_with_end_superblock_it(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct btree_iter *iter = btree_first(_cache.devices);
|
||||
struct device *dev;
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
|
||||
while (iter) {
|
||||
dev = btree_get_data(iter);
|
||||
|
||||
if (dev_is_md_with_end_superblock(dt, dev))
|
||||
return true;
|
||||
|
||||
iter = btree_next(iter);
|
||||
if (dev_is_md_with_end_superblock(vt->dt, dev)) {
|
||||
vt->found = 1;
|
||||
return false; /* stop further search */
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
|
||||
{
|
||||
struct visitor vt = {
|
||||
.it.visit = _dev_cache_has_md_with_end_superblock_it,
|
||||
.dt = dt,
|
||||
};
|
||||
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
return vt.found;
|
||||
}
|
||||
|
||||
static int _setup_devices_list(struct cmd_context *cmd)
|
||||
|
@ -69,6 +69,8 @@ struct dev_iter;
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
|
||||
void dev_iter_destroy(struct dev_iter *iter);
|
||||
struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter);
|
||||
struct radix_tree_iterator;
|
||||
void dev_cache_iterate(struct radix_tree_iterator *it);
|
||||
|
||||
void dev_cache_failed_path(struct device *dev, const char *path);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "base/data-struct/radix-tree.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/device/device.h"
|
||||
@ -2663,12 +2664,41 @@ void device_ids_match_device_list(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
struct visitor {
|
||||
struct radix_tree_iterator it;
|
||||
struct cmd_context *cmd;
|
||||
struct dev_use *du;
|
||||
struct dm_list *serial_str_list;
|
||||
struct dm_list *devs;
|
||||
unsigned count;
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
static bool _visit_device_ids_match(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
|
||||
/* skip a dev that's already matched to another entry */
|
||||
if (dev->flags & DEV_MATCHED_USE_ID ||
|
||||
!_match_du_to_dev(vt->cmd, vt->du, dev))
|
||||
return true; /* search next */
|
||||
|
||||
vt->count = 1;
|
||||
|
||||
return false; /* stop search */
|
||||
}
|
||||
|
||||
void device_ids_match(struct cmd_context *cmd)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_device_ids_match,
|
||||
.cmd = cmd,
|
||||
};
|
||||
struct dev_use *du;
|
||||
struct device *dev;
|
||||
int found;
|
||||
|
||||
if (cmd->enable_devices_list) {
|
||||
device_ids_match_device_list(cmd);
|
||||
@ -2736,26 +2766,16 @@ void device_ids_match(struct cmd_context *cmd)
|
||||
* NULL filter is used because we are just setting up the
|
||||
* the du/dev pairs in preparation for using the filters.
|
||||
*/
|
||||
found = 0;
|
||||
vt.du = du;
|
||||
vt.count = 0;
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
continue;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
/* skip a dev that's already matched to another entry */
|
||||
if (dev->flags & DEV_MATCHED_USE_ID)
|
||||
continue;
|
||||
if (_match_du_to_dev(cmd, du, dev)) {
|
||||
log_debug("Match %s %s PVID %s: done %s",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
|
||||
dev_name(du->dev));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (!found)
|
||||
log_debug("Match %s %s PVID %s: no device matches",
|
||||
if (vt.count)
|
||||
log_debug("Match %s %s PVID %s: done %s.",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".",
|
||||
dev_name(du->dev));
|
||||
else
|
||||
log_debug("Match %s %s PVID %s: no device matches.",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", du->pvid ?: ".");
|
||||
}
|
||||
|
||||
@ -2847,61 +2867,56 @@ void device_ids_match(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static void _get_devs_with_serial_numbers(struct cmd_context *cmd, struct dm_list *serial_str_list, struct dm_list *devs)
|
||||
static bool _visit_get_devs_with_serial_numbers(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct cmd_context *cmd = vt->cmd;
|
||||
struct device *dev = v.ptr;
|
||||
struct device_list *devl;
|
||||
struct dev_id *id;
|
||||
const char *idname;
|
||||
struct dev_filter *f = cmd->filter;
|
||||
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
return;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
/* if serial has already been read for this dev then use it */
|
||||
dm_list_iterate_items(id, &dev->ids) {
|
||||
if (id->idtype == DEV_ID_TYPE_SYS_SERIAL && id->idname) {
|
||||
if (str_list_match_item(serial_str_list, id->idname)) {
|
||||
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
|
||||
goto next_continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(devs, &devl->list);
|
||||
}
|
||||
goto next_continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* just copying the no-data filters in similar device_ids_search */
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "usable"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "mpath"))
|
||||
continue;
|
||||
|
||||
if ((idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_SERIAL))) {
|
||||
if (str_list_match_item(serial_str_list, idname)) {
|
||||
/* if serial has already been read for this dev then use it */
|
||||
dm_list_iterate_items(id, &dev->ids)
|
||||
if (id->idtype == DEV_ID_TYPE_SYS_SERIAL && id->idname) {
|
||||
if (str_list_match_item(vt->serial_str_list, id->idname)) {
|
||||
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
|
||||
goto next_free;
|
||||
if (!(id = zalloc(sizeof(struct dev_id))))
|
||||
goto next_free;
|
||||
id->idtype = DEV_ID_TYPE_SYS_SERIAL;
|
||||
id->idname = (char *)idname;
|
||||
dm_list_add(&dev->ids, &id->list);
|
||||
return true;
|
||||
devl->dev = dev;
|
||||
dm_list_add(devs, &devl->list);
|
||||
idname = NULL;
|
||||
dm_list_add(vt->devs, &devl->list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
next_free:
|
||||
if (idname)
|
||||
free((char *)idname);
|
||||
next_continue:
|
||||
continue;
|
||||
|
||||
/* just copying the no-data filters in similar device_ids_search */
|
||||
if (!f->passes_filter(cmd, f, dev, "sysfs") ||
|
||||
!f->passes_filter(cmd, f, dev, "type") ||
|
||||
!f->passes_filter(cmd, f, dev, "usable") ||
|
||||
!f->passes_filter(cmd, f, dev, "mpath"))
|
||||
return true;
|
||||
|
||||
if ((idname = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_SERIAL)) &&
|
||||
str_list_match_item(vt->serial_str_list, idname)) {
|
||||
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
|
||||
goto next_free;
|
||||
if (!(id = zalloc(sizeof(struct dev_id))))
|
||||
goto next_free;
|
||||
id->idtype = DEV_ID_TYPE_SYS_SERIAL;
|
||||
id->idname = (char *)idname;
|
||||
dm_list_add(&dev->ids, &id->list);
|
||||
devl->dev = dev;
|
||||
dm_list_add(vt->devs, &devl->list);
|
||||
idname = NULL;
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
next_free:
|
||||
if (idname)
|
||||
free((char *)idname);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3412,6 +3427,12 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
|
||||
int found;
|
||||
int count;
|
||||
int err;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_get_devs_with_serial_numbers,
|
||||
.cmd = cmd,
|
||||
.serial_str_list = &cmd->device_ids_check_serial,
|
||||
.devs = &devs_check,
|
||||
};
|
||||
|
||||
dm_list_init(&dus_check);
|
||||
dm_list_init(&devs_check);
|
||||
@ -3440,7 +3461,7 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
|
||||
* devs that match the suspect serial numbers.
|
||||
*/
|
||||
log_debug("Finding all devs with suspect serial numbers.");
|
||||
_get_devs_with_serial_numbers(cmd, &cmd->device_ids_check_serial, &devs_check);
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
/*
|
||||
* Read the PVID from any devs_check entries that have not been scanned
|
||||
@ -3656,6 +3677,36 @@ void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs,
|
||||
_device_ids_update_try(cmd);
|
||||
}
|
||||
|
||||
static bool _visit_device_ids_search(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct cmd_context *cmd = vt->cmd;
|
||||
struct device *dev = v.ptr;
|
||||
struct dev_filter *f = cmd->filter;
|
||||
struct device_list *devl; /* holds struct device */
|
||||
|
||||
if (dev->flags & DEV_MATCHED_USE_ID)
|
||||
return true;
|
||||
|
||||
if (!f->passes_filter(cmd, f, dev, "sysfs") ||
|
||||
!f->passes_filter(cmd, f, dev, "type") ||
|
||||
!f->passes_filter(cmd, f, dev, "usable") ||
|
||||
!f->passes_filter(cmd, f, dev, "mpath"))
|
||||
return true;
|
||||
|
||||
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
|
||||
return true;
|
||||
|
||||
devl->dev = dev;
|
||||
dm_list_add(vt->devs, &devl->list);
|
||||
vt->count++;
|
||||
vt->hash = calc_crc(vt->hash, (const uint8_t *)&dev->dev, sizeof(dev_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Devices with IDNAME=devname that are mistakenly included by filter-deviceid
|
||||
* due to a devname change are fully scanned and added to lvmcache.
|
||||
@ -3683,7 +3734,6 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
|
||||
struct device *dev;
|
||||
struct dev_use *du;
|
||||
struct dev_id *id;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl; /* holds struct device */
|
||||
struct device_id_list *dil, *dil2; /* holds struct device + pvid */
|
||||
struct dm_list search_pvids; /* list of device_id_list */
|
||||
@ -3698,7 +3748,14 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
|
||||
int search_pvids_count = 0;
|
||||
int search_devs_count = 0;
|
||||
uint32_t search_pvids_hash = INITIAL_CRC;
|
||||
uint32_t search_devs_hash = INITIAL_CRC;
|
||||
uint32_t search_devs_hash;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_device_ids_search,
|
||||
.cmd = cmd,
|
||||
.serial_str_list = &cmd->device_ids_check_serial,
|
||||
.devs = &search_devs,
|
||||
.hash = INITIAL_CRC,
|
||||
};
|
||||
|
||||
dm_list_init(&search_pvids);
|
||||
dm_list_init(&search_devs);
|
||||
@ -3794,27 +3851,9 @@ void device_ids_search(struct cmd_context *cmd, struct dm_list *new_devs,
|
||||
* filter), in the process of doing this search outside the deviceid
|
||||
* filter.
|
||||
*/
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
return;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (dev->flags & DEV_MATCHED_USE_ID)
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "sysfs"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "type"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "usable"))
|
||||
continue;
|
||||
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "mpath"))
|
||||
continue;
|
||||
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
|
||||
continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(&search_devs, &devl->list);
|
||||
search_devs_count++;
|
||||
search_devs_hash = calc_crc(search_devs_hash, (const uint8_t *)&devl->dev->dev, sizeof(dev_t));
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
dev_cache_iterate(&vt.it);
|
||||
search_devs_count = vt.count;
|
||||
search_devs_hash = vt.hash;
|
||||
|
||||
/*
|
||||
* A previous command searched for devnames and found nothing, so it
|
||||
|
@ -137,6 +137,7 @@
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "base/data-struct/radix-tree.h"
|
||||
#include "lib/label/label.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#include "lib/cache/lvmcache.h"
|
||||
@ -454,6 +455,58 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct visitor {
|
||||
struct radix_tree_iterator it;
|
||||
FILE *fp;
|
||||
struct cmd_context *cmd;
|
||||
struct dm_list *hints;
|
||||
uint32_t hash;
|
||||
uint32_t count;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static bool _visit_validate_hints(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
struct hint *hint;
|
||||
|
||||
if (dm_list_empty(&dev->aliases))
|
||||
return true;
|
||||
if (!(hint = _find_hint_name(vt->hints, dev_name(dev))))
|
||||
return true;
|
||||
|
||||
/* The cmd hasn't needed this hint's dev so it's not been scanned. */
|
||||
if (!hint->chosen)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* label_scan was unable to read the dev so we don't know its pvid.
|
||||
* Since we are unable to verify the hint is correct, it's possible
|
||||
* that the PVID is actually found on a different device, so don't
|
||||
* depend on hints. (This would also fail the following pvid check.)
|
||||
*/
|
||||
if (dev->flags & DEV_SCAN_NOT_READ) {
|
||||
log_debug("Uncertain hint for unread device %d:%d %s",
|
||||
major(hint->devt), minor(hint->devt), dev_name(dev));
|
||||
vt->ret = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp(dev->pvid, hint->pvid)) {
|
||||
log_debug("Invalid hint device %d:%d %s pvid %s had hint pvid %s",
|
||||
major(hint->devt), minor(hint->devt), dev_name(dev),
|
||||
dev->pvid, hint->pvid);
|
||||
vt->ret = 0;
|
||||
}
|
||||
|
||||
vt->count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hints were used to reduce devs that were scanned. After the reduced
|
||||
* scanning is done, this is called to check if the hints may have been
|
||||
@ -465,9 +518,12 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev)
|
||||
*/
|
||||
int validate_hints(struct cmd_context *cmd, struct dm_list *hints)
|
||||
{
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_validate_hints,
|
||||
.cmd = cmd,
|
||||
.hints = hints,
|
||||
};
|
||||
struct hint *hint;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
int valid_hints = 0;
|
||||
int ret = 1;
|
||||
|
||||
@ -499,41 +555,10 @@ int validate_hints(struct cmd_context *cmd, struct dm_list *hints)
|
||||
* became stale somehow (e.g. manually copying devices with dd) and
|
||||
* need to be refreshed.
|
||||
*/
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
return 0;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (dm_list_empty(&dev->aliases))
|
||||
continue;
|
||||
if (!(hint = _find_hint_name(hints, dev_name(dev))))
|
||||
continue;
|
||||
|
||||
/* The cmd hasn't needed this hint's dev so it's not been scanned. */
|
||||
if (!hint->chosen)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* label_scan was unable to read the dev so we don't know its pvid.
|
||||
* Since we are unable to verify the hint is correct, it's possible
|
||||
* that the PVID is actually found on a different device, so don't
|
||||
* depend on hints. (This would also fail the following pvid check.)
|
||||
*/
|
||||
if (dev->flags & DEV_SCAN_NOT_READ) {
|
||||
log_debug("Uncertain hint for unread device %d:%d %s",
|
||||
major(hint->devt), minor(hint->devt), dev_name(dev));
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(dev->pvid, hint->pvid)) {
|
||||
log_debug("Invalid hint device %d:%d %s pvid %s had hint pvid %s",
|
||||
major(hint->devt), minor(hint->devt), dev_name(dev),
|
||||
dev->pvid, hint->pvid);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
valid_hints++;
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
vt.ret = ret;
|
||||
dev_cache_iterate(&vt.it);
|
||||
ret = vt.ret;
|
||||
valid_hints = vt.count;
|
||||
|
||||
/*
|
||||
* Check in lvmcache to see if the scan noticed any missing PVs
|
||||
@ -682,6 +707,33 @@ static void _filter_to_str(struct cmd_context *cmd, int filter_cfg, char **strp)
|
||||
*strp = str;
|
||||
}
|
||||
|
||||
static bool _visit_read_hint_file(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
const char *devpath;
|
||||
|
||||
/*
|
||||
* This loop does two different things (for clarity this should be
|
||||
* two separate dev_iter loops, but one is used for efficiency).
|
||||
* 1. compute the hint hash from all relevant devs
|
||||
* 2. add PVs to the hint file
|
||||
*/
|
||||
if (vt->cmd->enable_devices_file && !get_du_for_dev(vt->cmd, dev))
|
||||
return true;
|
||||
|
||||
if (!_dev_in_hint_hash(vt->cmd, dev))
|
||||
return true;
|
||||
|
||||
devpath = dev_name(dev);
|
||||
vt->hash = calc_crc(vt->hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
vt->count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 and needs_refresh 0: the hints can be used
|
||||
* Return 1 and needs_refresh 1: the hints can't be used and should be updated
|
||||
@ -691,19 +743,19 @@ static void _filter_to_str(struct cmd_context *cmd, int filter_cfg, char **strp)
|
||||
*/
|
||||
static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *needs_refresh)
|
||||
{
|
||||
char devpath[PATH_MAX];
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_read_hint_file,
|
||||
.cmd = cmd,
|
||||
.hash = INITIAL_CRC,
|
||||
};
|
||||
FILE *fp;
|
||||
struct dev_iter *iter;
|
||||
struct dev_use *du;
|
||||
struct hint hint;
|
||||
struct hint *alloc_hint, *hp;
|
||||
struct device *dev;
|
||||
char *split[HINT_LINE_WORDS];
|
||||
char *name, *pvid, *devn, *vgname, *p, *filter_str = NULL;
|
||||
uint32_t read_hash = 0;
|
||||
uint32_t calc_hash = INITIAL_CRC;
|
||||
uint32_t read_count = 0;
|
||||
uint32_t calc_count = 0;
|
||||
int found = 0;
|
||||
int keylen;
|
||||
int hv_major, hv_minor;
|
||||
@ -877,25 +929,12 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
/*
|
||||
* Calculate and compare hash of devices that may be scanned.
|
||||
*/
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
return 0;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (cmd->enable_devices_file && !get_du_for_dev(cmd, dev))
|
||||
continue;
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
if (!_dev_in_hint_hash(cmd, dev))
|
||||
continue;
|
||||
|
||||
dm_strncpy(devpath, dev_name(dev), sizeof(devpath));
|
||||
calc_hash = calc_crc(calc_hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
calc_count++;
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (read_hash && (read_hash != calc_hash)) {
|
||||
if (read_hash && (read_hash != vt.hash)) {
|
||||
/* The count is just informational. */
|
||||
log_debug("ignore hints with read_hash %u count %u calc_hash %u count %u",
|
||||
read_hash, read_count, calc_hash, calc_count);
|
||||
read_hash, read_count, vt.hash, vt.count);
|
||||
*needs_refresh = 1;
|
||||
return 1;
|
||||
}
|
||||
@ -930,6 +969,74 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool _visit_write_hint_file(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
const char *devpath;
|
||||
const char *vgname;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
/*
|
||||
* This loop does two different things (for clarity this should be
|
||||
* two separate dev_iter loops, but one is used for efficiency).
|
||||
* 1. compute the hint hash from all relevant devs
|
||||
* 2. add PVs to the hint file
|
||||
*/
|
||||
|
||||
if (vt->cmd->enable_devices_file && !get_du_for_dev(vt->cmd, dev))
|
||||
return true;
|
||||
|
||||
if (!_dev_in_hint_hash(vt->cmd, dev)) {
|
||||
if (dev->flags & DEV_SCAN_FOUND_LABEL) {
|
||||
/* should never happen */
|
||||
log_error("skip hint hash but found label %s.", dev_name(dev));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a hash of all device names on the system so we can
|
||||
* detect when the devices on the system change, which
|
||||
* invalidates the existing hints.
|
||||
*/
|
||||
devpath = dev_name(dev);
|
||||
vt->hash = calc_crc(vt->hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
vt->count++;
|
||||
|
||||
if (!(dev->flags & DEV_SCAN_FOUND_LABEL))
|
||||
return true;
|
||||
|
||||
if (dev->flags & DEV_IS_MD_COMPONENT) {
|
||||
log_debug_devs("exclude md component from hints %s.", dev_name(dev));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* No vgname will be found here for a PV with no mdas,
|
||||
* in which case the vgname hint will be incomplete.
|
||||
* (The label scan cannot associate nomda-pvs with the
|
||||
* correct vg in lvmcache; that is only done by vg_read.)
|
||||
* When using vgname hint we would always want to also
|
||||
* scan any PVs missing a vgname hint in case they are
|
||||
* part of the vg we are looking for.
|
||||
*/
|
||||
if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
else
|
||||
vgname = NULL;
|
||||
|
||||
if (vgname && is_orphan_vg(vgname))
|
||||
vgname = NULL;
|
||||
|
||||
fprintf(vt->fp, "scan:%s pvid:%s devn:%u:%u vg:%s\n", dev_name(dev),
|
||||
dev->pvid, MAJOR(dev->dev), MINOR(dev->dev), vgname ?: "-");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Include any device in the hints that label_scan saw which had an lvm label
|
||||
* header. label_scan set DEV_SCAN_FOUND_LABEL on the dev if it saw an lvm
|
||||
@ -963,16 +1070,14 @@ static int _read_hint_file(struct cmd_context *cmd, struct dm_list *hints, int *
|
||||
|
||||
int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
{
|
||||
char devpath[PATH_MAX];
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_write_hint_file,
|
||||
.cmd = cmd,
|
||||
.hash = INITIAL_CRC,
|
||||
};
|
||||
FILE *fp;
|
||||
struct lvmcache_info *info;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
const char *vgname;
|
||||
char *filter_str = NULL;
|
||||
const char *config_devices_file = NULL;
|
||||
uint32_t hash = INITIAL_CRC;
|
||||
uint32_t count = 0;
|
||||
time_t t;
|
||||
int ret = 1;
|
||||
|
||||
@ -1048,79 +1153,16 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
* iterate through all devs and write a line for each
|
||||
* dev flagged DEV_SCAN_FOUND_LABEL
|
||||
*/
|
||||
vt.fp = fp;
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
if (!(iter = dev_iter_create(NULL, 0))) {
|
||||
ret = 0;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
/*
|
||||
* This loop does two different things (for clarity this should be
|
||||
* two separate dev_iter loops, but one is used for efficiency).
|
||||
* 1. compute the hint hash from all relevant devs
|
||||
* 2. add PVs to the hint file
|
||||
*/
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (cmd->enable_devices_file && !get_du_for_dev(cmd, dev))
|
||||
continue;
|
||||
|
||||
if (!_dev_in_hint_hash(cmd, dev)) {
|
||||
if (dev->flags & DEV_SCAN_FOUND_LABEL) {
|
||||
/* should never happen */
|
||||
log_error("skip hint hash but found label %s", dev_name(dev));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a hash of all device names on the system so we can
|
||||
* detect when the devices on the system change, which
|
||||
* invalidates the existing hints.
|
||||
*/
|
||||
dm_strncpy(devpath, dev_name(dev), sizeof(devpath));
|
||||
hash = calc_crc(hash, (const uint8_t *)devpath, strlen(devpath));
|
||||
count++;
|
||||
|
||||
if (!(dev->flags & DEV_SCAN_FOUND_LABEL))
|
||||
continue;
|
||||
|
||||
if (dev->flags & DEV_IS_MD_COMPONENT) {
|
||||
log_debug("exclude md component from hints %s", dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* No vgname will be found here for a PV with no mdas,
|
||||
* in which case the vgname hint will be incomplete.
|
||||
* (The label scan cannot associate nomda-pvs with the
|
||||
* correct vg in lvmcache; that is only done by vg_read.)
|
||||
* When using vgname hint we would always want to also
|
||||
* scan any PVs missing a vgname hint in case they are
|
||||
* part of the vg we are looking for.
|
||||
*/
|
||||
if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
else
|
||||
vgname = NULL;
|
||||
|
||||
if (vgname && is_orphan_vg(vgname))
|
||||
vgname = NULL;
|
||||
|
||||
fprintf(fp, "scan:%s pvid:%s devn:%d:%d vg:%s\n",
|
||||
dev_name(dev),
|
||||
dev->pvid,
|
||||
major(dev->dev), minor(dev->dev),
|
||||
vgname ?: "-");
|
||||
}
|
||||
|
||||
fprintf(fp, "devs_hash: %u %u\n", hash, count);
|
||||
dev_iter_destroy(iter);
|
||||
fprintf(fp, "devs_hash: %u %u\n", vt.hash, vt.count);
|
||||
|
||||
out_flush:
|
||||
if (fflush(fp))
|
||||
stack;
|
||||
|
||||
log_debug("Wrote hint file with devs_hash %u count %u", hash, count);
|
||||
log_debug("Wrote hint file with devs_hash %u count %u", vt.hash, vt.count);
|
||||
|
||||
/*
|
||||
* We are writing refreshed hints because another command told us to by
|
||||
@ -1129,7 +1171,6 @@ int write_hint_file(struct cmd_context *cmd, int newhints)
|
||||
if (newhints == NEWHINTS_FILE)
|
||||
_unlink_newhints();
|
||||
|
||||
out_close:
|
||||
if (fclose(fp))
|
||||
log_debug("write_hint_file close errno %d", errno);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "base/data-struct/radix-tree.h"
|
||||
#include "lib/label/label.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
@ -864,6 +865,49 @@ void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct visitor {
|
||||
struct radix_tree_iterator it;
|
||||
struct cmd_context *cmd;
|
||||
struct device *dev;
|
||||
const char *pvid;
|
||||
struct dm_list *all_devs;
|
||||
};
|
||||
|
||||
static bool _visit_label_scan_for_pvid(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
char buf[LABEL_SIZE] __attribute__((aligned(8)));
|
||||
const struct pv_header *pvh = (const struct pv_header *)(buf + 32);
|
||||
struct device *dev = v.ptr;
|
||||
struct dev_filter *f = vt->cmd->filter;
|
||||
|
||||
if (f) {
|
||||
if (!(dev->flags & DEV_REGULAR) &&
|
||||
!f->passes_filter(vt->cmd, f, dev, NULL))
|
||||
return true; /* next */
|
||||
} else if (!(dev->flags & DEV_REGULAR))
|
||||
return true; /* next */
|
||||
|
||||
if (!label_scan_open(dev))
|
||||
return true; /* next */
|
||||
|
||||
if (!dev_read_bytes(dev, 512, LABEL_SIZE, buf)) {
|
||||
_scan_dev_close(dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
_scan_dev_close(dev);
|
||||
|
||||
if (memcmp(pvh->pv_uuid, vt->pvid, ID_LEN))
|
||||
return true; /* next */
|
||||
|
||||
vt->dev = dev;
|
||||
|
||||
return false; /* stop search */
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently the only caller is pvck which probably doesn't need
|
||||
* deferred filters checked after the read... it wants to know if
|
||||
@ -872,15 +916,11 @@ void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
|
||||
|
||||
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out)
|
||||
{
|
||||
char buf[LABEL_SIZE] __attribute__((aligned(8)));
|
||||
struct dm_list devs;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
struct pv_header *pvh;
|
||||
int ret = 0;
|
||||
|
||||
dm_list_init(&devs);
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_label_scan_for_pvid,
|
||||
.cmd = cmd,
|
||||
.pvid = pvid,
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates a list of available devices, does not open or read any,
|
||||
@ -891,62 +931,21 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!label_scan_setup_bcache())
|
||||
return_0;
|
||||
|
||||
log_debug_devs("Filtering devices to scan.");
|
||||
|
||||
/*
|
||||
* Iterating over all available devices with cmd->filter filters
|
||||
* devices; those returned from dev_iter_get are the devs that
|
||||
* pass filters, and are those we can use.
|
||||
*/
|
||||
cmd->filter->use_count++;
|
||||
dev_cache_iterate(&vt.it);
|
||||
cmd->filter->use_count--;
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter, 0))) {
|
||||
log_error("Scanning failed to get devices.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_devs("Filtering devices to scan");
|
||||
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(&devs, &devl->list);
|
||||
};
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
if (!label_scan_setup_bcache())
|
||||
goto_out;
|
||||
|
||||
log_debug_devs("Reading labels for pvid");
|
||||
|
||||
dm_list_iterate_items(devl, &devs) {
|
||||
dev = devl->dev;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (!label_scan_open(dev))
|
||||
continue;
|
||||
|
||||
if (!dev_read_bytes(dev, 512, LABEL_SIZE, buf)) {
|
||||
_scan_dev_close(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pvh = (struct pv_header *)(buf + 32);
|
||||
|
||||
if (!memcmp(pvh->pv_uuid, pvid, ID_LEN)) {
|
||||
*dev_out = devl->dev;
|
||||
_scan_dev_close(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
_scan_dev_close(dev);
|
||||
}
|
||||
ret = 1;
|
||||
out:
|
||||
dm_list_iterate_items_safe(devl, devl2, &devs) {
|
||||
dm_list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
return ret;
|
||||
return ((*dev_out = vt.dev)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1239,6 +1238,28 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool _visit_label_scan(struct radix_tree_iterator *it,
|
||||
const void *key, size_t keylen,
|
||||
union radix_value v)
|
||||
{
|
||||
struct visitor *vt = container_of(it, struct visitor, it);
|
||||
struct device *dev = v.ptr;
|
||||
struct device_list *devl;
|
||||
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
return true;
|
||||
devl->dev = dev;
|
||||
dm_list_add(vt->all_devs, &devl->list);
|
||||
|
||||
/*
|
||||
* label_scan should not generally be called a second time,
|
||||
* so this will usually do nothing.
|
||||
*/
|
||||
label_scan_invalidate(dev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan devices on the system to discover which are LVM devices.
|
||||
* Info about the LVM devices (PVs) is saved in lvmcache in a
|
||||
@ -1253,13 +1274,17 @@ int label_scan(struct cmd_context *cmd)
|
||||
struct dm_list filtered_devs;
|
||||
struct dm_list scan_devs;
|
||||
struct dm_list hints_list;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
uint64_t max_metadata_size_bytes;
|
||||
int using_hints;
|
||||
int create_hints = 0; /* NEWHINTS_NONE */
|
||||
unsigned devs_features = 0;
|
||||
struct visitor vt = {
|
||||
.it.visit = _visit_label_scan,
|
||||
.cmd = cmd,
|
||||
.all_devs = &all_devs,
|
||||
};
|
||||
|
||||
log_debug_devs("Finding devices to scan");
|
||||
|
||||
@ -1313,23 +1338,7 @@ int label_scan(struct cmd_context *cmd)
|
||||
* Invalidate bcache data for all devs (there will usually be no bcache
|
||||
* data to invalidate.)
|
||||
*/
|
||||
if (!(iter = dev_iter_create(NULL, 0))) {
|
||||
log_error("Failed to get device list.");
|
||||
return 0;
|
||||
}
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (!(devl = zalloc(sizeof(*devl))))
|
||||
continue;
|
||||
devl->dev = dev;
|
||||
dm_list_add(&all_devs, &devl->list);
|
||||
|
||||
/*
|
||||
* label_scan should not generally be called a second time,
|
||||
* so this will usually do nothing.
|
||||
*/
|
||||
label_scan_invalidate(dev);
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
dev_cache_iterate(&vt.it);
|
||||
|
||||
/*
|
||||
* Exclude devices that fail nodata filters. (Those filters that can be
|
||||
|
Loading…
x
Reference in New Issue
Block a user