diff options
author | David Teigland <teigland@redhat.com> | 2015-01-09 14:55:16 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2015-01-12 15:29:39 -0600 |
commit | ae7f35942edbda694967e0289d79c7a6f349be01 (patch) | |
tree | 500c06e769c4d508b85ba59aaab74ecda520c847 | |
parent | 1e4a4d48aeb1e56a8df19ba73425eb5f7632c9d2 (diff) | |
download | lvm2-dev-dct-pvdup2.tar.gz |
toollib: handle duplicate pvs in process_in_pvdev-dct-pvdup2
If /dev/loop0 and /dev/loop1 are duplicates,
pvs /dev/loop0 or pvs /dev/loop1 will both display the
same information.
pvs /dev/loop0 /dev/loop1 will display two lines, but
both will be the same.
-rw-r--r-- | lib/cache/lvmcache.c | 4 | ||||
-rw-r--r-- | lib/device/dev-cache.c | 32 | ||||
-rw-r--r-- | lib/device/dev-cache.h | 3 | ||||
-rw-r--r-- | tools/toollib.c | 126 |
4 files changed, 156 insertions, 9 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 416907e99..cd608b4b2 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -1539,10 +1539,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, //else if (dm_is_dm_major(MAJOR(existing->dev->dev)) && //dm_is_dm_major(MAJOR(dev->dev))) // - else if (!strcmp(pvid_s, existing->dev->pvid)) + else if (!strcmp(pvid_s, existing->dev->pvid)) { log_error("Found duplicate PV %s: using %s not " "%s", pvid, dev_name(dev), dev_name(existing->dev)); + dev_save_duplicate(fmt->cmd, existing->dev, pvid_s); + } } if (strcmp(pvid_s, existing->dev->pvid)) log_debug_cache("Updating pvid cache to %s (%s) from %s (%s)", diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index ba4ee5462..8d8890d91 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -35,6 +35,12 @@ struct dir_list { char dir[0]; }; +struct device_id_list { + struct dm_list list; + struct device *dev; + char pvid[ID_LEN + 1]; +}; + static struct { struct dm_pool *mem; struct dm_hash_table *names; @@ -45,6 +51,7 @@ static struct { int has_scanned; struct dm_list dirs; struct dm_list files; + struct dm_list duplicates; /* device_id_list */ } _cache; @@ -751,6 +758,7 @@ int dev_cache_init(struct cmd_context *cmd) dm_list_init(&_cache.dirs); dm_list_init(&_cache.files); + dm_list_init(&_cache.duplicates); if (!_init_preferred_names(cmd)) goto_bad; @@ -1067,6 +1075,30 @@ void dev_reset_error_count(struct cmd_context *cmd) _iter_next(&iter)->error_count = 0; } +void dev_save_duplicate(struct cmd_context *cmd, struct device *dev, const char *pvid) +{ + struct device_id_list *dil; + + if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) + return; + + strncpy(dil->pvid, pvid, ID_LEN); + dil->dev = dev; + dm_list_add(&_cache.duplicates, &dil->list); +} + +struct device *dev_find_duplicate(const char *pvid) +{ + struct device_id_list *dil; + + dm_list_iterate_items(dil, &_cache.duplicates) { + if (!strcmp(dil->pvid, pvid)) + return dil->dev; + } + + return NULL; +} + int dev_fd(struct device *dev) { return dev->fd; diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h index 4fca35885..cf2e9c299 100644 --- a/lib/device/dev-cache.h +++ b/lib/device/dev-cache.h @@ -56,6 +56,9 @@ struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f); void dev_set_preferred_name(struct dm_str_list *sl, struct device *dev); +void dev_save_duplicate(struct cmd_context *cmd, struct device *dev, const char *pvid); +struct device *dev_find_duplicate(const char *pvid); + /* * Object for iterating through the cache. */ diff --git a/tools/toollib.c b/tools/toollib.c index 1b3883e7f..d2e787e4a 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -2129,6 +2129,37 @@ out: return r; } +static void _get_arg_duplicates(struct cmd_context *cmd, struct dm_list *arg_devices, + struct dm_list *arg_duplicates) +{ + struct device_list *devl; + struct device_list *devl2; + struct device *dev_dup; + char pvid_s[ID_LEN + 1] __attribute__((aligned(8))); + + dm_list_iterate_items(devl, arg_devices) { + if (!devl->dev->pvid[0]) + continue; + + strncpy(pvid_s, devl->dev->pvid, sizeof(pvid_s) - 1); + pvid_s[sizeof(pvid_s) - 1] = '\0'; + + if (!(dev_dup = dev_find_duplicate(pvid_s))) + continue; + + if (!(devl2 = dm_pool_alloc(cmd->mem, sizeof(*devl2)))) { + log_error("device_list alloc failed."); + return; + } + + log_verbose("Duplicate device for arg %s is %s", + dev_name(devl->dev), dev_name(dev_dup)); + + devl2->dev = dev_dup; + dm_list_add(arg_duplicates, &devl2->list); + } +} + static int _device_list_remove(struct dm_list *all_devices, struct device *dev) { struct device_list *devl; @@ -2155,6 +2186,36 @@ static int _device_list_match(struct dm_list *devices, struct device *dev) return 0; } +/* Remove a device from the list if it has a matching pv id. */ + +static int _device_list_remove_pvid(struct dm_list *devices, struct physical_volume *pv) +{ + struct device_list *devl; + + dm_list_iterate_items(devl, devices) { + if (id_equal((struct id *) devl->dev->pvid, &pv->id)) { + dm_list_del(&devl->list); + return 1; + } + } + + return 0; +} + +/* Match a device from the list if it has a matching pv id. */ + +static int _device_list_match_pvid(struct dm_list *devices, struct physical_volume *pv) +{ + struct device_list *devl; + + dm_list_iterate_items(devl, devices) { + if (id_equal((struct id *) devl->dev->pvid, &pv->id)) + return 1; + } + + return 0; +} + static int _process_device_list(struct cmd_context *cmd, struct dm_list *all_devices, void *handle, process_single_pv_fn_t process_single_pv) { @@ -2193,6 +2254,7 @@ static int _process_pvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *all_devices, struct dm_list *arg_devices, + struct dm_list *arg_duplicates, struct dm_list *arg_tags, int process_all, int skip, @@ -2224,6 +2286,16 @@ static int _process_pvs_in_vg(struct cmd_context *cmd, _device_list_remove(arg_devices, pv->dev); } + /* Select the PV if the command was given a duplicate of its device. */ + + if (!process_pv && !dm_list_empty(arg_duplicates) && + _device_list_match_pvid(arg_duplicates, pv)) { + log_warn("PV %s is selected by duplicate device.", pv_name); + process_pv = 1; + _device_list_remove_pvid(arg_devices, pv); + _device_list_remove_pvid(arg_duplicates, pv); + } + if (!process_pv && !dm_list_empty(arg_tags) && str_list_match_list(arg_tags, &pv->tags, NULL)) process_pv = 1; @@ -2257,6 +2329,28 @@ 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 both duplicate + * devices are specified on the command line. Both refer to + * this PV. In this case we want to process the PV twice, once + * for each device that is specified. The first device was + * removed from arg_devices above. In this case, the PV will + * still exist in arg_devices via another device with the same + * pv id. + */ + if (!skip && !dm_list_empty(arg_devices) && !dm_list_empty(arg_duplicates) && + _device_list_match_pvid(arg_devices, pv)) { + log_warn("PV %s is repeated for duplicate command arg.", pv_name); + + _device_list_remove_pvid(arg_devices, pv); + + ret = process_single_pv(cmd, vg, pv, handle); + if (ret != ECMD_PROCESSED) + stack; + if (ret > ret_max) + ret_max = ret; + } } /* @@ -2284,6 +2378,7 @@ static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags, struct dm_list *all_vgnameids, struct dm_list *all_devices, struct dm_list *arg_devices, + struct dm_list *arg_duplicates, struct dm_list *arg_tags, int process_all, void *handle, @@ -2318,8 +2413,8 @@ static int _process_pvs_in_vgs(struct cmd_context *cmd, uint32_t flags, * vg->pvs entries from devices list. */ - ret = _process_pvs_in_vg(cmd, vg, all_devices, arg_devices, arg_tags, - process_all, skip, handle, process_single_pv); + ret = _process_pvs_in_vg(cmd, vg, all_devices, arg_devices, arg_duplicates, + arg_tags, process_all, skip, handle, process_single_pv); if (ret != ECMD_PROCESSED) stack; if (ret > ret_max) @@ -2348,6 +2443,7 @@ 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_duplicates; /* device_list */ struct dm_list all_vgnameids; /* vgnameid_list */ struct dm_list all_devices; /* device_list */ struct device_list *devl; @@ -2359,10 +2455,21 @@ int process_each_pv(struct cmd_context *cmd, dm_list_init(&arg_tags); dm_list_init(&arg_pvnames); dm_list_init(&arg_devices); + dm_list_init(&arg_duplicates); dm_list_init(&all_vgnameids); 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 to use + * in get_arg_duplicates. + */ + 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,14 +2503,17 @@ 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; - } + /* + * If an entry in arg_devices has a duplicate then create an entry for + * the duplicate in arg_duplicates. A user may specify/select a PV by + * either naming the PV's device, or by naming a duplicate of the PV's + * device. + */ + _get_arg_duplicates(cmd, &arg_devices, &arg_duplicates); ret = _process_pvs_in_vgs(cmd, flags, &all_vgnameids, &all_devices, - &arg_devices, &arg_tags, process_all_pvs, - handle, process_single_pv); + &arg_devices, &arg_duplicates, &arg_tags, + process_all_pvs, handle, process_single_pv); if (ret != ECMD_PROCESSED) stack; if (ret > ret_max) |