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

metadata: use radix tree to find lv_names

Replace usage of dm_hash with radix_tree to quickly find LV name
with a vg and also index PV names with set of available PVs.
This PV index is only needed during the import, but instead
of passing 'radix_tree *' everywhere, just keep this within
a VG struct as well and once the parsing is finished, release
this PV index radix_tree.

This also makes it easier to replace this structure
in the future if needed.

lv_set_name now uses  radix_tree remove+insert to keep lv_names
tree in-sync and usable for  find_lv queries.
This commit is contained in:
Zdenek Kabelac 2024-10-24 16:12:18 +02:00
parent 1825e782cc
commit 21517c2bd5
19 changed files with 100 additions and 96 deletions

View File

@ -202,8 +202,7 @@ static int _settings_text_export(const struct lv_segment *seg,
}
static int _cache_pool_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
struct logical_volume *data_lv, *meta_lv;
const char *str = NULL;
@ -438,8 +437,7 @@ static const struct segtype_handler _cache_pool_ops = {
};
static int _cache_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
struct logical_volume *pool_lv, *origin_lv;
const char *name;

View File

@ -26,6 +26,7 @@
#include "lib/format_text/text_import.h"
#include "lib/config/defaults.h"
#include "lib/datastruct/str_list.h"
#include "base/data-struct/radix-tree.h"
typedef int (*section_fn) (struct cmd_context *cmd,
struct format_type *fmt,
@ -34,9 +35,7 @@ typedef int (*section_fn) (struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *pvn,
const struct dm_config_node *vgn,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash);
const struct dm_config_node *vgn);
#define _read_int32(root, path, result) \
dm_config_get_uint32(root, path, (uint32_t *) (result))
@ -180,9 +179,7 @@ static int _read_pv(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash __attribute__((unused)))
const struct dm_config_node *vgn __attribute__((unused)))
{
struct physical_volume *pv;
struct pv_list *pvl;
@ -200,8 +197,8 @@ static int _read_pv(struct cmd_context *cmd,
* Add the pv to the pv hash for quick lookup when we read
* the lv segments.
*/
if (!dm_hash_insert(pv_hash, pvn->key, pv))
return_0;
if (!radix_tree_insert_ptr(vg->pv_names, pvn->key, strlen(pvn->key), pv))
return_0;
if (!(pvn = pvn->child)) {
log_error("Empty pv section.");
@ -310,9 +307,7 @@ static int _read_pvsummary(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash __attribute__((unused)))
const struct dm_config_node *vgn __attribute__((unused)))
{
struct physical_volume *pv;
struct pv_list *pvl;
@ -395,8 +390,7 @@ static int _read_segment(struct cmd_context *cmd,
struct format_type *fmt,
struct format_instance *fid,
struct dm_pool *mem,
struct logical_volume *lv, const struct dm_config_node *sn,
struct dm_hash_table *pv_hash)
struct logical_volume *lv, const struct dm_config_node *sn)
{
uint32_t area_count = 0u;
struct lv_segment *seg;
@ -456,7 +450,7 @@ static int _read_segment(struct cmd_context *cmd,
}
if (seg->segtype->ops->text_import &&
!seg->segtype->ops->text_import(seg, sn_child, pv_hash))
!seg->segtype->ops->text_import(seg, sn_child))
return_0;
/* Optional tags */
@ -491,7 +485,7 @@ static int _read_segment(struct cmd_context *cmd,
}
int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
const struct dm_config_value *cv, struct dm_hash_table *pv_hash,
const struct dm_config_value *cv,
uint64_t status)
{
unsigned int s;
@ -523,7 +517,7 @@ int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
}
/* FIXME Cope if LV not yet read in */
if ((pv = dm_hash_lookup(pv_hash, cv->v.str))) {
if ((pv = find_pv_by_pv_name(seg->lv->vg, cv->v.str))) {
if (!set_lv_segment_area_pv(seg, s, pv, (uint32_t) cv->next->v.i))
return_0;
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
@ -557,8 +551,7 @@ static int _read_segments(struct cmd_context *cmd,
struct format_type *fmt,
struct format_instance *fid,
struct dm_pool *mem,
struct logical_volume *lv, const struct dm_config_node *lvn,
struct dm_hash_table *pv_hash)
struct logical_volume *lv, const struct dm_config_node *lvn)
{
const struct dm_config_node *sn;
int count = 0, seg_count;
@ -569,7 +562,7 @@ static int _read_segments(struct cmd_context *cmd,
* All sub-sections are assumed to be segments.
*/
if (!sn->v) {
if (!_read_segment(cmd, fmt, fid, mem, lv, sn, pv_hash))
if (!_read_segment(cmd, fmt, fid, mem, lv, sn))
return_0;
count++;
@ -615,9 +608,7 @@ static int _read_lvnames(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash)
const struct dm_config_node *vgn __attribute__((unused)))
{
struct logical_volume *lv;
const char *str;
@ -740,9 +731,6 @@ static int _read_lvnames(struct cmd_context *cmd,
return 0;
}
if (!dm_hash_insert(lv_hash, lv->name, lv))
return_0;
if (timestamp && !lv_set_creation(lv, hostname, timestamp))
return_0;
@ -775,9 +763,7 @@ static int _read_historical_lvnames(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash __attribute__((unused)))
const struct dm_config_node *vgn __attribute__((unused)))
{
struct generic_logical_volume *glv;
struct glv_list *glvl;
@ -848,9 +834,7 @@ static int _read_historical_lvnames_interconnections(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash __attribute__((unused)))
const struct dm_config_node *vgn __attribute__((unused)))
{
const char *historical_lv_name, *origin_name = NULL;
struct generic_logical_volume *glv, *origin_glv, *descendant_glv;
@ -962,13 +946,11 @@ static int _read_lvsegs(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash)
const struct dm_config_node *vgn __attribute__((unused)))
{
struct logical_volume *lv;
if (!(lv = dm_hash_lookup(lv_hash, lvn->key))) {
if (!(lv = find_lv(vg, lvn->key))) {
log_error("Lost logical volume reference %s", lvn->key);
return 0;
}
@ -987,7 +969,7 @@ static int _read_lvsegs(struct cmd_context *cmd,
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!_read_segments(cmd, fmt, fid, mem, lv, lvn, pv_hash))
if (!_read_segments(cmd, fmt, fid, mem, lv, lvn))
return_0;
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
@ -1028,8 +1010,6 @@ static int _read_sections(struct cmd_context *cmd,
struct volume_group *vg,
struct lvmcache_vgsummary *vgsummary,
const struct dm_config_node *vgn,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash,
int optional)
{
const struct dm_config_node *n;
@ -1044,7 +1024,7 @@ static int _read_sections(struct cmd_context *cmd,
}
for (n = n->child; n; n = n->sib) {
if (!fn(cmd, (struct format_type *)fmt, fid, mem, vg, vgsummary, n, vgn, pv_hash, lv_hash))
if (!fn(cmd, (struct format_type *)fmt, fid, mem, vg, vgsummary, n, vgn))
return_0;
}
@ -1061,7 +1041,6 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
const struct dm_config_value *cv;
const char *str, *format_str, *system_id;
struct volume_group *vg;
struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
uint64_t vgstatus;
/* skip any top-level values */
@ -1079,20 +1058,20 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
mem = vg->vgmem;
/*
* The pv hash memorizes the pv section names -> pv
* The pv_names memorizes the pv section names -> pv
* structures.
*/
if (!(pv_hash = dm_hash_create(59))) {
log_error("Couldn't create pv hash table.");
if (!(vg->pv_names = radix_tree_create(NULL, NULL))) {
log_error("Couldn't create pv_names radix tree.");
goto bad;
}
/*
* The lv hash memorizes the lv section names -> lv
* The lv_names radix_tree memorizes the lv section names -> lv
* structures.
*/
if (!(lv_hash = dm_hash_create(1023))) {
log_error("Couldn't create lv hash table.");
if (!(vg->lv_names = radix_tree_create(NULL, NULL))) {
log_error("Couldn't create lv_names radix tree.");
goto bad;
}
@ -1211,7 +1190,7 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
}
if (!_read_sections(cmd, fmt, fid, mem, "physical_volumes", _read_pv, vg, NULL,
vgn, pv_hash, lv_hash, 0)) {
vgn, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
@ -1225,28 +1204,28 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
}
if (!_read_sections(cmd, fmt, fid, mem, "logical_volumes", _read_lvnames, vg, NULL,
vgn, pv_hash, lv_hash, 1)) {
vgn, 1)) {
log_error("Couldn't read all logical volume names for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(cmd, fmt, fid, mem, "historical_logical_volumes", _read_historical_lvnames, vg, NULL,
vgn, pv_hash, lv_hash, 1)) {
vgn, 1)) {
log_error("Couldn't read all historical logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(cmd, fmt, fid, mem, "logical_volumes", _read_lvsegs, vg, NULL,
vgn, pv_hash, lv_hash, 1)) {
vgn, 1)) {
log_error("Couldn't read all logical volumes for "
"volume group %s.", vg->name);
goto bad;
}
if (!_read_sections(cmd, fmt, fid, mem, "historical_logical_volumes", _read_historical_lvnames_interconnections,
vg, NULL, vgn, pv_hash, lv_hash, 1)) {
vg, NULL, vgn, 1)) {
log_error("Couldn't read all removed logical volume interconnections "
"for volume group %s.", vg->name);
goto bad;
@ -1259,24 +1238,20 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
goto bad;
}
dm_hash_destroy(pv_hash);
dm_hash_destroy(lv_hash);
if (fid)
vg_set_fid(vg, fid);
if (vg->pv_names) {
radix_tree_destroy(vg->pv_names);
vg->pv_names = NULL; /* PV names are no longer valid outside of _read_vg() */
}
/*
* Finished.
*/
return vg;
bad:
if (pv_hash)
dm_hash_destroy(pv_hash);
if (lv_hash)
dm_hash_destroy(lv_hash);
release_vg(vg);
return NULL;
}
@ -1360,7 +1335,7 @@ static int _read_vgsummary(const struct format_type *fmt, const struct dm_config
}
if (!_read_sections(fmt->cmd, NULL, NULL, mem, "physical_volumes", _read_pvsummary, NULL, vgsummary,
vgn, NULL, NULL, 0)) {
vgn, 0)) {
log_debug("Couldn't read pv summaries");
}

View File

@ -23,7 +23,6 @@ struct lv_segment;
struct dm_config_node;
int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn,
const struct dm_config_value *cv, struct dm_hash_table *pv_hash,
uint64_t status);
const struct dm_config_value *cv, uint64_t status);
#endif

