From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 13 Apr 2022 23:27:37 -0500
Subject: [PATCH] libmultipath: add a protocol subsection to multipath.conf
Some storage arrays can be accessed using multiple protocols at the same
time. In these cases, users may want to set path attributes
differently, depending on the protocol that the path is using. To allow
this, add a protocol subsection to the overrides section in
multipath.conf, which allows select path-specific options to be set.
This commit simply adds the subsection, and handles merging matching
entries. Future patches will make use of the section.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Reviewed-by: Martin Wilck <mwilck@suse.com>
---
libmultipath/config.c | 83 ++++++++++++++++++++++++++++++++++++
libmultipath/config.h | 10 +++++
libmultipath/dict.c | 99 +++++++++++++++++++++++++++++++++++++++++++
libmultipath/print.c | 44 +++++++++++++++++++
4 files changed, 236 insertions(+)
diff --git a/libmultipath/config.c b/libmultipath/config.c
index aa79561e..88975323 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -173,6 +173,18 @@ char *get_mpe_wwid(vector mptable, char *alias)
return NULL;
}
+static void
+free_pctable (vector pctable)
+{
+ int i;
+ struct pcentry *pce;
+
+ vector_foreach_slot(pctable, pce, i)
+ free(pce);
+
+ vector_free(pctable);
+}
+
void
free_hwe (struct hwentry * hwe)
{
@@ -218,6 +230,9 @@ free_hwe (struct hwentry * hwe)
if (hwe->bl_product)
FREE(hwe->bl_product);
+ if (hwe->pctable)
+ free_pctable(hwe->pctable);
+
FREE(hwe);
}
@@ -299,6 +314,15 @@ alloc_hwe (void)
return hwe;
}
+struct pcentry *
+alloc_pce (void)
+{
+ struct pcentry *pce = (struct pcentry *)
+ calloc(1, sizeof(struct pcentry));
+ pce->type = -1;
+ return pce;
+}
+
static char *
set_param_str(const char * str)
{
@@ -332,6 +356,13 @@ set_param_str(const char * str)
if (!dst->s && src->s) \
dst->s = src->s
+static void
+merge_pce(struct pcentry *dst, struct pcentry *src)
+{
+ merge_num(fast_io_fail);
+ merge_num(dev_loss);
+ merge_num(eh_deadline);
+}
static void
merge_hwe (struct hwentry * dst, struct hwentry * src)
@@ -538,6 +569,51 @@ out:
return 1;
}
+static void
+validate_pctable(struct hwentry *ovr, int idx, const char *table_desc)
+{
+ struct pcentry *pce;
+
+ if (!ovr || !ovr->pctable)
+ return;
+
+ vector_foreach_slot_after(ovr->pctable, pce, idx) {
+ if (pce->type < 0) {
+ condlog(0, "protocol section in %s missing type",
+ table_desc);
+ vector_del_slot(ovr->pctable, idx--);
+ free(pce);
+ }
+ }
+
+ if (VECTOR_SIZE(ovr->pctable) == 0) {
+ vector_free(ovr->pctable);
+ ovr->pctable = NULL;
+ }
+}
+
+static void
+merge_pctable(struct hwentry *ovr)
+{
+ struct pcentry *pce1, *pce2;
+ int i, j;
+
+ if (!ovr || !ovr->pctable)
+ return;
+
+ vector_foreach_slot(ovr->pctable, pce1, i) {
+ j = i + 1;
+ vector_foreach_slot_after(ovr->pctable, pce2, j) {
+ if (pce1->type != pce2->type)
+ continue;
+ merge_pce(pce2,pce1);
+ vector_del_slot(ovr->pctable, i--);
+ free(pce1);
+ break;
+ }
+ }
+}
+
static void
factorize_hwtable (vector hw, int n, const char *table_desc)
{
@@ -666,6 +742,7 @@ process_config_dir(struct config *conf, char *dir)
int i, n;
char path[LINE_MAX];
int old_hwtable_size;
+ int old_pctable_size = 0;
if (dir[0] != '/') {
condlog(1, "config_dir '%s' must be a fully qualified path",
@@ -692,11 +769,15 @@ process_config_dir(struct config *conf, char *dir)
continue;
old_hwtable_size = VECTOR_SIZE(conf->hwtable);
+ old_pctable_size = conf->overrides ?
+ VECTOR_SIZE(conf->overrides->pctable) : 0;
snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
path[LINE_MAX-1] = '\0';
process_file(conf, path);
factorize_hwtable(conf->hwtable, old_hwtable_size,
namelist[i]->d_name);
+ validate_pctable(conf->overrides, old_pctable_size,
+ namelist[i]->d_name);
}
pthread_cleanup_pop(1);
}
@@ -784,6 +865,7 @@ load_config (char * file)
goto out;
}
factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
+ validate_pctable(conf->overrides, 0, file);
} else {
condlog(0, "/etc/multipath.conf does not exist, blacklisting all devices.");
condlog(0, "You can run \"/sbin/mpathconf --enable\" to create");
@@ -898,6 +980,7 @@ load_config (char * file)
goto out;
}
+ merge_pctable(conf->overrides);
merge_mptable(conf->mptable);
merge_blacklist(conf->blist_devnode);
merge_blacklist(conf->blist_property);
diff --git a/libmultipath/config.h b/libmultipath/config.h
index e2e3f143..143116b3 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -41,6 +41,13 @@ enum force_reload_types {
FORCE_RELOAD_WEAK,
};
+struct pcentry {
+ int type;
+ int fast_io_fail;
+ unsigned int dev_loss;
+ int eh_deadline;
+};
+
struct hwentry {
char * vendor;
char * product;
@@ -86,6 +93,8 @@ struct hwentry {
int vpd_vendor_id;
int recheck_wwid;
char * bl_product;
+
+ vector pctable;
};
struct mpentry {
@@ -240,6 +249,7 @@ char * get_mpe_wwid (vector mptable, char * alias);
struct hwentry * alloc_hwe (void);
struct mpentry * alloc_mpe (void);
+struct pcentry * alloc_pce (void);
void free_hwe (struct hwentry * hwe);
void free_hwtable (vector hwtable);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 5a0255b0..8321ec1e 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -457,6 +457,29 @@ snprint_mp_ ## option (struct config *conf, char * buff, int len, \
return function (buff, len, mpe->option); \
}
+#define declare_pc_handler(option, function) \
+static int \
+pc_ ## option ## _handler (struct config *conf, vector strvec, \
+ const char *file, int line_nr) \
+{ \
+ struct pcentry *pce; \
+ if (!conf->overrides || !conf->overrides->pctable) \
+ return 1; \
+ pce = VECTOR_LAST_SLOT(conf->overrides->pctable); \
+ if (!pce) \
+ return 1; \
+ return function (strvec, &pce->option, file, line_nr); \
+}
+
+#define declare_pc_snprint(option, function) \
+static int \
+snprint_pc_ ## option (struct config *conf, char * buff, int len, \
+ const void *data) \
+{ \
+ const struct pcentry *pce = (const struct pcentry *)data; \
+ return function(buff, len, pce->option); \
+}
+
static int checkint_handler(struct config *conf, vector strvec,
const char *file, int line_nr)
{
@@ -1022,6 +1045,8 @@ declare_ovr_handler(fast_io_fail, set_undef_off_zero)
declare_ovr_snprint(fast_io_fail, print_undef_off_zero)
declare_hw_handler(fast_io_fail, set_undef_off_zero)
declare_hw_snprint(fast_io_fail, print_undef_off_zero)
+declare_pc_handler(fast_io_fail, set_undef_off_zero)
+declare_pc_snprint(fast_io_fail, print_undef_off_zero)
static int
set_dev_loss(vector strvec, void *ptr, const char *file, int line_nr)
@@ -1059,6 +1084,8 @@ declare_ovr_handler(dev_loss, set_dev_loss)
declare_ovr_snprint(dev_loss, print_dev_loss)
declare_hw_handler(dev_loss, set_dev_loss)
declare_hw_snprint(dev_loss, print_dev_loss)
+declare_pc_handler(dev_loss, set_dev_loss)
+declare_pc_snprint(dev_loss, print_dev_loss)
declare_def_handler(eh_deadline, set_undef_off_zero)
declare_def_snprint(eh_deadline, print_undef_off_zero)
@@ -1066,6 +1093,8 @@ declare_ovr_handler(eh_deadline, set_undef_off_zero)
declare_ovr_snprint(eh_deadline, print_undef_off_zero)
declare_hw_handler(eh_deadline, set_undef_off_zero)
declare_hw_snprint(eh_deadline, print_undef_off_zero)
+declare_pc_handler(eh_deadline, set_undef_off_zero)
+declare_pc_snprint(eh_deadline, print_undef_off_zero)
static int
set_pgpolicy(vector strvec, void *ptr, const char *file, int line_nr)
@@ -1876,6 +1905,69 @@ declare_mp_snprint(wwid, print_str)
declare_mp_handler(alias, set_str_noslash)
declare_mp_snprint(alias, print_str)
+
+static int
+protocol_handler(struct config *conf, vector strvec, const char *file,
+ int line_nr)
+{
+ struct pcentry *pce;
+
+ if (!conf->overrides)
+ return 1;
+
+ if (!conf->overrides->pctable &&
+ !(conf->overrides->pctable = vector_alloc()))
+ return 1;
+
+ if (!(pce = alloc_pce()))
+ return 1;
+
+ if (!vector_alloc_slot(conf->overrides->pctable)) {
+ free(pce);
+ return 1;
+ }
+ vector_set_slot(conf->overrides->pctable, pce);
+
+ return 0;
+}
+
+static int
+set_protocol_type(vector strvec, void *ptr, const char *file, int line_nr)
+{
+ int *int_ptr = (int *)ptr;
+ char *buff;
+ int i;
+
+ buff = set_value(strvec);
+
+ if (!buff)
+ return 1;
+
+ for (i = 0; i <= LAST_BUS_PROTOCOL_ID; i++) {
+ if (protocol_name[i] && !strcmp(buff, protocol_name[i])) {
+ *int_ptr = i;
+ break;
+ }
+ }
+ if (i > LAST_BUS_PROTOCOL_ID)
+ condlog(1, "%s line %d, invalid value for type: \"%s\"",
+ file, line_nr, buff);
+
+ free(buff);
+ return 0;
+}
+
+static int
+print_protocol_type(char *buff, int len, int type)
+{
+ if (type < 0)
+ return 0;
+ return snprintf(buff, len, "\"%s\"", protocol_name[type]);
+}
+
+declare_pc_handler(type, set_protocol_type)
+declare_pc_snprint(type, print_protocol_type)
+
/*
* deprecated handlers
*/
@@ -2117,6 +2209,13 @@ init_keywords(vector keywords)
install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay);
install_keyword("all_tg_pt", &ovr_all_tg_pt_handler, &snprint_ovr_all_tg_pt);
install_keyword("recheck_wwid", &ovr_recheck_wwid_handler, &snprint_ovr_recheck_wwid);
+ install_keyword_multi("protocol", &protocol_handler, NULL);
+ install_sublevel();
+ install_keyword("type", &pc_type_handler, &snprint_pc_type);
+ install_keyword("fast_io_fail_tmo", &pc_fast_io_fail_handler, &snprint_pc_fast_io_fail);
+ install_keyword("dev_loss_tmo", &pc_dev_loss_handler, &snprint_pc_dev_loss);
+ install_keyword("eh_deadline", &pc_eh_deadline_handler, &snprint_pc_eh_deadline);
+ install_sublevel_end();
install_keyword_root("multipaths", &multipaths_handler);
install_keyword_multi("multipath", &multipath_handler, NULL);
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 1f6d27bd..8a6fbe83 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -1392,6 +1392,39 @@ snprint_multipath_topology_json (char * buff, int len, const struct vectors * ve
return fwd;
}
+static int
+snprint_pcentry (const struct config *conf, char *buff, int len,
+ const struct pcentry *pce)
+{
+ int i;
+ int fwd = 0;
+ struct keyword *kw;
+ struct keyword *rootkw;
+
+ rootkw = find_keyword(conf->keywords, NULL, "overrides");
+ if (!rootkw || !rootkw->sub)
+ return 0;
+
+ rootkw = find_keyword(conf->keywords, rootkw->sub, "protocol");
+ if (!rootkw)
+ return 0;
+
+ fwd += snprintf(buff + fwd, len - fwd, "\tprotocol {\n");
+ if (fwd >= len)
+ return len;
+
+ iterate_sub_keywords(rootkw, kw, i) {
+ fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
+ kw, pce);
+ if (fwd >= len)
+ return len;
+ }
+ fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
+ if (fwd >= len)
+ return len;
+ return fwd;
+}
+
static int
snprint_hwentry (const struct config *conf,
char * buff, int len, const struct hwentry * hwe)
@@ -1575,6 +1608,17 @@ static int snprint_overrides(const struct config *conf, char * buff, int len,
if (fwd >= len)
return len;
}
+
+ if (overrides->pctable) {
+ struct pcentry *pce;
+
+ vector_foreach_slot(overrides->pctable, pce, i) {
+ fwd += snprint_pcentry(conf, buff + fwd, len - fwd,
+ pce);
+ if (fwd >= len)
+ return len;
+ }
+ }
out:
fwd += snprintf(buff + fwd, len - fwd, "}\n");
if (fwd >= len)