diff options
-rw-r--r-- | lib/cache/lvmcache.c | 168 |
1 files changed, 149 insertions, 19 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index a0811d4ea..0e62cd267 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -673,7 +673,7 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in wwid = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID); if (!wwid && wwid1) { - log_print("Different wwids for duplicate PVs %s %s %s none", + log_debug("Different wwids for duplicate PVs %s %s %s none", dev_name(dev1), wwid1, dev_name(dev)); diff_wwid++; continue; @@ -690,7 +690,7 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in /* Different wwids indicates these are not multipath components. */ if (strcmp(wwid1, wwid)) { - log_print("Different wwids for duplicate PVs %s %s %s %s", + log_debug("Different wwids for duplicate PVs %s %s %s %s", dev_name(dev1), wwid1, dev_name(dev), wwid); diff_wwid++; continue; @@ -721,6 +721,52 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in return 1; } +static int _all_md_components(struct cmd_context *cmd, struct lvmcache_info *info, const char *pvid, + struct dm_list *altdevs, struct device **dev_md_out) +{ + struct device_list *devl; + struct device *dev_md = NULL; + struct device *dev; + int real_dup = 0; + + *dev_md_out = NULL; + + /* There will often be no info struct because of the extra_md_checks function. */ + + if (info && (cmd->dev_types->md_major == MAJOR(info->dev->dev))) + dev_md = info->dev; + + dm_list_iterate_items(devl, altdevs) { + dev = devl->dev; + + if (cmd->dev_types->md_major == MAJOR(dev->dev)) { + if (dev_md) { + /* md devs themselves are dups */ + log_debug("Found multiple md devices for PVID %s: %s %s", + pvid, dev_name(dev_md), dev_name(dev)); + real_dup = 1; + break; + } else + dev_md = dev; + } else { + if (!dev_is_md_component(cmd, dev, NULL, 1)) { + /* md dev copied to another device */ + real_dup = 1; + break; + } + } + } + + if (real_dup) + return 0; + + if (dev_md) + log_debug("Found md device %s for PVID %s.", dev_name(dev_md), pvid); + + *dev_md_out = dev_md; + return 1; +} + /* * If we've found devices with the same PVID, decide which one * to use. @@ -776,7 +822,7 @@ static void _choose_duplicates(struct cmd_context *cmd, struct device_list *devl, *devl_safe, *devl_add, *devl_del; struct lvmcache_info *info; struct device *dev1, *dev2; - struct device *dev_mpath; + struct device *dev_mpath, *dev_md; struct device *dev_drop; const char *device_id = NULL, *device_id_type = NULL; const char *idname1 = NULL, *idname2 = NULL; @@ -801,6 +847,7 @@ next: dm_list_init(&altdevs); pvid = NULL; dev_mpath = NULL; + dev_md = NULL; dm_list_iterate_items_safe(devl, devl_safe, &_initial_duplicates) { if (!pvid) { @@ -829,6 +876,11 @@ next: * the md/mpath device gives us a last chance to drop the component. * An md/mpath component device is completely ignored, as if it had * been filtered, and not kept in the list unused duplicates. + * + * One issue related to eliminating mpath/md duplicate PVs here is + * that it occurs after label_scan, and hints are created based + * on what label_scan finds, so hints are disabled due to duplicate + * PVs that are later resolved here. */ /* @@ -898,24 +950,89 @@ next: /* * Get rid of any md components. - * FIXME: use a function like _all_multipath_components to pick the actual md device. */ - if (info && dev_is_md_component(cmd, info->dev, NULL, 1)) { - /* does not go in del_cache_devs which become unused_duplicates */ - log_debug("Ignoring md component %s with PVID %s (dropping info)", dev_name(info->dev), pvid); - lvmcache_del(info); - info = NULL; - } + if (_all_md_components(cmd, info, pvid, &altdevs, &dev_md)) { + if (info && dev_md && (info->dev != dev_md)) { + /* + * info should be dropped from lvmcache and info->dev + * should be treated as if it had been excluded by a filter. + * dev_md should be added to lvmcache by the caller. + * Often this info struct has been removed by + * lvmcache_extra_md_component_checks. + */ + dev_drop = info->dev; - dm_list_iterate_items_safe(devl, devl_safe, &altdevs) { - if (dev_is_md_component(cmd, devl->dev, NULL, 1)) { - log_debug("Ignoring md component %s with PVID %s (dropping duplicate)", dev_name(devl->dev), pvid); - dm_list_del(&devl->list); + /* Have caller add dev_md to lvmcache. */ + log_debug("Using md device %s for PVID %s.", dev_name(dev_md), pvid); + if ((devl_add = zalloc(sizeof(*devl_add)))) { + devl_add->dev = dev_md; + dm_list_add(add_cache_devs, &devl_add->list); + } + + /* Remove dev_md from altdevs. */ + if ((devl = _get_devl_in_device_list(dev_md, &altdevs))) + dm_list_del(&devl->list); + + /* Remove info from lvmcache that came from the component dev. */ + log_debug("Ignoring md component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid); + lvmcache_del(info); + info = NULL; + + /* Make the component dev look like it was filtered. */ + cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL); + dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL; } - } - if (dm_list_empty(&altdevs)) + if (!info && dev_md) { + /* + * The info struct was from a component and was dropped + * and the actual md dev was found on initial_duplicates + * and the caller should add it to lvmcache. + */ + + /* Have caller add dev_md to lvmcache. */ + log_debug("Using md device %s for PVID %s.", dev_name(dev_md), pvid); + if ((devl_add = zalloc(sizeof(*devl_add)))) { + devl_add->dev = dev_md; + dm_list_add(add_cache_devs, &devl_add->list); + } + + /* Remove dev_md from altdevs. */ + if ((devl = _get_devl_in_device_list(dev_md, &altdevs))) + dm_list_del(&devl->list); + } + + if (info && !dev_md) { + /* + * Only md component devs were found and no actual + * md dev, so drop the component from lvmcache. + */ + dev_drop = info->dev; + + log_debug("Ignoring md component %s with PVID %s (dropping info)", dev_name(dev_drop), pvid); + lvmcache_del(info); + info = NULL; + + /* Make the component dev look like it was filtered. */ + cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL); + dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL; + } + + dm_list_iterate_items_safe(devl, devl_safe, &altdevs) { + /* + * The altdevs are all md components that should look + * like they were filtered, they are not in lvmcache. + */ + dev_drop = devl->dev; + + log_debug("Ignoring md component %s with PVID %s (dropping duplicate)", dev_name(dev_drop), pvid); + dm_list_del(&devl->list); + + cmd->filter->wipe(cmd, cmd->filter, dev_drop, NULL); + dev_drop->flags &= ~DEV_SCAN_FOUND_LABEL; + } goto next; + } /* * Find the device for the pvid that's currently in lvmcache. @@ -1321,6 +1438,18 @@ int lvmcache_label_reopen_vg_rw(struct cmd_context *cmd, const char *vgname, con * times it can be a clue that label_scan mistakenly read the pv from an md * component device instead of from the md device itself. So for unmatching * sizes, we do a full md component check on the device. + * + * It might be nice to do this checking in the filter (when passes_filter is + * called after the initial read), but that doesn't work because passes_filter + * is called before _text_read so metadata/pvsummary info is not yet available + * which this function uses. + * + * The unique value of this function is that it can eliminate md components + * without there being duplicate PVs. But, there will often be duplicate PVs, + * handled by _all_md_components(), where other devs with the same pvid will be + * in _initial_duplicates. One could be the md device itself which will be + * added to lvmcache by choose_duplicates, and other duplicates that are + * components will be dropped. */ void lvmcache_extra_md_component_checks(struct cmd_context *cmd) @@ -1382,7 +1511,8 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd) */ if (pvsize && devsize && (pvsize != devsize)) do_check_size = 1; - if (device_hint && !strncmp(device_hint, "/dev/md", 7)) + if (device_hint && !strncmp(device_hint, "/dev/md", 7) && + (MAJOR(info->dev->dev) != cmd->dev_types->md_major)) do_check_name = 1; if (!do_check_size && !do_check_name) @@ -1412,11 +1542,11 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd) device_hint ?: "none", dev_name(dev)); if (dev_is_md_component(cmd, dev, NULL, 1)) { - log_debug("dropping PV from md component %s", dev_name(dev)); + log_debug("Ignoring PV from md component %s with PVID %s (metadata %s %llu)", + dev_name(dev), dev->pvid, device_hint ?: "none", (unsigned long long)pvsize); dev->flags &= ~DEV_SCAN_FOUND_LABEL; /* lvmcache_del will also delete vginfo if info was last one */ lvmcache_del(info); - lvmcache_del_dev_from_duplicates(dev); cmd->filter->wipe(cmd, cmd->filter, dev, NULL); } } |