Blame SOURCES/0066-multipathd-add-recheck_wwid-option-to-verify-the-pat.patch

b46d12
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b46d12
From: Benjamin Marzinski <bmarzins@redhat.com>
b46d12
Date: Wed, 24 Feb 2021 00:33:22 -0600
b46d12
Subject: [PATCH] multipathd: add recheck_wwid option to verify the path wwid
b46d12
b46d12
There are cases where the wwid of a path changes due to LUN remapping
b46d12
without triggering uevent for the changed path. Multipathd has no method
b46d12
for trying to catch these cases, and corruption has resulted because of
b46d12
it.
b46d12
b46d12
In order to have a better chance at catching these cases, multipath now
b46d12
has a recheck_wwid option. If this is set to "yes", when a failed path
b46d12
has become active again, multipathd will recheck its wwid. If multipathd
b46d12
notices that a path's wwid has changed, it will remove and re-add the
b46d12
path, just like the existing wwid checking code for change events does.
b46d12
In cases where the no uevent occurs, both the udev database entry and
b46d12
sysfs will have the old wwid, so the only way to get a current wwid is
b46d12
to ask the device directly. Currently multipath only has code to
b46d12
directly get the wwid for scsi devices, so this option only effects scsi
b46d12
devices, and they must be configured to be able to use the uid_fallback
b46d12
methods. To make sure both the sysfs and udev database values are
b46d12
updated, multipathd triggers a both a rescan of the device and a udev
b46d12
add event.
b46d12
b46d12
Co-developed-by: Chongyun Wu <wucy11@chinatelecom.cn>
b46d12
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
b46d12
Reviewed-by: Martin Wilck <mwilck@suse.com>Reviewed-by: Martin Wilck <mwilck@suse.com>
b46d12
---
b46d12
 libmultipath/config.c      |  2 +
b46d12
 libmultipath/config.h      |  2 +
b46d12
 libmultipath/configure.c   |  4 +-
b46d12
 libmultipath/configure.h   |  2 +
b46d12
 libmultipath/defaults.h    |  1 +
b46d12
 libmultipath/dict.c        | 11 ++++++
b46d12
 libmultipath/discovery.c   |  3 +-
b46d12
 libmultipath/discovery.h   |  1 +
b46d12
 libmultipath/propsel.c     | 21 ++++++++++
b46d12
 libmultipath/propsel.h     |  1 +
b46d12
 libmultipath/structs.h     |  7 ++++
b46d12
 multipath/multipath.conf.5 | 14 +++++++
b46d12
 multipathd/cli_handlers.c  |  9 +++++
b46d12
 multipathd/main.c          | 78 ++++++++++++++++++++++++++++++++++++++
b46d12
 multipathd/main.h          |  2 +
b46d12
 15 files changed, 155 insertions(+), 3 deletions(-)
b46d12
b46d12
diff --git a/libmultipath/config.c b/libmultipath/config.c
b46d12
index dd645f17..abbddaf1 100644
b46d12
--- a/libmultipath/config.c
b46d12
+++ b/libmultipath/config.c
b46d12
@@ -371,6 +371,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
b46d12
 	merge_num(max_sectors_kb);
b46d12
 	merge_num(ghost_delay);
b46d12
 	merge_num(all_tg_pt);
b46d12
+	merge_num(recheck_wwid);
b46d12
 	merge_num(vpd_vendor_id);
b46d12
 	merge_num(san_path_err_threshold);
b46d12
 	merge_num(san_path_err_forget_rate);
b46d12
@@ -762,6 +763,7 @@ load_config (char * file)
b46d12
 	conf->remove_retries = 0;
b46d12
 	conf->ghost_delay = DEFAULT_GHOST_DELAY;
b46d12
 	conf->all_tg_pt = DEFAULT_ALL_TG_PT;
