From bfb6a4ecc6ad7bb06649ffd026d9c997443dd684 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Fri, 3 Oct 2014 20:47:19 +0100 Subject: [PATCH] toollib: Rewrite process_each_vg. Split VG argument collection from processing. This allows the two different loops through VGs to be replaced by a single loop. Replace unused struct cmd_vg and cmd_vg_read() replicator code with struct vg and vg_read() directly. [Committed by agk with cosmetic changes and tweaks.] --- WHATS_NEW | 1 + tools/toollib.c | 391 ++++++++++++++++++++++++++++++------------------ 2 files changed, 246 insertions(+), 146 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index a94edc690..ad7bafbd7 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.112 - ===================================== + Refactor process_each_vg in toollib. Pools cannot be used as external origin. Use lv_update_and_reload() for snapshot reload. Don't print message in adjusted_mirror_region_size() in activation. diff --git a/tools/toollib.c b/tools/toollib.c index c5395baba..8049b1fbe 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -169,7 +169,9 @@ int ignore_vg(struct volume_group *vg, const char *vg_name, int allow_inconsiste if ((read_error == FAILED_INCONSISTENT) && allow_inconsistent) return 0; - if (read_error == FAILED_CLUSTERED && vg->cmd->ignore_clustered_vgs) + if (read_error == FAILED_NOTFOUND) + *ret = ECMD_FAILED; + else if (read_error == FAILED_CLUSTERED && vg->cmd->ignore_clustered_vgs) log_verbose("Skipping volume group %s", vg_name); else { log_error("Skipping volume group %s", vg_name); @@ -566,151 +568,6 @@ int process_each_segment_in_lv(struct cmd_context *cmd, return ret_max; } -static int _process_one_vg(struct cmd_context *cmd, const char *vg_name, - const char *vgid, - struct dm_list *tagsl, struct dm_list *arg_vgnames, - uint32_t flags, void *handle, int ret_max, - process_single_vg_fn_t process_single_vg) -{ - struct dm_list cmd_vgs; - struct cmd_vg *cvl_vg; - int ret = ECMD_PROCESSED; - - log_verbose("Finding volume group \"%s\"", vg_name); - - dm_list_init(&cmd_vgs); - if (!(cvl_vg = cmd_vg_add(cmd->mem, &cmd_vgs, vg_name, vgid, flags))) - return_ECMD_FAILED; - - for (;;) { - if (sigint_caught()) { - ret = ECMD_FAILED; - stack; - break; - } - - if (!cmd_vg_read(cmd, &cmd_vgs)) { - /* Allow FAILED_INCONSISTENT through only for vgcfgrestore */ - if (ignore_vg(cvl_vg->vg, vg_name, flags & READ_ALLOW_INCONSISTENT, &ret)) { - stack; - break; - } - } - - if (!dm_list_empty(tagsl) && - /* Only process if a tag matches or it's on arg_vgnames */ - !str_list_match_item(arg_vgnames, vg_name) && - !str_list_match_list(tagsl, &cvl_vg->vg->tags, NULL)) - break; - - ret = process_single_vg(cmd, vg_name, cvl_vg->vg, handle); - - if (vg_read_error(cvl_vg->vg)) /* FAILED_INCONSISTENT */ - break; - - if (!cvl_vg->vg->cmd_missing_vgs) - break; - - free_cmd_vgs(&cmd_vgs); - } - - free_cmd_vgs(&cmd_vgs); - - return (ret > ret_max) ? ret : ret_max; -} - -int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - uint32_t flags, void *handle, - process_single_vg_fn_t process_single_vg) -{ - int opt = 0; - int ret_max = ECMD_PROCESSED; - - struct dm_str_list *sl; - struct dm_list *vgnames, *vgids; - struct dm_list arg_vgnames, tagsl; - - const char *vg_name, *vgid; - - dm_list_init(&tagsl); - dm_list_init(&arg_vgnames); - - if (argc) { - log_verbose("Using volume group(s) on command line"); - - for (; opt < argc; opt++) { - vg_name = argv[opt]; - if (*vg_name == '@') { - if (!validate_tag(vg_name + 1)) { - log_error("Skipping invalid tag %s", - vg_name); - if (ret_max < EINVALID_CMD_LINE) - ret_max = EINVALID_CMD_LINE; - continue; - } - if (!str_list_add(cmd->mem, &tagsl, - dm_pool_strdup(cmd->mem, - vg_name + 1))) { - log_error("strlist allocation failed"); - return ECMD_FAILED; - } - continue; - } - - vg_name = skip_dev_dir(cmd, vg_name, NULL); - if (strchr(vg_name, '/')) { - log_error("Invalid volume group name: %s", - vg_name); - if (ret_max < EINVALID_CMD_LINE) - ret_max = EINVALID_CMD_LINE; - continue; - } - if (!str_list_add(cmd->mem, &arg_vgnames, - dm_pool_strdup(cmd->mem, vg_name))) { - log_error("strlist allocation failed"); - return ECMD_FAILED; - } - } - - vgnames = &arg_vgnames; - } - - if (!argc || !dm_list_empty(&tagsl)) { - log_verbose("Finding all volume groups"); - if (!lvmetad_vg_list_to_lvmcache(cmd)) - stack; - if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) { - log_error("No volume groups found"); - return ret_max; - } - dm_list_iterate_items(sl, vgids) { - if (sigint_caught()) - return_ECMD_FAILED; - vgid = sl->str; - if (!vgid || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) - continue; - ret_max = _process_one_vg(cmd, vg_name, vgid, &tagsl, - &arg_vgnames, - flags, handle, - ret_max, process_single_vg); - } - } else { - dm_list_iterate_items(sl, vgnames) { - if (sigint_caught()) - return_ECMD_FAILED; - vg_name = sl->str; - if (is_orphan_vg(vg_name)) - continue; /* FIXME Unnecessary? */ - ret_max = _process_one_vg(cmd, vg_name, NULL, &tagsl, - &arg_vgnames, - flags, handle, - ret_max, process_single_vg); - } - } - - return ret_max; -} - int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, const struct dm_list *tagsl, void *handle, process_single_pv_fn_t process_single_pv) @@ -1986,3 +1843,245 @@ int validate_lvname_param(struct cmd_context *cmd, const char **vg_name, return 1; } + +struct vgnameid_list { + struct dm_list list; + const char *vg_name; + const char *vgid; +}; + +/* + * Extract list of VG names and list of tags from command line arguments. + */ +static int _get_arg_vgnames(struct cmd_context *cmd, + int argc, char **argv, + struct dm_list *arg_vgnames, + struct dm_list *arg_tags) +{ + int opt = 0; + int ret_max = ECMD_PROCESSED; + const char *vg_name; + + log_verbose("Using volume group(s) on command line"); + + for (; opt < argc; opt++) { + vg_name = argv[opt]; + if (*vg_name == '@') { + if (!validate_tag(vg_name + 1)) { + log_error("Skipping invalid tag: %s", vg_name); + if (ret_max < EINVALID_CMD_LINE) + ret_max = EINVALID_CMD_LINE; + continue; + } + if (!str_list_add(cmd->mem, arg_tags, + dm_pool_strdup(cmd->mem, vg_name + 1))) { + log_error("strlist allocation failed"); + return ECMD_FAILED; + } + continue; + } + + vg_name = skip_dev_dir(cmd, vg_name, NULL); + if (strchr(vg_name, '/')) { + log_error("Invalid volume group name: %s", vg_name); + if (ret_max < EINVALID_CMD_LINE) + ret_max = EINVALID_CMD_LINE; + continue; + } + if (!str_list_add(cmd->mem, arg_vgnames, + dm_pool_strdup(cmd->mem, vg_name))) { + log_error("strlist allocation failed"); + return ECMD_FAILED; + } + } + + return ret_max; +} + +/* + * FIXME Add arg to include (or not) entries with duplicate vg names? + * + * Obtain complete list of VG name/vgid pairs known on the system. + */ +static int _get_vgnameids_on_system(struct cmd_context *cmd, + struct dm_list *vgnameids_on_system) +{ + struct vgnameid_list *vgnl; + struct dm_list *vgids; + struct dm_str_list *sl; + const char *vgid; + + log_verbose("Finding all volume groups"); + + if (!lvmetad_vg_list_to_lvmcache(cmd)) + stack; + + /* + * Start with complete vgid list because multiple VGs might have same name. + */ + vgids = get_vgids(cmd, 0); + if (!vgids || dm_list_empty(vgids)) { + stack; + return ECMD_PROCESSED; + } + + /* FIXME get_vgids() should provide these pairings directly */ + dm_list_iterate_items(sl, vgids) { + if (!(vgid = sl->str)) + continue; + + if (!(vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)))) { + log_error("vgnameid_list allocation failed"); + return ECMD_FAILED; + } + + vgnl->vgid = dm_pool_strdup(cmd->mem, vgid); + vgnl->vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid); + + dm_list_add(vgnameids_on_system, &vgnl->list); + } + + return ECMD_PROCESSED; +} + +static int _process_vgnameid_list(struct cmd_context *cmd, uint32_t flags, + struct dm_list *vgnameids_to_process, + struct dm_list *arg_vgnames, + struct dm_list *arg_tags, void *handle, + process_single_vg_fn_t process_single_vg) +{ + struct volume_group *vg; + struct vgnameid_list *vgnl; + const char *vg_name; + const char *vg_uuid; + int ret_max = ECMD_PROCESSED; + int ret; + int process_all = 0; + + /* + * If no VG names or tags were supplied, then process all VGs. + */ + if (dm_list_empty(arg_vgnames) && dm_list_empty(arg_tags)) + process_all = 1; + + dm_list_iterate_items(vgnl, vgnameids_to_process) { + vg_name = vgnl->vg_name; + vg_uuid = vgnl->vgid; + ret = 0; + + vg = vg_read(cmd, vg_name, vg_uuid, flags); + if (ignore_vg(vg, vg_name, flags & READ_ALLOW_INCONSISTENT, &ret)) { + if (ret > ret_max) + ret_max = ret; + release_vg(vg); + stack; + continue; + } + + /* Process this VG? */ + if (process_all || + (!dm_list_empty(arg_vgnames) && str_list_match_item(arg_vgnames, vg_name)) || + (!dm_list_empty(arg_tags) && str_list_match_list(arg_tags, &vg->tags, NULL))) + ret = process_single_vg(cmd, vg_name, vg, handle); + + if (vg_read_error(vg)) + release_vg(vg); + else + unlock_and_release_vg(cmd, vg, vg_name); + + if (ret > ret_max) + ret_max = ret; + if (sigint_caught()) + break; + } + + return ret_max; +} + +/* + * Copy the contents of a str_list of VG names to a name list, filling + * in the vgid with NULL (unknown). + */ +static int _copy_str_to_name_list(struct cmd_context *cmd, struct dm_list *sll, + struct dm_list *vgnll) +{ + const char *vgname; + struct dm_str_list *sl; + struct vgnameid_list *vgnl; + + dm_list_iterate_items(sl, sll) { + vgname = sl->str; + + vgnl = dm_pool_alloc(cmd->mem, sizeof(*vgnl)); + if (!vgnl) { + log_error("vgnameid_list allocation failed"); + return ECMD_FAILED; + } + + vgnl->vgid = NULL; + vgnl->vg_name = dm_pool_strdup(cmd->mem, vgname); + + dm_list_add(vgnll, &vgnl->list); + } + + return ECMD_PROCESSED; +} + +/* + * Call process_single_vg() for each VG selected by the command line arguments. + */ +int process_each_vg(struct cmd_context *cmd, int argc, char **argv, + uint32_t flags, void *handle, + process_single_vg_fn_t process_single_vg) +{ + struct dm_list arg_tags; /* str_list */ + struct dm_list arg_vgnames; /* str_list */ + struct dm_list vgnameids_on_system; /* vgnameid_list */ + struct dm_list vgnameids_to_process; /* vgnameid_list */ + + int enable_all_vgs = (cmd->command->flags & ALL_VGS_IS_DEFAULT); + int ret; + + dm_list_init(&arg_tags); + dm_list_init(&arg_vgnames); + dm_list_init(&vgnameids_on_system); + dm_list_init(&vgnameids_to_process); + + /* + * Find any VGs or tags explicitly provided on the command line. + */ + if ((ret = _get_arg_vgnames(cmd, argc, argv, &arg_vgnames, &arg_tags)) != ECMD_PROCESSED) { + stack; + return ret; + } + + /* + * Obtain the complete list of VGs present on the system if it is needed because: + * any tags were supplied and need resolving; or + * no VG names were given and the command defaults to processing all VGs. + */ + if (((dm_list_empty(&arg_vgnames) && enable_all_vgs) || !dm_list_empty(&arg_tags)) && + ((ret = _get_vgnameids_on_system(cmd, &vgnameids_on_system)) != ECMD_PROCESSED)) { + stack; + return ret; + } + + if (dm_list_empty(&arg_vgnames) && dm_list_empty(&vgnameids_on_system)) { + log_error("No volume groups found"); + return ECMD_PROCESSED; + } + + /* + * If we obtained a full list of VGs on the system, we need to work through them all; + * otherwise we can merely work through the VG names provided. + */ + if (!dm_list_empty(&vgnameids_on_system)) + dm_list_splice(&vgnameids_to_process, &vgnameids_on_system); + else if ((ret = _copy_str_to_name_list(cmd, &arg_vgnames, &vgnameids_to_process)) != ECMD_PROCESSED) { + stack; + return ret; + } + + return _process_vgnameid_list(cmd, flags, &vgnameids_to_process, + &arg_vgnames, &arg_tags, handle, process_single_vg); +} -- 2.43.5