420 lines
11 KiB
Diff
420 lines
11 KiB
Diff
|
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)
|