View File

@ -36,8 +36,7 @@ static void _integrity_display(const struct lv_segment *seg)
}
static int _integrity_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
struct integrity_settings *set;
struct logical_volume *origin_lv = NULL;

View File

@ -21,6 +21,7 @@
#include "lib/metadata/segtype.h"
#include "lib/datastruct/str_list.h"
#include "lib/locking/lvmlockd.h"
#include "base/data-struct/radix-tree.h"
#include <time.h>
#include <sys/utsname.h>
@ -1577,10 +1578,26 @@ int lv_set_creation(struct logical_volume *lv,
return 1;
}
/*
* As we keep now vg->lv_names for quick looking of an LV by name
* when the LV name is changed, we need to also update our lookup tree
*/
int lv_set_name(struct logical_volume *lv, const char *lv_name)
{
if (lv->vg->lv_names && lv->name &&
!radix_tree_remove(lv->vg->lv_names, lv->name, strlen(lv->name))) {
log_error("Cannot remove from lv_names LV %s", lv->name);
return 0;
}
lv->name = lv_name; /* NULL -> LV is removed from tree */
if (lv->vg->lv_names && lv->name &&
!radix_tree_insert_ptr(lv->vg->lv_names, lv->name, strlen(lv->name), lv)) {
log_error("Cannot insert to lv_names LV %s", lv->name);
return 0;
}
return 1;
}

