Blame SOURCES/0028-devices-exclude-multipath-components-based-on-matchi.patch

38b7b2
From 5403a6f05987b21addb50c9b056e36567d631df7 Mon Sep 17 00:00:00 2001
38b7b2
From: David Teigland <teigland@redhat.com>
38b7b2
Date: Wed, 17 Nov 2021 17:10:45 -0600
38b7b2
Subject: [PATCH 28/54] devices: exclude multipath components based on matching
38b7b2
 wwid
38b7b2
38b7b2
If multipath component devices get through the filter and
38b7b2
cause lvm to see duplicate PVs, then check the wwid of the
38b7b2
devs and drop the component devices as if they had been
38b7b2
filtered.  If a dm mpath device was found among the duplicates
38b7b2
then use that as the PV, otherwise do not use any of the
38b7b2
components as the PV.
38b7b2
38b7b2
"duplicate PVs" associated with multipath configs will no
38b7b2
longer stop commands from working.
38b7b2
---
38b7b2
 lib/cache/lvmcache.c                  | 186 +++++++++++++++++++++++++-
38b7b2
 lib/device/dev-mpath.c                |  71 ++++++++++
38b7b2
 lib/device/dev-type.h                 |   2 +
38b7b2
 lib/device/device_id.c                |   4 +-
38b7b2
 lib/device/device_id.h                |   2 +
38b7b2
 test/shell/duplicate-pvs-multipath.sh |  67 ++++++++++
38b7b2
 6 files changed, 323 insertions(+), 9 deletions(-)
38b7b2
 create mode 100644 test/shell/duplicate-pvs-multipath.sh
38b7b2
38b7b2
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
38b7b2
index bee63ebb4..a0811d4ea 100644
38b7b2
--- a/lib/cache/lvmcache.c
38b7b2
+++ b/lib/cache/lvmcache.c
38b7b2
@@ -625,6 +625,102 @@ static void _warn_unused_duplicates(struct cmd_context *cmd)
38b7b2
 	}
38b7b2
 }
38b7b2
 
