426 lines
12 KiB
Diff
426 lines
12 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 | 50 ++++++++++++++++++++++
|
|
4 files changed, 242 insertions(+)
|
|
|
|
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
|
index 005d6b54..8b0e1f72 100644
|
|
--- a/libmultipath/config.c
|
|
+++ b/libmultipath/config.c
|
|
@@ -238,6 +238,18 @@ const char *get_mpe_wwid(const struct _vector *mptable, const 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)
|
|
{
|
|
@@ -283,6 +295,9 @@ free_hwe (struct hwentry * hwe)
|
|
if (hwe->bl_product)
|
|
FREE(hwe->bl_product);
|
|
|
|
+ if (hwe->pctable)
|
|
+ free_pctable(hwe->pctable);
|
|
+
|
|
FREE(hwe);
|
|
}
|
|
|
|
@@ -364,6 +379,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)
|
|
{
|
|
@@ -397,6 +421,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)
|
|
@@ -603,6 +634,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)
|
|
{
|
|
@@ -751,6 +827,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",
|
|
@@ -777,11 +854,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);
|
|
}
|
|
@@ -889,6 +970,7 @@ int _init_config (const char *file, struct config *conf)
|
|
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");
|
|
@@ -1004,6 +1086,7 @@ int _init_config (const char *file, struct config *conf)
|
|
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 5f01c1fc..57992604 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 {
|
|
@@ -286,6 +295,7 @@ const char *get_mpe_wwid (const struct _vector *mptable, const 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 eb5a8083..46b9f225 100644
|
|
--- a/libmultipath/dict.c
|
|
+++ b/libmultipath/dict.c
|
|
@@ -414,6 +414,29 @@ snprint_mp_ ## option (struct config *conf, struct strbuf *buff, \
|
|
return function(buff, 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, struct strbuf *buff, \
|
|
+ const void *data) \
|
|
+{ \
|
|
+ const struct pcentry *pce = (const struct pcentry *)data; \
|
|
+ return function(buff, pce->option); \
|
|
+}
|
|
+
|
|
static int checkint_handler(struct config *conf, vector strvec,
|
|
const char *file, int line_nr)
|
|
{
|
|
@@ -1038,6 +1061,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)
|
|
@@ -1075,6 +1100,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)
|
|
@@ -1082,6 +1109,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)
|
|
@@ -1889,6 +1918,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(struct strbuf *buff, int type)
|
|
+{
|
|
+ if (type < 0)
|
|
+ return 0;
|
|
+ return append_strbuf_quoted(buff, protocol_name[type]);
|
|
+}
|
|
+
|
|
+declare_pc_handler(type, set_protocol_type)
|
|
+declare_pc_snprint(type, print_protocol_type)
|
|
+
|
|
/*
|
|
* deprecated handlers
|
|
*/
|
|
@@ -2130,6 +2222,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 0dbd34e4..46e3d32e 100644
|
|
--- a/libmultipath/print.c
|
|
+++ b/libmultipath/print.c
|
|
@@ -1318,6 +1318,52 @@ int snprint_multipath_topology_json (struct strbuf *buff,
|
|
return get_strbuf_len(buff) - initial_len;
|
|
}
|
|
|
|
+static int
|
|
+snprint_pcentry (const struct config *conf, struct strbuf *buff,
|
|
+ const struct pcentry *pce)
|
|
+{
|
|
+ int i, rc;
|
|
+ struct keyword *kw;
|
|
+ struct keyword * rootkw;
|
|
+ size_t initial_len = get_strbuf_len(buff);
|
|
+
|
|
+ rootkw = find_keyword(conf->keywords, NULL, "overrides");
|
|
+ assert(rootkw && rootkw->sub);
|
|
+ rootkw = find_keyword(conf->keywords, rootkw->sub, "protocol");
|
|
+ assert(rootkw);
|
|
+
|
|
+ if ((rc = append_strbuf_str(buff, "\tprotocol {\n")) < 0)
|
|
+ return rc;
|
|
+
|
|
+ iterate_sub_keywords(rootkw, kw, i) {
|
|
+ if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, pce)) < 0)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
|
|
+ return rc;
|
|
+ return get_strbuf_len(buff) - initial_len;
|
|
+}
|
|
+
|
|
+static int
|
|
+snprint_pctable (const struct config *conf, struct strbuf *buff,
|
|
+ const struct _vector *pctable)
|
|
+{
|
|
+ int i, rc;
|
|
+ struct pcentry *pce;
|
|
+ struct keyword * rootkw;
|
|
+ size_t initial_len = get_strbuf_len(buff);
|
|
+
|
|
+ rootkw = find_keyword(conf->keywords, NULL, "overrides");
|
|
+ assert(rootkw);
|
|
+
|
|
+ vector_foreach_slot(pctable, pce, i) {
|
|
+ if ((rc = snprint_pcentry(conf, buff, pce)) < 0)
|
|
+ return rc;
|
|
+ }
|
|
+ return get_strbuf_len(buff) - initial_len;
|
|
+}
|
|
+
|
|
static int
|
|
snprint_hwentry (const struct config *conf,
|
|
struct strbuf *buff, const struct hwentry * hwe)
|
|
@@ -1472,6 +1518,10 @@ static int snprint_overrides(const struct config *conf, struct strbuf *buff,
|
|
if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
|
|
return rc;
|
|
}
|
|
+
|
|
+ if (overrides->pctable &&
|
|
+ (rc = snprint_pctable(conf, buff, overrides->pctable)) < 0)
|
|
+ return rc;
|
|
out:
|
|
if ((rc = append_strbuf_str(buff, "}\n")) < 0)
|
|
return rc;
|