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

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