38b7b2
+static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_info *info, const char *pvid,
38b7b2
+				     struct dm_list *altdevs, struct device **dev_mpath)
38b7b2
+{
38b7b2
+	struct device_list *devl;
38b7b2
+	struct device *dev_mp = NULL;
38b7b2
+	struct device *dev1 = NULL;
38b7b2
+	struct device *dev;
38b7b2
+	const char *wwid1 = NULL;
38b7b2
+	const char *wwid;
38b7b2
+	int diff_wwid = 0;
38b7b2
+	int same_wwid = 0;
38b7b2
+	int dev_is_mp;
38b7b2
+
38b7b2
+	*dev_mpath = NULL;
38b7b2
+
38b7b2
+	/* This function only makes sense with more than one dev. */
38b7b2
+	if ((info && dm_list_empty(altdevs)) || (!info && (dm_list_size(altdevs) == 1))) {
38b7b2
+		log_debug("Skip multipath component checks with single device for PVID %s", pvid);
38b7b2
+		return 0;
38b7b2
+	}
38b7b2
+
38b7b2
+	log_debug("Checking for multipath components for duplicate PVID %s", pvid);
38b7b2
+
38b7b2
+	if (info) {
38b7b2
+		dev = info->dev;
38b7b2
+		dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
38b7b2
+
38b7b2
+		if (dev_is_mp) {
38b7b2
+			if ((wwid1 = dev_mpath_component_wwid(cmd, dev))) {
38b7b2
+				dev_mp = dev;
38b7b2
+				dev1 = dev;
38b7b2
+			}
38b7b2
+		} else {
38b7b2
+			if ((wwid1 = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID)))
38b7b2
+				dev1 = dev;
38b7b2
+		}
38b7b2
+	}
38b7b2
+
38b7b2
+	dm_list_iterate_items(devl, altdevs) {
38b7b2
+		dev = devl->dev;
38b7b2
+		dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
38b7b2
+
38b7b2
+		if (dev_is_mp)
38b7b2
+			wwid = dev_mpath_component_wwid(cmd, dev);
38b7b2
+		else
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
+				  dev_name(dev1), wwid1, dev_name(dev));
38b7b2
+			diff_wwid++;
38b7b2
+			continue;
38b7b2
+		}
38b7b2
+
38b7b2
+		if (!wwid)
38b7b2
+			continue;
38b7b2
+
38b7b2
+		if (!wwid1) {
38b7b2
+			wwid1 = wwid;
38b7b2
+			dev1 = dev;
38b7b2
+			continue;
38b7b2
+		}
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
+				  dev_name(dev1), wwid1, dev_name(dev), wwid);
38b7b2
+			diff_wwid++;
38b7b2
+			continue;
38b7b2
+		}
38b7b2
+
38b7b2
+		/* Different mpath devs with the same wwid shouldn't happen. */
38b7b2
+		if (dev_is_mp && dev_mp) {
38b7b2
+			log_print("Found multiple multipath devices for PVID %s WWID %s: %s %s",
38b7b2
+				   pvid, wwid1, dev_name(dev_mp), dev_name(dev));
38b7b2
+			continue;
38b7b2
+		}
38b7b2
+
38b7b2
+		log_debug("Same wwids for duplicate PVs %s %s", dev_name(dev1), dev_name(dev));
38b7b2
+		same_wwid++;
38b7b2
+
38b7b2
+		/* Save the mpath device so it can be used as the PV. */
38b7b2
+		if (dev_is_mp)
38b7b2
+			dev_mp = dev;
38b7b2
+	}
38b7b2
+
38b7b2
+	if (diff_wwid || !same_wwid)
38b7b2
+		return 0;
38b7b2
+
38b7b2
+	if (dev_mp)
38b7b2
+		log_debug("Found multipath device %s for PVID %s WWID %s.", dev_name(dev_mp), pvid, wwid1);
38b7b2
+
38b7b2
+	*dev_mpath = dev_mp;
38b7b2
+	return 1;
38b7b2
+}
38b7b2
+
38b7b2
 /*
38b7b2
  * If we've found devices with the same PVID, decide which one
38b7b2
  * to use.
38b7b2
@@ -680,6 +776,8 @@ 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_drop;
38b7b2
 	const char *device_id = NULL, *device_id_type = NULL;
38b7b2
 	const char *idname1 = NULL, *idname2 = NULL;
38b7b2
 	uint32_t dev1_major, dev1_minor, dev2_major, dev2_minor;
38b7b2
@@ -702,6 +800,7 @@ static void _choose_duplicates(struct cmd_context *cmd,
38b7b2
 next:
38b7b2
 	dm_list_init(&altdevs);
38b7b2
 	pvid = NULL;
38b7b2
+	dev_mpath = NULL;
38b7b2
 
38b7b2
 	dm_list_iterate_items_safe(devl, devl_safe, &_initial_duplicates) {
38b7b2
 		if (!pvid) {
38b7b2
@@ -720,23 +819,97 @@ next:
38b7b2
 		return;
38b7b2
 	}
38b7b2
 
38b7b2
+	info = lvmcache_info_from_pvid(pvid, NULL, 0);
38b7b2
+
38b7b2
 	/*
38b7b2
-	 * Get rid of any md components before comparing alternatives.
38b7b2
-	 * (Since an md component can never be used, it's not an
38b7b2
-	 * option to use like other kinds of alternatives.)
38b7b2
+	 * Usually and ideally, components of md and multipath devs should have
38b7b2
+	 * been excluded by filters, and not scanned for a PV.  In some unusual
38b7b2
+	 * cases the components can get through the filters, and a PV can be
38b7b2
+	 * found on them.  Detecting the same PVID on both the component and
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
 
38b7b2
-	info = lvmcache_info_from_pvid(pvid, NULL, 0);
38b7b2
+	/*
38b7b2
+	 * Get rid of multipath components based on matching wwids.
38b7b2
+	 */
38b7b2
+	if (_all_multipath_components(cmd, info, pvid, &altdevs, &dev_mpath)) {
38b7b2
+		if (info && dev_mpath && (info->dev != dev_mpath)) {
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_mpath should be added to lvmcache by the caller.
38b7b2
+			 */
38b7b2
+			dev_drop = info->dev;
38b7b2
+
38b7b2
+			/* Have caller add dev_mpath to lvmcache. */
38b7b2
+			log_debug("Using multipath device %s for PVID %s.", dev_name(dev_mpath), pvid);
38b7b2
+			if ((devl_add = zalloc(sizeof(*devl_add)))) {
38b7b2
+				devl_add->dev = dev_mpath;
38b7b2
+				dm_list_add(add_cache_devs, &devl_add->list);
38b7b2
+			}
38b7b2
+
38b7b2
+			/* Remove dev_mpath from altdevs. */
38b7b2
+			if ((devl = _get_devl_in_device_list(dev_mpath, &altdevs)))
38b7b2
+				dm_list_del(&devl->list);
38b7b2
+
38b7b2
+			/* Remove info from lvmcache that came from the component dev. */
38b7b2
+			log_debug("Ignoring multipath 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
+		if (info && !dev_mpath) {
38b7b2
+			/*
38b7b2
+			 * Only mpath component devs were found and no actual
38b7b2
+			 * multipath dev, so drop the component from lvmcache.
38b7b2
+			 */
38b7b2
+			dev_drop = info->dev;
38b7b2
+
38b7b2
+			log_debug("Ignoring multipath 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 mpath 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 multipath 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
+	 * 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_cache("PV %s drop MD component from scan selection %s", pvid, dev_name(info->dev));
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
 
38b7b2
 	dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
38b7b2
 		if (dev_is_md_component(cmd, devl->dev, NULL, 1)) {
38b7b2
-			log_debug_cache("PV %s drop MD component from scan duplicates %s", pvid, dev_name(devl->dev));
38b7b2
+			log_debug("Ignoring md component %s with PVID %s (dropping duplicate)", dev_name(devl->dev), pvid);
38b7b2
 			dm_list_del(&devl->list);
38b7b2
 		}
38b7b2
 	}
38b7b2
@@ -744,7 +917,6 @@ next:
38b7b2
 	if (dm_list_empty(&altdevs))
38b7b2
 		goto next;
38b7b2
 
38b7b2
-
38b7b2
 	/*
38b7b2
 	 * Find the device for the pvid that's currently in lvmcache.
38b7b2
 	 */
38b7b2
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
38b7b2
index ba7bf9740..cbbad9dc9 100644
38b7b2
--- a/lib/device/dev-mpath.c
38b7b2
+++ b/lib/device/dev-mpath.c
38b7b2
@@ -482,3 +482,74 @@ found:
38b7b2
 	return 1;
38b7b2
 }
38b7b2
 
38b7b2
+const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev)
38b7b2
+{
38b7b2
+	char slaves_path[PATH_MAX];
38b7b2
+	char wwid_path[PATH_MAX];
38b7b2
+	char sysbuf[PATH_MAX] = { 0 };
38b7b2
+	char *slave_name;
38b7b2
+	const char *wwid = NULL;
38b7b2
+	struct stat info;
38b7b2
+	DIR *dr;
38b7b2
+	struct dirent *de;
38b7b2
+
38b7b2
+	/* /sys/dev/block/253:7/slaves/sda/device/wwid */
38b7b2
+
38b7b2
+	if (dm_snprintf(slaves_path, sizeof(slaves_path), "%s/dev/block/%d:%d/slaves",
38b7b2
+			dm_sysfs_dir(), (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
38b7b2
+		log_warn("Sysfs path to check mpath components is too long.");
38b7b2
+		return NULL;
38b7b2
+	}
38b7b2
+
38b7b2
+	if (stat(slaves_path, &info))
38b7b2
+		return NULL;
38b7b2
+
38b7b2
+	if (!S_ISDIR(info.st_mode)) {
38b7b2
+		log_warn("Path %s is not a directory.", slaves_path);
38b7b2
+		return NULL;
38b7b2
+	}
38b7b2
+
38b7b2
+	/* Get wwid from first component */
38b7b2
+
38b7b2
+	if (!(dr = opendir(slaves_path))) {
38b7b2
+		log_debug("Device %s has no slaves dir", dev_name(dev));
38b7b2
+		return NULL;
38b7b2
+	}
38b7b2
+
38b7b2
+	while ((de = readdir(dr))) {
38b7b2
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
38b7b2
+			continue;
38b7b2
+
38b7b2
+		/* slave_name "sda" */
38b7b2
+		slave_name = de->d_name;
38b7b2
+
38b7b2
+		/* read /sys/block/sda/device/wwid */
38b7b2
+
38b7b2
+		if (dm_snprintf(wwid_path, sizeof(wwid_path), "%s/block/%s/device/wwid",
38b7b2
+       				dm_sysfs_dir(), slave_name) < 0) {
38b7b2
+			log_warn("Failed to create sysfs wwid path for %s", slave_name);
38b7b2
+			continue;
38b7b2
+		}
38b7b2
+
38b7b2
+		get_sysfs_value(wwid_path, sysbuf, sizeof(sysbuf), 0);
38b7b2
+		if (!sysbuf[0])
38b7b2
+			continue;
38b7b2
+
38b7b2
+		if (strstr(sysbuf, "scsi_debug")) {
38b7b2
+			int i;
38b7b2
+			for (i = 0; i < strlen(sysbuf); i++) {
38b7b2
+				if (sysbuf[i] == ' ')
38b7b2
+					sysbuf[i] = '_';
38b7b2
+			}
38b7b2
+		}
38b7b2
+
38b7b2
+		if ((wwid = dm_pool_strdup(cmd->mem, sysbuf)))
38b7b2
+			break;
38b7b2
+	}
38b7b2
+	if (closedir(dr))
38b7b2
+		stack;
38b7b2
+
38b7b2
+	return wwid;
38b7b2
+}
38b7b2
+
38b7b2
+
38b7b2
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
38b7b2
index f3521c6e0..36fb8f258 100644
38b7b2
--- a/lib/device/dev-type.h
38b7b2
+++ b/lib/device/dev-type.h
38b7b2
@@ -63,6 +63,8 @@ int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *signature
38b7b2
 int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
38b7b2
 int dasd_is_cdl_formatted(struct device *dev);
38b7b2
 
38b7b2
+const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev);
38b7b2
+
38b7b2
 int dev_is_lvm1(struct device *dev, char *buf, int buflen);
38b7b2
 int dev_is_pool(struct device *dev, char *buf, int buflen);
38b7b2
 
38b7b2
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
38b7b2
index a33dcebe0..625576ec6 100644
38b7b2
--- a/lib/device/device_id.c
38b7b2
+++ b/lib/device/device_id.c
38b7b2
@@ -243,7 +243,7 @@ static int _dm_uuid_has_prefix(char *sysbuf, const char *prefix)
38b7b2
 }
38b7b2
 
38b7b2
 /* the dm uuid uses the wwid of the underlying dev */
38b7b2
-static int _dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, const char **idname_out)
38b7b2
+int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, const char **idname_out)
38b7b2
 {
38b7b2
 	char sysbuf[PATH_MAX] = { 0 };
38b7b2
 	const char *idname;
38b7b2
@@ -988,7 +988,7 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
38b7b2
 	}