b46d12
+	conf->recheck_wwid = DEFAULT_RECHECK_WWID;
b46d12
 	/*
b46d12
 	 * preload default hwtable
b46d12
 	 */
b46d12
diff --git a/libmultipath/config.h b/libmultipath/config.h
b46d12
index a22c1b4e..e2e3f143 100644
b46d12
--- a/libmultipath/config.h
b46d12
+++ b/libmultipath/config.h
b46d12
@@ -84,6 +84,7 @@ struct hwentry {
b46d12
 	int ghost_delay;
b46d12
 	int all_tg_pt;
b46d12
 	int vpd_vendor_id;
b46d12
+	int recheck_wwid;
b46d12
 	char * bl_product;
b46d12
 };
b46d12
 
b46d12
@@ -188,6 +189,7 @@ struct config {
b46d12
 	int skip_delegate;
b46d12
 	unsigned int version[3];
b46d12
 	unsigned int sequence_nr;
b46d12
+	int recheck_wwid;
b46d12
 
b46d12
 	char * multipath_dir;
b46d12
 	char * selector;
b46d12
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
b46d12
index a6893d8d..f24d9283 100644
b46d12
--- a/libmultipath/configure.c
b46d12
+++ b/libmultipath/configure.c
b46d12
@@ -506,8 +506,8 @@ trigger_udev_change(const struct multipath *mpp)
b46d12
 	udev_device_unref(udd);
b46d12
 }
b46d12
 
b46d12
-static void trigger_partitions_udev_change(struct udev_device *dev,
b46d12
-					   const char *action, int len)
b46d12
+void trigger_partitions_udev_change(struct udev_device *dev,
b46d12
+				    const char *action, int len)
b46d12
 {
b46d12
 	struct udev_enumerate *part_enum;
b46d12
 	struct udev_list_entry *item;
b46d12
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
b46d12
index 0e33bf40..81090dd4 100644
b46d12
--- a/libmultipath/configure.h
b46d12
+++ b/libmultipath/configure.h
b46d12
@@ -57,3 +57,5 @@ int get_refwwid (enum mpath_cmds cmd, char * dev, enum devtypes dev_type,
b46d12
 int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, int is_daemon);
b46d12
 struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type);
b46d12
 void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
b46d12
+void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
b46d12
+				    int len);
b46d12
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
b46d12
index 52fe05b9..f1cb000d 100644
b46d12
--- a/libmultipath/defaults.h
b46d12
+++ b/libmultipath/defaults.h
b46d12
@@ -50,6 +50,7 @@
b46d12
 #define DEFAULT_FIND_MULTIPATHS_TIMEOUT -10
b46d12
 #define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1
b46d12
 #define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF
b46d12
+#define DEFAULT_RECHECK_WWID RECHECK_WWID_OFF
b46d12
 /* Enable all foreign libraries by default */
b46d12
 #define DEFAULT_ENABLE_FOREIGN ""
b46d12
 
b46d12
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
b46d12
index 8fd91d8c..13698b76 100644
b46d12
--- a/libmultipath/dict.c
b46d12
+++ b/libmultipath/dict.c
b46d12
@@ -1413,6 +1413,14 @@ declare_hw_snprint(all_tg_pt, print_yes_no_undef)
b46d12
 declare_def_handler(marginal_pathgroups, set_yes_no)
b46d12
 declare_def_snprint(marginal_pathgroups, print_yes_no)
b46d12
 
b46d12
+declare_def_handler(recheck_wwid, set_yes_no_undef)
b46d12
+declare_def_snprint_defint(recheck_wwid, print_yes_no_undef, DEFAULT_RECHECK_WWID)
b46d12
+declare_ovr_handler(recheck_wwid, set_yes_no_undef)
b46d12
+declare_ovr_snprint(recheck_wwid, print_yes_no_undef)
b46d12
+declare_hw_handler(recheck_wwid, set_yes_no_undef)
b46d12
+declare_hw_snprint(recheck_wwid, print_yes_no_undef)
b46d12
+
b46d12
+
b46d12
 static int
