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

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