38b7b2
 
38b7b2
 	if (MAJOR(dev->dev) == cmd->dev_types->device_mapper_major) {
38b7b2
-		if (_dev_has_mpath_uuid(cmd, dev, &idname)) {
38b7b2
+		if (dev_has_mpath_uuid(cmd, dev, &idname)) {
38b7b2
 			idtype = DEV_ID_TYPE_MPATH_UUID;
38b7b2
 			goto id_done;
38b7b2
 		}
38b7b2
diff --git a/lib/device/device_id.h b/lib/device/device_id.h
38b7b2
index 939b3a0f4..4cf1374c8 100644
38b7b2
--- a/lib/device/device_id.h
38b7b2
+++ b/lib/device/device_id.h
38b7b2
@@ -55,4 +55,6 @@ void unlink_searched_devnames(struct cmd_context *cmd);
38b7b2
 
38b7b2
 int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize);
38b7b2
 
38b7b2
+int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, const char **idname_out);
38b7b2
+
38b7b2
 #endif
38b7b2
diff --git a/test/shell/duplicate-pvs-multipath.sh b/test/shell/duplicate-pvs-multipath.sh
38b7b2
new file mode 100644
38b7b2
index 000000000..a145e4afb
38b7b2
--- /dev/null
38b7b2
+++ b/test/shell/duplicate-pvs-multipath.sh
38b7b2
@@ -0,0 +1,67 @@
38b7b2
+#!/usr/bin/env bash
38b7b2
+
38b7b2
+# Copyright (C) 2021 Red Hat, Inc. All rights reserved.
38b7b2
+#
38b7b2
+# This copyrighted material is made available to anyone wishing to use,
38b7b2
+# modify, copy, or redistribute it subject to the terms and conditions
38b7b2
+# of the GNU General Public License v.2.
38b7b2
+#
38b7b2
+# You should have received a copy of the GNU General Public License
38b7b2
+# along with this program; if not, write to the Free Software Foundation,
38b7b2
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38b7b2
+
38b7b2
+test_description='udev rule and systemd unit run vgchange'
38b7b2
+
38b7b2
+SKIP_WITH_LVMPOLLD=1
38b7b2
+SKIP_WITH_LVMLOCKD=1
38b7b2
+
38b7b2
+. lib/inittest
38b7b2
+
38b7b2
+# FIXME: skip until mpath/scsi_debug cleanup works after a failure
38b7b2
+skip
38b7b2
+
38b7b2
+modprobe --dry-run scsi_debug || skip
38b7b2
+multipath -l || skip
38b7b2
+multipath -l | grep scsi_debug && skip
38b7b2
+
38b7b2
+# Turn off multipath_component_detection so that the duplicate
38b7b2
+# resolution of mpath components is used.
38b7b2
+aux lvmconf 'devices/multipath_component_detection = 0'
38b7b2
+# Prevent wwids from being used for filtering.
38b7b2
+aux lvmconf 'devices/multipath_wwids_file = "/dev/null"'
38b7b2
+# Need to use /dev/mapper/mpath
38b7b2
+aux lvmconf 'devices/dir = "/dev"'
38b7b2
+aux lvmconf 'devices/scan = "/dev"'
38b7b2
+# Could set filter to $MP and the component /dev/sd devs
38b7b2
+aux lvmconf "devices/filter = [ \"a|.*|\" ]"
38b7b2
+aux lvmconf "devices/global_filter = [ \"a|.*|\" ]"
38b7b2
+
38b7b2
+modprobe scsi_debug dev_size_mb=100 num_tgts=1 vpd_use_hostno=0 add_host=4 delay=20 max_luns=2 no_lun_0=1
38b7b2
+sleep 2
38b7b2
+
38b7b2
+multipath -r
38b7b2
+sleep 2
38b7b2
+
38b7b2
+MPB=$(multipath -l | grep scsi_debug | cut -f1 -d ' ')
38b7b2
+echo $MPB
38b7b2
+MP=/dev/mapper/$MPB
38b7b2
+echo $MP
38b7b2
+
38b7b2
+pvcreate $MP
38b7b2
+vgcreate $vg1 $MP
38b7b2
+lvcreate -l1 $vg1
38b7b2
+vgchange -an $vg1
38b7b2
+
38b7b2
+pvs |tee out
38b7b2
+grep $MP out
38b7b2
+for i in $(grep -H scsi_debug /sys/block/sd*/device/model | cut -f4 -d /); do
38b7b2
+	not grep /dev/$i out;
38b7b2
+done
38b7b2
+
38b7b2
+vgchange -an $vg1
38b7b2
+vgremove -y $vg1
38b7b2
+
38b7b2
+sleep 2
38b7b2
+multipath -f $MP
38b7b2
+sleep 1
38b7b2
+rmmod scsi_debug
38b7b2
-- 
38b7b2
2.34.3
38b7b2