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

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