b46d12
 def_uxsock_timeout_handler(struct config *conf, vector strvec)
b46d12
 {
b46d12
@@ -1824,6 +1832,7 @@ init_keywords(vector keywords)
b46d12
 	install_keyword("enable_foreign", &def_enable_foreign_handler,
b46d12
 			&snprint_def_enable_foreign);
b46d12
 	install_keyword("marginal_pathgroups", &def_marginal_pathgroups_handler, &snprint_def_marginal_pathgroups);
b46d12
+	install_keyword("recheck_wwid", &def_recheck_wwid_handler, &snprint_def_recheck_wwid);
b46d12
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
b46d12
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
b46d12
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
b46d12
@@ -1913,6 +1922,7 @@ init_keywords(vector keywords)
b46d12
 	install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay);
b46d12
 	install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt);
b46d12
 	install_keyword("vpd_vendor", &hw_vpd_vendor_handler, &snprint_hw_vpd_vendor);
b46d12
+	install_keyword("recheck_wwid", &hw_recheck_wwid_handler, &snprint_hw_recheck_wwid);
b46d12
 	install_sublevel_end();
b46d12
 
b46d12
 	install_keyword_root("overrides", &overrides_handler);
b46d12
@@ -1954,6 +1964,7 @@ init_keywords(vector keywords)
b46d12
 	install_keyword("max_sectors_kb", &ovr_max_sectors_kb_handler, &snprint_ovr_max_sectors_kb);
b46d12
 	install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay);
b46d12
 	install_keyword("all_tg_pt", &ovr_all_tg_pt_handler, &snprint_ovr_all_tg_pt);
b46d12
+	install_keyword("recheck_wwid", &ovr_recheck_wwid_handler, &snprint_ovr_recheck_wwid);
b46d12
 
b46d12
 	install_keyword_root("multipaths", &multipaths_handler);
b46d12
 	install_keyword_multi("multipath", &multipath_handler, NULL);
b46d12
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
b46d12
index 126a70b3..bc267609 100644
b46d12
--- a/libmultipath/discovery.c
b46d12
+++ b/libmultipath/discovery.c
b46d12
@@ -2040,7 +2040,7 @@ static ssize_t uid_fallback(struct path *pp, int path_state,
b46d12
 	return len;
b46d12
 }
b46d12
 
