summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2015-01-09 14:55:16 -0600
committerDavid Teigland <teigland@redhat.com>2015-01-12 15:29:39 -0600
commitae7f35942edbda694967e0289d79c7a6f349be01 (patch)
tree500c06e769c4d508b85ba59aaab74ecda520c847
parent1e4a4d48aeb1e56a8df19ba73425eb5f7632c9d2 (diff)
downloadlvm2-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.c4
-rw-r--r--lib/device/dev-cache.c32
-rw-r--r--lib/device/dev-cache.h3
-rw-r--r--tools/toollib.c126
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)