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

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