b46d12
-static bool has_uid_fallback(struct path *pp)
b46d12
+bool has_uid_fallback(struct path *pp)
b46d12
 {
b46d12
 	/*
b46d12
 	 * Falling back to direct WWID determination is dangerous
b46d12
@@ -2072,6 +2072,7 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev,
b46d12
 		conf = get_multipath_config();
b46d12
 		pthread_cleanup_push(put_multipath_config, conf);
b46d12
 		select_getuid(conf, pp);
b46d12
+		select_recheck_wwid(conf, pp);
b46d12
 		pthread_cleanup_pop(1);
b46d12
 	}
b46d12
 
b46d12
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
b46d12
index d3193daf..a5446b4d 100644
b46d12
--- a/libmultipath/discovery.h
b46d12
+++ b/libmultipath/discovery.h
b46d12
@@ -54,6 +54,7 @@ ssize_t sysfs_get_inquiry(struct udev_device *udev,
b46d12
 			  unsigned char *buff, size_t len);
b46d12
 int sysfs_get_asymmetric_access_state(struct path *pp,
b46d12
 				      char *buff, int buflen);
b46d12
+bool has_uid_fallback(struct path *pp);
b46d12
 int get_uid(struct path * pp, int path_state, struct udev_device *udev,
b46d12
 	    int allow_fallback);
b46d12
 bool is_vpd_page_supported(int fd, int pg);
b46d12
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
b46d12
index 1150cfe8..127b3370 100644
b46d12
--- a/libmultipath/propsel.c
b46d12
+++ b/libmultipath/propsel.c
b46d12
@@ -581,6 +581,27 @@ out:
b46d12
 	return 0;
b46d12
 }
b46d12
 
b46d12
+/* must be called after select_getuid */
b46d12
+int select_recheck_wwid(struct config *conf, struct path * pp)
b46d12
+{
b46d12
+	const char *origin;
b46d12
+
b46d12
+	pp_set_ovr(recheck_wwid);
b46d12
+	pp_set_hwe(recheck_wwid);
b46d12
+	pp_set_conf(recheck_wwid);
b46d12
+	pp_set_default(recheck_wwid, DEFAULT_RECHECK_WWID);
b46d12
+out:
b46d12
+	if (pp->recheck_wwid == RECHECK_WWID_ON &&
b46d12
+	    (pp->bus != SYSFS_BUS_SCSI || pp->getuid != NULL ||
b46d12
+	     !has_uid_fallback(pp))) {
b46d12
+		pp->recheck_wwid = RECHECK_WWID_OFF;
b46d12
+		origin = "(setting: unsupported by device type/config)";
b46d12
+	}
b46d12
+	condlog(3, "%s: recheck_wwid = %i %s", pp->dev, pp->recheck_wwid,
b46d12
+		origin);
b46d12
+	return 0;
b46d12
+}
b46d12
+
b46d12
 void
b46d12
 detect_prio(struct config *conf, struct path * pp)
b46d12
 {
b46d12
diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h
b46d12
index a68bacf0..72a7e33c 100644
b46d12
--- a/libmultipath/propsel.h
b46d12
+++ b/libmultipath/propsel.h
b46d12
@@ -7,6 +7,7 @@ int select_features (struct config *conf, struct multipath * mp);
b46d12
 int select_hwhandler (struct config *conf, struct multipath * mp);
b46d12
 int select_checker(struct config *conf, struct path *pp);
b46d12
 int select_getuid (struct config *conf, struct path * pp);
b46d12
+int select_recheck_wwid(struct config *conf, struct path * pp);
b46d12
 int select_prio (struct config *conf, struct path * pp);
b46d12
 int select_find_multipaths_timeout(struct config *conf, struct path *pp);
b46d12
 int select_no_path_retry(struct config *conf, struct multipath *mp);
b46d12
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
b46d12
index 65542dea..a5dbad5b 100644
b46d12
--- a/libmultipath/structs.h
b46d12
+++ b/libmultipath/structs.h
b46d12
@@ -252,6 +252,12 @@ enum eh_deadline_states {
b46d12
 	EH_DEADLINE_ZERO = UOZ_ZERO,
b46d12
 };
b46d12
 
b46d12
+enum recheck_wwid_states {
b46d12
+	RECHECK_WWID_UNDEF = YNU_UNDEF,
b46d12
+	RECHECK_WWID_OFF = YNU_NO,
b46d12
+	RECHECK_WWID_ON = YNU_YES,
b46d12
+};
b46d12
+
b46d12
 struct vpd_vendor_page {
b46d12
 	int pg;
b46d12
 	const char *name;
b46d12
@@ -326,6 +332,7 @@ struct path {
b46d12
 	int find_multipaths_timeout;
b46d12
 	int marginal;
b46d12
 	int vpd_vendor_id;
b46d12
+	int recheck_wwid;
b46d12
 	/* configlet pointers */
b46d12
 	vector hwe;
b46d12
 	struct gen_path generic_path;
b46d12
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
b46d12
index a5686090..6da15aad 100644
b46d12
--- a/multipath/multipath.conf.5
b46d12
+++ b/multipath/multipath.conf.5
b46d12
@@ -1256,6 +1256,20 @@ The default is: \fB\(dq\(dq\fR (the empty regular expression)
b46d12
 .RE
b46d12
 .
b46d12
 .
b46d12
+.TP
b46d12
+.B recheck_wwid
b46d12
+If set to \fIyes\fR, when a failed path is restored, its wwid is rechecked. If
b46d12
+the wwid has changed, the path is removed from the current multipath device,
b46d12
+and re-added as a new path. Multipathd will also recheck a path's wwid if it is
b46d12
+manually re-added. This option only works for SCSI devices that are configured
b46d12
+to use the default uid_attribute, \fIID_SERIAL\fR, or sysfs for getting their
b46d12
+wwid.
b46d12
+.RS
b46d12
+.TP
b46d12
+The default is \fBno\fR
b46d12
+.RE
b46d12
+.
b46d12
+.
b46d12
 
b46d12
 .
b46d12
 .\" ----------------------------------------------------------------------------
b46d12
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
b46d12
index 782bb003..8b4bd187 100644
b46d12
--- a/multipathd/cli_handlers.c
b46d12
+++ b/multipathd/cli_handlers.c
b46d12
@@ -715,6 +715,15 @@ cli_add_path (void * v, char ** reply, int * len, void * data)
b46d12
 	pp = find_path_by_dev(vecs->pathvec, param);
b46d12
 	if (pp) {
b46d12
 		condlog(2, "%s: path already in pathvec", param);
b46d12
+
b46d12
+		if (pp->recheck_wwid == RECHECK_WWID_ON &&
b46d12
+		    check_path_wwid_change(pp)) {
b46d12
+			condlog(0, "%s: wwid changed. Removing device",
b46d12
+				pp->dev);
b46d12
+			handle_path_wwid_change(pp, vecs);
b46d12
+			return 1;
b46d12
+		}
b46d12
+
b46d12
 		if (pp->mpp)
b46d12
 			return 0;
b46d12
 	} else {
b46d12
diff --git a/multipathd/main.c b/multipathd/main.c
b46d12
index cc1aeea2..1fbc31eb 100644
b46d12
--- a/multipathd/main.c
b46d12
+++ b/multipathd/main.c
b46d12
@@ -822,6 +822,73 @@ ev_remove_map (char * devname, char * alias, int minor, struct vectors * vecs)
b46d12
 	return flush_map(mpp, vecs, 0);
b46d12
 }
b46d12
 
b46d12
+static void
b46d12
+rescan_path(struct udev_device *parent)
b46d12
+{
b46d12
+	while(parent) {
b46d12
+		const char *subsys = udev_device_get_subsystem(parent);
b46d12
+		if (subsys && !strncmp(subsys, "scsi", 4))
b46d12
+			break;
b46d12
+		parent = udev_device_get_parent(parent);
b46d12
+	}
b46d12
+	if (parent)
b46d12
+		sysfs_attr_set_value(parent, "rescan", "1", strlen("1"));
b46d12
+}
b46d12
+
b46d12
+void
b46d12
+handle_path_wwid_change(struct path *pp, struct vectors *vecs)
b46d12
+{
b46d12
+	struct udev_device *udd;
b46d12
+
b46d12
+	if (!pp || !pp->udev)
b46d12
+		return;
b46d12
+
b46d12
+	udd = udev_device_ref(pp->udev);
b46d12
+	if (ev_remove_path(pp, vecs, 1) != 0 && pp->mpp) {
b46d12
+		pp->dmstate = PSTATE_FAILED;
b46d12
+		dm_fail_path(pp->mpp->alias, pp->dev_t);
b46d12
+	}
b46d12
+	rescan_path(udd);
b46d12
+	sysfs_attr_set_value(udd, "uevent", "add", strlen("add"));
b46d12
+	trigger_partitions_udev_change(udd, "add", strlen("add"));
b46d12
+	udev_device_unref(udd);
b46d12
+}
b46d12
+
b46d12
+bool
b46d12
+check_path_wwid_change(struct path *pp)
b46d12
+{
b46d12
+	char wwid[WWID_SIZE];
b46d12
+	int len = 0;
b46d12
+	size_t i;
b46d12
+
b46d12
+	if (!strlen(pp->wwid))
b46d12
+		return false;
b46d12
+
b46d12
+	/* Get the real fresh device wwid by sgio. sysfs still has old
b46d12
+	 * data, so only get_vpd_sgio will work to get the new wwid */
b46d12
+	len = get_vpd_sgio(pp->fd, 0x83, 0, wwid, WWID_SIZE);
b46d12
+
b46d12
+	if (len <= 0) {
b46d12
+		condlog(2, "%s: failed to check wwid by sgio: len = %d",
b46d12
+			pp->dev, len);
b46d12
+		return false;
b46d12
+	}
b46d12
+
b46d12
+	/*Strip any trailing blanks */
b46d12
+	for (i = strlen(pp->wwid); i > 0 && pp->wwid[i-1] == ' '; i--);
b46d12
+		/* no-op */
b46d12
+	pp->wwid[i] = '\0';
b46d12
+	condlog(4, "%s: Got wwid %s by sgio", pp->dev, wwid);
b46d12
+
b46d12
+	if (strncmp(wwid, pp->wwid, WWID_SIZE)) {
b46d12
+		condlog(0, "%s: wwid '%s' doesn't match wwid '%s' from device",
b46d12
+			pp->dev, pp->wwid, wwid);
b46d12
+		return true;
b46d12
+	}
b46d12
+
b46d12
+	return false;
b46d12
+}
b46d12
+
b46d12
 static int
b46d12
 uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
b46d12
 {
b46d12
@@ -1241,6 +1308,7 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
b46d12
 			condlog(0, "%s: path wwid changed from '%s' to '%s'",
b46d12
 				uev->kernel, wwid, pp->wwid);
b46d12
 			ev_remove_path(pp, vecs, 1);
b46d12
+			rescan_path(uev->udev);
b46d12
 			needs_reinit = 1;
b46d12
 			goto out;
b46d12
 		} else {
b46d12
@@ -2101,6 +2169,16 @@ check_path (struct vectors * vecs, struct path * pp, unsigned int ticks)
b46d12
 		return 0;
b46d12
 	set_no_path_retry(pp->mpp);
b46d12
 
b46d12
+	if (pp->recheck_wwid == RECHECK_WWID_ON &&
b46d12
+	    (newstate == PATH_UP || newstate == PATH_GHOST) &&
b46d12
+	    ((pp->state != PATH_UP && pp->state != PATH_GHOST) ||
b46d12
+	     pp->dmstate == PSTATE_FAILED) &&
b46d12
+	    check_path_wwid_change(pp)) {
b46d12
+		condlog(0, "%s: path wwid change detected. Removing", pp->dev);
b46d12
+		handle_path_wwid_change(pp, vecs);
b46d12
+		return 0;
b46d12
+	}
b46d12
+
b46d12
 	if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
b46d12
 	    (san_path_check_enabled(pp->mpp) ||
b46d12
 	     marginal_path_check_enabled(pp->mpp))) {
b46d12
diff --git a/multipathd/main.h b/multipathd/main.h
b46d12
index 5dff17e5..8f0028a9 100644
b46d12
--- a/multipathd/main.h
b46d12
+++ b/multipathd/main.h
b46d12
@@ -49,4 +49,6 @@ int update_multipath (struct vectors *vecs, char *mapname, int reset);
b46d12
 int update_path_groups(struct multipath *mpp, struct vectors *vecs,
b46d12
 		       int refresh);
b46d12
 
b46d12
+void handle_path_wwid_change(struct path *pp, struct vectors *vecs);
b46d12
+bool check_path_wwid_change(struct path *pp);
b46d12
 #endif /* MAIN_H */
b46d12
-- 
b46d12
2.17.2
b46d12