diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index 3a824f5a3..58c645660 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -395,7 +395,7 @@ static int _read_segment(struct cmd_context *cmd, uint32_t area_count = 0u; struct lv_segment *seg; const struct dm_config_node *sn_child = sn->child; - const struct dm_config_value *cv; + const struct dm_config_value *cv = NULL; uint32_t area_extents, start_extent, extent_count, reshape_count, data_copies; struct segment_type *segtype; const char *segtype_str; @@ -404,7 +404,7 @@ static int _read_segment(struct cmd_context *cmd, log_error("Empty segment section."); return 0; } - +#if 0 if (!_read_int32(sn_child, "start_extent", &start_extent)) { log_error("Couldn't read 'start_extent' for segment '%s' " "of logical volume %s.", sn->key, lv->name); @@ -430,6 +430,28 @@ static int _read_segment(struct cmd_context *cmd, return 0; } + /* Optional tags */ + dm_config_get_list(sn_child, "tags", &cv); +#else + segtype_str = SEG_TYPE_NAME_STRIPED; + reshape_count = 0; + data_copies = 1; + + struct config_values v[] = { + { "data_copies", CONFIG_VALUE_UINT32, &data_copies }, + { "extent_count", CONFIG_VALUE_UINT32, &extent_count, 1 }, + { "reshape_count", CONFIG_VALUE_UINT32, &reshape_count }, + { "start_extent", CONFIG_VALUE_UINT32, &start_extent, 1 }, + { "tags", CONFIG_VALUE_LIST, &cv }, + { "type", CONFIG_VALUE_STRING, &segtype_str }, + }; + + if (!text_import_values(sn_child, DM_ARRAY_SIZE(v), v)) { + log_error("Could not read segment values for %s.", + display_lvname(lv)); + return 0; + } +#endif if (!(segtype = _read_segtype_and_lvflags(cmd, &lv->status, segtype_str))) { log_error("Couldn't read segtype %s for logical volume %s.", segtype_str, display_lvname(lv)); @@ -454,13 +476,11 @@ static int _read_segment(struct cmd_context *cmd, return_0; /* Optional tags */ - if (dm_config_get_list(sn_child, "tags", &cv) && - !(_read_str_list(mem, &seg->tags, cv))) { + if (cv && !(_read_str_list(mem, &seg->tags, cv))) { log_error("Couldn't read tags for a segment of %s/%s.", lv->vg->name, lv->name); return 0; } - /* * Insert into correct part of segment list. */ @@ -547,6 +567,58 @@ int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, return 1; } +static int _compare_config_values_s(const void *a, const void *b) +{ + return strcmp(((const struct config_values*)a)->path, + ((const struct config_values*)b)->path); +} + +/* + * Read set of values out of config tree nodes + * + * config_values are expected to be in Alphabetic order for use with bsearch!! + */ +int text_import_values(const struct dm_config_node *cn, + size_t values_count, struct config_values *values) +{ + struct config_values *found; + unsigned i; + int ret = 1; + + while (cn) { + found = bsearch((struct config_values *)cn->key, values, values_count, + sizeof(*found), _compare_config_values_s); + + if (found) { + switch (found->type) { + case CONFIG_VALUE_STRING: + *(const char**)(found->result) = cn->v->v.str; + break; + case CONFIG_VALUE_UINT64: + *(uint64_t*)(found->result) = (uint64_t)cn->v->v.i; + break; + case CONFIG_VALUE_UINT32: + *(uint32_t*)(found->result) = (uint32_t)cn->v->v.i; + break; + case CONFIG_VALUE_LIST: + *(struct dm_config_value**)(found->result) = cn->v; + break; + } + --(found->mandatory); + } + + cn = cn->sib; + } + + for (i = 0 ; i < values_count; ++i) + if (values[i].mandatory > 0) { + log_error("Required option %s is missing!", values[i].path); + ret = 0; + } + + return ret; +} + static int _read_segments(struct cmd_context *cmd, struct format_type *fmt, struct format_instance *fid, diff --git a/lib/format_text/text_import.h b/lib/format_text/text_import.h index 643751b65..7a0292e59 100644 --- a/lib/format_text/text_import.h +++ b/lib/format_text/text_import.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2024 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -25,4 +25,21 @@ struct dm_config_node; int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, const struct dm_config_value *cv, uint64_t status); +typedef enum { + CONFIG_VALUE_STRING, + CONFIG_VALUE_UINT64, + CONFIG_VALUE_UINT32, + CONFIG_VALUE_LIST, +} config_value_t; + +struct config_values { + const char path[16]; /* option name/path to look for */ + config_value_t type; /* type of resulting value */ + void *result; /* where to place resulting value of given type */ + int mandatory; /* If this path is missing in config node, import fails */ +}; + +int text_import_values(const struct dm_config_node *cn, + size_t values_count, struct config_values *values); + #endif diff --git a/lib/striped/striped.c b/lib/striped/striped.c index 09c3fca8e..b684a07d5 100644 --- a/lib/striped/striped.c +++ b/lib/striped/striped.c @@ -72,7 +72,28 @@ static int _striped_text_import_area_count(const struct dm_config_node *sn, uint static int _striped_text_import(struct lv_segment *seg, const struct dm_config_node *sn) { const struct dm_config_value *cv; +#if 1 + uint32_t stripe_size = 0; + struct config_values v[] = { + { "stripe_size", CONFIG_VALUE_UINT32, &stripe_size }, + { "stripes", CONFIG_VALUE_LIST, &cv }, + }; + + if (!text_import_values(sn, DM_ARRAY_SIZE(v), v)) { + log_error("Could not read segment values for"); + return 0; + } + + if (seg->area_count != 1) { + if (!stripe_size) { + log_error("Couldn't read stripe_size for segment %s " + "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); + return 0; + } + seg->stripe_size = stripe_size; + } +#else if ((seg->area_count != 1) && !dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) { log_error("Couldn't read stripe_size for segment %s " @@ -85,6 +106,7 @@ static int _striped_text_import(struct lv_segment *seg, const struct dm_config_n "of logical volume %s.", dm_config_parent_name(sn), seg->lv->name); return 0; } +#endif seg->area_len /= seg->area_count; diff --git a/lib/thin/thin.c b/lib/thin/thin.c index 4407294b6..8ad7d023d 100644 --- a/lib/thin/thin.c +++ b/lib/thin/thin.c @@ -21,6 +21,7 @@ #include "lib/config/config.h" #include "lib/activate/activate.h" #include "lib/datastruct/str_list.h" +#include "lib/format_text/text_import.h" /* Dm kernel module name for thin provisioning */ static const char _thin_pool_module[] = "thin-pool"; @@ -86,7 +87,20 @@ static int _thin_pool_text_import(struct lv_segment *seg, const char *discards_str = NULL; uint32_t zero = 0; uint32_t crop = UINT32_MAX; +#if 1 + struct config_values v[] = { + { "chunk_size", CONFIG_VALUE_UINT32, &seg->chunk_size, 1 }, + { "crop_metadata", CONFIG_VALUE_UINT32, &crop }, + { "discards", CONFIG_VALUE_STRING, &discards_str }, + { "metadata", CONFIG_VALUE_STRING, &meta_name, 1 }, + { "pool", CONFIG_VALUE_STRING, &lv_name, 1 }, + { "transaction_id", CONFIG_VALUE_UINT64, &seg->transaction_id, 1 }, + { "zero_new_blocks", CONFIG_VALUE_UINT32, &zero }, + }; + if (!text_import_values(sn, DM_ARRAY_SIZE(v), v)) + return SEG_LOG_ERROR("Could not read segment values for"); +#else if (!dm_config_get_str(sn, "metadata", &meta_name)) return SEG_LOG_ERROR("Metadata must be a string in"); @@ -111,7 +125,7 @@ static int _thin_pool_text_import(struct lv_segment *seg, if (!dm_config_get_uint32(sn, "crop_metadata", &crop)) return SEG_LOG_ERROR("Could not read crop_metadata for"); } - +#endif if (!(pool_data_lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown pool %s in", lv_name); @@ -471,10 +485,46 @@ static void _thin_display(const struct lv_segment *seg) static int _thin_text_import(struct lv_segment *seg, const struct dm_config_node *sn) { - const char *lv_name; - struct logical_volume *pool_lv, *origin = NULL, *external_lv = NULL, *merge_lv = NULL; + const char *pool_name = NULL, *origin_name = NULL, *external_name = NULL, *merge_name = NULL; + struct logical_volume *pool_lv, *origin_lv = NULL, *external_lv = NULL, *merge_lv = NULL; struct generic_logical_volume *indirect_origin = NULL; + int64_t transaction_id = -1, device_id = -1; + struct config_values v[] = { + { "device_id", CONFIG_VALUE_UINT64, &device_id, 1 }, + { "external_origin", CONFIG_VALUE_STRING, &external_name }, + { "merge", CONFIG_VALUE_STRING, &merge_name }, + { "origin", CONFIG_VALUE_STRING, &origin_name }, + { "thin_pool", CONFIG_VALUE_STRING, &pool_name, 1 }, + { "transaction_id", CONFIG_VALUE_UINT64, &transaction_id, 1 }, + }; + + if (!text_import_values(sn, DM_ARRAY_SIZE(v), v)) + return SEG_LOG_ERROR("Could not read segment values for"); + + seg->transaction_id = (uint64_t)transaction_id; + seg->device_id = (uint64_t)device_id; + if (seg->device_id > DM_THIN_MAX_DEVICE_ID) + return SEG_LOG_ERROR("Unsupported value %u for device_id", + seg->device_id); + if (!pool_name) + return SEG_LOG_ERROR("Thin pool must be a string in"); + + if (!(pool_lv = find_lv(seg->lv->vg, pool_name))) + return SEG_LOG_ERROR("Unknown thin pool %s in", pool_name); + + if (origin_name && + !(origin_lv = find_lv(seg->lv->vg, origin_name))) + return SEG_LOG_ERROR("Unknown origin %s in", origin_name); + + if (merge_name && + !(merge_lv = find_lv(seg->lv->vg, merge_name))) + return SEG_LOG_ERROR("Unknown merge lv %s in", merge_name); + + if (external_name && + !(external_lv = find_lv(seg->lv->vg, external_name))) + return SEG_LOG_ERROR("Unknown external origin %s in", external_name); +#if 0 if (!dm_config_get_str(sn, "thin_pool", &lv_name)) return SEG_LOG_ERROR("Thin pool must be a string in"); @@ -513,8 +563,8 @@ static int _thin_text_import(struct lv_segment *seg, if (!(external_lv = find_lv(seg->lv->vg, lv_name))) return SEG_LOG_ERROR("Unknown external origin %s in", lv_name); } - - if (!attach_pool_lv(seg, pool_lv, origin, indirect_origin, merge_lv)) +#endif + if (!attach_pool_lv(seg, pool_lv, origin_lv, indirect_origin, merge_lv)) return_0; if (!attach_thin_external_origin(seg, external_lv))