Blame SOURCES/0051-libmultipath-add-a-protocol-subsection-to-multipath..patch

ca7c20
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
ca7c20
From: Benjamin Marzinski <bmarzins@redhat.com>
ca7c20
Date: Wed, 13 Apr 2022 23:27:37 -0500
ca7c20
Subject: [PATCH] libmultipath: add a protocol subsection to multipath.conf
ca7c20
ca7c20
Some storage arrays can be accessed using multiple protocols at the same
ca7c20
time.  In these cases, users may want to set path attributes
ca7c20
differently, depending on the protocol that the path is using. To allow
ca7c20
this, add a protocol subsection to the overrides section in
ca7c20
multipath.conf, which allows select path-specific options to be set.
ca7c20
This commit simply adds the subsection, and handles merging matching
ca7c20
entries. Future patches will make use of the section.
ca7c20
ca7c20
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
ca7c20
Reviewed-by: Martin Wilck <mwilck@suse.com>
ca7c20
---
ca7c20
 libmultipath/config.c | 83 ++++++++++++++++++++++++++++++++++++
ca7c20
 libmultipath/config.h | 10 +++++
ca7c20
 libmultipath/dict.c   | 99 +++++++++++++++++++++++++++++++++++++++++++
ca7c20
 libmultipath/print.c  | 50 ++++++++++++++++++++++
ca7c20
 4 files changed, 242 insertions(+)
ca7c20
ca7c20
diff --git a/libmultipath/config.c b/libmultipath/config.c
ca7c20
index 005d6b54..8b0e1f72 100644
ca7c20
--- a/libmultipath/config.c
ca7c20
+++ b/libmultipath/config.c
ca7c20
@@ -238,6 +238,18 @@ const char *get_mpe_wwid(const struct _vector *mptable, const char *alias)
ca7c20
 	return NULL;
ca7c20
 }
ca7c20
 
ca7c20
+static void
ca7c20
+free_pctable (vector pctable)
ca7c20
+{
ca7c20
+	int i;
ca7c20
+	struct pcentry *pce;
ca7c20
+
ca7c20
+	vector_foreach_slot(pctable, pce, i)
ca7c20
+		free(pce);
ca7c20
+
ca7c20
+	vector_free(pctable);
ca7c20
+}
ca7c20
+
ca7c20
 void
ca7c20
 free_hwe (struct hwentry * hwe)
ca7c20
 {
ca7c20
@@ -283,6 +295,9 @@ free_hwe (struct hwentry * hwe)
ca7c20
 	if (hwe->bl_product)
ca7c20
 		FREE(hwe->bl_product);
ca7c20
 
ca7c20
+	if (hwe->pctable)
ca7c20
+		free_pctable(hwe->pctable);
ca7c20
+
ca7c20
 	FREE(hwe);
ca7c20
 }
ca7c20
 
ca7c20
@@ -364,6 +379,15 @@ alloc_hwe (void)
ca7c20
 	return hwe;
ca7c20
 }
ca7c20
 
ca7c20
+struct pcentry *
ca7c20
+alloc_pce (void)
ca7c20
+{
ca7c20
+	struct pcentry *pce = (struct pcentry *)
ca7c20
+				calloc(1, sizeof(struct pcentry));
ca7c20
+	pce->type = -1;
ca7c20
+	return pce;
ca7c20
+}
ca7c20
+
ca7c20
 static char *
ca7c20
 set_param_str(const char * str)
ca7c20
 {
ca7c20
@@ -397,6 +421,13 @@ set_param_str(const char * str)
ca7c20
 	if (!dst->s && src->s) \
ca7c20
 		dst->s = src->s
ca7c20
 
ca7c20
+static void
ca7c20
+merge_pce(struct pcentry *dst, struct pcentry *src)
ca7c20
+{
ca7c20
+	merge_num(fast_io_fail);
ca7c20
+	merge_num(dev_loss);
ca7c20
+	merge_num(eh_deadline);
ca7c20
+}
ca7c20
 
ca7c20
 static void
ca7c20
 merge_hwe (struct hwentry * dst, struct hwentry * src)
ca7c20
@@ -603,6 +634,51 @@ out:
ca7c20
 	return 1;
ca7c20
 }
ca7c20
 
