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

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