View File

@ -32,6 +32,7 @@
#include "lib/label/label.h"
#include "lib/misc/lvm-signal.h"
#include "lib/device/filesystem.h"
#include "base/data-struct/radix-tree.h"
#ifdef HAVE_BLKZEROOUT
#include <sys/ioctl.h>

View File

@ -1671,8 +1671,7 @@ struct logical_volume *find_lv_in_vg_by_lvid(const struct volume_group *vg,
struct logical_volume *find_lv(const struct volume_group *vg,
const char *lv_name)
{
struct lv_list *lvl = find_lv_in_vg(vg, lv_name);
return lvl ? lvl->lv : NULL;
return radix_tree_lookup_ptr(vg->lv_names, lv_name, strlen(lv_name));
}
struct generic_logical_volume *find_historical_glv(const struct volume_group *vg,
@ -1734,6 +1733,16 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
return NULL;
}
struct physical_volume *find_pv_by_pv_name(struct volume_group *vg, const char *pv_name)
{
if (!vg->pv_names) {
log_error(INTERNAL_ERROR "Cannot find pv name %s outside of _read_vg()", pv_name);
return NULL;
}
return radix_tree_lookup_ptr(vg->pv_names, pv_name, strlen(pv_name));
}
/* Find segment at a given logical extent in an LV */
struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le)
{

View File

@ -395,6 +395,7 @@ struct logical_volume *find_lv_in_vg_by_lvid(const struct volume_group *vg,
/* FIXME Merge these functions with ones above */
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
struct physical_volume *find_pv_by_pv_name(struct volume_group *vg, const char *pv_name);
struct pv_list *find_pv_in_pv_list(const struct dm_list *pl,
const struct physical_volume *pv);

View File

@ -254,8 +254,7 @@ struct segtype_handler {
int (*text_import_area_count) (const struct dm_config_node * sn,
uint32_t *area_count);
int (*text_import) (struct lv_segment * seg,
const struct dm_config_node * sn,
struct dm_hash_table * pv_hash);
const struct dm_config_node * sn);
int (*merge_segments) (struct lv_segment * seg1,
struct lv_segment * seg2);
int (*add_target_line) (struct dev_manager *dm, struct dm_pool *mem,

View File

@ -19,6 +19,7 @@
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/format_text/archiver.h"
#include "base/data-struct/radix-tree.h"
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
const char *vg_name)
@ -76,6 +77,13 @@ static void _free_vg(struct volume_group *vg)
if (vg->committed_cft)
config_destroy(vg->committed_cft);
if (vg->lv_names)
radix_tree_destroy(vg->lv_names);
if (vg->pv_names)
radix_tree_destroy(vg->pv_names);
dm_pool_destroy(vg->vgmem);
}
@ -129,6 +137,12 @@ int unlink_lv_from_vg(struct logical_volume *lv)
dm_list_move(&lv->vg->removed_lvs, &lvl->list);
lv->status |= LV_REMOVED;
/* lv->lv_name stays valid for historical LV usage
* So just remove the name from active lv_names */
if (lv->vg->lv_names &&
!radix_tree_remove(lv->vg->lv_names, lv->name, strlen(lv->name)))
stack;
return 1;
}