ca7c20
+static void
ca7c20
+validate_pctable(struct hwentry *ovr, int idx, const char *table_desc)
ca7c20
+{
ca7c20
+	struct pcentry *pce;
ca7c20
+
ca7c20
+	if (!ovr || !ovr->pctable)
ca7c20
+		return;
ca7c20
+
ca7c20
+	vector_foreach_slot_after(ovr->pctable, pce, idx) {
ca7c20
+		if (pce->type < 0) {
ca7c20
+			condlog(0, "protocol section in %s missing type",
ca7c20
+				table_desc);
ca7c20
+			vector_del_slot(ovr->pctable, idx--);
ca7c20
+			free(pce);
ca7c20
+		}
ca7c20
+	}
ca7c20
+
ca7c20
+	if (VECTOR_SIZE(ovr->pctable) == 0) {
ca7c20
+		vector_free(ovr->pctable);
ca7c20
+		ovr->pctable = NULL;
ca7c20
+	}
ca7c20
+}
ca7c20
+
ca7c20
+static void
ca7c20
+merge_pctable(struct hwentry *ovr)
ca7c20
+{
ca7c20
+	struct pcentry *pce1, *pce2;
ca7c20
+	int i, j;
ca7c20
+
ca7c20
+	if (!ovr || !ovr->pctable)
ca7c20
+		return;
ca7c20
+
ca7c20
+	vector_foreach_slot(ovr->pctable, pce1, i) {
ca7c20
+		j = i + 1;
ca7c20
+		vector_foreach_slot_after(ovr->pctable, pce2, j) {
ca7c20
+			if (pce1->type != pce2->type)
ca7c20
+				continue;
ca7c20
+			merge_pce(pce2,pce1);
ca7c20
+			vector_del_slot(ovr->pctable, i--);
ca7c20
+			free(pce1);
ca7c20
+			break;
ca7c20
+		}
ca7c20
+	}
ca7c20
+}
ca7c20
+
ca7c20
 static void
ca7c20
 factorize_hwtable (vector hw, int n, const char *table_desc)
ca7c20
 {
ca7c20
@@ -751,6 +827,7 @@ process_config_dir(struct config *conf, char *dir)
ca7c20
 	int i, n;
ca7c20
 	char path[LINE_MAX];
ca7c20
 	int old_hwtable_size;
ca7c20
+	int old_pctable_size = 0;
ca7c20
 
ca7c20
 	if (dir[0] != '/') {
ca7c20
 		condlog(1, "config_dir '%s' must be a fully qualified path",
ca7c20
@@ -777,11 +854,15 @@ process_config_dir(struct config *conf, char *dir)
ca7c20
 			continue;
ca7c20
 
ca7c20
 		old_hwtable_size = VECTOR_SIZE(conf->hwtable);
ca7c20
+		old_pctable_size = conf->overrides ?
ca7c20
+				   VECTOR_SIZE(conf->overrides->pctable) : 0;
ca7c20
 		snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
ca7c20
 		path[LINE_MAX-1] = '\0';
ca7c20
 		process_file(conf, path);
ca7c20
 		factorize_hwtable(conf->hwtable, old_hwtable_size,
ca7c20
 				  namelist[i]->d_name);
ca7c20
+		validate_pctable(conf->overrides, old_pctable_size,
ca7c20
+				 namelist[i]->d_name);
ca7c20
 	}
ca7c20
 	pthread_cleanup_pop(1);
ca7c20
 }
ca7c20
@@ -889,6 +970,7 @@ int _init_config (const char *file, struct config *conf)
ca7c20
 			goto out;
ca7c20
 		}
ca7c20
 		factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
ca7c20
+		validate_pctable(conf->overrides, 0, file);
ca7c20
 	} else {
ca7c20
 		condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
ca7c20
 		condlog(0, "You can run \"/sbin/mpathconf --enable\" to create");
ca7c20
@@ -1004,6 +1086,7 @@ int _init_config (const char *file, struct config *conf)
ca7c20
 			goto out;
ca7c20
 	}
ca7c20
 
ca7c20
+	merge_pctable(conf->overrides);
ca7c20
 	merge_mptable(conf->mptable);
ca7c20
 	merge_blacklist(conf->blist_devnode);
ca7c20
 	merge_blacklist(conf->blist_property);
