Blame SOURCES/0029-devices-exclude-md-components-when-duplicate-pvs-are.patch

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