diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 46bd15be5..9639b926b 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -1667,6 +1667,13 @@ struct logical_volume *find_lv_in_vg_by_lvid(const struct volume_group *vg, if (memcmp(&lvid->id[0], &vg->id, ID_LEN)) return NULL; /* Check VG does not match */ + if (vg->lv_uuids) + /* Used only for committed read-only VG (which happens to be + * the only user of this 'find' function. + * ATM we do NOT update this radix_tree when LV is added/removed! */ + return radix_tree_lookup_ptr(vg->lv_uuids, &lvid->id[1], + sizeof(lvid->id[1])); + dm_list_iterate_items(lvl, &vg->lvs) if (!memcmp(&lvid->id[1], &lvl->lv->lvid.id[1], sizeof(lvid->id[1]))) return lvl->lv; /* LV uuid match */ @@ -4349,6 +4356,8 @@ const struct logical_volume *lv_committed(const struct logical_volume *lv) { struct volume_group *vg; const struct logical_volume *found_lv; + struct lv_list *lvl; + int r; if (!lv) return NULL; @@ -4358,6 +4367,24 @@ const struct logical_volume *lv_committed(const struct logical_volume *lv) vg = lv->vg->vg_committed; + if (!vg->lv_uuids && + (vg->lv_uuids = radix_tree_create(NULL, NULL))) + /* Create radix_tree for the 'committed' VG, that should + * never be modified and is only used for 'activation' + * so the tree need to constructed just once. */ + dm_list_iterate_items(lvl, &vg->lvs) { + if (!(r = radix_tree_uniq_insert_ptr(vg->lv_uuids, + &lvl->lv->lvid.id[1], + sizeof(lvl->lv->lvid.id[1]), + lvl->lv))) { + radix_tree_destroy(vg->lv_uuids); + vg->lv_uuids = NULL; /* fallback to linear search */ + break; + } + if (r != 1) /* There is duplicate ID, but continue with 'best' effort */ + log_warn("WARNING: Duplicate id found!"); + } + if (!(found_lv = find_lv_in_vg_by_lvid(vg, &lv->lvid))) { log_error(INTERNAL_ERROR "LV %s (UUID %s) not found in committed metadata.", display_lvname(lv), lv->lvid.s); diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c index 49dfe0266..d78022bb7 100644 --- a/lib/metadata/vg.c +++ b/lib/metadata/vg.c @@ -81,6 +81,9 @@ static void _free_vg(struct volume_group *vg) if (vg->lv_names) radix_tree_destroy(vg->lv_names); + if (vg->lv_uuids) + radix_tree_destroy(vg->lv_uuids); + if (vg->pv_names) radix_tree_destroy(vg->pv_names); diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h index 4117932bd..92a15ef2f 100644 --- a/lib/metadata/vg.h +++ b/lib/metadata/vg.h @@ -65,6 +65,7 @@ struct volume_group { uint64_t status; struct radix_tree *lv_names; /* maintained tree for LV names within VG */ + struct radix_tree *lv_uuids; /* LV uuid (when searching committed metadata) */ struct radix_tree *pv_names; /* PV names used for metadata import */ struct id id;