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

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.]
This commit is contained in:
David Teigland 2014-10-03 20:47:19 +01:00 committed by Alasdair G Kergon
parent 91198ac13e
commit bfb6a4ecc6
2 changed files with 246 additions and 146 deletions

View File

@ -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.

View File

@ -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);
}