diff options
Diffstat (limited to 'tools/toollib.c')
-rw-r--r-- | tools/toollib.c | 131 |
1 files changed, 94 insertions, 37 deletions
diff --git a/tools/toollib.c b/tools/toollib.c index 1b3883e7f..82251b905 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -2079,20 +2079,21 @@ static int _get_arg_devices(struct cmd_context *cmd, struct dm_list *arg_devices) { struct dm_str_list *sl; - struct device_list *devl; + struct device_id_list *dil; int ret_max = ECMD_PROCESSED; dm_list_iterate_items(sl, arg_pvnames) { - if (!(devl = dm_pool_alloc(cmd->mem, sizeof(*devl)))) { - log_error("device_list alloc failed."); + if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) { + log_error("device_id_list alloc failed."); return ECMD_FAILED; } - if (!(devl->dev = dev_cache_get(sl->str, cmd->filter))) { - log_error("Failed to find physical volume \"%s\".", sl->str); + if (!(dil->dev = dev_cache_get(sl->str, cmd->filter))) { + log_error("Failed to find device for physical volume \"%s\".", sl->str); ret_max = ECMD_FAILED; } else { - dm_list_add(arg_devices, &devl->list); + strncpy(dil->pvid, dil->dev->pvid, ID_LEN); + dm_list_add(arg_devices, &dil->list); } } @@ -2103,7 +2104,7 @@ static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices { struct dev_iter *iter; struct device *dev; - struct device_list *devl; + struct device_id_list *dil; int r = ECMD_FAILED; lvmcache_seed_infos_from_lvmetad(cmd); @@ -2114,13 +2115,13 @@ static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices } while ((dev = dev_iter_get(iter))) { - if (!(devl = dm_pool_alloc(cmd->mem, sizeof(*devl)))) { - log_error("device_list alloc failed."); + if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) { + log_error("device_id_list alloc failed."); goto out; } - devl->dev = dev; - dm_list_add(all_devices, &devl->list); + dil->dev = dev; + dm_list_add(all_devices, &dil->list); } r = ECMD_PROCESSED; @@ -2129,13 +2130,13 @@ out: return r; } -static int _device_list_remove(struct dm_list *all_devices, struct device *dev) +static int _device_list_remove(struct dm_list *devices, struct device *dev) { - struct device_list *devl; + struct device_id_list *dil; - dm_list_iterate_items(devl, all_devices) { - if (devl->dev == dev) { - dm_list_del(&devl->list); + dm_list_iterate_items(dil, devices) { + if (dil->dev == dev) { + dm_list_del(&dil->list); return 1; } } @@ -2143,16 +2144,28 @@ static int _device_list_remove(struct dm_list *all_devices, struct device *dev) return 0; } -static int _device_list_match(struct dm_list *devices, struct device *dev) +static struct device_id_list *_device_list_find_dev(struct dm_list *devices, struct device *dev) { - struct device_list *devl; + struct device_id_list *dil; - dm_list_iterate_items(devl, devices) { - if (devl->dev == dev) - return 1; + dm_list_iterate_items(dil, devices) { + if (dil->dev == dev) + return dil; } - return 0; + return NULL; +} + +static struct device_id_list *_device_list_find_pvid(struct dm_list *devices, struct physical_volume *pv) +{ + struct device_id_list *dil; + + dm_list_iterate_items(dil, devices) { + if (id_equal((struct id *) dil->pvid, &pv->id)) + return dil; + } + + return NULL; } static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_devices, @@ -2160,7 +2173,7 @@ static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_dev { struct physical_volume pv_dummy; struct physical_volume *pv; - struct device_list *devl; + struct device_id_list *dil; int ret_max = ECMD_PROCESSED; int ret = 0; @@ -2168,17 +2181,17 @@ static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_dev * Pretend that each device is a PV with dummy values. * FIXME Formalise this extension or find an alternative. */ - dm_list_iterate_items(devl, all_devices) { + dm_list_iterate_items(dil, all_devices) { if (sigint_caught()) return_ECMD_FAILED; memset(&pv_dummy, 0, sizeof(pv_dummy)); dm_list_init(&pv_dummy.tags); dm_list_init(&pv_dummy.segments); - pv_dummy.dev = devl->dev; + pv_dummy.dev = dil->dev; pv = &pv_dummy; - log_very_verbose("Processing device %s.", dev_name(devl->dev)); + log_very_verbose("Processing device %s.", dev_name(dil->dev)); ret = process_single_pv(cmd, NULL, pv, handle); @@ -2201,6 +2214,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd, { struct physical_volume *pv; struct pv_list *pvl; + struct device_id_list *dil; const char *pv_name; int process_pv; int dev_found; @@ -2219,9 +2233,19 @@ static int _process_pvs_in_vg(struct cmd_context *cmd, /* Remove each arg_devices entry as it is processed. */ if (!process_pv && !dm_list_empty(arg_devices) && - _device_list_match(arg_devices, pv->dev)) { + (dil = _device_list_find_dev(arg_devices, pv->dev))) { process_pv = 1; - _device_list_remove(arg_devices, pv->dev); + _device_list_remove(arg_devices, dil->dev); + } + + /* Select the PV if the device arg has the same pvid. */ + + if (!process_pv && !dm_list_empty(arg_devices) && + (dil = _device_list_find_pvid(arg_devices, pv))) { + log_warn("PV %s selected by duplicate device %s.", + pv_name, dev_name(dil->dev)); + process_pv = 1; + _device_list_remove(arg_devices, dil->dev); } if (!process_pv && !dm_list_empty(arg_tags) && @@ -2257,6 +2281,35 @@ static int _process_pvs_in_vg(struct cmd_context *cmd, if (ret > ret_max) ret_max = ret; } + + /* + * This is a very rare and obscure case where multiple + * duplicate devices are specified on the command line + * referring to this PV. In this case we want to + * process this PV once for each specified device. + */ + + if (!skip && !dm_list_empty(arg_devices)) { + while ((dil = _device_list_find_pvid(arg_devices, pv))) { + log_warn("PV %s repeated for duplicate device %s.", + pv_name, dev_name(dil->dev)); + + _device_list_remove(arg_devices, dil->dev); + + /* + * This will simply display the same PV + * multiple times. Further changes would + * be needed to make this display the details + * of dil->dev instead of pv->dev. + */ + + ret = process_single_pv(cmd, vg, pv, handle); + if (ret != ECMD_PROCESSED) + stack; + if (ret > ret_max) + ret_max = ret; + } + } } /* @@ -2347,10 +2400,10 @@ int process_each_pv(struct cmd_context *cmd, { struct dm_list arg_tags; /* str_list */ struct dm_list arg_pvnames; /* str_list */ - struct dm_list arg_devices; /* device_list */ + struct dm_list arg_devices; /* device_id_list */ struct dm_list all_vgnameids; /* vgnameid_list */ struct dm_list all_devices; /* device_list */ - struct device_list *devl; + struct device_id_list *dil; int process_all_pvs; int process_all_devices; int ret_max = ECMD_PROCESSED; @@ -2363,6 +2416,15 @@ int process_each_pv(struct cmd_context *cmd, dm_list_init(&all_devices); /* + * We need to read all the vgs first because this has the effect + * of initializing other device/lvmcache info that we need. + */ + if ((ret = _get_vgnameids_on_system(cmd, &all_vgnameids, only_this_vgname, 1) != ECMD_PROCESSED)) { + stack; + return ret; + } + + /* * Create two lists from argv: * arg_pvnames: pvs explicitly named in argv * arg_tags: tags explicitly named in argv @@ -2396,11 +2458,6 @@ int process_each_pv(struct cmd_context *cmd, return ret; } - if ((ret = _get_vgnameids_on_system(cmd, &all_vgnameids, only_this_vgname, 1) != ECMD_PROCESSED)) { - stack; - return ret; - } - ret = _process_pvs_in_vgs(cmd, flags, &all_vgnameids, &all_devices, &arg_devices, &arg_tags, process_all_pvs, handle, process_single_pv); @@ -2409,8 +2466,8 @@ int process_each_pv(struct cmd_context *cmd, if (ret > ret_max) ret_max = ret; - dm_list_iterate_items(devl, &arg_devices) { - log_error("Failed to find physical volume \"%s\".", dev_name(devl->dev)); + dm_list_iterate_items(dil, &arg_devices) { + log_error("Failed to find physical volume \"%s\".", dev_name(dil->dev)); ret_max = ECMD_FAILED; } |