ca7c20
diff --git a/libmultipath/config.h b/libmultipath/config.h
ca7c20
index 5f01c1fc..57992604 100644
ca7c20
--- a/libmultipath/config.h
ca7c20
+++ b/libmultipath/config.h
ca7c20
@@ -41,6 +41,13 @@ enum force_reload_types {
ca7c20
 	FORCE_RELOAD_WEAK,
ca7c20
 };
ca7c20
 
ca7c20
+struct pcentry {
ca7c20
+	int type;
ca7c20
+	int fast_io_fail;
ca7c20
+	unsigned int dev_loss;
ca7c20
+	int eh_deadline;
ca7c20
+};
ca7c20
+
ca7c20
 struct hwentry {
ca7c20
 	char * vendor;
ca7c20
 	char * product;
ca7c20
@@ -86,6 +93,8 @@ struct hwentry {
ca7c20
 	int vpd_vendor_id;
ca7c20
 	int recheck_wwid;
ca7c20
 	char * bl_product;
ca7c20
+
ca7c20
+	vector pctable;
ca7c20
 };
ca7c20
 
ca7c20
 struct mpentry {
ca7c20
@@ -286,6 +295,7 @@ const char *get_mpe_wwid (const struct _vector *mptable, const char *alias);
ca7c20
 
ca7c20
 struct hwentry * alloc_hwe (void);
ca7c20
 struct mpentry * alloc_mpe (void);
ca7c20
+struct pcentry * alloc_pce (void);
ca7c20
 
ca7c20
 void free_hwe (struct hwentry * hwe);
ca7c20
 void free_hwtable (vector hwtable);
ca7c20
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
ca7c20
index eb5a8083..46b9f225 100644
ca7c20
--- a/libmultipath/dict.c
ca7c20
+++ b/libmultipath/dict.c
ca7c20
@@ -414,6 +414,29 @@ snprint_mp_ ## option (struct config *conf, struct strbuf *buff,	\
ca7c20
 	return function(buff, mpe->option);				\
ca7c20
 }
ca7c20
 
ca7c20
+#define declare_pc_handler(option, function)				\
ca7c20
+static int								\
ca7c20
+pc_ ## option ## _handler (struct config *conf, vector strvec,		\
ca7c20
+			   const char *file, int line_nr)		\
ca7c20
+{									\
ca7c20
+	struct pcentry *pce;						\
ca7c20
+	if (!conf->overrides || !conf->overrides->pctable)		\
ca7c20
+		return 1;						\
ca7c20
+	pce = VECTOR_LAST_SLOT(conf->overrides->pctable);		\
ca7c20
+	if (!pce)							\
ca7c20
+		return 1;						\
ca7c20
+	return function (strvec, &pce->option, file, line_nr);		\
ca7c20
+}
ca7c20
+
ca7c20
+#define declare_pc_snprint(option, function)				\
ca7c20
+static int								\
ca7c20
+snprint_pc_ ## option (struct config *conf, struct strbuf *buff,	\
ca7c20
+		       const void *data)				\
ca7c20
+{									\
ca7c20
+	const struct pcentry *pce  = (const struct pcentry *)data;	\
ca7c20
+	return function(buff, pce->option);				\
ca7c20
+}
ca7c20
+
ca7c20
 static int checkint_handler(struct config *conf, vector strvec,
ca7c20
 			    const char *file, int line_nr)
