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

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