View File

@ -64,6 +64,9 @@ struct volume_group {
struct profile *profile;
uint64_t status;
struct radix_tree *lv_names; /* maintained tree for LV names within VG */
struct radix_tree *pv_names; /* PV names used for metadata import */
struct id id;
const char *name;
const char *old_name; /* Set during vgrename and vgcfgrestore */

View File

@ -73,8 +73,7 @@ static int _mirrored_text_import_area_count(const struct dm_config_node *sn, uin
return 1;
}
static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
struct dm_hash_table *pv_hash)
static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_node *sn)
{
const struct dm_config_value *cv;
const char *logname = NULL;
@ -126,7 +125,7 @@ static int _mirrored_text_import(struct lv_segment *seg, const struct dm_config_
return 0;
}
return text_import_areas(seg, sn, cv, pv_hash, MIRROR_IMAGE);
return text_import_areas(seg, sn, cv, MIRROR_IMAGE);
}
static int _mirrored_text_export(const struct lv_segment *seg, struct formatter *f)

View File

@ -128,8 +128,7 @@ static int _raid_text_import_areas(struct lv_segment *seg,
}
static int _raid_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash)
const struct dm_config_node *sn)
{
const struct dm_config_value *cv;
const struct {

View File

@ -34,9 +34,7 @@ static const char *_snap_target_name(const struct lv_segment *seg,
return lvseg_name(seg);
}
static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
static int _snap_text_import(struct lv_segment *seg, const struct dm_config_node *sn)
{
uint32_t chunk_size;
struct logical_volume *org, *cow;

View File

@ -69,8 +69,7 @@ static int _striped_text_import_area_count(const struct dm_config_node *sn, uint
return 1;
}
static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
struct dm_hash_table *pv_hash)
static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn)
{
const struct dm_config_value *cv;
@ -89,7 +88,7 @@ static int _striped_text_import(struct lv_segment *seg, const struct dm_config_n
seg->area_len /= seg->area_count;
return text_import_areas(seg, sn, cv, pv_hash, 0);
return text_import_areas(seg, sn, cv, 0);
}
static int _striped_text_export(const struct lv_segment *seg, struct formatter *f)

View File

@ -79,8 +79,7 @@ static int _thin_pool_add_message(struct lv_segment *seg,
}
static int _thin_pool_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
const char *lv_name;
struct logical_volume *pool_data_lv, *pool_metadata_lv;
@ -467,8 +466,7 @@ static void _thin_display(const struct lv_segment *seg)
}
static int _thin_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
const char *lv_name;
struct logical_volume *pool_lv, *origin = NULL, *external_lv = NULL, *merge_lv = NULL;

View File

@ -19,8 +19,7 @@
#include "lib/format_text/text_export.h"
#include "lib/config/config.h"
static int _unknown_text_import(struct lv_segment *seg, const struct dm_config_node *sn,
struct dm_hash_table *pv_hash)
static int _unknown_text_import(struct lv_segment *seg, const struct dm_config_node *sn)
{
struct dm_config_node *new, *last = NULL, *head = NULL;
const struct dm_config_node *current;

View File

@ -74,8 +74,7 @@ static void _vdo_display(const struct lv_segment *seg)
}
static int _vdo_text_import(struct lv_segment *seg,
const struct dm_config_node *n,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *n)
{
struct logical_volume *vdo_pool_lv;
const char *str;
@ -206,8 +205,7 @@ static int _vdo_pool_text_import_area_count(const struct dm_config_node *sn __at
}
static int _vdo_pool_text_import(struct lv_segment *seg,
const struct dm_config_node *n,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *n)
{
struct dm_vdo_target_params *vtp = &seg->vdo_params;
struct logical_volume *data_lv;

View File

@ -39,8 +39,7 @@ static void _writecache_display(const struct lv_segment *seg)
}
static int _writecache_text_import(struct lv_segment *seg,
const struct dm_config_node *sn,
struct dm_hash_table *pv_hash __attribute__((unused)))
const struct dm_config_node *sn)
{
struct logical_volume *origin_lv = NULL;
struct logical_volume *fast_lv;