ca7c20
 {
ca7c20
@@ -1038,6 +1061,8 @@ declare_ovr_handler(fast_io_fail, set_undef_off_zero)
ca7c20
 declare_ovr_snprint(fast_io_fail, print_undef_off_zero)
ca7c20
 declare_hw_handler(fast_io_fail, set_undef_off_zero)
ca7c20
 declare_hw_snprint(fast_io_fail, print_undef_off_zero)
ca7c20
+declare_pc_handler(fast_io_fail, set_undef_off_zero)
ca7c20
+declare_pc_snprint(fast_io_fail, print_undef_off_zero)
ca7c20
 
ca7c20
 static int
ca7c20
 set_dev_loss(vector strvec, void *ptr, const char *file, int line_nr)
ca7c20
@@ -1075,6 +1100,8 @@ declare_ovr_handler(dev_loss, set_dev_loss)
ca7c20
 declare_ovr_snprint(dev_loss, print_dev_loss)
ca7c20
 declare_hw_handler(dev_loss, set_dev_loss)
ca7c20
 declare_hw_snprint(dev_loss, print_dev_loss)
ca7c20
+declare_pc_handler(dev_loss, set_dev_loss)
ca7c20
+declare_pc_snprint(dev_loss, print_dev_loss)
ca7c20
 
ca7c20
 declare_def_handler(eh_deadline, set_undef_off_zero)
ca7c20
 declare_def_snprint(eh_deadline, print_undef_off_zero)
ca7c20
@@ -1082,6 +1109,8 @@ declare_ovr_handler(eh_deadline, set_undef_off_zero)
ca7c20
 declare_ovr_snprint(eh_deadline, print_undef_off_zero)
ca7c20
 declare_hw_handler(eh_deadline, set_undef_off_zero)
ca7c20
 declare_hw_snprint(eh_deadline, print_undef_off_zero)
ca7c20
+declare_pc_handler(eh_deadline, set_undef_off_zero)
ca7c20
+declare_pc_snprint(eh_deadline, print_undef_off_zero)
ca7c20
 
ca7c20
 static int
ca7c20
 set_pgpolicy(vector strvec, void *ptr, const char *file, int line_nr)
ca7c20
@@ -1889,6 +1918,69 @@ declare_mp_snprint(wwid, print_str)
ca7c20
 declare_mp_handler(alias, set_str_noslash)
ca7c20
 declare_mp_snprint(alias, print_str)
ca7c20
 
ca7c20
+
ca7c20
+static int
ca7c20
+protocol_handler(struct config *conf, vector strvec, const char *file,
ca7c20
+               int line_nr)
ca7c20
+{
ca7c20
+	struct pcentry *pce;
ca7c20
+
ca7c20
+	if (!conf->overrides)
ca7c20
+		return 1;
ca7c20
+
ca7c20
+	if (!conf->overrides->pctable &&
ca7c20
+	    !(conf->overrides->pctable = vector_alloc()))
ca7c20
+		return 1;
ca7c20
+
ca7c20
+	if (!(pce = alloc_pce()))
ca7c20
+		return 1;
ca7c20
+
ca7c20
+	if (!vector_alloc_slot(conf->overrides->pctable)) {
ca7c20
+		free(pce);
ca7c20
+		return 1;
ca7c20
+	}
ca7c20
+	vector_set_slot(conf->overrides->pctable, pce);
ca7c20
+
ca7c20
+	return 0;
ca7c20
+}
ca7c20
+
ca7c20
+static int
ca7c20
+set_protocol_type(vector strvec, void *ptr, const char *file, int line_nr)
ca7c20
+{
ca7c20
+	int *int_ptr = (int *)ptr;
ca7c20
+	char *buff;
ca7c20
+	int i;
ca7c20
+
ca7c20
+	buff = set_value(strvec);
ca7c20
+
ca7c20
+	if (!buff)
ca7c20
+		return 1;
ca7c20
+
ca7c20
+	for (i = 0; i <= LAST_BUS_PROTOCOL_ID; i++) {
ca7c20
+		if (protocol_name[i] && !strcmp(buff, protocol_name[i])) {
ca7c20
+			*int_ptr = i;
ca7c20
+			break;
ca7c20
+		}
ca7c20
+	}
ca7c20
+	if (i > LAST_BUS_PROTOCOL_ID)
ca7c20
+		condlog(1, "%s line %d, invalid value for type: \"%s\"",
ca7c20
+			file, line_nr, buff);
ca7c20
+
ca7c20
+	free(buff);
ca7c20
+	return 0;
ca7c20
+}
ca7c20
+
ca7c20
+static int
ca7c20
+print_protocol_type(struct strbuf *buff, int type)
ca7c20
+{
ca7c20
+	if (type < 0)
ca7c20
+		return 0;
ca7c20
+	return append_strbuf_quoted(buff, protocol_name[type]);
ca7c20
+}
ca7c20
+
ca7c20
+declare_pc_handler(type, set_protocol_type)
ca7c20
+declare_pc_snprint(type, print_protocol_type)
ca7c20
+
ca7c20
 /*
ca7c20
  * deprecated handlers
ca7c20
  */
ca7c20
@@ -2130,6 +2222,13 @@ init_keywords(vector keywords)
ca7c20
 	install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay);
ca7c20
 	install_keyword("all_tg_pt", &ovr_all_tg_pt_handler, &snprint_ovr_all_tg_pt);
ca7c20
 	install_keyword("recheck_wwid", &ovr_recheck_wwid_handler, &snprint_ovr_recheck_wwid);
ca7c20
+	install_keyword_multi("protocol", &protocol_handler, NULL);
ca7c20
+	install_sublevel();
ca7c20
+	install_keyword("type", &pc_type_handler, &snprint_pc_type);
ca7c20
+	install_keyword("fast_io_fail_tmo", &pc_fast_io_fail_handler, &snprint_pc_fast_io_fail);
ca7c20
+	install_keyword("dev_loss_tmo", &pc_dev_loss_handler, &snprint_pc_dev_loss);
ca7c20
+	install_keyword("eh_deadline", &pc_eh_deadline_handler, &snprint_pc_eh_deadline);
ca7c20
+	install_sublevel_end();
ca7c20
 
ca7c20
 	install_keyword_root("multipaths", &multipaths_handler);
ca7c20
 	install_keyword_multi("multipath", &multipath_handler, NULL);
ca7c20
diff --git a/libmultipath/print.c b/libmultipath/print.c
ca7c20
index 0dbd34e4..46e3d32e 100644
ca7c20
--- a/libmultipath/print.c
ca7c20
+++ b/libmultipath/print.c
ca7c20
@@ -1318,6 +1318,52 @@ int snprint_multipath_topology_json (struct strbuf *buff,
ca7c20
 	return get_strbuf_len(buff) - initial_len;
ca7c20
 }
ca7c20
 
ca7c20
+static int
ca7c20
+snprint_pcentry (const struct config *conf, struct strbuf *buff,
ca7c20
+		 const struct pcentry *pce)
ca7c20
+{
ca7c20
+	int i, rc;
ca7c20
+	struct keyword *kw;
ca7c20
+	struct keyword * rootkw;
ca7c20
+	size_t initial_len = get_strbuf_len(buff);
ca7c20
+
ca7c20
+	rootkw = find_keyword(conf->keywords, NULL, "overrides");
ca7c20
+	assert(rootkw && rootkw->sub);
ca7c20
+	rootkw = find_keyword(conf->keywords, rootkw->sub, "protocol");
ca7c20
+	assert(rootkw);
ca7c20
+
ca7c20
+	if ((rc = append_strbuf_str(buff, "\tprotocol {\n")) < 0)
ca7c20
+		return rc;
ca7c20
+
ca7c20
+	iterate_sub_keywords(rootkw, kw, i) {
ca7c20
+		if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, pce)) < 0)
ca7c20
+			return rc;
ca7c20
+	}
ca7c20
+
ca7c20
+	if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
ca7c20
+		return rc;
ca7c20
+	return get_strbuf_len(buff) - initial_len;
ca7c20
+}
ca7c20
+
ca7c20
+static int
ca7c20
+snprint_pctable (const struct config *conf, struct strbuf *buff,
ca7c20
+		 const struct _vector *pctable)
ca7c20
+{
ca7c20
+	int i, rc;
ca7c20
+	struct pcentry *pce;
ca7c20
+	struct keyword * rootkw;
ca7c20
+	size_t initial_len = get_strbuf_len(buff);
ca7c20
+
ca7c20
+	rootkw = find_keyword(conf->keywords, NULL, "overrides");
ca7c20
+	assert(rootkw);
ca7c20
+
ca7c20
+	vector_foreach_slot(pctable, pce, i) {
ca7c20
+		if ((rc = snprint_pcentry(conf, buff, pce)) < 0)
ca7c20
+			return rc;
ca7c20
+	}
ca7c20
+	return get_strbuf_len(buff) - initial_len;
ca7c20
+}
ca7c20
+
ca7c20
 static int
ca7c20
 snprint_hwentry (const struct config *conf,
ca7c20
 		 struct strbuf *buff, const struct hwentry * hwe)
ca7c20
@@ -1472,6 +1518,10 @@ static int snprint_overrides(const struct config *conf, struct strbuf *buff,
ca7c20
 		if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
ca7c20
 			return rc;
ca7c20
 	}
ca7c20
+
ca7c20
+	if (overrides->pctable &&
ca7c20
+	    (rc = snprint_pctable(conf, buff, overrides->pctable)) < 0)
ca7c20
+		return rc;
ca7c20
 out:
ca7c20
 	if ((rc = append_strbuf_str(buff, "}\n")) < 0)
ca7c20
 		return rc;