All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6][RESEND] configuration overhaul and find_multipaths
@ 2014-11-19  6:17 Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 1/6] libmultipath: rewrite dict.c with function generation macros Benjamin Marzinski
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

Since the first time I sent them, they got no response at all, I'm resending
the alternative solution to my all_devs patch, which uses a whole new
multipath.conf section. "overrides"

Adding an overrides section to the existing multipath configuration system
would have involved a lot (over 1500 lines) of mostly copy/paste code. Intead
of doing that, I overhauled dict.c and propsel.c to use macros to cut down on
code duplication. This made adding the new section much easier.

Also, I'm resending my find_multipaths patch, based on the conversation I had
here.

http://www.redhat.com/archives/dm-devel/2014-July/msg00029.html

Just to clarify. find_multipaths is a configurable option that when set to
'yes' will make multipath only run on devices have more than one path.  This
means that users can mostly leave the blacklist alone, and they will only get
the multipath devices that they want. The only time the blacklist is necessary
is when users actually have multiple paths to a device, but still don't want
multipath set up on it.  It's been around since RHEL6, and it is turned on
in the default multipath.conf file in RHEL7. The internal default is "off".

Benjamin Marzinski (6):
  libmultipath: rewrite dict.c with function generation macros
  libmultipath: cleanup propsel.c with macros for common actions
  libmultipath: add overrides section to multipath.conf
  add find_multipaths option
  correctly set partition delimiter on rename
  libmultipath: only add uninitialized paths in check_path

 libmultipath/config.c      |   10 +-
 libmultipath/config.h      |    3 +
 libmultipath/configure.c   |   11 +
 libmultipath/defaults.h    |    3 +-
 libmultipath/devmapper.c   |   14 +-
 libmultipath/dict.c        | 3221 +++++++++++---------------------------------
 libmultipath/dict.h        |    7 +
 libmultipath/discovery.c   |    2 +
 libmultipath/pgpolicies.c  |    2 +-
 libmultipath/print.c       |   30 +
 libmultipath/print.h       |    1 +
 libmultipath/propsel.c     |  761 +++++------
 libmultipath/structs.c     |    9 +-
 libmultipath/structs.h     |   45 +-
 libmultipath/wwids.c       |   26 +
 libmultipath/wwids.h       |    1 +
 multipath.conf.annotated   |   18 +-
 multipath.conf.defaults    |    2 +
 multipath.conf.synthetic   |    3 +
 multipath/main.c           |   33 +-
 multipath/multipath.conf.5 |   57 +
 multipathd/cli_handlers.c  |   10 +
 multipathd/main.c          |    9 +
 23 files changed, 1375 insertions(+), 2903 deletions(-)

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/6] libmultipath: rewrite dict.c with function generation macros
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 2/6] libmultipath: cleanup propsel.c with macros for common actions Benjamin Marzinski
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

dict.c is full of nearly identical functions for setting and printing the
configuration. Many options use the exact same function with just the
variable name changing.  For options that exist in multiple sections of
multipath.conf, the functions for setting and printing the option are also
nearly identical, except for the config structure that is used.

In order to avoid this massive amount of code duplication, and also to
standardize and avoid copy/paste errors, I've written some standard
functions with the most common setting and printing code, and some macros
that take the setting and printing functions, and add the boilerplate code
that is necessary for the different sections. This means that there is
at most one unique function to set and print an option, regardless of
home many sections is appears in.  Options that just set a string or
integer don't even need their own function. They can use one of the generic
ones.

There's one trade-off that I'm not sure I chose the right way on. In
order to keep the number of macros down, I made them transfer the
data using void pointers. This means that the macro works regardless
of whether the data is a signed or unsigned int or a string or whatever.
The downside to this is that there isn't type checking.  This means that
if, for instance, someone called a function that expected a string, but
passed in an integer. The complier wouldn't catch the error.

declare_def_snprint(verbosity, print_str)

as an example, would happily treat &conf->verbosity as a string pointer.
I'm not sure how worried people are about this, but it wouldn't be too
hard to add a bunch more declare_* macros so that each was typed.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/config.c   |    5 +-
 libmultipath/defaults.h |    2 -
 libmultipath/dict.c     | 3097 +++++++++++------------------------------------
 libmultipath/structs.h  |   44 +-
 4 files changed, 719 insertions(+), 2429 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 39963b4..bfd8ee8 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -556,7 +556,7 @@ load_config (char * file, struct udev *udev)
 	conf->attribute_flags = 0;
 	conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
 	conf->checkint = DEFAULT_CHECKINT;
-	conf->max_checkint = MAX_CHECKINT(conf->checkint);
+	conf->max_checkint = 0;
 	conf->pgfailback = DEFAULT_FAILBACK;
 	conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
 	conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
@@ -599,7 +599,8 @@ load_config (char * file, struct udev *udev)
 	} else {
 		init_keywords();
 	}
-
+	if (conf->max_checkint == 0)
+		conf->max_checkint = MAX_CHECKINT(conf->checkint);
 	/*
 	 * fill the voids left in the config file
 	 */
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index b83d9fb..99cf4b1 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -11,8 +11,6 @@
 #define DEFAULT_FAILBACK       -FAILBACK_MANUAL
 #define DEFAULT_RR_WEIGHT      RR_WEIGHT_NONE
 #define DEFAULT_NO_PATH_RETRY  NO_PATH_RETRY_UNDEF
-#define DEFAULT_PGTIMEOUT      -PGTIMEOUT_NONE
-#define DEFAULT_USER_FRIENDLY_NAMES    0
 #define DEFAULT_VERBOSITY	2
 #define DEFAULT_REASSIGN_MAPS	1
 #define DEFAULT_FAST_IO_FAIL	5
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 7de7a67..e88c122 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -22,245 +22,572 @@
 #include "errno.h"
 #include <inttypes.h>
 
-/*
- * default block handlers
- */
 static int
-polling_interval_handler(vector strvec)
+set_int(vector strvec, void *ptr)
 {
+	int *int_ptr = (int *)ptr;
 	char * buff;
 
 	buff = VECTOR_SLOT(strvec, 1);
-	conf->checkint = atoi(buff);
-	conf->max_checkint = MAX_CHECKINT(conf->checkint);
+	*int_ptr = atoi(buff);
 
 	return 0;
 }
 
 static int
-def_fast_io_fail_handler(vector strvec)
+set_str(vector strvec, void *ptr)
 {
-	char * buff;
+	char **str_ptr = (char **)ptr;
+	*str_ptr = set_value(strvec);
 
-	buff = set_value(strvec);
-	if (!buff)
+	if (!*str_ptr)
 		return 1;
 
-	if (strlen(buff) == 3 && !strcmp(buff, "off"))
-		conf->fast_io_fail = MP_FAST_IO_FAIL_OFF;
-	else if (sscanf(buff, "%d", &conf->fast_io_fail) != 1 ||
-		 conf->fast_io_fail < MP_FAST_IO_FAIL_ZERO)
-		conf->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
-	else if (conf->fast_io_fail == 0)
-		conf->fast_io_fail = MP_FAST_IO_FAIL_ZERO;
-
-	FREE(buff);
 	return 0;
 }
 
 static int
-def_dev_loss_handler(vector strvec)
+set_yes_no(vector strvec, void *ptr)
 {
 	char * buff;
+	int *int_ptr = (int *)ptr;
 
 	buff = set_value(strvec);
 	if (!buff)
 		return 1;
 
-	if (strlen(buff) == 8 && !strcmp(buff, "infinity"))
-		conf->dev_loss = MAX_DEV_LOSS_TMO;
-	else if (sscanf(buff, "%u", &conf->dev_loss) != 1)
-		conf->dev_loss = 0;
+	if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+		*int_ptr = YN_YES;
+	else
+		*int_ptr = YN_NO;
 
 	FREE(buff);
 	return 0;
 }
 
 static int
-verbosity_handler(vector strvec)
+set_yes_no_undef(vector strvec, void *ptr)
 {
 	char * buff;
+	int *int_ptr = (int *)ptr;
 
-	buff = VECTOR_SLOT(strvec, 1);
-	conf->verbosity = atoi(buff);
+	buff = set_value(strvec);
+	if (!buff)
+		return 1;
 
+	if (strcmp(buff, "no") == 0 || strcmp(buff, "0") == 0)
+		*int_ptr = YNU_NO;
+	else if (strcmp(buff, "yes") == 0 || strcmp(buff, "1") == 0)
+		*int_ptr = YNU_YES;
+	else
+		*int_ptr = YNU_UNDEF;
+
+	FREE(buff);
 	return 0;
 }
 
 static int
-max_polling_interval_handler(vector strvec)
+print_int (char *buff, int len, void *ptr)
 {
-	char *buff;
-
-	buff = VECTOR_SLOT(strvec, 1);
-	conf->max_checkint = atoi(buff);
+	int *int_ptr = (int *)ptr;
+	return snprintf(buff, len, "%i", *int_ptr);
+}
 
-	return 0;
+static int
+print_nonzero (char *buff, int len, void *ptr)
+{
+	int *int_ptr = (int *)ptr;
+	if (!*int_ptr)
+		return 0;
+	return snprintf(buff, len, "%i", *int_ptr);
 }
 
 static int
-reassign_maps_handler(vector strvec)
+print_str (char *buff, int len, void *ptr)
 {
-	char * buff;
+	char **str_ptr = (char **)ptr;
+	if (!*str_ptr)
+		return 0;
+	return snprintf(buff, len, "\"%s\"", *str_ptr);
+}
 
-	buff = set_value(strvec);
-	if (!strcmp(buff, "yes"))
-		conf->reassign_maps = 1;
-	else if (!strcmp(buff, "no"))
-		conf->reassign_maps = 0;
-	else
-		return 1;
+static int
+print_yes_no (char *buff, int len, void *ptr)
+{
+	int *int_ptr = (int *)ptr;
+	return snprintf(buff, len, "\"%s\"",
+			(*int_ptr == YN_NO)? "no" : "yes");
+}
 
-	return 0;
+static int
+print_yes_no_undef (char *buff, int len, void *ptr)
+{
+	int *int_ptr = (int *)ptr;
+	if (!*int_ptr)
+		return 0;
+	return snprintf(buff, len, "\"%s\"",
+			(*int_ptr == YNU_NO)? "no" : "yes");
 }
 
+#define declare_def_handler(option, function)				\
+static int								\
+def_ ## option ## _handler (vector strvec)				\
+{									\
+	return function (strvec, &conf->option);			\
+}
+
+#define declare_def_snprint(option, function)				\
+static int								\
+snprint_def_ ## option (char * buff, int len, void * data)		\
+{									\
+	return function (buff, len, &conf->option);			\
+}
+
+#define declare_def_snprint_defint(option, function, value)		\
+static int								\
+snprint_def_ ## option (char * buff, int len, void * data)		\
+{									\
+	int i = value;							\
+	if (!conf->option)						\
+		return function (buff, len, &i);			\
+	return function (buff, len, &conf->option);			\
+}
+
+#define declare_def_snprint_defstr(option, function, value)		\
+static int								\
+snprint_def_ ## option (char * buff, int len, void * data)		\
+{									\
+	char *s = value;						\
+	if (!conf->option)						\
+		return function (buff, len, &s);			\
+	return function (buff, len, &conf->option);			\
+}
+
+#define declare_hw_handler(option, function)				\
+static int								\
+hw_ ## option ## _handler (vector strvec)				\
+{									\
+	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);		\
+	if (!hwe)							\
+		return 1;						\
+	return function (strvec, &hwe->option);				\
+}
+
+#define declare_hw_snprint(option, function)				\
+static int								\
+snprint_hw_ ## option (char * buff, int len, void * data)		\
+{									\
+	struct hwentry * hwe = (struct hwentry *)data;			\
+	return function (buff, len, &hwe->option);			\
+}
+
+#define declare_mp_handler(option, function)				\
+static int								\
+mp_ ## option ## _handler (vector strvec)				\
+{									\
+	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);		\
+	if (!mpe)							\
+		return 1;						\
+	return function (strvec, &mpe->option);				\
+}
+
+#define declare_mp_snprint(option, function)				\
+static int								\
+snprint_mp_ ## option (char * buff, int len, void * data)		\
+{									\
+	struct mpentry * mpe = (struct mpentry *)data;			\
+	return function (buff, len, &mpe->option);			\
+}
+
+declare_def_handler(checkint, set_int)
+declare_def_snprint(checkint, print_int)
+
+declare_def_handler(max_checkint, set_int)
+declare_def_snprint(max_checkint, print_int)
+
+declare_def_handler(verbosity, set_int)
+declare_def_snprint(verbosity, print_int)
+
+declare_def_handler(reassign_maps, set_yes_no)
+declare_def_snprint(reassign_maps, print_yes_no)
+
+declare_def_handler(multipath_dir, set_str)
+declare_def_snprint(multipath_dir, print_str)
+
+declare_def_handler(selector, set_str)
+declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
+declare_hw_handler(selector, set_str)
+declare_hw_snprint(selector, print_str)
+declare_mp_handler(selector, set_str)
+declare_mp_snprint(selector, print_str)
+
+declare_def_handler(uid_attribute, set_str)
+declare_def_snprint_defstr(uid_attribute, print_str, DEFAULT_UID_ATTRIBUTE)
+declare_hw_handler(uid_attribute, set_str)
+declare_hw_snprint(uid_attribute, print_str)
+
+declare_def_handler(getuid, set_str)
+declare_def_snprint(getuid, print_str)
+declare_hw_handler(getuid, set_str)
+declare_hw_snprint(getuid, print_str)
+
+declare_def_handler(prio_name, set_str)
+declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
+declare_hw_handler(prio_name, set_str)
+declare_hw_snprint(prio_name, print_str)
+declare_mp_handler(prio_name, set_str)
+declare_mp_snprint(prio_name, print_str)
+
+declare_def_handler(alias_prefix, set_str)
+declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
+declare_hw_handler(alias_prefix, set_str)
+declare_hw_snprint(alias_prefix, print_str)
+
+declare_def_handler(prio_args, set_str)
+declare_def_snprint_defstr(prio_args, print_str, DEFAULT_PRIO_ARGS)
+declare_hw_handler(prio_args, set_str)
+declare_hw_snprint(prio_args, print_str)
+declare_mp_handler(prio_args, set_str)
+declare_mp_snprint(prio_args, print_str)
+
+declare_def_handler(features, set_str)
+declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
+declare_hw_handler(features, set_str)
+declare_hw_snprint(features, print_str)
+declare_mp_handler(features, set_str)
+declare_mp_snprint(features, print_str)
+
+declare_def_handler(checker_name, set_str)
+declare_def_snprint_defstr(checker_name, print_str, DEFAULT_CHECKER)
+declare_hw_handler(checker_name, set_str)
+declare_hw_snprint(checker_name, print_str)
+
+declare_def_handler(minio, set_int)
+declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
+declare_hw_handler(minio, set_int)
+declare_hw_snprint(minio, print_nonzero)
+declare_mp_handler(minio, set_int)
+declare_mp_snprint(minio, print_nonzero)
+
+declare_def_handler(minio_rq, set_int)
+declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
+declare_hw_handler(minio_rq, set_int)
+declare_hw_snprint(minio_rq, print_nonzero)
+declare_mp_handler(minio_rq, set_int)
+declare_mp_snprint(minio_rq, print_nonzero)
+
+declare_def_handler(queue_without_daemon, set_yes_no)
 static int
-multipath_dir_handler(vector strvec)
+snprint_def_queue_without_daemon (char * buff, int len, void * data)
 {
-	conf->multipath_dir = set_value(strvec);
+	switch (conf->queue_without_daemon) {
+	case QUE_NO_DAEMON_OFF:
+		return snprintf(buff, len, "\"no\"");
+	case QUE_NO_DAEMON_ON:
+		return snprintf(buff, len, "\"yes\"");
+	case QUE_NO_DAEMON_FORCE:
+		return snprintf(buff, len, "\"forced\"");
+	}
+	return 0;
+}
 
-	if (!conf->multipath_dir)
-		return 1;
+declare_def_handler(checker_timeout, set_int)
+declare_def_snprint(checker_timeout, print_nonzero)
 
-	return 0;
+declare_def_handler(flush_on_last_del, set_yes_no_undef)
+declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, YNU_NO)
+declare_hw_handler(flush_on_last_del, set_yes_no_undef)
+declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
+declare_mp_handler(flush_on_last_del, set_yes_no_undef)
+declare_mp_snprint(flush_on_last_del, print_yes_no_undef)
+
+declare_def_handler(user_friendly_names, set_yes_no_undef)
+declare_def_snprint_defint(user_friendly_names, print_yes_no_undef, YNU_NO)
+declare_hw_handler(user_friendly_names, set_yes_no_undef)
+declare_hw_snprint(user_friendly_names, print_yes_no_undef)
+declare_mp_handler(user_friendly_names, set_yes_no_undef)
+declare_mp_snprint(user_friendly_names, print_yes_no_undef)
+
+declare_def_handler(bindings_file, set_str)
+declare_def_snprint(bindings_file, print_str)
+
+declare_def_handler(wwids_file, set_str)
+declare_def_snprint(wwids_file, print_str)
+
+declare_def_handler(retain_hwhandler, set_yes_no_undef)
+declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, YNU_NO)
+declare_hw_handler(retain_hwhandler, set_yes_no_undef)
+declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
+
+declare_def_handler(detect_prio, set_yes_no_undef)
+declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
+declare_hw_handler(detect_prio, set_yes_no_undef)
+declare_hw_snprint(detect_prio, print_yes_no_undef)
+
+declare_def_handler(force_sync, set_yes_no)
+declare_def_snprint(force_sync, print_yes_no)
+
+#define declare_def_attr_handler(option, function)			\
+static int								\
+def_ ## option ## _handler (vector strvec)				\
+{									\
+	return function (strvec, &conf->option, &conf->attribute_flags);\
 }
 
-static int
-def_selector_handler(vector strvec)
-{
-	conf->selector = set_value(strvec);
+#define declare_def_attr_snprint(option, function)			\
+static int								\
+snprint_def_ ## option (char * buff, int len, void * data)		\
+{									\
+	return function (buff, len, &conf->option,			\
+			 &conf->attribute_flags);			\
+}
 
-	if (!conf->selector)
-		return 1;
+#define declare_mp_attr_handler(option, function)			\
+static int								\
+mp_ ## option ## _handler (vector strvec)				\
+{									\
+	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);		\
+	if (!mpe)							\
+		return 1;						\
+	return function (strvec, &mpe->option, &mpe->attribute_flags);	\
+}
 
-	return 0;
+#define declare_mp_attr_snprint(option, function)			\
+static int								\
+snprint_mp_ ## option (char * buff, int len, void * data)		\
+{									\
+	struct mpentry * mpe = (struct mpentry *)data;			\
+	return function (buff, len, &mpe->option,			\
+			 &mpe->attribute_flags);			\
 }
 
 static int
-def_pgpolicy_handler(vector strvec)
+set_mode(vector strvec, void *ptr, int *flags)
 {
-	char * buff;
+	mode_t mode;
+	mode_t *mode_ptr = (mode_t *)ptr;
+	char *buff;
 
 	buff = set_value(strvec);
 
 	if (!buff)
 		return 1;
 
-	conf->pgpolicy = get_pgpolicy_id(buff);
-	FREE(buff);
+	if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
+		*flags |= (1 << ATTR_MODE);
+		*mode_ptr = mode;
+	}
 
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_uid_attribute_handler(vector strvec)
+set_uid(vector strvec, void *ptr, int *flags)
 {
-	conf->uid_attribute = set_value(strvec);
+	uid_t uid;
+	uid_t *uid_ptr = (uid_t *)ptr;
+	char *buff;
+	char passwd_buf[1024];
+	struct passwd info, *found;
 
-	if (!conf->uid_attribute)
+	buff = set_value(strvec);
+	if (!buff)
 		return 1;
+	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
+		*flags |= (1 << ATTR_UID);
+		*uid_ptr = info.pw_uid;
+	}
+	else if (sscanf(buff, "%u", &uid) == 1){
+		*flags |= (1 << ATTR_UID);
+		*uid_ptr = uid;
+	}
 
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_getuid_callout_handler(vector strvec)
+set_gid(vector strvec, void *ptr, int *flags)
 {
-	conf->getuid = set_value(strvec);
+	gid_t gid;
+	gid_t *gid_ptr = (gid_t *)ptr;
+	char *buff;
+	char passwd_buf[1024];
+	struct passwd info, *found;
 
-	if (!conf->getuid)
+	buff = set_value(strvec);
+	if (!buff)
 		return 1;
 
+	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
+		*flags |= (1 << ATTR_GID);
+		*gid_ptr = info.pw_gid;
+	}
+	else if (sscanf(buff, "%u", &gid) == 1){
+		*flags |= (1 << ATTR_GID);
+		*gid_ptr = gid;
+	}
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_prio_handler(vector strvec)
+print_mode(char * buff, int len, void *ptr, int *flags)
 {
-	conf->prio_name = set_value(strvec);
+	mode_t *mode_ptr = (mode_t *)ptr;
+	if ((*flags & (1 << ATTR_MODE)) == 0)
+		return 0;
+	return snprintf(buff, len, "0%o", *mode_ptr);
+}
 
-	if (!conf->prio_name)
-		return 1;
+static int
+print_uid(char * buff, int len, void *ptr, int *flags)
+{
+	uid_t *uid_ptr = (uid_t *)ptr;
+	if ((*flags & (1 << ATTR_UID)) == 0)
+		return 0;
+	return snprintf(buff, len, "0%o", *uid_ptr);
+}
 
-	return 0;
+static int
+print_gid(char * buff, int len, void *ptr, int *flags)
+{
+	gid_t *gid_ptr = (gid_t *)ptr;
+	if ((*flags & (1 << ATTR_GID)) == 0)
+		return 0;
+	return snprintf(buff, len, "0%o", *gid_ptr);
 }
 
+declare_def_attr_handler(mode, set_mode)
+declare_def_attr_snprint(mode, print_mode)
+declare_mp_attr_handler(mode, set_mode)
+declare_mp_attr_snprint(mode, print_mode)
+
+declare_def_attr_handler(uid, set_uid)
+declare_def_attr_snprint(uid, print_uid)
+declare_mp_attr_handler(uid, set_uid)
+declare_mp_attr_snprint(uid, print_uid)
+
+declare_def_attr_handler(gid, set_gid)
+declare_def_attr_snprint(gid, print_gid)
+declare_mp_attr_handler(gid, set_gid)
+declare_mp_attr_snprint(gid, print_gid)
+
 static int
-def_alias_prefix_handler(vector strvec)
+set_fast_io_fail(vector strvec, void *ptr)
 {
-	conf->alias_prefix = set_value(strvec);
+	char * buff;
+	int *int_ptr = (int *)ptr;
 
-	if (!conf->alias_prefix)
+	buff = set_value(strvec);
+	if (!buff)
 		return 1;
 
+	if (strcmp(buff, "off") == 0)
+		*int_ptr = MP_FAST_IO_FAIL_OFF;
+	else if (sscanf(buff, "%d", int_ptr) != 1 ||
+		 *int_ptr < MP_FAST_IO_FAIL_ZERO)
+		*int_ptr = MP_FAST_IO_FAIL_UNSET;
+	else if (*int_ptr == 0)
+		*int_ptr = MP_FAST_IO_FAIL_ZERO;
+
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_prio_args_handler(vector strvec)
+print_fast_io_fail(char * buff, int len, void *ptr)
 {
-	conf->prio_args = set_value(strvec);
+	int *int_ptr = (int *)ptr;
 
-	if (!conf->prio_args)
-		return 1;
-
-	return 0;
+	if (*int_ptr == MP_FAST_IO_FAIL_UNSET)
+		return 0;
+	if (*int_ptr == MP_FAST_IO_FAIL_OFF)
+		return snprintf(buff, len, "\"off\"");
+	if (*int_ptr == MP_FAST_IO_FAIL_ZERO)
+		return snprintf(buff, len, "0");
+	return snprintf(buff, len, "%d", *int_ptr);
 }
 
+declare_def_handler(fast_io_fail, set_fast_io_fail)
+declare_def_snprint(fast_io_fail, print_fast_io_fail)
+declare_hw_handler(fast_io_fail, set_fast_io_fail)
+declare_hw_snprint(fast_io_fail, print_fast_io_fail)
+
 static int
-def_features_handler(vector strvec)
+set_dev_loss(vector strvec, void *ptr)
 {
-	conf->features = set_value(strvec);
+	char * buff;
+	unsigned int *uint_ptr = (unsigned int *)ptr;
 
-	if (!conf->features)
+	buff = set_value(strvec);
+	if (!buff)
 		return 1;
 
+	if (!strcmp(buff, "infinity"))
+		*uint_ptr = MAX_DEV_LOSS_TMO;
+	else if (sscanf(buff, "%u", uint_ptr) != 1)
+		*uint_ptr = 0;
+
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_path_checker_handler(vector strvec)
+print_dev_loss(char * buff, int len, void *ptr)
 {
-	conf->checker_name = set_value(strvec);
+	unsigned int *uint_ptr = (unsigned int *)ptr;
 
-	if (!conf->checker_name)
-		return 1;
-
-	return 0;
+	if (!*uint_ptr)
+		return 0;
+	if (*uint_ptr >= MAX_DEV_LOSS_TMO)
+		return snprintf(buff, len, "\"infinity\"");
+	return snprintf(buff, len, "%u", *uint_ptr);
 }
 
+declare_def_handler(dev_loss, set_dev_loss)
+declare_def_snprint(dev_loss, print_dev_loss)
+declare_hw_handler(dev_loss, set_dev_loss)
+declare_hw_snprint(dev_loss, print_dev_loss)
+
 static int
-def_minio_handler(vector strvec)
+set_pgpolicy(vector strvec, void *ptr)
 {
 	char * buff;
+	int *int_ptr = (int *)ptr;
 
 	buff = set_value(strvec);
-
 	if (!buff)
 		return 1;
 
-	conf->minio = atoi(buff);
+	*int_ptr = get_pgpolicy_id(buff);
 	FREE(buff);
 
 	return 0;
 }
 
 static int
-def_minio_rq_handler(vector strvec)
+print_pgpolicy(char * buff, int len, void *ptr)
 {
-	char * buff;
-
-	buff = set_value(strvec);
+	char str[POLICY_NAME_SIZE];
+	int pgpolicy = *(int *)ptr;
 
-	if (!buff)
-		return 1;
+	if (!pgpolicy)
+		return 0;
 
-	conf->minio_rq = atoi(buff);
-	FREE(buff);
+	get_pgpolicy_name(str, POLICY_NAME_SIZE, pgpolicy);
 
-	return 0;
+	return snprintf(buff, len, "\"%s\"", str);
 }
 
+declare_def_handler(pgpolicy, set_pgpolicy)
+declare_def_snprint_defint(pgpolicy, print_pgpolicy, DEFAULT_PGPOLICY)
+declare_hw_handler(pgpolicy, set_pgpolicy)
+declare_hw_snprint(pgpolicy, print_pgpolicy)
+declare_mp_handler(pgpolicy, set_pgpolicy)
+declare_mp_snprint(pgpolicy, print_pgpolicy)
+
 int
 get_sys_max_fds(int *max_fds)
 {
@@ -320,111 +647,80 @@ max_fds_handler(vector strvec)
 }
 
 static int
-def_mode_handler(vector strvec)
+snprint_max_fds (char * buff, int len, void * data)
 {
-	mode_t mode;
-	char *buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
+	int r = 0, max_fds;
 
-	if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
-		conf->attribute_flags |= (1 << ATTR_MODE);
-		conf->mode = mode;
-	}
+	if (!conf->max_fds)
+		return 0;
 
-	FREE(buff);
-	return 0;
+	r = get_sys_max_fds(&max_fds);
+	if (!r && conf->max_fds >= max_fds)
+		return snprintf(buff, len, "\"max\"");
+	else
+		return snprintf(buff, len, "%d", conf->max_fds);
 }
 
 static int
-def_uid_handler(vector strvec)
+set_rr_weight(vector strvec, void *ptr)
 {
-	uid_t uid;
-	char *buff;
-	char passwd_buf[1024];
-	struct passwd info, *found;
+	int *int_ptr = (int *)ptr;
+	char * buff;
 
 	buff = set_value(strvec);
+
 	if (!buff)
 		return 1;
-	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-		conf->attribute_flags |= (1 << ATTR_UID);
-		conf->uid = info.pw_uid;
-	}
-	else if (sscanf(buff, "%u", &uid) == 1){
-		conf->attribute_flags |= (1 << ATTR_UID);
-		conf->uid = uid;
-	}
-
-	FREE(buff);
-	return 0;
-}
 
-static int
-def_gid_handler(vector strvec)
-{
-	gid_t gid;
-	char *buff;
-	char passwd_buf[1024];
-	struct passwd info, *found;
+	if (!strcmp(buff, "priorities"))
+		*int_ptr = RR_WEIGHT_PRIO;
 
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
+	if (!strcmp(buff, "uniform"))
+		*int_ptr = RR_WEIGHT_NONE;
 
-	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-		conf->attribute_flags |= (1 << ATTR_GID);
-		conf->gid = info.pw_gid;
-	}
-	else if (sscanf(buff, "%u", &gid) == 1){
-		conf->attribute_flags |= (1 << ATTR_GID);
-		conf->gid = gid;
-	}
 	FREE(buff);
+
 	return 0;
 }
 
 static int
-def_weight_handler(vector strvec)
+print_rr_weight (char * buff, int len, void *ptr)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if (strlen(buff) == 10 &&
-	    !strcmp(buff, "priorities"))
-		conf->rr_weight = RR_WEIGHT_PRIO;
-
-	if (strlen(buff) == strlen("uniform") &&
-	    !strcmp(buff, "uniform"))
-		conf->rr_weight = RR_WEIGHT_NONE;
+	int *int_ptr = (int *)ptr;
 
-	FREE(buff);
+	if (!*int_ptr)
+		return 0;
+	if (*int_ptr == RR_WEIGHT_PRIO)
+		return snprintf(buff, len, "\"priorities\"");
+	if (*int_ptr == RR_WEIGHT_NONE)
+		return snprintf(buff, len, "\"uniform\"");
 
 	return 0;
 }
 
+declare_def_handler(rr_weight, set_rr_weight)
+declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
+declare_hw_handler(rr_weight, set_rr_weight)
+declare_hw_snprint(rr_weight, print_rr_weight)
+declare_mp_handler(rr_weight, set_rr_weight)
+declare_mp_snprint(rr_weight, print_rr_weight)
+
 static int
-default_failback_handler(vector strvec)
+set_pgfailback(vector strvec, void *ptr)
 {
+	int *int_ptr = (int *)ptr;
 	char * buff;
 
 	buff = set_value(strvec);
 
 	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-		conf->pgfailback = -FAILBACK_MANUAL;
+		*int_ptr = -FAILBACK_MANUAL;
 	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-		conf->pgfailback = -FAILBACK_IMMEDIATE;
+		*int_ptr = -FAILBACK_IMMEDIATE;
 	else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-		conf->pgfailback = -FAILBACK_FOLLOWOVER;
+		*int_ptr = -FAILBACK_FOLLOWOVER;
 	else
-		conf->pgfailback = atoi(buff);
+		*int_ptr = atoi(buff);
 
 	FREE(buff);
 
@@ -432,66 +728,78 @@ default_failback_handler(vector strvec)
 }
 
 static int
-def_no_path_retry_handler(vector strvec)
+print_pgfailback (char * buff, int len, void *ptr)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
+	int *int_ptr = (int *)ptr;
 
-	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		conf->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-		conf->no_path_retry = NO_PATH_RETRY_QUEUE;
-	else if ((conf->no_path_retry = atoi(buff)) < 1)
-		conf->no_path_retry = NO_PATH_RETRY_UNDEF;
-
-	FREE(buff);
-	return 0;
+	switch(*int_ptr) {
+	case  FAILBACK_UNDEF:
+		return 0;
+	case -FAILBACK_MANUAL:
+		return snprintf(buff, len, "\"manual\"");
+	case -FAILBACK_IMMEDIATE:
+		return snprintf(buff, len, "\"immediate\"");
+	case -FAILBACK_FOLLOWOVER:
+		return snprintf(buff, len, "\"followover\"");
+	default:
+		return snprintf(buff, len, "%i", *int_ptr);
+	}
 }
 
+declare_def_handler(pgfailback, set_pgfailback)
+declare_def_snprint_defint(pgfailback, print_pgfailback, DEFAULT_FAILBACK)
+declare_hw_handler(pgfailback, set_pgfailback)
+declare_hw_snprint(pgfailback, print_pgfailback)
+declare_mp_handler(pgfailback, set_pgfailback)
+declare_mp_snprint(pgfailback, print_pgfailback)
+
 static int
-def_queue_without_daemon(vector strvec)
+set_no_path_retry(vector strvec, void *ptr)
 {
+	int *int_ptr = (int *)ptr;
 	char * buff;
 
 	buff = set_value(strvec);
 	if (!buff)
 		return 1;
 
-	if (!strncmp(buff, "on", 2) || !strncmp(buff, "yes", 3) ||
-		 !strncmp(buff, "1", 1))
-		conf->queue_without_daemon = QUE_NO_DAEMON_ON;
-	else
-		conf->queue_without_daemon = QUE_NO_DAEMON_OFF;
+	if (!strcmp(buff, "fail") || !strcmp(buff, "0"))
+		*int_ptr = NO_PATH_RETRY_FAIL;
+	else if (!strcmp(buff, "queue"))
+		*int_ptr = NO_PATH_RETRY_QUEUE;
+	else if ((*int_ptr = atoi(buff)) < 1)
+		*int_ptr = NO_PATH_RETRY_UNDEF;
 
-	free(buff);
+	FREE(buff);
 	return 0;
 }
 
 static int
-def_checker_timeout_handler(vector strvec)
+print_no_path_retry(char * buff, int len, void *ptr)
 {
-	unsigned int checker_timeout;
-	char *buff;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
+	int *int_ptr = (int *)ptr;
 
-	if (sscanf(buff, "%u", &checker_timeout) == 1)
-		conf->checker_timeout = checker_timeout;
-	else
-		conf->checker_timeout = 0;
-
-	free(buff);
-	return 0;
+	switch(*int_ptr) {
+	case NO_PATH_RETRY_UNDEF:
+		return 0;
+	case NO_PATH_RETRY_FAIL:
+		return snprintf(buff, len, "\"fail\"");
+	case NO_PATH_RETRY_QUEUE:
+		return snprintf(buff, len, "\"queue\"");
+	default:
+		return snprintf(buff, len, "%i", *int_ptr);
+	}
 }
 
+declare_def_handler(no_path_retry, set_no_path_retry)
+declare_def_snprint(no_path_retry, print_no_path_retry)
+declare_hw_handler(no_path_retry, set_no_path_retry)
+declare_hw_snprint(no_path_retry, print_no_path_retry)
+declare_mp_handler(no_path_retry, set_no_path_retry)
+declare_mp_snprint(no_path_retry, print_no_path_retry)
+
 static int
-def_pg_timeout_handler(vector strvec)
+def_log_checker_err_handler(vector strvec)
 {
 	char * buff;
 
@@ -500,56 +808,27 @@ def_pg_timeout_handler(vector strvec)
 	if (!buff)
 		return 1;
 
-	/* Deprecated; device-mapper support has been removed */
+	if (strlen(buff) == 4 && !strcmp(buff, "once"))
+		conf->log_checker_err = LOG_CHKR_ERR_ONCE;
+	else if (strlen(buff) == 6 && !strcmp(buff, "always"))
+		conf->log_checker_err = LOG_CHKR_ERR_ALWAYS;
 
-	FREE(buff);
+	free(buff);
 	return 0;
 }
 
 static int
-def_flush_on_last_del_handler(vector strvec)
+snprint_def_log_checker_err (char * buff, int len, void * data)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-		conf->flush_on_last_del = FLUSH_DISABLED;
-	else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-		conf->flush_on_last_del = FLUSH_ENABLED;
-	else
-		conf->flush_on_last_del = FLUSH_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-def_log_checker_err_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if (strlen(buff) == 4 && !strcmp(buff, "once"))
-		conf->log_checker_err = LOG_CHKR_ERR_ONCE;
-	else if (strlen(buff) == 6 && !strcmp(buff, "always"))
-		conf->log_checker_err = LOG_CHKR_ERR_ALWAYS;
-
-	free(buff);
-	return 0;
+	if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
+		return snprintf(buff, len, "once");
+	return snprintf(buff, len, "always");
 }
 
 static int
-def_reservation_key_handler(vector strvec)
+set_reservation_key(vector strvec, void *ptr)
 {
+	unsigned char **uchar_ptr = (unsigned char **)ptr;
 	char *buff;
 	char *tbuff;
 	int j, k;
@@ -580,13 +859,13 @@ def_reservation_key_handler(vector strvec)
 		return 1;
 	}
 
-	if (!conf->reservation_key)
-		conf->reservation_key = (unsigned char *) malloc(8);
+	if (!*uchar_ptr)
+		*uchar_ptr = (unsigned char *) malloc(8);
 
-	memset(conf->reservation_key, 0, 8);
+	memset(*uchar_ptr, 0, 8);
 
 	for (j = 7; j >= 0; --j) {
-		conf->reservation_key[j] = (prkey & 0xff);
+		(*uchar_ptr)[j] = (prkey & 0xff);
 		prkey >>= 8;
 	}
 
@@ -595,118 +874,29 @@ def_reservation_key_handler(vector strvec)
 }
 
 static int
-def_names_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		conf->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		conf->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-	else
-		conf->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-bindings_file_handler(vector strvec)
-{
-	conf->bindings_file = set_value(strvec);
-
-	if (!conf->bindings_file)
-		return 1;
-
-	return 0;
-}
-
-static int
-wwids_file_handler(vector strvec)
-{
-	conf->wwids_file = set_value(strvec);
-
-	if (!conf->wwids_file)
-		return 1;
-
-	return 0;
-}
-
-static int
-def_retain_hwhandler_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		conf->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		conf->retain_hwhandler = RETAIN_HWHANDLER_ON;
-	else
-		conf->retain_hwhandler = RETAIN_HWHANDLER_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-def_detect_prio_handler(vector strvec)
+print_reservation_key(char * buff, int len, void * ptr)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		conf->detect_prio = DETECT_PRIO_OFF;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		conf->detect_prio = DETECT_PRIO_ON;
-	else
-		conf->detect_prio = DETECT_PRIO_UNDEF;
+	unsigned char **uchar_ptr = (unsigned char **)ptr;
+	int i;
+	unsigned char *keyp;
+	uint64_t prkey = 0;
 
-	FREE(buff);
-	return 0;
+	if (!*uchar_ptr)
+		return 0;
+	keyp = (unsigned char *)(*uchar_ptr);
+	for (i = 0; i < 8; i++) {
+		if (i > 0)
+			prkey <<= 8;
+		prkey |= *keyp;
+		keyp++;
+	}
+	return snprintf(buff, len, "0x%" PRIx64, prkey);
 }
 
-static int
-def_force_sync_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		conf->force_sync = 0;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		conf->force_sync = 1;
-	else
-		conf->force_sync = 0;
-
-	FREE(buff);
-	return 0;
-}
+declare_def_handler(reservation_key, set_reservation_key)
+declare_def_snprint(reservation_key, print_reservation_key)
+declare_mp_handler(reservation_key, set_reservation_key)
+declare_mp_snprint(reservation_key, print_reservation_key)
 
 /*
  * blacklist block handlers
@@ -741,82 +931,51 @@ blacklist_exceptions_handler(vector strvec)
 	return 0;
 }
 
-static int
-ble_devnode_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return store_ble(conf->blist_devnode, buff, ORIGIN_CONFIG);
-}
-
-static int
-ble_except_devnode_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return store_ble(conf->elist_devnode, buff, ORIGIN_CONFIG);
-}
-
-static int
-ble_wwid_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return store_ble(conf->blist_wwid, buff, ORIGIN_CONFIG);
+#define declare_ble_handler(option)					\
+static int								\
+ble_ ## option ## _handler (vector strvec)				\
+{									\
+	char * buff;							\
+									\
+	if (!conf->option)						\
+		return 1;						\
+									\
+	buff = set_value(strvec);					\
+	if (!buff)							\
+		return 1;						\
+									\
+	return store_ble(conf->option, buff, ORIGIN_CONFIG);		\
 }
 
-static int
-ble_except_wwid_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return store_ble(conf->elist_wwid, buff, ORIGIN_CONFIG);
+#define declare_ble_device_handler(name, option, vend, prod)		\
+static int								\
+ble_ ## option ## _ ## name ## _handler (vector strvec)			\
+{									\
+	char * buff;							\
+									\
+	if (!conf->option)						\
+		return 1;						\
+									\
+	buff = set_value(strvec);					\
+	if (!buff)							\
+		return 1;						\
+									\
+	return set_ble_device(conf->option, vend, prod, ORIGIN_CONFIG);	\
 }
 
-static int
-ble_property_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return store_ble(conf->blist_property, buff, ORIGIN_CONFIG);
-}
+declare_ble_handler(blist_devnode)
+declare_ble_handler(elist_devnode)
+declare_ble_handler(blist_wwid)
+declare_ble_handler(elist_wwid)
+declare_ble_handler(blist_property)
+declare_ble_handler(elist_property)
 
 static int
-ble_except_property_handler(vector strvec)
+snprint_ble_simple (char * buff, int len, void * data)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
+	struct blentry * ble = (struct blentry *)data;
 
-	return store_ble(conf->elist_property, buff, ORIGIN_CONFIG);
+	return snprintf(buff, len, "\"%s\"", ble->str);
 }
 
 static int
@@ -831,56 +990,25 @@ ble_except_device_handler(vector strvec)
 	return alloc_ble_device(conf->elist_device);
 }
 
-static int
-ble_vendor_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return set_ble_device(conf->blist_device, buff, NULL, ORIGIN_CONFIG);
-}
-
-static int
-ble_except_vendor_handler(vector strvec)
-{
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	return set_ble_device(conf->elist_device, buff, NULL, ORIGIN_CONFIG);
-}
+declare_ble_device_handler(vendor, blist_device, buff, NULL)
+declare_ble_device_handler(vendor, elist_device, buff, NULL)
+declare_ble_device_handler(product, blist_device, NULL, buff)
+declare_ble_device_handler(product, elist_device, NULL, buff)
 
 static int
-ble_product_handler(vector strvec)
+snprint_bled_vendor (char * buff, int len, void * data)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
+	struct blentry_device * bled = (struct blentry_device *)data;
 
-	return set_ble_device(conf->blist_device, NULL, buff, ORIGIN_CONFIG);
+	return snprintf(buff, len, "\"%s\"", bled->vendor);
 }
 
 static int
-ble_except_product_handler(vector strvec)
+snprint_bled_product (char * buff, int len, void * data)
 {
-	char * buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
+	struct blentry_device * bled = (struct blentry_device *)data;
 
-	return set_ble_device(conf->elist_device, NULL, buff, ORIGIN_CONFIG);
+	return snprintf(buff, len, "\"%s\"", bled->product);
 }
 
 /*
@@ -917,1995 +1045,152 @@ device_handler(vector strvec)
 	return 0;
 }
 
-static int
-vendor_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+declare_hw_handler(vendor, set_str)
+declare_hw_snprint(vendor, print_str)
 
-	if (!hwe)
-		return 1;
+declare_hw_handler(product, set_str)
+declare_hw_snprint(product, print_str)
 
-	hwe->vendor = set_value(strvec);
+declare_hw_handler(revision, set_str)
+declare_hw_snprint(revision, print_str)
 
-	if (!hwe->vendor)
-		return 1;
+declare_hw_handler(bl_product, set_str)
+declare_hw_snprint(bl_product, print_str)
 
-	return 0;
-}
+declare_hw_handler(hwhandler, set_str)
+declare_hw_snprint(hwhandler, print_str)
 
+/*
+ * multipaths block handlers
+ */
 static int
-product_handler(vector strvec)
+multipaths_handler(vector strvec)
 {
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->product = set_value(strvec);
+	conf->mptable = vector_alloc();
 
-	if (!hwe->product)
+	if (!conf->mptable)
 		return 1;
 
 	return 0;
 }
 
 static int
-revision_handler(vector strvec)
+multipath_handler(vector strvec)
 {
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->revision = set_value(strvec);
-
-	if (!hwe->revision)
-		return 1;
-
-	return 0;
-}
+	struct mpentry * mpe;
 
-static int
-bl_product_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+	mpe = alloc_mpe();
 
-	if (!hwe)
+	if (!mpe)
 		return 1;
 
-	hwe->bl_product = set_value(strvec);
-	if (!hwe->bl_product)
+	if (!vector_alloc_slot(conf->mptable)) {
+		free_mpe(mpe);
 		return 1;
+	}
+	vector_set_slot(conf->mptable, mpe);
 
 	return 0;
 }
 
-static int
-hw_fast_io_fail_handler(vector strvec)
-{
-	char * buff;
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+declare_mp_handler(wwid, set_str)
+declare_mp_snprint(wwid, print_str)
 
-	buff = set_value(strvec);
-	if (strlen(buff) == 3 && !strcmp(buff, "off"))
-		hwe->fast_io_fail = MP_FAST_IO_FAIL_OFF;
-	else if (sscanf(buff, "%d", &hwe->fast_io_fail) != 1 ||
-		 hwe->fast_io_fail < MP_FAST_IO_FAIL_ZERO)
-		hwe->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
-	else if (hwe->fast_io_fail == 0)
-		hwe->fast_io_fail = MP_FAST_IO_FAIL_ZERO;
+declare_mp_handler(alias, set_str)
+declare_mp_snprint(alias, print_str)
 
-	FREE(buff);
-	return 0;
-}
+/*
+ * deprecated handlers
+ */
 
 static int
-hw_dev_loss_handler(vector strvec)
+deprecated_handler(vector strvec)
 {
 	char * buff;
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
 
 	buff = set_value(strvec);
+
 	if (!buff)
 		return 1;
 
-	if (strlen(buff) == 8 && !strcmp(buff, "infinity"))
-		hwe->dev_loss = MAX_DEV_LOSS_TMO;
-	else if (sscanf(buff, "%u", &hwe->dev_loss) != 1)
-		hwe->dev_loss = 0;
-
 	FREE(buff);
 	return 0;
 }
 
 static int
-hw_pgpolicy_handler(vector strvec)
+snprint_deprecated (char * buff, int len, void * data)
 {
-	char * buff;
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	hwe->pgpolicy = get_pgpolicy_id(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-hw_uid_attribute_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	hwe->uid_attribute = set_value(strvec);
-
-	if (!hwe->uid_attribute)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_getuid_callout_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	hwe->getuid = set_value(strvec);
-
-	if (!hwe->getuid)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_selector_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->selector = set_value(strvec);
-
-	if (!hwe->selector)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_path_checker_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->checker_name = set_value(strvec);
-
-	if (!hwe->checker_name)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_features_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->features = set_value(strvec);
-
-	if (!hwe->features)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_handler_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->hwhandler = set_value(strvec);
-
-	if (!hwe->hwhandler)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_prio_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->prio_name = set_value(strvec);
-
-	if (!hwe->prio_name)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_alias_prefix_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->alias_prefix = set_value(strvec);
-
-	if (!hwe->alias_prefix)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_prio_args_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-
-	if (!hwe)
-		return 1;
-
-	hwe->prio_args = set_value(strvec);
-
-	if (!hwe->prio_args)
-		return 1;
-
-	return 0;
-}
-
-static int
-hw_failback_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-		hwe->pgfailback = -FAILBACK_MANUAL;
-	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-		hwe->pgfailback = -FAILBACK_IMMEDIATE;
-	else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-		hwe->pgfailback = -FAILBACK_FOLLOWOVER;
-	else
-		hwe->pgfailback = atoi(buff);
-
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-hw_weight_handler(vector strvec)
-{
-	struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if (strlen(buff) == 10 &&
-	    !strcmp(buff, "priorities"))
-		hwe->rr_weight = RR_WEIGHT_PRIO;
-
-	if (strlen(buff) == strlen("uniform") &&
-	    !strcmp(buff, "uniform"))
-		hwe->rr_weight = RR_WEIGHT_NONE;
-
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-hw_no_path_retry_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char *buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		hwe->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-		hwe->no_path_retry = NO_PATH_RETRY_QUEUE;
-	else if ((hwe->no_path_retry = atoi(buff)) < 1)
-		hwe->no_path_retry = NO_PATH_RETRY_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-hw_minio_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	hwe->minio = atoi(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-hw_minio_rq_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	hwe->minio_rq = atoi(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-hw_pg_timeout_handler(vector strvec)
-{
-	char *buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	/* Deprecated; device-mapper support has been removed */
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-hw_flush_on_last_del_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-		hwe->flush_on_last_del = FLUSH_DISABLED;
-	else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-		hwe->flush_on_last_del = FLUSH_ENABLED;
-	else
-		hwe->flush_on_last_del = FLUSH_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-hw_names_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-		hwe->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-	else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-		 (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-		hwe->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-	else
-		hwe->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-hw_retain_hwhandler_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		hwe->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		hwe->retain_hwhandler = RETAIN_HWHANDLER_ON;
-	else
-		hwe->user_friendly_names = RETAIN_HWHANDLER_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-hw_detect_prio_handler(vector strvec)
-{
-	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
-	char * buff;
-
-	if (!hwe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		hwe->detect_prio = DETECT_PRIO_OFF;
-	else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) ||
-		 (strlen(buff) == 1 && !strcmp(buff, "1")))
-		hwe->detect_prio = DETECT_PRIO_ON;
-	else
-		hwe->detect_prio = DETECT_PRIO_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-/*
- * multipaths block handlers
- */
-static int
-multipaths_handler(vector strvec)
-{
-	conf->mptable = vector_alloc();
-
-	if (!conf->mptable)
-		return 1;
-
-	return 0;
-}
-
-static int
-multipath_handler(vector strvec)
-{
-	struct mpentry * mpe;
-
-	mpe = alloc_mpe();
-
-	if (!mpe)
-		return 1;
-
-	if (!vector_alloc_slot(conf->mptable)) {
-		free_mpe(mpe);
-		return 1;
-	}
-	vector_set_slot(conf->mptable, mpe);
-
-	return 0;
-}
-
-static int
-wwid_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->wwid = set_value(strvec);
-
-	if (!mpe->wwid)
-		return 1;
-
-	return 0;
-}
-
-static int
-alias_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->alias = set_value(strvec);
-
-	if (!mpe->alias)
-		return 1;
-
-	return 0;
-}
-
-static int
-mp_pgpolicy_handler(vector strvec)
-{
-	char * buff;
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	mpe->pgpolicy = get_pgpolicy_id(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-mp_selector_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->selector = set_value(strvec);
-
-	if (!mpe->selector)
-		return 1;
-
-	return 0;
-}
-
-static int
-mp_failback_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (strlen(buff) == 6 && !strcmp(buff, "manual"))
-		mpe->pgfailback = -FAILBACK_MANUAL;
-	else if (strlen(buff) == 9 && !strcmp(buff, "immediate"))
-		mpe->pgfailback = -FAILBACK_IMMEDIATE;
-	else if (strlen(buff) == 10 && !strcmp(buff, "followover"))
-		mpe->pgfailback = -FAILBACK_FOLLOWOVER;
-	else
-		mpe->pgfailback = atoi(buff);
-
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-mp_mode_handler(vector strvec)
-{
-	mode_t mode;
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char *buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-	if (sscanf(buff, "%o", &mode) == 1 && mode <= 0777) {
-		mpe->attribute_flags |= (1 << ATTR_MODE);
-		mpe->mode = mode;
-	}
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_uid_handler(vector strvec)
-{
-	uid_t uid;
-	char *buff;
-	char passwd_buf[1024];
-	struct passwd info, *found;
-
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-		mpe->attribute_flags |= (1 << ATTR_UID);
-		mpe->uid = info.pw_uid;
-	}
-	else if (sscanf(buff, "%u", &uid) == 1){
-		mpe->attribute_flags |= (1 << ATTR_UID);
-		mpe->uid = uid;
-	}
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_gid_handler(vector strvec)
-{
-	gid_t gid;
-	char *buff;
-	char passwd_buf[1024];
-	struct passwd info, *found;
-
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if (getpwnam_r(buff, &info, passwd_buf, 1024, &found) == 0 && found) {
-		mpe->attribute_flags |= (1 << ATTR_GID);
-		mpe->gid = info.pw_gid;
-	}
-	else if (sscanf(buff, "%u", &gid) == 1) {
-		mpe->attribute_flags |= (1 << ATTR_GID);
-		mpe->gid = gid;
-	}
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_weight_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	if (strlen(buff) == 10 &&
-	    !strcmp(buff, "priorities"))
-		mpe->rr_weight = RR_WEIGHT_PRIO;
-
-	if (strlen(buff) == strlen("uniform") &&
-	    !strcmp(buff, "uniform"))
-		mpe->rr_weight = RR_WEIGHT_NONE;
-
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-mp_no_path_retry_handler(vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char *buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 4 && !strcmp(buff, "fail")) ||
-	    (strlen(buff) == 1 && !strcmp(buff, "0")))
-		mpe->no_path_retry = NO_PATH_RETRY_FAIL;
-	else if (strlen(buff) == 5 && !strcmp(buff, "queue"))
-		mpe->no_path_retry = NO_PATH_RETRY_QUEUE;
-	else if ((mpe->no_path_retry = atoi(buff)) < 1)
-		mpe->no_path_retry = NO_PATH_RETRY_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_minio_handler(vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	mpe->minio = atoi(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-mp_minio_rq_handler(vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	mpe->minio_rq = atoi(buff);
-	FREE(buff);
-
-	return 0;
-}
-
-static int
-mp_pg_timeout_handler(vector strvec)
-{
-	char *buff;
-
-	buff = set_value(strvec);
-
-	if (!buff)
-		return 1;
-
-	/* Deprecated; device-mapper support has been removed */
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_features_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->features = set_value(strvec);
-
-	if (!mpe->features)
-		return 1;
-
-	return 0;
-}
-
-static int
-mp_flush_on_last_del_handler(vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-		mpe->flush_on_last_del = FLUSH_DISABLED;
-	else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-		mpe->flush_on_last_del = FLUSH_ENABLED;
-	else
-		mpe->flush_on_last_del = FLUSH_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-static int
-mp_prio_handler(vector strvec)
-{
-	struct mpentry * mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->prio_name = set_value(strvec);
-
-	if (!mpe->prio_name)
-		return 1;
-
-	return 0;
-}
-
-static int
-mp_prio_args_handler (vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	if (!mpe)
-		return 1;
-
-	mpe->prio_args = set_value(strvec);
-	if (!mpe->prio_args)
-		return 1;
-
-	return 0;
-}
-
-static int
-mp_reservation_key_handler (vector strvec)
-{
-	char *buff;
-	char *tbuff;
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-
-	int j, k, len;
-	uint64_t prkey;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	tbuff = buff;
-	if (!memcmp(buff, "0x", 2))
-		buff = buff + 2;
-
-	len = strlen(buff);
-
-	k = strspn(buff, "0123456789aAbBcCdDeEfF");
-	if (len != k) {
-		FREE(tbuff);
-		return 1;
-	}
-
-	if (1 != sscanf (buff, "%" SCNx64 "", &prkey))
-	{
-		FREE(tbuff);
-		return 1;
-	}
-
-	if (!mpe->reservation_key)
-		mpe->reservation_key = (unsigned char *) malloc(8);
-
-	memset(mpe->reservation_key, 0, 8);
-
-	for (j = 7; j >= 0; --j) {
-		mpe->reservation_key[j] = (prkey & 0xff);
-		prkey >>= 8;
-	}
-
-	FREE(tbuff);
-	return 0;
-}
-
-static int
-mp_names_handler(vector strvec)
-{
-	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
-	char * buff;
-
-	if (!mpe)
-		return 1;
-
-	buff = set_value(strvec);
-	if (!buff)
-		return 1;
-
-	if ((strlen(buff) == 2 && strcmp(buff, "no") == 0) ||
-	    (strlen(buff) == 1 && strcmp(buff, "0") == 0))
-		mpe->user_friendly_names = USER_FRIENDLY_NAMES_OFF;
-	else if ((strlen(buff) == 3 && strcmp(buff, "yes") == 0) ||
-		 (strlen(buff) == 1 && strcmp(buff, "1") == 0))
-		mpe->user_friendly_names = USER_FRIENDLY_NAMES_ON;
-	else
-		mpe->user_friendly_names = USER_FRIENDLY_NAMES_UNDEF;
-
-	FREE(buff);
-	return 0;
-}
-
-/*
- * config file keywords printing
- */
-static int
-snprint_mp_wwid (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	return snprintf(buff, len, "%s", mpe->wwid);
-}
-
-static int
-snprint_mp_alias (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->alias)
-		return 0;
-
-	return snprintf(buff, len, "%s", mpe->alias);
-}
-
-static int
-snprint_mp_path_grouping_policy (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-	char str[POLICY_NAME_SIZE];
-
-	if (!mpe->pgpolicy)
-		return 0;
-	get_pgpolicy_name(str, POLICY_NAME_SIZE, mpe->pgpolicy);
-
-	return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_mp_selector (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->selector)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", mpe->selector);
-}
-
-static int
-snprint_mp_failback (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (mpe->pgfailback == FAILBACK_UNDEF ||
-	    mpe->pgfailback == DEFAULT_FAILBACK)
-		return 0;
-
-	switch(mpe->pgfailback) {
-	case -FAILBACK_MANUAL:
-		return snprintf(buff, len, "\"manual\"");
-	case -FAILBACK_IMMEDIATE:
-		return snprintf(buff, len, "\"immediate\"");
-	case -FAILBACK_FOLLOWOVER:
-		return snprintf(buff, len, "\"followover\"");
-	default:
-		return snprintf(buff, len, "%i", mpe->pgfailback);
-	}
-	return 0;
-}
-
-static int
-snprint_mp_mode(char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if ((mpe->attribute_flags & (1 << ATTR_MODE)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", mpe->mode);
-}
-
-static int
-snprint_mp_uid(char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if ((mpe->attribute_flags & (1 << ATTR_UID)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", mpe->uid);
-}
-
-static int
-snprint_mp_gid(char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if ((mpe->attribute_flags & (1 << ATTR_GID)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", mpe->gid);
-}
-
-static int
-snprint_mp_rr_weight (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->rr_weight)
-		return 0;
-	if (mpe->rr_weight == RR_WEIGHT_PRIO)
-		return snprintf(buff, len, "\"priorities\"");
-	if (mpe->rr_weight == RR_WEIGHT_NONE)
-		return snprintf(buff, len, "\"uniform\"");
-
-	return 0;
-}
-
-static int
-snprint_mp_no_path_retry (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->no_path_retry)
-		return 0;
-
-	switch(mpe->no_path_retry) {
-	case NO_PATH_RETRY_UNDEF:
-		break;
-	case NO_PATH_RETRY_FAIL:
-		return snprintf(buff, len, "\"fail\"");
-	case NO_PATH_RETRY_QUEUE:
-		return snprintf(buff, len, "\"queue\"");
-	default:
-		return snprintf(buff, len, "%i",
-				mpe->no_path_retry);
-	}
-	return 0;
-}
-
-static int
-snprint_mp_rr_min_io (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->minio)
-		return 0;
-
-	return snprintf(buff, len, "%u", mpe->minio);
-}
-
-static int
-snprint_mp_rr_min_io_rq (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->minio_rq)
-		return 0;
-
-	return snprintf(buff, len, "%u", mpe->minio_rq);
-}
-
-static int
-snprint_mp_pg_timeout (char * buff, int len, void * data)
-{
-	return 0;
-}
-
-static int
-snprint_mp_features (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->features)
-		return 0;
-	if (strlen(mpe->features) == strlen(conf->features) &&
-	    !strcmp(mpe->features, conf->features))
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", mpe->features);
-}
-
-static int
-snprint_mp_flush_on_last_del (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	switch (mpe->flush_on_last_del) {
-	case FLUSH_DISABLED:
-		return snprintf(buff, len, "\"no\"");
-	case FLUSH_ENABLED:
-		return snprintf(buff, len, "\"yes\"");
-	}
-	return 0;
-}
-
-static int
-snprint_mp_prio(char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->prio_name)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", mpe->prio_name);
-}
-
-static int
-snprint_mp_prio_args(char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->prio_args)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", mpe->prio_args);
-}
-
-static int
-snprint_mp_reservation_key (char * buff, int len, void * data)
-{
-	int i;
-	unsigned char *keyp;
-	uint64_t prkey = 0;
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (!mpe->reservation_key)
-		return 0;
-	keyp = (unsigned char *)mpe->reservation_key;
-	for (i = 0; i < 8; i++) {
-		if (i > 0)
-			prkey <<= 8;
-		prkey |= *keyp;
-		keyp++;
-	}
-
-	return snprintf(buff, len, "0x%" PRIx64, prkey);
-}
-
-	static int
-snprint_mp_user_friendly_names (char * buff, int len, void * data)
-{
-	struct mpentry * mpe = (struct mpentry *)data;
-
-	if (mpe->user_friendly_names == USER_FRIENDLY_NAMES_UNDEF)
-		return 0;
-	else if (mpe->user_friendly_names == USER_FRIENDLY_NAMES_OFF)
-		return snprintf(buff, len, "\"no\"");
-	else
-		return snprintf(buff, len, "\"yes\"");
-}
-
-static int
-snprint_hw_fast_io_fail(char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-	if (hwe->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
-		return 0;
-	if (hwe->fast_io_fail == conf->fast_io_fail)
-		return 0;
-	if (hwe->fast_io_fail == MP_FAST_IO_FAIL_OFF)
-		return snprintf(buff, len, "\"off\"");
-	if (hwe->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
-		return snprintf(buff, len, "0");
-	return snprintf(buff, len, "%d", hwe->fast_io_fail);
-}
-
-static int
-snprint_hw_dev_loss(char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-	if (!hwe->dev_loss)
-		return 0;
-	if (hwe->dev_loss == conf->dev_loss)
-		return 0;
-	if (hwe->dev_loss >= MAX_DEV_LOSS_TMO)
-		return snprintf(buff, len, "\"infinity\"");
-
-	return snprintf(buff, len, "%u", hwe->dev_loss);
-}
-
-static int
-snprint_hw_vendor (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->vendor)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->vendor);
-}
-
-static int
-snprint_hw_product (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->product)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->product);
-}
-
-static int
-snprint_hw_revision (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->revision)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->revision);
-}
-
-static int
-snprint_hw_bl_product (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->bl_product)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->bl_product);
-}
-
-static int
-snprint_hw_uid_attribute (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->uid_attribute)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->uid_attribute);
-}
-
-static int
-snprint_hw_getuid_callout (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->getuid)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->getuid);
-}
-
-static int
-snprint_hw_prio (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->prio_name)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->prio_name);
-}
-
-static int
-snprint_hw_alias_prefix (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->alias_prefix)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->alias_prefix);
-}
-
-static int
-snprint_hw_prio_args (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->prio_args)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->prio_args);
-}
-
-static int
-snprint_hw_features (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->features)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->features);
-}
-
-static int
-snprint_hw_hardware_handler (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->hwhandler)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->hwhandler);
-}
-
-static int
-snprint_hw_selector (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->selector)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->selector);
-}
-
-static int
-snprint_hw_path_grouping_policy (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	char str[POLICY_NAME_SIZE];
-
-	if (!hwe->pgpolicy)
-		return 0;
-
-	get_pgpolicy_name(str, POLICY_NAME_SIZE, hwe->pgpolicy);
-
-	return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_hw_failback (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (hwe->pgfailback == FAILBACK_UNDEF ||
-	    hwe->pgfailback == DEFAULT_FAILBACK)
-		return 0;
-
-	switch(hwe->pgfailback) {
-	case -FAILBACK_MANUAL:
-		return snprintf(buff, len, "\"manual\"");
-	case -FAILBACK_IMMEDIATE:
-		return snprintf(buff, len, "\"immediate\"");
-	case -FAILBACK_FOLLOWOVER:
-		return snprintf(buff, len, "\"followover\"");
-	default:
-		return snprintf(buff, len, "%i", hwe->pgfailback);
-	}
-	return 0;
-}
-
-static int
-snprint_hw_rr_weight (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->rr_weight)
-		return 0;
-	if (hwe->rr_weight == RR_WEIGHT_PRIO)
-		return snprintf(buff, len, "\"priorities\"");
-	if (hwe->rr_weight == RR_WEIGHT_NONE)
-		return snprintf(buff, len, "\"uniform\"");
-
-	return 0;
-}
-
-static int
-snprint_hw_no_path_retry (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->no_path_retry)
-		return 0;
-
-	switch(hwe->no_path_retry) {
-	case NO_PATH_RETRY_UNDEF:
-		break;
-	case NO_PATH_RETRY_FAIL:
-		return snprintf(buff, len, "\"fail\"");
-	case NO_PATH_RETRY_QUEUE:
-		return snprintf(buff, len, "\"queue\"");
-	default:
-		return snprintf(buff, len, "%i",
-				hwe->no_path_retry);
-	}
-	return 0;
-}
-
-static int
-snprint_hw_rr_min_io (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->minio)
-		return 0;
-
-	return snprintf(buff, len, "%u", hwe->minio);
-}
-
-static int
-snprint_hw_rr_min_io_rq (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->minio_rq)
-		return 0;
-
-	return snprintf(buff, len, "%u", hwe->minio_rq);
-}
-
-static int
-snprint_hw_pg_timeout (char * buff, int len, void * data)
-{
-	return 0;
-}
-
-static int
-snprint_hw_flush_on_last_del (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	switch (hwe->flush_on_last_del) {
-	case FLUSH_DISABLED:
-		return snprintf(buff, len, "\"no\"");
-	case FLUSH_ENABLED:
-		return snprintf(buff, len, "\"yes\"");
-	}
-	return 0;
-}
-
-static int
-snprint_hw_path_checker (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (!hwe->checker_name)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", hwe->checker_name);
-}
-
-	static int
-snprint_hw_user_friendly_names (char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (hwe->user_friendly_names == USER_FRIENDLY_NAMES_UNDEF)
-		return 0;
-	else if (hwe->user_friendly_names == USER_FRIENDLY_NAMES_OFF)
-		return snprintf(buff, len, "\"no\"");
-	else
-		return snprintf(buff, len, "\"yes\"");
-}
-
-static int
-snprint_hw_retain_hwhandler_handler(char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (hwe->retain_hwhandler == RETAIN_HWHANDLER_ON)
-		return snprintf(buff, len, "\"yes\"");
-	else if (hwe->retain_hwhandler == RETAIN_HWHANDLER_OFF)
-		return snprintf(buff, len, "\"no\"");
-	else
-		return 0;
-}
-
-static int
-snprint_detect_prio(char * buff, int len, void * data)
-{
-	struct hwentry * hwe = (struct hwentry *)data;
-
-	if (hwe->detect_prio == DETECT_PRIO_ON)
-		return snprintf(buff, len, "\"yes\"");
-	else if (hwe->detect_prio == DETECT_PRIO_OFF)
-		return snprintf(buff, len, "\"no\"");
-	else
-		return 0;
-}
-
-static int
-snprint_def_polling_interval (char * buff, int len, void * data)
-{
-	return snprintf(buff, len, "%i", conf->checkint);
-}
-
-static int
-snprint_def_fast_io_fail(char * buff, int len, void * data)
-{
-	if (conf->fast_io_fail == MP_FAST_IO_FAIL_UNSET)
-		return 0;
-	if (conf->fast_io_fail == MP_FAST_IO_FAIL_OFF)
-		return snprintf(buff, len, "\"off\"");
-	if (conf->fast_io_fail == MP_FAST_IO_FAIL_ZERO)
-		return snprintf(buff, len, "0");
-	return snprintf(buff, len, "%d", conf->fast_io_fail);
-}
-
-static int
-snprint_def_dev_loss(char * buff, int len, void * data)
-{
-	if (!conf->dev_loss)
-		return 0;
-	if (conf->dev_loss >= MAX_DEV_LOSS_TMO)
-		return snprintf(buff, len, "\"infinity\"");
-	return snprintf(buff, len, "%u", conf->dev_loss);
-}
-
-static int
-snprint_def_verbosity (char * buff, int len, void * data)
-{
-	return snprintf(buff, len, "%i", conf->verbosity);
-}
-
-static int
-snprint_def_max_polling_interval (char * buff, int len, void * data)
-{
-	return snprintf(buff, len, "%i", conf->max_checkint);
-}
-
-static int
-snprint_reassign_maps (char * buff, int len, void * data)
-{
-	return snprintf(buff, len, "\"%s\"",
-			conf->reassign_maps?"yes":"no");
-}
-
-static int
-snprint_def_multipath_dir (char * buff, int len, void * data)
-{
-	if (!conf->multipath_dir)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", conf->multipath_dir);
-}
-
-static int
-snprint_def_selector (char * buff, int len, void * data)
-{
-	if (!conf->selector)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_SELECTOR);
-
-	return snprintf(buff, len, "\"%s\"", conf->selector);
-}
-
-static int
-snprint_def_path_grouping_policy (char * buff, int len, void * data)
-{
-	char str[POLICY_NAME_SIZE];
-	int pgpolicy = conf->pgpolicy;
-
-	if (!pgpolicy)
-		pgpolicy = DEFAULT_PGPOLICY;
-
-	get_pgpolicy_name(str, POLICY_NAME_SIZE, pgpolicy);
-
-	return snprintf(buff, len, "\"%s\"", str);
-}
-
-static int
-snprint_def_uid_attribute (char * buff, int len, void * data)
-{
-	if (!conf->uid_attribute)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_UID_ATTRIBUTE);
-
-	return snprintf(buff, len, "\"%s\"", conf->uid_attribute);
-}
-
-static int
-snprint_def_getuid_callout (char * buff, int len, void * data)
-{
-	if (!conf->getuid)
-		return 0;
-
-	return snprintf(buff, len, "\"%s\"", conf->getuid);
-}
-
-static int
-snprint_def_prio (char * buff, int len, void * data)
-{
-	if (!conf->prio_name)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_PRIO);
-
-	return snprintf(buff, len, "\"%s\"", conf->prio_name);
-}
-
-static int
-snprint_def_prio_args (char * buff, int len, void * data)
-{
-	if (!conf->prio_args)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_PRIO_ARGS);
-
-	return snprintf(buff, len, "\"%s\"", conf->prio_args);
-}
-
-static int
-snprint_def_features (char * buff, int len, void * data)
-{
-	if (!conf->features)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_FEATURES);
-
-	return snprintf(buff, len, "\"%s\"", conf->features);
-}
-
-static int
-snprint_def_path_checker (char * buff, int len, void * data)
-{
-	if (!conf->checker_name)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_CHECKER);
-
-	return snprintf(buff, len, "\"%s\"", conf->checker_name);
-}
-
-static int
-snprint_def_failback (char * buff, int len, void * data)
-{
-	switch(conf->pgfailback) {
-	case  FAILBACK_UNDEF:
-		return snprintf(buff, len, "\"undef\"");
-	case -FAILBACK_MANUAL:
-		return snprintf(buff, len, "\"manual\"");
-	case -FAILBACK_IMMEDIATE:
-		return snprintf(buff, len, "\"immediate\"");
-	case -FAILBACK_FOLLOWOVER:
-		return snprintf(buff, len, "\"followover\"");
-	default:
-		return snprintf(buff, len, "%i", conf->pgfailback);
-	}
-	return 0;
-}
-
-static int
-snprint_def_rr_min_io (char * buff, int len, void * data)
-{
-	if (!conf->minio)
-		return 0;
-
-	return snprintf(buff, len, "%u", conf->minio);
-}
-
-static int
-snprint_def_rr_min_io_rq (char * buff, int len, void * data)
-{
-	if (!conf->minio_rq)
-		return 0;
-
-	return snprintf(buff, len, "%u", conf->minio_rq);
-}
-
-static int
-snprint_max_fds (char * buff, int len, void * data)
-{
-	int r = 0, max_fds;
-
-	if (!conf->max_fds)
-		return 0;
-
-	r = get_sys_max_fds(&max_fds);
-	if (!r && conf->max_fds >= max_fds)
-		return snprintf(buff, len, "\"max\"");
-	else
-		return snprintf(buff, len, "%d", conf->max_fds);
-}
-
-static int
-snprint_def_mode(char * buff, int len, void * data)
-{
-	if ((conf->attribute_flags & (1 << ATTR_MODE)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", conf->mode);
-}
-
-static int
-snprint_def_uid(char * buff, int len, void * data)
-{
-	if ((conf->attribute_flags & (1 << ATTR_UID)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", conf->uid);
-}
-
-static int
-snprint_def_gid(char * buff, int len, void * data)
-{
-	if ((conf->attribute_flags & (1 << ATTR_GID)) == 0)
-		return 0;
-	return snprintf(buff, len, "0%o", conf->gid);
-}
-
-static int
-snprint_def_rr_weight (char * buff, int len, void * data)
-{
-	if (!conf->rr_weight || conf->rr_weight == RR_WEIGHT_NONE)
-		return snprintf(buff, len, "\"uniform\"");
-	if (conf->rr_weight == RR_WEIGHT_PRIO)
-		return snprintf(buff, len, "\"priorities\"");
-
-	return 0;
-}
-
-static int
-snprint_def_no_path_retry (char * buff, int len, void * data)
-{
-	switch(conf->no_path_retry) {
-	case NO_PATH_RETRY_UNDEF:
-		break;
-	case NO_PATH_RETRY_FAIL:
-		return snprintf(buff, len, "\"fail\"");
-	case NO_PATH_RETRY_QUEUE:
-		return snprintf(buff, len, "\"queue\"");
-	default:
-		return snprintf(buff, len, "%i",
-				conf->no_path_retry);
-	}
-	return 0;
-}
-
-static int
-snprint_def_queue_without_daemon (char * buff, int len, void * data)
-{
-	switch (conf->queue_without_daemon) {
-	case QUE_NO_DAEMON_OFF:
-		return snprintf(buff, len, "\"no\"");
-	case QUE_NO_DAEMON_ON:
-		return snprintf(buff, len, "\"yes\"");
-	case QUE_NO_DAEMON_FORCE:
-		return snprintf(buff, len, "\"forced\"");
-	}
-	return 0;
-}
-
-static int
-snprint_def_checker_timeout (char *buff, int len, void *data)
-{
-	if (!conf->checker_timeout)
-		return 0;
-
-	return snprintf(buff, len, "%u", conf->checker_timeout);
-}
-
-static int
-snprint_def_pg_timeout (char * buff, int len, void * data)
-{
-	return 0;
-}
-
-static int
-snprint_def_flush_on_last_del (char * buff, int len, void * data)
-{
-	switch (conf->flush_on_last_del) {
-	case FLUSH_UNDEF:
-	case FLUSH_DISABLED:
-		return snprintf(buff, len, "\"no\"");
-	case FLUSH_ENABLED:
-	case FLUSH_IN_PROGRESS:
-		return snprintf(buff, len, "\"yes\"");
-	}
 	return 0;
 }
 
-static int
-snprint_def_log_checker_err (char * buff, int len, void * data)
-{
-	if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
-		return snprintf(buff, len, "once");
-	return snprintf(buff, len, "always");
-}
-
-static int
-snprint_def_user_friendly_names (char * buff, int len, void * data)
-{
-	if (conf->user_friendly_names  == USER_FRIENDLY_NAMES_ON)
-		return snprintf(buff, len, "\"yes\"");
-	else
-		return snprintf(buff, len, "\"no\"");
-}
-
-static int
-snprint_def_alias_prefix (char * buff, int len, void * data)
-{
-	if (!conf->alias_prefix)
-		return snprintf(buff, len, "\"%s\"", DEFAULT_ALIAS_PREFIX);
-	return snprintf(buff, len, "\"%s\"", conf->alias_prefix);
-}
-
-static int
-snprint_def_bindings_file (char * buff, int len, void * data)
-{
-	if (conf->bindings_file == NULL)
-		return 0;
-	return snprintf(buff, len, "\"%s\"", conf->bindings_file);
-}
-
-static int
-snprint_def_wwids_file (char * buff, int len, void * data)
-{
-	if (conf->wwids_file == NULL)
-		return 0;
-	return snprintf(buff, len, "%s", conf->wwids_file);
-}
-
-static int
-snprint_def_reservation_key(char * buff, int len, void * data)
-{
-	int i;
-	unsigned char *keyp;
-	uint64_t prkey = 0;
-
-	if (!conf->reservation_key)
-		return 0;
-	keyp = (unsigned char *)conf->reservation_key;
-	for (i = 0; i < 8; i++) {
-		if (i > 0)
-			prkey <<= 8;
-		prkey |= *keyp;
-		keyp++;
-	}
-	return snprintf(buff, len, "0x%" PRIx64, prkey);
-}
-
-static int
-snprint_def_retain_hwhandler_handler(char * buff, int len, void * data)
-{
-	if (conf->retain_hwhandler == RETAIN_HWHANDLER_ON)
-		return snprintf(buff, len, "yes");
-	else
-		return snprintf(buff, len, "no");
-}
-
-static int
-snprint_def_detect_prio(char * buff, int len, void * data)
-{
-	if (conf->detect_prio == DETECT_PRIO_ON)
-		return snprintf(buff, len, "yes");
-	else
-		return snprintf(buff, len, "no");
-}
-
-static int
-snprint_def_force_sync(char * buff, int len, void * data)
-{
-	if (conf->force_sync)
-		return snprintf(buff, len, "yes");
-	else
-		return snprintf(buff, len, "no");
-}
-
-static int
-snprint_ble_simple (char * buff, int len, void * data)
-{
-	struct blentry * ble = (struct blentry *)data;
-
-	return snprintf(buff, len, "\"%s\"", ble->str);
-}
-
-static int
-snprint_bled_vendor (char * buff, int len, void * data)
-{
-	struct blentry_device * bled = (struct blentry_device *)data;
-
-	return snprintf(buff, len, "\"%s\"", bled->vendor);
-}
-
-static int
-snprint_bled_product (char * buff, int len, void * data)
-{
-	struct blentry_device * bled = (struct blentry_device *)data;
-
-	return snprintf(buff, len, "\"%s\"", bled->product);
-}
-
 #define __deprecated
 
 void
 init_keywords(void)
 {
 	install_keyword_root("defaults", NULL);
-	install_keyword("verbosity", &verbosity_handler, &snprint_def_verbosity);
-	install_keyword("polling_interval", &polling_interval_handler, &snprint_def_polling_interval);
-	install_keyword("max_polling_interval", &max_polling_interval_handler, &snprint_def_max_polling_interval);
-	install_keyword("reassign_maps", &reassign_maps_handler, &snprint_reassign_maps);
-	install_keyword("multipath_dir", &multipath_dir_handler, &snprint_def_multipath_dir);
+	install_keyword("verbosity", &def_verbosity_handler, &snprint_def_verbosity);
+	install_keyword("polling_interval", &def_checkint_handler, &snprint_def_checkint);
+	install_keyword("max_polling_interval", &def_max_checkint_handler, &snprint_def_max_checkint);
+	install_keyword("reassign_maps", &def_reassign_maps_handler, &snprint_def_reassign_maps);
+	install_keyword("multipath_dir", &def_multipath_dir_handler, &snprint_def_multipath_dir);
 	install_keyword("path_selector", &def_selector_handler, &snprint_def_selector);
-	install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
+	install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_pgpolicy);
 	install_keyword("uid_attribute", &def_uid_attribute_handler, &snprint_def_uid_attribute);
-	install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
-	install_keyword("prio", &def_prio_handler, &snprint_def_prio);
+	install_keyword("getuid_callout", &def_getuid_handler, &snprint_def_getuid);
+	install_keyword("prio", &def_prio_name_handler, &snprint_def_prio_name);
 	install_keyword("prio_args", &def_prio_args_handler, &snprint_def_prio_args);
 	install_keyword("features", &def_features_handler, &snprint_def_features);
-	install_keyword("path_checker", &def_path_checker_handler, &snprint_def_path_checker);
-	install_keyword("checker", &def_path_checker_handler, NULL);
+	install_keyword("path_checker", &def_checker_name_handler, &snprint_def_checker_name);
+	install_keyword("checker", &def_checker_name_handler, NULL);
 	install_keyword("alias_prefix", &def_alias_prefix_handler, &snprint_def_alias_prefix);
-	install_keyword("failback", &default_failback_handler, &snprint_def_failback);
-	install_keyword("rr_min_io", &def_minio_handler, &snprint_def_rr_min_io);
-	install_keyword("rr_min_io_rq", &def_minio_rq_handler, &snprint_def_rr_min_io_rq);
+	install_keyword("failback", &def_pgfailback_handler, &snprint_def_pgfailback);
+	install_keyword("rr_min_io", &def_minio_handler, &snprint_def_minio);
+	install_keyword("rr_min_io_rq", &def_minio_rq_handler, &snprint_def_minio_rq);
 	install_keyword("max_fds", &max_fds_handler, &snprint_max_fds);
-	install_keyword("rr_weight", &def_weight_handler, &snprint_def_rr_weight);
+	install_keyword("rr_weight", &def_rr_weight_handler, &snprint_def_rr_weight);
 	install_keyword("no_path_retry", &def_no_path_retry_handler, &snprint_def_no_path_retry);
-	install_keyword("queue_without_daemon", &def_queue_without_daemon, &snprint_def_queue_without_daemon);
+	install_keyword("queue_without_daemon", &def_queue_without_daemon_handler, &snprint_def_queue_without_daemon);
 	install_keyword("checker_timeout", &def_checker_timeout_handler, &snprint_def_checker_timeout);
-	install_keyword("pg_timeout", &def_pg_timeout_handler, &snprint_def_pg_timeout);
+	install_keyword("pg_timeout", &deprecated_handler, &snprint_deprecated);
 	install_keyword("flush_on_last_del", &def_flush_on_last_del_handler, &snprint_def_flush_on_last_del);
-	install_keyword("user_friendly_names", &def_names_handler, &snprint_def_user_friendly_names);
+	install_keyword("user_friendly_names", &def_user_friendly_names_handler, &snprint_def_user_friendly_names);
 	install_keyword("mode", &def_mode_handler, &snprint_def_mode);
 	install_keyword("uid", &def_uid_handler, &snprint_def_uid);
 	install_keyword("gid", &def_gid_handler, &snprint_def_gid);
 	install_keyword("fast_io_fail_tmo", &def_fast_io_fail_handler, &snprint_def_fast_io_fail);
 	install_keyword("dev_loss_tmo", &def_dev_loss_handler, &snprint_def_dev_loss);
-	install_keyword("bindings_file", &bindings_file_handler, &snprint_def_bindings_file);
-	install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file);
+	install_keyword("bindings_file", &def_bindings_file_handler, &snprint_def_bindings_file);
+	install_keyword("wwids_file", &def_wwids_file_handler, &snprint_def_wwids_file);
 	install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err);
 	install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key);
-	install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler);
+	install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler);
 	install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
 	install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
-	__deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
+	__deprecated install_keyword("default_getuid_callout", &def_getuid_handler, NULL);
 	__deprecated install_keyword("default_features", &def_features_handler, NULL);
-	__deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
+	__deprecated install_keyword("default_path_checker", &def_checker_name_handler, NULL);
 
 	install_keyword_root("blacklist", &blacklist_handler);
-	install_keyword_multi("devnode", &ble_devnode_handler, &snprint_ble_simple);
-	install_keyword_multi("wwid", &ble_wwid_handler, &snprint_ble_simple);
-	install_keyword_multi("property", &ble_property_handler, &snprint_ble_simple);
+	install_keyword_multi("devnode", &ble_blist_devnode_handler, &snprint_ble_simple);
+	install_keyword_multi("wwid", &ble_blist_wwid_handler, &snprint_ble_simple);
+	install_keyword_multi("property", &ble_blist_property_handler, &snprint_ble_simple);
 	install_keyword_multi("device", &ble_device_handler, NULL);
 	install_sublevel();
-	install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
-	install_keyword("product", &ble_product_handler, &snprint_bled_product);
+	install_keyword("vendor", &ble_blist_device_vendor_handler, &snprint_bled_vendor);
+	install_keyword("product", &ble_blist_device_product_handler, &snprint_bled_product);
 	install_sublevel_end();
 	install_keyword_root("blacklist_exceptions", &blacklist_exceptions_handler);
-	install_keyword_multi("devnode", &ble_except_devnode_handler, &snprint_ble_simple);
-	install_keyword_multi("wwid", &ble_except_wwid_handler, &snprint_ble_simple);
-	install_keyword_multi("property", &ble_except_property_handler, &snprint_ble_simple);
+	install_keyword_multi("devnode", &ble_elist_devnode_handler, &snprint_ble_simple);
+	install_keyword_multi("wwid", &ble_elist_wwid_handler, &snprint_ble_simple);
+	install_keyword_multi("property", &ble_elist_property_handler, &snprint_ble_simple);
 	install_keyword_multi("device", &ble_except_device_handler, NULL);
 	install_sublevel();
-	install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor);
-	install_keyword("product", &ble_except_product_handler, &snprint_bled_product);
+	install_keyword("vendor", &ble_elist_device_vendor_handler, &snprint_bled_vendor);
+	install_keyword("product", &ble_elist_device_product_handler, &snprint_bled_product);
 	install_sublevel_end();
 
 #if 0
@@ -2922,56 +1207,56 @@ init_keywords(void)
 	install_keyword_root("devices", &devices_handler);
 	install_keyword_multi("device", &device_handler, NULL);
 	install_sublevel();
-	install_keyword("vendor", &vendor_handler, &snprint_hw_vendor);
-	install_keyword("product", &product_handler, &snprint_hw_product);
-	install_keyword("revision", &revision_handler, &snprint_hw_revision);
-	install_keyword("product_blacklist", &bl_product_handler, &snprint_hw_bl_product);
-	install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_path_grouping_policy);
+	install_keyword("vendor", &hw_vendor_handler, &snprint_hw_vendor);
+	install_keyword("product", &hw_product_handler, &snprint_hw_product);
+	install_keyword("revision", &hw_revision_handler, &snprint_hw_revision);
+	install_keyword("product_blacklist", &hw_bl_product_handler, &snprint_hw_bl_product);
+	install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_pgpolicy);
 	install_keyword("uid_attribute", &hw_uid_attribute_handler, &snprint_hw_uid_attribute);
-	install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
+	install_keyword("getuid_callout", &hw_getuid_handler, &snprint_hw_getuid);
 	install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
-	install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
-	install_keyword("checker", &hw_path_checker_handler, NULL);
+	install_keyword("path_checker", &hw_checker_name_handler, &snprint_hw_checker_name);
+	install_keyword("checker", &hw_checker_name_handler, NULL);
 	install_keyword("alias_prefix", &hw_alias_prefix_handler, &snprint_hw_alias_prefix);
 	install_keyword("features", &hw_features_handler, &snprint_hw_features);
-	install_keyword("hardware_handler", &hw_handler_handler, &snprint_hw_hardware_handler);
-	install_keyword("prio", &hw_prio_handler, &snprint_hw_prio);
+	install_keyword("hardware_handler", &hw_hwhandler_handler, &snprint_hw_hwhandler);
+	install_keyword("prio", &hw_prio_name_handler, &snprint_hw_prio_name);
 	install_keyword("prio_args", &hw_prio_args_handler, &snprint_hw_prio_args);
-	install_keyword("failback", &hw_failback_handler, &snprint_hw_failback);
-	install_keyword("rr_weight", &hw_weight_handler, &snprint_hw_rr_weight);
+	install_keyword("failback", &hw_pgfailback_handler, &snprint_hw_pgfailback);
+	install_keyword("rr_weight", &hw_rr_weight_handler, &snprint_hw_rr_weight);
 	install_keyword("no_path_retry", &hw_no_path_retry_handler, &snprint_hw_no_path_retry);
-	install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_rr_min_io);
-	install_keyword("rr_min_io_rq", &hw_minio_rq_handler, &snprint_hw_rr_min_io_rq);
-	install_keyword("pg_timeout", &hw_pg_timeout_handler, &snprint_hw_pg_timeout);
+	install_keyword("rr_min_io", &hw_minio_handler, &snprint_hw_minio);
+	install_keyword("rr_min_io_rq", &hw_minio_rq_handler, &snprint_hw_minio_rq);
+	install_keyword("pg_timeout", &deprecated_handler, &snprint_deprecated);
 	install_keyword("flush_on_last_del", &hw_flush_on_last_del_handler, &snprint_hw_flush_on_last_del);
 	install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail);
 	install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss);
-	install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names);
-	install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler);
-	install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio);
+	install_keyword("user_friendly_names", &hw_user_friendly_names_handler, &snprint_hw_user_friendly_names);
+	install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler);
+	install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio);
 	install_sublevel_end();
 
 	install_keyword_root("multipaths", &multipaths_handler);
 	install_keyword_multi("multipath", &multipath_handler, NULL);
 	install_sublevel();
-	install_keyword("wwid", &wwid_handler, &snprint_mp_wwid);
-	install_keyword("alias", &alias_handler, &snprint_mp_alias);
-	install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_path_grouping_policy);
+	install_keyword("wwid", &mp_wwid_handler, &snprint_mp_wwid);
+	install_keyword("alias", &mp_alias_handler, &snprint_mp_alias);
+	install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_pgpolicy);
 	install_keyword("path_selector", &mp_selector_handler, &snprint_mp_selector);
-	install_keyword("prio", &mp_prio_handler, &snprint_mp_prio);
+	install_keyword("prio", &mp_prio_name_handler, &snprint_mp_prio_name);
 	install_keyword("prio_args", &mp_prio_args_handler, &snprint_mp_prio_args);
-	install_keyword("failback", &mp_failback_handler, &snprint_mp_failback);
-	install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
+	install_keyword("failback", &mp_pgfailback_handler, &snprint_mp_pgfailback);
+	install_keyword("rr_weight", &mp_rr_weight_handler, &snprint_mp_rr_weight);
 	install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
-	install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_rr_min_io);
-	install_keyword("rr_min_io_rq", &mp_minio_rq_handler, &snprint_mp_rr_min_io_rq);
-	install_keyword("pg_timeout", &mp_pg_timeout_handler, &snprint_mp_pg_timeout);
+	install_keyword("rr_min_io", &mp_minio_handler, &snprint_mp_minio);
+	install_keyword("rr_min_io_rq", &mp_minio_rq_handler, &snprint_mp_minio_rq);
+	install_keyword("pg_timeout", &deprecated_handler, &snprint_deprecated);
 	install_keyword("flush_on_last_del", &mp_flush_on_last_del_handler, &snprint_mp_flush_on_last_del);
 	install_keyword("features", &mp_features_handler, &snprint_mp_features);
 	install_keyword("mode", &mp_mode_handler, &snprint_mp_mode);
 	install_keyword("uid", &mp_uid_handler, &snprint_mp_uid);
 	install_keyword("gid", &mp_gid_handler, &snprint_mp_gid);
 	install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
-	install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names);
+	install_keyword("user_friendly_names", &mp_user_friendly_names_handler, &snprint_mp_user_friendly_names);
 	install_sublevel_end();
 }
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index af03edf..15e7e19 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -67,15 +67,15 @@ enum pgstates {
 	PGSTATE_ACTIVE
 };
 
-enum queue_without_daemon_states {
-	QUE_NO_DAEMON_OFF,
-	QUE_NO_DAEMON_ON,
-	QUE_NO_DAEMON_FORCE,
+enum yes_no_states {
+	YN_NO,
+	YN_YES,
 };
 
-enum pgtimeouts {
-	PGTIMEOUT_UNDEF,
-	PGTIMEOUT_NONE
+enum queue_without_daemon_states {
+	QUE_NO_DAEMON_OFF = YN_NO,
+	QUE_NO_DAEMON_ON = YN_YES,
+	QUE_NO_DAEMON_FORCE,
 };
 
 enum attribute_bits {
@@ -84,10 +84,16 @@ enum attribute_bits {
 	ATTR_MODE,
 };
 
+enum yes_no_undef_states {
+	YNU_UNDEF,
+	YNU_NO,
+	YNU_YES,
+};
+
 enum flush_states {
-	FLUSH_UNDEF,
-	FLUSH_DISABLED,
-	FLUSH_ENABLED,
+	FLUSH_UNDEF = YNU_UNDEF,
+	FLUSH_DISABLED = YNU_NO,
+	FLUSH_ENABLED = YNU_YES,
 	FLUSH_IN_PROGRESS,
 };
 
@@ -97,21 +103,21 @@ enum log_checker_err_states {
 };
 
 enum user_friendly_names_states {
-	USER_FRIENDLY_NAMES_UNDEF,
-	USER_FRIENDLY_NAMES_OFF,
-	USER_FRIENDLY_NAMES_ON,
+	USER_FRIENDLY_NAMES_UNDEF = YNU_UNDEF,
+	USER_FRIENDLY_NAMES_OFF = YNU_NO,
+	USER_FRIENDLY_NAMES_ON = YNU_YES,
 };
 
 enum retain_hwhandler_states {
-	RETAIN_HWHANDLER_UNDEF,
-	RETAIN_HWHANDLER_OFF,
-	RETAIN_HWHANDLER_ON,
+	RETAIN_HWHANDLER_UNDEF = YNU_UNDEF,
+	RETAIN_HWHANDLER_OFF = YNU_NO,
+	RETAIN_HWHANDLER_ON = YNU_YES,
 };
 
 enum detect_prio_states {
-	DETECT_PRIO_UNDEF,
-	DETECT_PRIO_OFF,
-	DETECT_PRIO_ON,
+	DETECT_PRIO_UNDEF = YNU_UNDEF,
+	DETECT_PRIO_OFF = YNU_NO,
+	DETECT_PRIO_ON = YNU_YES,
 };
 
 enum scsi_protocol {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/6] libmultipath: cleanup propsel.c with macros for common actions
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 1/6] libmultipath: rewrite dict.c with function generation macros Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 3/6] libmultipath: add overrides section to multipath.conf Benjamin Marzinski
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

Many of the functions in propsel.c are nearly identical, except for the
names of the variables that they are dealing with.  Also, some variables
that the user configured with a keyword were just printing the variable
as an integer, which isn't very helpful without looking at the code to
see what the number stands for. They were using the variable names
instead of the config file names as well.  This patch tries to simplify
the file by using macros for the repetitive work of the functions, and
standardizes and clarifies the debug messages by using the print functions
from dict.c

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/dict.c       |  14 +-
 libmultipath/dict.h       |   7 +
 libmultipath/pgpolicies.c |   2 +-
 libmultipath/propsel.c    | 712 +++++++++++++++++-----------------------------
 4 files changed, 282 insertions(+), 453 deletions(-)

diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index e88c122..98cbe48 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -496,7 +496,7 @@ set_fast_io_fail(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_fast_io_fail(char * buff, int len, void *ptr)
 {
 	int *int_ptr = (int *)ptr;
@@ -534,7 +534,7 @@ set_dev_loss(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_dev_loss(char * buff, int len, void *ptr)
 {
 	unsigned int *uint_ptr = (unsigned int *)ptr;
@@ -567,7 +567,7 @@ set_pgpolicy(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_pgpolicy(char * buff, int len, void *ptr)
 {
 	char str[POLICY_NAME_SIZE];
@@ -683,7 +683,7 @@ set_rr_weight(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_rr_weight (char * buff, int len, void *ptr)
 {
 	int *int_ptr = (int *)ptr;
@@ -727,7 +727,7 @@ set_pgfailback(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_pgfailback (char * buff, int len, void *ptr)
 {
 	int *int_ptr = (int *)ptr;
@@ -774,7 +774,7 @@ set_no_path_retry(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_no_path_retry(char * buff, int len, void *ptr)
 {
 	int *int_ptr = (int *)ptr;
@@ -873,7 +873,7 @@ set_reservation_key(vector strvec, void *ptr)
 	return 0;
 }
 
-static int
+int
 print_reservation_key(char * buff, int len, void * ptr)
 {
 	unsigned char **uchar_ptr = (unsigned char **)ptr;
diff --git a/libmultipath/dict.h b/libmultipath/dict.h
index 688eab7..84b6180 100644
--- a/libmultipath/dict.h
+++ b/libmultipath/dict.h
@@ -7,5 +7,12 @@
 
 void init_keywords(void);
 int get_sys_max_fds(int *);
+int print_rr_weight (char * buff, int len, void *ptr);
+int print_pgfailback (char * buff, int len, void *ptr);
+int print_pgpolicy(char * buff, int len, void *ptr);
+int print_no_path_retry(char * buff, int len, void *ptr);
+int print_fast_io_fail(char * buff, int len, void *ptr);
+int print_dev_loss(char * buff, int len, void *ptr);
+int print_reservation_key(char * buff, int len, void * ptr);
 
 #endif /* _DICT_H */
diff --git a/libmultipath/pgpolicies.c b/libmultipath/pgpolicies.c
index f76ad60..2981d51 100644
--- a/libmultipath/pgpolicies.c
+++ b/libmultipath/pgpolicies.c
@@ -27,7 +27,7 @@ get_pgpolicy_id (char * str)
 	if (0 == strncmp(str, "group_by_node_name", 18))
 		return GROUP_BY_NODE_NAME;
 
-	return -1;
+	return IOPOLICY_UNDEF;
 }
 
 extern int
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index 7a966bb..f2ab7d2 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -17,6 +17,7 @@
 #include "devmapper.h"
 #include "prio.h"
 #include "discovery.h"
+#include "dict.h"
 #include "prioritizers/alua_rtpg.h"
 #include <inttypes.h>
 
@@ -29,57 +30,92 @@ pgpolicyfn *pgpolicies[] = {
 	group_by_node_name
 };
 
+#define do_set(var, src, dest, msg)					\
+do {									\
+	if (src && src->var) {						\
+		dest = src->var;					\
+		origin = msg;						\
+		goto out;						\
+	}								\
+} while(0)
+#define do_default(dest, value)						\
+do {									\
+	dest = value;							\
+	origin = "(internal default)";					\
+} while(0)
+
+#define mp_set_mpe(var)							\
+do_set(var, mp->mpe, mp->var, "(LUN setting)")
+#define mp_set_hwe(var)							\
+do_set(var, mp->hwe, mp->var, "(controller setting)")
+#define mp_set_conf(var)						\
+do_set(var, conf, mp->var, "(config file default)")
+#define mp_set_default(var, value)					\
+do_default(mp->var, value)
+
+#define pp_set_mpe(var)							\
+do_set(var, mpe, pp->var, "(LUN setting)")
+#define pp_set_hwe(var)							\
+do_set(var, pp->hwe, pp->var, "(controller setting)")
+#define pp_set_conf(var)						\
+do_set(var, conf, pp->var, "(config file default)")
+#define pp_set_default(var, value)					\
+do_default(pp->var, value)
+
+#define do_attr_set(var, src, shift, msg)				\
+do {									\
+	if (src && (src->attribute_flags & (1 << shift))) {		\
+		mp->attribute_flags |= (1 << shift);			\
+		mp->var = src->var;					\
+		origin = msg;						\
+		goto out;						\
+	}								\
+} while(0)
+
+#define set_attr_mpe(var, shift)					\
+do_attr_set(var, mp->mpe, shift, "(LUN setting)")
+#define set_attr_conf(var, shift)					\
+do_attr_set(var, conf, shift, "(config file default)")
+
 extern int
 select_mode (struct multipath *mp)
 {
-	if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_MODE))) {
-		mp->attribute_flags |= (1 << ATTR_MODE);
-		mp->mode = mp->mpe->mode;
-		condlog(3, "mode = 0%o (LUN setting)", mp->mode);
-	}
-	else if (conf->attribute_flags & (1 << ATTR_MODE)) {
-		mp->attribute_flags |= (1 << ATTR_MODE);
-		mp->mode = conf->mode;
-		condlog(3, "mode = 0%o (config file default)", mp->mode);
-	}
-	else
-		mp->attribute_flags &= ~(1 << ATTR_MODE);
+	char *origin;
+
+	set_attr_mpe(mode, ATTR_MODE);
+	set_attr_conf(mode, ATTR_MODE);
+	mp->attribute_flags &= ~(1 << ATTR_MODE);
+	return 0;
+out:
+	condlog(3, "%s: mode = 0%o %s", mp->alias, mp->mode, origin);
 	return 0;
 }
 
 extern int
 select_uid (struct multipath *mp)
 {
-	if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_UID))) {
-		mp->attribute_flags |= (1 << ATTR_UID);
-		mp->uid = mp->mpe->uid;
-		condlog(3, "uid = %u (LUN setting)", mp->uid);
-	}
-	else if (conf->attribute_flags & (1 << ATTR_UID)) {
-		mp->attribute_flags |= (1 << ATTR_UID);
-		mp->uid = conf->uid;
-		condlog(3, "uid = %u (config file default)", mp->uid);
-	}
-	else
-		mp->attribute_flags &= ~(1 << ATTR_UID);
+	char *origin;
+
+	set_attr_mpe(uid, ATTR_UID);
+	set_attr_conf(uid, ATTR_UID);
+	mp->attribute_flags &= ~(1 << ATTR_UID);
+	return 0;
+out:
+	condlog(3, "%s: uid = 0%o %s", mp->alias, mp->uid, origin);
 	return 0;
 }
 
 extern int
 select_gid (struct multipath *mp)
 {
-	if (mp->mpe && (mp->mpe->attribute_flags & (1 << ATTR_GID))) {
-		mp->attribute_flags |= (1 << ATTR_GID);
-		mp->gid = mp->mpe->gid;
-		condlog(3, "gid = %u (LUN setting)", mp->gid);
-	}
-	else if (conf->attribute_flags & (1 << ATTR_GID)) {
-		mp->attribute_flags |= (1 << ATTR_GID);
-		mp->gid = conf->gid;
-		condlog(3, "gid = %u (config file default)", mp->gid);
-	}
-	else
-		mp->attribute_flags &= ~(1 << ATTR_GID);
+	char *origin;
+
+	set_attr_mpe(gid, ATTR_GID);
+	set_attr_conf(gid, ATTR_GID);
+	mp->attribute_flags &= ~(1 << ATTR_GID);
+	return 0;
+out:
+	condlog(3, "%s: gid = 0%o %s", mp->alias, mp->gid, origin);
 	return 0;
 }
 
@@ -91,151 +127,80 @@ select_gid (struct multipath *mp)
 extern int
 select_rr_weight (struct multipath * mp)
 {
-	if (mp->mpe && mp->mpe->rr_weight) {
-		mp->rr_weight = mp->mpe->rr_weight;
-		condlog(3, "%s: rr_weight = %i (LUN setting)",
-			mp->alias, mp->rr_weight);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->rr_weight) {
-		mp->rr_weight = mp->hwe->rr_weight;
-		condlog(3, "%s: rr_weight = %i (controller setting)",
-			mp->alias, mp->rr_weight);
-		return 0;
-	}
-	if (conf->rr_weight) {
-		mp->rr_weight = conf->rr_weight;
-		condlog(3, "%s: rr_weight = %i (config file default)",
-			mp->alias, mp->rr_weight);
-		return 0;
-	}
-	mp->rr_weight = RR_WEIGHT_NONE;
-	condlog(3, "%s: rr_weight = %i (internal default)",
-		mp->alias, mp->rr_weight);
+	char *origin, buff[13];
+
+	mp_set_mpe(rr_weight);
+	mp_set_hwe(rr_weight);
+	mp_set_conf(rr_weight);
+	mp_set_default(rr_weight, RR_WEIGHT_NONE);
+out:
+	print_rr_weight(buff, 13, &mp->rr_weight);
+	condlog(3, "%s: rr_weight = %s %s", mp->alias, buff, origin);
 	return 0;
 }
 
 extern int
 select_pgfailback (struct multipath * mp)
 {
-	if (mp->mpe && mp->mpe->pgfailback != FAILBACK_UNDEF) {
-		mp->pgfailback = mp->mpe->pgfailback;
-		condlog(3, "%s: pgfailback = %i (LUN setting)",
-			mp->alias, mp->pgfailback);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->pgfailback != FAILBACK_UNDEF) {
-		mp->pgfailback = mp->hwe->pgfailback;
-		condlog(3, "%s: pgfailback = %i (controller setting)",
-			mp->alias, mp->pgfailback);
-		return 0;
-	}
-	if (conf->pgfailback != FAILBACK_UNDEF) {
-		mp->pgfailback = conf->pgfailback;
-		condlog(3, "%s: pgfailback = %i (config file default)",
-			mp->alias, mp->pgfailback);
-		return 0;
-	}
-	mp->pgfailback = DEFAULT_FAILBACK;
-	condlog(3, "%s: pgfailover = %i (internal default)",
-		mp->alias, mp->pgfailback);
+	char *origin, buff[13];
+
+	mp_set_mpe(pgfailback);
+	mp_set_hwe(pgfailback);
+	mp_set_conf(pgfailback);
+	mp_set_default(pgfailback, DEFAULT_FAILBACK);
+out:
+	print_pgfailback(buff, 13, &mp->pgfailback);
+	condlog(3, "%s: failback = %s %s", mp->alias, buff, origin);
 	return 0;
 }
 
 extern int
 select_pgpolicy (struct multipath * mp)
 {
-	char pgpolicy_name[POLICY_NAME_SIZE];
+	char *origin, buff[POLICY_NAME_SIZE];
 
 	if (conf->pgpolicy_flag > 0) {
 		mp->pgpolicy = conf->pgpolicy_flag;
-		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-				  mp->pgpolicy);
-		condlog(3, "%s: pgpolicy = %s (cmd line flag)",
-			mp->alias, pgpolicy_name);
-		return 0;
-	}
-	if (mp->mpe && mp->mpe->pgpolicy > 0) {
-		mp->pgpolicy = mp->mpe->pgpolicy;
-		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-				  mp->pgpolicy);
-		condlog(3, "%s: pgpolicy = %s (LUN setting)",
-			mp->alias, pgpolicy_name);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->pgpolicy > 0) {
-		mp->pgpolicy = mp->hwe->pgpolicy;
-		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-				  mp->pgpolicy);
-		condlog(3, "%s: pgpolicy = %s (controller setting)",
-			mp->alias, pgpolicy_name);
-		return 0;
-	}
-	if (conf->pgpolicy > 0) {
-		mp->pgpolicy = conf->pgpolicy;
-		mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-		get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE,
-				  mp->pgpolicy);
-		condlog(3, "%s: pgpolicy = %s (config file default)",
-			mp->alias, pgpolicy_name);
-		return 0;
+		origin = "(cmd line flag)";
+		goto out;
 	}
-	mp->pgpolicy = DEFAULT_PGPOLICY;
+	mp_set_mpe(pgpolicy);
+	mp_set_hwe(pgpolicy);
+	mp_set_conf(pgpolicy);
+	mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
+out:
 	mp->pgpolicyfn = pgpolicies[mp->pgpolicy];
-	get_pgpolicy_name(pgpolicy_name, POLICY_NAME_SIZE, mp->pgpolicy);
-	condlog(3, "%s: pgpolicy = %s (internal default)",
-		mp->alias, pgpolicy_name);
+	get_pgpolicy_name(buff, POLICY_NAME_SIZE, mp->pgpolicy);
+	condlog(3, "%s: path_grouping_policy = %s %s", mp->alias, buff, origin);
 	return 0;
 }
 
 extern int
 select_selector (struct multipath * mp)
 {
-	if (mp->mpe && mp->mpe->selector) {
-		mp->selector = mp->mpe->selector;
-		condlog(3, "%s: selector = %s (LUN setting)",
-			mp->alias, mp->selector);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->selector) {
-		mp->selector = mp->hwe->selector;
-		condlog(3, "%s: selector = %s (controller setting)",
-			mp->alias, mp->selector);
-		return 0;
-	}
-	if (conf->selector) {
-		mp->selector = conf->selector;
-		condlog(3, "%s: selector = %s (config file default)",
-			mp->alias, mp->selector);
-		return 0;
-	}
-	mp->selector = set_default(DEFAULT_SELECTOR);
-	condlog(3, "%s: selector = %s (internal default)",
-		mp->alias, mp->selector);
+	char *origin;
+
+	mp_set_mpe(selector);
+	mp_set_hwe(selector);
+	mp_set_conf(selector);
+	mp_set_default(selector, set_default(DEFAULT_SELECTOR));
+out:
+	condlog(3, "%s: path_selector = \"%s\" %s", mp->alias, mp->selector,
+		origin);
 	return 0;
 }
 
 static void
 select_alias_prefix (struct multipath * mp)
 {
-	if (mp->hwe && mp->hwe->alias_prefix) {
-		mp->alias_prefix = mp->hwe->alias_prefix;
-		condlog(3, "%s: alias_prefix = %s (controller setting)",
-			mp->wwid, mp->alias_prefix);
-		return;
-	}
-	if (conf->alias_prefix) {
-		mp->alias_prefix = conf->alias_prefix;
-		condlog(3, "%s: alias_prefix = %s (config file default)",
-			mp->wwid, mp->alias_prefix);
-		return;
-	}
-	mp->alias_prefix = set_default(DEFAULT_ALIAS_PREFIX);
-	condlog(3, "%s: alias_prefix = %s (internal default)",
-		mp->wwid, mp->alias_prefix);
+	char *origin;
+
+	mp_set_hwe(alias_prefix);
+	mp_set_conf(alias_prefix);
+	mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
+out:
+	condlog(3, "%s: alias_prefix = %s %s", mp->wwid, mp->alias_prefix,
+		origin);
 }
 
 static int
@@ -253,8 +218,11 @@ want_user_friendly_names(struct multipath * mp)
 extern int
 select_alias (struct multipath * mp)
 {
+	char *origin;
+
 	if (mp->mpe && mp->mpe->alias) {
 		mp->alias = STRDUP(mp->mpe->alias);
+		origin = "(LUN setting)";
 		goto out;
 	}
 
@@ -269,39 +237,37 @@ select_alias (struct multipath * mp)
 				mp->alias_old, mp->alias_prefix,
 				conf->bindings_read_only);
 		memset (mp->alias_old, 0, WWID_SIZE);
+		origin = "(using existing alias)";
 	}
 
-	if (mp->alias == NULL)
+	if (mp->alias == NULL) {
 		mp->alias = get_user_friendly_alias(mp->wwid,
 				conf->bindings_file, mp->alias_prefix, conf->bindings_read_only);
+		origin = "(user_friendly_name)";
+	}
 out:
-	if (mp->alias == NULL)
+	if (mp->alias == NULL) {
 		mp->alias = STRDUP(mp->wwid);
-
+		origin = "(default to wwid)";
+	}
+	if (mp->alias)
+		condlog(3, "%s: alias = %s %s", mp->wwid, mp->alias, origin);
 	return mp->alias ? 0 : 1;
 }
 
 extern int
 select_features (struct multipath * mp)
 {
-	struct mpentry * mpe;
 	char *origin;
 
-	if ((mpe = find_mpe(mp->wwid)) && mpe->features) {
-		mp->features = STRDUP(mpe->features);
-		origin = "LUN setting";
-	} else if (mp->hwe && mp->hwe->features) {
-		mp->features = STRDUP(mp->hwe->features);
-		origin = "controller setting";
-	} else if (conf->features) {
-		mp->features = STRDUP(conf->features);
-		origin = "config file default";
-	} else {
-		mp->features = set_default(DEFAULT_FEATURES);
-		origin = "internal default";
-	}
-	condlog(3, "%s: features = %s (%s)",
-		mp->alias, mp->features, origin);
+	mp_set_mpe(features);
+	mp_set_hwe(features);
+	mp_set_conf(features);
+	mp_set_default(features, DEFAULT_FEATURES);
+out:
+	mp->features = STRDUP(mp->features);
+	condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
+
 	if (strstr(mp->features, "queue_if_no_path")) {
 		if (mp->no_path_retry == NO_PATH_RETRY_UNDEF)
 			mp->no_path_retry = NO_PATH_RETRY_QUEUE;
@@ -317,45 +283,29 @@ select_features (struct multipath * mp)
 extern int
 select_hwhandler (struct multipath * mp)
 {
-	if (mp->hwe && mp->hwe->hwhandler) {
-		mp->hwhandler = mp->hwe->hwhandler;
-		condlog(3, "%s: hwhandler = %s (controller setting)",
-			mp->alias, mp->hwhandler);
-		return 0;
-	}
-	if (conf->hwhandler) {
-		mp->hwhandler = conf->hwhandler;
-		condlog(3, "%s: hwhandler = %s (config file default)",
-			mp->alias, mp->hwhandler);
-		return 0;
-	}
-	mp->hwhandler = set_default(DEFAULT_HWHANDLER);
-	condlog(3, "%s: hwhandler = %s (internal default)",
-		mp->alias, mp->hwhandler);
+	char *origin;
+
+	mp_set_hwe(hwhandler);
+	mp_set_conf(hwhandler);
+	mp_set_default(hwhandler, set_default(DEFAULT_HWHANDLER));
+out:
+	condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias, mp->hwhandler,
+		origin);
 	return 0;
 }
 
 extern int
 select_checker(struct path *pp)
 {
+	char *origin, *checker_name;
 	struct checker * c = &pp->checker;
 
-	if (pp->hwe && pp->hwe->checker_name) {
-		checker_get(c, pp->hwe->checker_name);
-		condlog(3, "%s: path checker = %s (controller setting)",
-			pp->dev, checker_name(c));
-		goto out;
-	}
-	if (conf->checker_name) {
-		checker_get(c, conf->checker_name);
-		condlog(3, "%s: path checker = %s (config file default)",
-			pp->dev, checker_name(c));
-		goto out;
-	}
-	checker_get(c, DEFAULT_CHECKER);
-	condlog(3, "%s: path checker = %s (internal default)",
-		pp->dev, checker_name(c));
+	do_set(checker_name, pp->hwe, checker_name, "(controller setting)");
+	do_set(checker_name, conf, checker_name, "(config file setting)");
+	do_default(checker_name, DEFAULT_CHECKER);
 out:
+	checker_get(c, checker_name);
+	condlog(3, "%s: path_checker = %s %s", pp->dev, c->name, origin);
 	if (conf->checker_timeout) {
 		c->timeout = conf->checker_timeout;
 		condlog(3, "%s: checker timeout = %u s (config file default)",
@@ -375,33 +325,20 @@ out:
 extern int
 select_getuid (struct path * pp)
 {
-	if (pp->hwe && pp->hwe->uid_attribute) {
-		pp->uid_attribute = pp->hwe->uid_attribute;
-		condlog(3, "%s: uid_attribute = %s (controller setting)",
-			pp->dev, pp->uid_attribute);
-		return 0;
-	}
-	if (pp->hwe && pp->hwe->getuid) {
-		pp->getuid = pp->hwe->getuid;
-		condlog(3, "%s: getuid = %s (deprecated) (controller setting)",
-			pp->dev, pp->getuid);
-		return 0;
-	}
-	if (conf->uid_attribute) {
-		pp->uid_attribute = conf->uid_attribute;
-		condlog(3, "%s: uid_attribute = %s (config file default)",
-			pp->dev, pp->uid_attribute);
-		return 0;
-	}
-	if (conf->getuid) {
-		pp->getuid = conf->getuid;
-		condlog(3, "%s: getuid = %s (deprecated) (config file default)",
-			pp->dev, pp->getuid);
-		return 0;
-	}
-	pp->uid_attribute = STRDUP(DEFAULT_UID_ATTRIBUTE);
-	condlog(3, "%s: uid_attribute = %s (internal default)",
-		pp->dev, pp->uid_attribute);
+	char *origin;
+
+	pp_set_hwe(uid_attribute);
+	pp_set_hwe(getuid);
+	pp_set_conf(uid_attribute);
+	pp_set_conf(getuid);
+	pp_set_default(uid_attribute, DEFAULT_UID_ATTRIBUTE);
+out:
+	if (pp->uid_attribute)
+		condlog(3, "%s: uid_attribute = %s %s", pp->dev,
+			pp->uid_attribute, origin);
+	else if (pp->getuid)
+		condlog(3, "%s: getuid = \"%s\" %s", pp->dev, pp->getuid,
+			origin);
 	return 0;
 }
 
@@ -421,140 +358,94 @@ detect_prio(struct path * pp)
 	prio_get(p, PRIO_ALUA, DEFAULT_PRIO_ARGS);
 }
 
+#define set_prio(src, msg)						\
+do {									\
+	if (src && src->prio_name) {					\
+		prio_get(p, src->prio_name, src->prio_args);		\
+		origin = msg;						\
+		goto out;						\
+	}								\
+} while(0)
+
 extern int
 select_prio (struct path * pp)
 {
+	char *origin;
 	struct mpentry * mpe;
 	struct prio * p = &pp->prio;
 
 	if (pp->detect_prio == DETECT_PRIO_ON) {
 		detect_prio(pp);
 		if (prio_selected(p)) {
-			condlog(3, "%s: prio = %s (detected setting)",
-				pp->dev, prio_name(p));
-			return 0;
-		}
-	}
-
-	if ((mpe = find_mpe(pp->wwid))) {
-		if (mpe->prio_name) {
-			prio_get(p, mpe->prio_name, mpe->prio_args);
-			condlog(3, "%s: prio = %s (LUN setting)",
-				pp->dev, prio_name(p));
-			return 0;
+			origin = "(detected setting)";
+			goto out;
 		}
 	}
-
-	if (pp->hwe && pp->hwe->prio_name) {
-		prio_get(p, pp->hwe->prio_name, pp->hwe->prio_args);
-		condlog(3, "%s: prio = %s (controller setting)",
-			pp->dev, pp->hwe->prio_name);
-		condlog(3, "%s: prio args = %s (controller setting)",
-			pp->dev, pp->hwe->prio_args);
-		return 0;
-	}
-	if (conf->prio_name) {
-		prio_get(p, conf->prio_name, conf->prio_args);
-		condlog(3, "%s: prio = %s (config file default)",
-			pp->dev, conf->prio_name);
-		condlog(3, "%s: prio args = %s (config file default)",
-			pp->dev, conf->prio_args);
-		return 0;
-	}
+	mpe = find_mpe(pp->wwid);
+	set_prio(mpe, "(LUN setting)");
+	set_prio(pp->hwe, "controller setting)");
+	set_prio(conf, "(config file default)");
 	prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
-	condlog(3, "%s: prio = %s (internal default)",
-		pp->dev, DEFAULT_PRIO);
-	condlog(3, "%s: prio args = %s (internal default)",
-		pp->dev, DEFAULT_PRIO_ARGS);
+	origin = "(internal default)";
+out:
+	condlog(3, "%s: prio = %s %s", pp->dev, prio_name(p), origin);
+	condlog(3, "%s: prio args = \"%s\" %s", pp->dev, prio_args(p), origin);
 	return 0;
 }
 
 extern int
 select_no_path_retry(struct multipath *mp)
 {
+	char *origin = NULL;
+	char buff[12];
+
 	if (mp->flush_on_last_del == FLUSH_IN_PROGRESS) {
 		condlog(0, "flush_on_last_del in progress");
 		mp->no_path_retry = NO_PATH_RETRY_FAIL;
 		return 0;
 	}
-	if (mp->mpe && mp->mpe->no_path_retry != NO_PATH_RETRY_UNDEF) {
-		mp->no_path_retry = mp->mpe->no_path_retry;
-		condlog(3, "%s: no_path_retry = %i (multipath setting)",
-			mp->alias, mp->no_path_retry);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->no_path_retry != NO_PATH_RETRY_UNDEF) {
-		mp->no_path_retry = mp->hwe->no_path_retry;
-		condlog(3, "%s: no_path_retry = %i (controller setting)",
-			mp->alias, mp->no_path_retry);
-		return 0;
-	}
-	if (conf->no_path_retry != NO_PATH_RETRY_UNDEF) {
-		mp->no_path_retry = conf->no_path_retry;
-		condlog(3, "%s: no_path_retry = %i (config file default)",
-			mp->alias, mp->no_path_retry);
-		return 0;
-	}
-	if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
-		condlog(3, "%s: no_path_retry = %i (inherited setting)",
-			mp->alias, mp->no_path_retry);
+	mp_set_mpe(no_path_retry);
+	mp_set_hwe(no_path_retry);
+	mp_set_conf(no_path_retry);
+out:
+	print_no_path_retry(buff, 12, &mp->no_path_retry);
+	if (origin)
+		condlog(3, "%s: no_path_retry = %s %s", mp->alias, buff,
+			origin);
+	else if (mp->no_path_retry != NO_PATH_RETRY_UNDEF)
+		condlog(3, "%s: no_path_retry = %s (inheritied setting)",
+			mp->alias, buff);
 	else
-		condlog(3, "%s: no_path_retry = %i (internal default)",
-			mp->alias, mp->no_path_retry);
+		condlog(3, "%s: no_path_retry = undef (internal default)",
+			mp->alias);
 	return 0;
 }
 
 int
 select_minio_rq (struct multipath * mp)
 {
-	if (mp->mpe && mp->mpe->minio_rq) {
-		mp->minio = mp->mpe->minio_rq;
-		condlog(3, "%s: minio = %i rq (LUN setting)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->minio_rq) {
-		mp->minio = mp->hwe->minio_rq;
-		condlog(3, "%s: minio = %i rq (controller setting)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	if (conf->minio) {
-		mp->minio = conf->minio_rq;
-		condlog(3, "%s: minio = %i rq (config file default)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	mp->minio = DEFAULT_MINIO_RQ;
-	condlog(3, "%s: minio = %i rq (internal default)",
-		mp->alias, mp->minio);
+	char *origin;
+
+	do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
+	do_set(minio_rq, mp->hwe, mp->minio, "(controller setting)");
+	do_set(minio_rq, conf, mp->minio, "(config file setting)");
+	do_default(mp->minio, DEFAULT_MINIO_RQ);
+out:
+	condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
 	return 0;
 }
 
 int
 select_minio_bio (struct multipath * mp)
 {
-	if (mp->mpe && mp->mpe->minio) {
-		mp->minio = mp->mpe->minio;
-		condlog(3, "%s: minio = %i (LUN setting)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->minio) {
-		mp->minio = mp->hwe->minio;
-		condlog(3, "%s: minio = %i (controller setting)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	if (conf->minio) {
-		mp->minio = conf->minio;
-		condlog(3, "%s: minio = %i (config file default)",
-			mp->alias, mp->minio);
-		return 0;
-	}
-	mp->minio = DEFAULT_MINIO;
-	condlog(3, "%s: minio = %i (internal default)",
-		mp->alias, mp->minio);
+	char *origin;
+
+	mp_set_mpe(minio);
+	mp_set_hwe(minio);
+	mp_set_conf(minio);
+	mp_set_default(minio, DEFAULT_MINIO);
+out:
+	condlog(3, "%s: minio = %i %s", mp->alias, mp->minio, origin);
 	return 0;
 }
 
@@ -572,164 +463,95 @@ select_minio (struct multipath * mp)
 extern int
 select_fast_io_fail(struct multipath *mp)
 {
-	if (mp->hwe && mp->hwe->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
-		mp->fast_io_fail = mp->hwe->fast_io_fail;
-		if (mp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
-			condlog(3, "%s: fast_io_fail_tmo = off "
-				"(controller setting)", mp->alias);
-		else
-			condlog(3, "%s: fast_io_fail_tmo = %d "
-				"(controller setting)", mp->alias,
-				mp->fast_io_fail == MP_FAST_IO_FAIL_ZERO ? 0 : mp->fast_io_fail);
-		return 0;
-	}
-	if (conf->fast_io_fail != MP_FAST_IO_FAIL_UNSET) {
-		mp->fast_io_fail = conf->fast_io_fail;
-		if (mp->fast_io_fail == MP_FAST_IO_FAIL_OFF)
-			condlog(3, "%s: fast_io_fail_tmo = off "
-				"(config file default)", mp->alias);
-		else
-			condlog(3, "%s: fast_io_fail_tmo = %d "
-				"(config file default)", mp->alias,
-				mp->fast_io_fail == MP_FAST_IO_FAIL_ZERO ? 0 : mp->fast_io_fail);
-		return 0;
-	}
-	mp->fast_io_fail = MP_FAST_IO_FAIL_UNSET;
+	char *origin, buff[12];
+
+	mp_set_hwe(fast_io_fail);
+	mp_set_conf(fast_io_fail);
+	mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
+out:
+	print_fast_io_fail(buff, 12, &mp->fast_io_fail);
+	condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin);
 	return 0;
 }
 
 extern int
 select_dev_loss(struct multipath *mp)
 {
-	if (mp->hwe && mp->hwe->dev_loss) {
-		mp->dev_loss = mp->hwe->dev_loss;
-		condlog(3, "%s: dev_loss_tmo = %u (controller default)",
-			mp->alias, mp->dev_loss);
-		return 0;
-	}
-	if (conf->dev_loss) {
-		mp->dev_loss = conf->dev_loss;
-		condlog(3, "%s: dev_loss_tmo = %u (config file default)",
-			mp->alias, mp->dev_loss);
-		return 0;
-	}
+	char *origin, buff[12];
+
+	mp_set_hwe(dev_loss);
+	mp_set_conf(dev_loss);
 	mp->dev_loss = 0;
 	return 0;
+out:
+	print_dev_loss(buff, 12, &mp->dev_loss);
+	condlog(3, "%s: dev_loss_tmo = %s %s", mp->alias, buff, origin);
+	return 0;
 }
 
 extern int
 select_flush_on_last_del(struct multipath *mp)
 {
+	char *origin;
+
 	if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
 		return 0;
-	if (mp->mpe && mp->mpe->flush_on_last_del != FLUSH_UNDEF) {
-		mp->flush_on_last_del = mp->mpe->flush_on_last_del;
-		condlog(3, "%s: flush_on_last_del = %i (multipath setting)",
-			mp->alias, mp->flush_on_last_del);
-		return 0;
-	}
-	if (mp->hwe && mp->hwe->flush_on_last_del != FLUSH_UNDEF) {
-		mp->flush_on_last_del = mp->hwe->flush_on_last_del;
-		condlog(3, "%s: flush_on_last_del = %i (controller setting)",
-			mp->alias, mp->flush_on_last_del);
-		return 0;
-	}
-	if (conf->flush_on_last_del != FLUSH_UNDEF) {
-		mp->flush_on_last_del = conf->flush_on_last_del;
-		condlog(3, "%s: flush_on_last_del = %i (config file default)",
-			mp->alias, mp->flush_on_last_del);
-		return 0;
-	}
-	mp->flush_on_last_del = FLUSH_UNDEF;
-	condlog(3, "%s: flush_on_last_del = DISABLED (internal default)",
-		mp->alias);
+	mp_set_mpe(flush_on_last_del);
+	mp_set_hwe(flush_on_last_del);
+	mp_set_conf(flush_on_last_del);
+	mp_set_default(flush_on_last_del, FLUSH_DISABLED);
+out:
+	condlog(3, "%s: flush_on_last_del = %s %s", mp->alias,
+		(mp->flush_on_last_del == FLUSH_ENABLED)? "yes" : "no", origin);
 	return 0;
 }
 
 extern int
 select_reservation_key (struct multipath * mp)
 {
-	int j;
-	unsigned char *keyp;
-	uint64_t prkey = 0;
+	char *origin, buff[12];
 
+	mp_set_mpe(reservation_key);
+	mp_set_conf(reservation_key);
 	mp->reservation_key = NULL;
-
-	if (mp->mpe && mp->mpe->reservation_key) {
-		keyp =  mp->mpe->reservation_key;
-		for (j = 0; j < 8; ++j) {
-			if (j > 0)
-				prkey <<= 8;
-			prkey |= *keyp;
-			++keyp;
-		}
-
-		condlog(3, "%s: reservation_key = 0x%" PRIx64 " "
-				"(multipath setting)",  mp->alias, prkey);
-
-		mp->reservation_key = mp->mpe->reservation_key;
-		return 0;
-	}
-
-	if (conf->reservation_key) {
-		keyp = conf->reservation_key;
-		for (j = 0; j < 8; ++j) {
-			if (j > 0)
-				prkey <<= 8;
-			prkey |= *keyp;
-			++keyp;
-		}
-
-		condlog(3, "%s: reservation_key  = 0x%" PRIx64
-				" (config file default)", mp->alias, prkey);
-
-		mp->reservation_key = conf->reservation_key;
-		return 0;
-	}
-
+	return 0;
+out:
+	print_reservation_key(buff, 12, &mp->reservation_key);
+	condlog(3, "%s: reservation_key = %s %s", mp->alias, buff, origin);
 	return 0;
 }
 
 extern int
 select_retain_hwhandler (struct multipath * mp)
 {
+	char *origin;
 	unsigned int minv_dm_retain[3] = {1, 5, 0};
 
 	if (!VERSION_GE(conf->version, minv_dm_retain)) {
 		mp->retain_hwhandler = RETAIN_HWHANDLER_OFF;
-		condlog(3, "%s: retain_attached_hw_handler disabled (requires kernel version >= 1.5.0)", mp->alias);
-		return 0;
-	}
-
-	if (mp->hwe && mp->hwe->retain_hwhandler) {
-		mp->retain_hwhandler = mp->hwe->retain_hwhandler;
-		condlog(3, "%s: retain_attached_hw_handler = %d (controller default)", mp->alias, mp->retain_hwhandler);
-		return 0;
-	}
-	if (conf->retain_hwhandler) {
-		mp->retain_hwhandler = conf->retain_hwhandler;
-		condlog(3, "%s: retain_attached_hw_handler = %d (config file default)", mp->alias, mp->retain_hwhandler);
-		return 0;
+		origin = "(requires kernel version >= 1.5.0)";
+		goto out;
 	}
-	mp->retain_hwhandler = 0;
-	condlog(3, "%s: retain_attached_hw_handler = %d (compiled in default)", mp->alias, mp->retain_hwhandler);
+	mp_set_hwe(retain_hwhandler);
+	mp_set_conf(retain_hwhandler);
+	mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
+out:
+	condlog(3, "%s: retain_attached_hw_handler = %s %s", mp->alias,
+		(mp->retain_hwhandler == RETAIN_HWHANDLER_ON)? "yes" : "no",
+		origin);
 	return 0;
 }
 
 extern int
 select_detect_prio (struct path * pp)
 {
-	if (pp->hwe && pp->hwe->detect_prio) {
-		pp->detect_prio = pp->hwe->detect_prio;
-		condlog(3, "%s: detect_prio = %d (controller default)", pp->dev, pp->detect_prio);
-		return 0;
-	}
-	if (conf->detect_prio) {
-		pp->detect_prio = conf->detect_prio;
-		condlog(3, "%s: detect_prio = %d (config file default)", pp->dev, pp->detect_prio);
-		return 0;
-	}
-	pp->detect_prio = 0;
-	condlog(3, "%s: detect_prio = %d (compiled in default)", pp->dev, pp->detect_prio);
+	char *origin;
+
+	pp_set_hwe(detect_prio);
+	pp_set_conf(detect_prio);
+	pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
+out:
+	condlog(3, "%s: detect_prio = %s %s", pp->dev,
+		(pp->detect_prio == DETECT_PRIO_ON)? "yes" : "no", origin);
 	return 0;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 1/6] libmultipath: rewrite dict.c with function generation macros Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 2/6] libmultipath: cleanup propsel.c with macros for common actions Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  2015-01-08 23:06   ` Christophe Varoqui
  2014-11-19  6:17 ` [PATCH 4/6] add find_multipaths option Benjamin Marzinski
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

Sometimes users want to be able to set a configuration value for all their
devices (for instance, they may want all devices to set no_path_retry to
fail). The builtin device configurations make this tricky, since users need
to change each device configuration individually. To avoid that, this patch
adds a new section to multipath.conf, "overrides".  This section has all of
the attributes that are in both the devices and defaults section.
Attributes set in the overrides section have a higher priority that those
in the devices section. With this section added, the multipath
configuration order now goes:

multipaths > overrides > devices > defaults

I also made want_user_friendly_names print out where the configuration came
from, and I made made select_hwhandler and select_selector always strdup
the string, instead of only on the defaults.  Since multipathd will update
the device strings from the kernel anyway, the old way just added
complexity without saving any memory.

To store the overrides configuration, I used a hwentry structure. We may
want to make a new overrides structure, so that we set any of the defaults
values in overrides.  That way, users could skip using defaults and just
use overrides if they wanted. However, this would take some additional
changes to make sure that all the defaults options can undefined, which
they can't currently be.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/config.c      |  1 +
 libmultipath/config.h      |  1 +
 libmultipath/dict.c        | 98 ++++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/print.c       | 30 ++++++++++++++
 libmultipath/print.h       |  1 +
 libmultipath/propsel.c     | 55 +++++++++++++++++++++-----
 libmultipath/structs.c     |  9 +----
 multipath.conf.annotated   | 18 ++++++++-
 multipath.conf.defaults    |  2 +
 multipath.conf.synthetic   |  3 ++
 multipath/main.c           |  6 +++
 multipath/multipath.conf.5 | 57 +++++++++++++++++++++++++++
 multipathd/cli_handlers.c  | 10 +++++
 13 files changed, 273 insertions(+), 18 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index bfd8ee8..7f7bd5a 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -523,6 +523,7 @@ free_config (struct config * conf)
 
 	free_mptable(conf->mptable);
 	free_hwtable(conf->hwtable);
+	free_hwe(conf->overrides);
 	free_keywords(conf->keywords);
 	FREE(conf);
 }
diff --git a/libmultipath/config.h b/libmultipath/config.h
index c57ab31..ef1d7c3 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -145,6 +145,7 @@ struct config {
 	vector keywords;
 	vector mptable;
 	vector hwtable;
+	struct hwentry *overrides;
 
 	vector blist_devnode;
 	vector blist_wwid;
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 98cbe48..737c9b0 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -181,6 +181,22 @@ snprint_hw_ ## option (char * buff, int len, void * data)		\
 	return function (buff, len, &hwe->option);			\
 }
 
+#define declare_ovr_handler(option, function)				\
+static int								\
+ovr_ ## option ## _handler (vector strvec)				\
+{									\
+	if (!conf->overrides)						\
+		return 1;						\
+	return function (strvec, &conf->overrides->option);		\
+}
+
+#define declare_ovr_snprint(option, function)				\
+static int								\
+snprint_ovr_ ## option (char * buff, int len, void * data)		\
+{									\
+	return function (buff, len, &conf->overrides->option);		\
+}
+
 #define declare_mp_handler(option, function)				\
 static int								\
 mp_ ## option ## _handler (vector strvec)				\
@@ -218,21 +234,29 @@ declare_def_handler(selector, set_str)
 declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
 declare_hw_handler(selector, set_str)
 declare_hw_snprint(selector, print_str)
+declare_ovr_handler(selector, set_str)
+declare_ovr_snprint(selector, print_str)
 declare_mp_handler(selector, set_str)
 declare_mp_snprint(selector, print_str)
 
 declare_def_handler(uid_attribute, set_str)
 declare_def_snprint_defstr(uid_attribute, print_str, DEFAULT_UID_ATTRIBUTE)
+declare_ovr_handler(uid_attribute, set_str)
+declare_ovr_snprint(uid_attribute, print_str)
 declare_hw_handler(uid_attribute, set_str)
 declare_hw_snprint(uid_attribute, print_str)
 
 declare_def_handler(getuid, set_str)
 declare_def_snprint(getuid, print_str)
+declare_ovr_handler(getuid, set_str)
+declare_ovr_snprint(getuid, print_str)
 declare_hw_handler(getuid, set_str)
 declare_hw_snprint(getuid, print_str)
 
 declare_def_handler(prio_name, set_str)
 declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
+declare_ovr_handler(prio_name, set_str)
+declare_ovr_snprint(prio_name, print_str)
 declare_hw_handler(prio_name, set_str)
 declare_hw_snprint(prio_name, print_str)
 declare_mp_handler(prio_name, set_str)
@@ -240,11 +264,15 @@ declare_mp_snprint(prio_name, print_str)
 
 declare_def_handler(alias_prefix, set_str)
 declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
+declare_ovr_handler(alias_prefix, set_str)
+declare_ovr_snprint(alias_prefix, print_str)
 declare_hw_handler(alias_prefix, set_str)
 declare_hw_snprint(alias_prefix, print_str)
 
 declare_def_handler(prio_args, set_str)
 declare_def_snprint_defstr(prio_args, print_str, DEFAULT_PRIO_ARGS)
+declare_ovr_handler(prio_args, set_str)
+declare_ovr_snprint(prio_args, print_str)
 declare_hw_handler(prio_args, set_str)
 declare_hw_snprint(prio_args, print_str)
 declare_mp_handler(prio_args, set_str)
@@ -252,6 +280,8 @@ declare_mp_snprint(prio_args, print_str)
 
 declare_def_handler(features, set_str)
 declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
+declare_ovr_handler(features, set_str)
+declare_ovr_snprint(features, print_str)
 declare_hw_handler(features, set_str)
 declare_hw_snprint(features, print_str)
 declare_mp_handler(features, set_str)
@@ -259,11 +289,15 @@ declare_mp_snprint(features, print_str)
 
 declare_def_handler(checker_name, set_str)
 declare_def_snprint_defstr(checker_name, print_str, DEFAULT_CHECKER)
+declare_ovr_handler(checker_name, set_str)
+declare_ovr_snprint(checker_name, print_str)
 declare_hw_handler(checker_name, set_str)
 declare_hw_snprint(checker_name, print_str)
 
 declare_def_handler(minio, set_int)
 declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
+declare_ovr_handler(minio, set_int)
+declare_ovr_snprint(minio, print_nonzero)
 declare_hw_handler(minio, set_int)
 declare_hw_snprint(minio, print_nonzero)
 declare_mp_handler(minio, set_int)
@@ -271,6 +305,8 @@ declare_mp_snprint(minio, print_nonzero)
 
 declare_def_handler(minio_rq, set_int)
 declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
+declare_ovr_handler(minio_rq, set_int)
+declare_ovr_snprint(minio_rq, print_nonzero)
 declare_hw_handler(minio_rq, set_int)
 declare_hw_snprint(minio_rq, print_nonzero)
 declare_mp_handler(minio_rq, set_int)
@@ -296,6 +332,8 @@ declare_def_snprint(checker_timeout, print_nonzero)
 
 declare_def_handler(flush_on_last_del, set_yes_no_undef)
 declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
+declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
 declare_hw_handler(flush_on_last_del, set_yes_no_undef)
 declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
 declare_mp_handler(flush_on_last_del, set_yes_no_undef)
@@ -303,6 +341,8 @@ declare_mp_snprint(flush_on_last_del, print_yes_no_undef)
 
 declare_def_handler(user_friendly_names, set_yes_no_undef)
 declare_def_snprint_defint(user_friendly_names, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(user_friendly_names, set_yes_no_undef)
+declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
 declare_hw_handler(user_friendly_names, set_yes_no_undef)
 declare_hw_snprint(user_friendly_names, print_yes_no_undef)
 declare_mp_handler(user_friendly_names, set_yes_no_undef)
@@ -316,11 +356,15 @@ declare_def_snprint(wwids_file, print_str)
 
 declare_def_handler(retain_hwhandler, set_yes_no_undef)
 declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
+declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
 declare_hw_handler(retain_hwhandler, set_yes_no_undef)
 declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
 
 declare_def_handler(detect_prio, set_yes_no_undef)
 declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
+declare_ovr_handler(detect_prio, set_yes_no_undef)
+declare_ovr_snprint(detect_prio, print_yes_no_undef)
 declare_hw_handler(detect_prio, set_yes_no_undef)
 declare_hw_snprint(detect_prio, print_yes_no_undef)
 
@@ -512,6 +556,8 @@ print_fast_io_fail(char * buff, int len, void *ptr)
 
 declare_def_handler(fast_io_fail, set_fast_io_fail)
 declare_def_snprint(fast_io_fail, print_fast_io_fail)
+declare_ovr_handler(fast_io_fail, set_fast_io_fail)
+declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
 declare_hw_handler(fast_io_fail, set_fast_io_fail)
 declare_hw_snprint(fast_io_fail, print_fast_io_fail)
 
@@ -548,6 +594,8 @@ print_dev_loss(char * buff, int len, void *ptr)
 
 declare_def_handler(dev_loss, set_dev_loss)
 declare_def_snprint(dev_loss, print_dev_loss)
+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)
 
@@ -583,6 +631,8 @@ print_pgpolicy(char * buff, int len, void *ptr)
 
 declare_def_handler(pgpolicy, set_pgpolicy)
 declare_def_snprint_defint(pgpolicy, print_pgpolicy, DEFAULT_PGPOLICY)
+declare_ovr_handler(pgpolicy, set_pgpolicy)
+declare_ovr_snprint(pgpolicy, print_pgpolicy)
 declare_hw_handler(pgpolicy, set_pgpolicy)
 declare_hw_snprint(pgpolicy, print_pgpolicy)
 declare_mp_handler(pgpolicy, set_pgpolicy)
@@ -700,6 +750,8 @@ print_rr_weight (char * buff, int len, void *ptr)
 
 declare_def_handler(rr_weight, set_rr_weight)
 declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
+declare_ovr_handler(rr_weight, set_rr_weight)
+declare_ovr_snprint(rr_weight, print_rr_weight)
 declare_hw_handler(rr_weight, set_rr_weight)
 declare_hw_snprint(rr_weight, print_rr_weight)
 declare_mp_handler(rr_weight, set_rr_weight)
@@ -748,6 +800,8 @@ print_pgfailback (char * buff, int len, void *ptr)
 
 declare_def_handler(pgfailback, set_pgfailback)
 declare_def_snprint_defint(pgfailback, print_pgfailback, DEFAULT_FAILBACK)
+declare_ovr_handler(pgfailback, set_pgfailback)
+declare_ovr_snprint(pgfailback, print_pgfailback)
 declare_hw_handler(pgfailback, set_pgfailback)
 declare_hw_snprint(pgfailback, print_pgfailback)
 declare_mp_handler(pgfailback, set_pgfailback)
@@ -793,6 +847,8 @@ print_no_path_retry(char * buff, int len, void *ptr)
 
 declare_def_handler(no_path_retry, set_no_path_retry)
 declare_def_snprint(no_path_retry, print_no_path_retry)
+declare_ovr_handler(no_path_retry, set_no_path_retry)
+declare_ovr_snprint(no_path_retry, print_no_path_retry)
 declare_hw_handler(no_path_retry, set_no_path_retry)
 declare_hw_snprint(no_path_retry, print_no_path_retry)
 declare_mp_handler(no_path_retry, set_no_path_retry)
@@ -1061,6 +1117,25 @@ declare_hw_handler(hwhandler, set_str)
 declare_hw_snprint(hwhandler, print_str)
 
 /*
+ * overrides handlers
+ */
+static int
+overrides_handler(vector strvec)
+{
+	struct hwentry * overrides;
+
+	overrides = alloc_hwe();
+
+	if (!overrides)
+		return 1;
+
+	conf->overrides = overrides;
+	return 0;
+}
+
+
+
+/*
  * multipaths block handlers
  */
 static int
@@ -1236,6 +1311,29 @@ init_keywords(void)
 	install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_hw_detect_prio);
 	install_sublevel_end();
 
+	install_keyword_root("overrides", &overrides_handler);
+	install_keyword("path_grouping_policy", &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy);
+	install_keyword("uid_attribute", &ovr_uid_attribute_handler, &snprint_ovr_uid_attribute);
+	install_keyword("getuid_callout", &ovr_getuid_handler, &snprint_ovr_getuid);
+	install_keyword("path_selector", &ovr_selector_handler, &snprint_ovr_selector);
+	install_keyword("path_checker", &ovr_checker_name_handler, &snprint_ovr_checker_name);
+	install_keyword("checker", &ovr_checker_name_handler, NULL);
+	install_keyword("alias_prefix", &ovr_alias_prefix_handler, &snprint_ovr_alias_prefix);
+	install_keyword("features", &ovr_features_handler, &snprint_ovr_features);
+	install_keyword("prio", &ovr_prio_name_handler, &snprint_ovr_prio_name);
+	install_keyword("prio_args", &ovr_prio_args_handler, &snprint_ovr_prio_args);
+	install_keyword("failback", &ovr_pgfailback_handler, &snprint_ovr_pgfailback);
+	install_keyword("rr_weight", &ovr_rr_weight_handler, &snprint_ovr_rr_weight);
+	install_keyword("no_path_retry", &ovr_no_path_retry_handler, &snprint_ovr_no_path_retry);
+	install_keyword("rr_min_io", &ovr_minio_handler, &snprint_ovr_minio);
+	install_keyword("rr_min_io_rq", &ovr_minio_rq_handler, &snprint_ovr_minio_rq);
+	install_keyword("flush_on_last_del", &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
+	install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail);
+	install_keyword("dev_loss_tmo", &ovr_dev_loss_handler, &snprint_ovr_dev_loss);
+	install_keyword("user_friendly_names", &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
+	install_keyword("retain_attached_hw_handler", &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
+	install_keyword("detect_prio", &ovr_detect_prio_handler, &snprint_ovr_detect_prio);
+
 	install_keyword_root("multipaths", &multipaths_handler);
 	install_keyword_multi("multipath", &multipath_handler, NULL);
 	install_sublevel();
diff --git a/libmultipath/print.c b/libmultipath/print.c
index 383eae4..ade3841 100644
--- a/libmultipath/print.c
+++ b/libmultipath/print.c
@@ -1080,6 +1080,36 @@ snprint_mptable (char * buff, int len, vector mptable)
 }
 
 extern int
+snprint_overrides (char * buff, int len, struct hwentry *overrides)
+{
+	int fwd = 0;
+	int i;
+	struct keyword *rootkw;
+	struct keyword *kw;
+
+	rootkw = find_keyword(NULL, "overrides");
+	if (!rootkw)
+		return 0;
+
+	fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
+	if (fwd > len)
+		return len;
+	if (!overrides)
+		goto out;
+	iterate_sub_keywords(rootkw, kw, i) {
+		fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+				       kw, NULL);
+		if (fwd > len)
+			return len;
+	}
+out:
+	fwd += snprintf(buff + fwd, len - fwd, "}\n");
+	if (fwd > len)
+		return len;
+	return fwd;
+}
+
+extern int
 snprint_defaults (char * buff, int len)
 {
 	int fwd = 0;
diff --git a/libmultipath/print.h b/libmultipath/print.h
index aef182b..a3c3319 100644
--- a/libmultipath/print.h
+++ b/libmultipath/print.h
@@ -50,6 +50,7 @@ int snprint_status (char *, int, struct vectors *);
 int snprint_devices (char *, int, struct vectors *);
 int snprint_hwtable (char *, int, vector);
 int snprint_mptable (char *, int, vector);
+int snprint_overrides (char *, int, struct hwentry *);
 
 void print_multipath_topology (struct multipath * mpp, int verbosity);
 void print_path (struct path * pp, char * style);
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
index f2ab7d2..440802c 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -48,6 +48,8 @@ do {									\
 do_set(var, mp->mpe, mp->var, "(LUN setting)")
 #define mp_set_hwe(var)							\
 do_set(var, mp->hwe, mp->var, "(controller setting)")
+#define mp_set_ovr(var)							\
+do_set(var, conf->overrides, mp->var, "(overrides setting)")
 #define mp_set_conf(var)						\
 do_set(var, conf, mp->var, "(config file default)")
 #define mp_set_default(var, value)					\
@@ -59,6 +61,8 @@ do_set(var, mpe, pp->var, "(LUN setting)")
 do_set(var, pp->hwe, pp->var, "(controller setting)")
 #define pp_set_conf(var)						\
 do_set(var, conf, pp->var, "(config file default)")
+#define pp_set_ovr(var)							\
+do_set(var, conf->overrides, pp->var, "(overrides setting)")
 #define pp_set_default(var, value)					\
 do_default(pp->var, value)
 
@@ -130,6 +134,7 @@ select_rr_weight (struct multipath * mp)
 	char *origin, buff[13];
 
 	mp_set_mpe(rr_weight);
+	mp_set_ovr(rr_weight);
 	mp_set_hwe(rr_weight);
 	mp_set_conf(rr_weight);
 	mp_set_default(rr_weight, RR_WEIGHT_NONE);
@@ -145,6 +150,7 @@ select_pgfailback (struct multipath * mp)
 	char *origin, buff[13];
 
 	mp_set_mpe(pgfailback);
+	mp_set_ovr(pgfailback);
 	mp_set_hwe(pgfailback);
 	mp_set_conf(pgfailback);
 	mp_set_default(pgfailback, DEFAULT_FAILBACK);
@@ -165,6 +171,7 @@ select_pgpolicy (struct multipath * mp)
 		goto out;
 	}
 	mp_set_mpe(pgpolicy);
+	mp_set_ovr(pgpolicy);
 	mp_set_hwe(pgpolicy);
 	mp_set_conf(pgpolicy);
 	mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
@@ -181,10 +188,12 @@ select_selector (struct multipath * mp)
 	char *origin;
 
 	mp_set_mpe(selector);
+	mp_set_ovr(selector);
 	mp_set_hwe(selector);
 	mp_set_conf(selector);
-	mp_set_default(selector, set_default(DEFAULT_SELECTOR));
+	mp_set_default(selector, DEFAULT_SELECTOR);
 out:
+	mp->selector = STRDUP(mp->selector);
 	condlog(3, "%s: path_selector = \"%s\" %s", mp->alias, mp->selector,
 		origin);
 	return 0;
@@ -195,6 +204,7 @@ select_alias_prefix (struct multipath * mp)
 {
 	char *origin;
 
+	mp_set_ovr(alias_prefix);
 	mp_set_hwe(alias_prefix);
 	mp_set_conf(alias_prefix);
 	mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
@@ -206,19 +216,30 @@ out:
 static int
 want_user_friendly_names(struct multipath * mp)
 {
-	if (mp->mpe &&
-	    mp->mpe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
-		return (mp->mpe->user_friendly_names == USER_FRIENDLY_NAMES_ON);
-	if (mp->hwe &&
-	    mp->hwe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
-		return (mp->hwe->user_friendly_names == USER_FRIENDLY_NAMES_ON);
-	return (conf->user_friendly_names  == USER_FRIENDLY_NAMES_ON);
+
+	char *origin;
+	int user_friendly_names;
+
+	do_set(user_friendly_names, mp->mpe, user_friendly_names,
+	       "(LUN setting)");
+	do_set(user_friendly_names, conf->overrides, user_friendly_names,
+	       "(overrides setting)");
+	do_set(user_friendly_names, mp->hwe, user_friendly_names,
+	       "(controller setting)");
+	do_set(user_friendly_names, conf, user_friendly_names,
+	       "(config file setting)");
+	do_default(user_friendly_names, USER_FRIENDLY_NAMES_OFF);
+out:
+	condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
+		(user_friendly_names == USER_FRIENDLY_NAMES_ON)? "yes" : "no",
+		origin);
+	return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
 }
 
 extern int
 select_alias (struct multipath * mp)
 {
-	char *origin;
+	char *origin = NULL;
 
 	if (mp->mpe && mp->mpe->alias) {
 		mp->alias = STRDUP(mp->mpe->alias);
@@ -261,6 +282,7 @@ select_features (struct multipath * mp)
 	char *origin;
 
 	mp_set_mpe(features);
+	mp_set_ovr(features);
 	mp_set_hwe(features);
 	mp_set_conf(features);
 	mp_set_default(features, DEFAULT_FEATURES);
@@ -287,8 +309,9 @@ select_hwhandler (struct multipath * mp)
 
 	mp_set_hwe(hwhandler);
 	mp_set_conf(hwhandler);
-	mp_set_default(hwhandler, set_default(DEFAULT_HWHANDLER));
+	mp_set_default(hwhandler, DEFAULT_HWHANDLER);
 out:
+	mp->hwhandler = STRDUP(mp->hwhandler);
 	condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias, mp->hwhandler,
 		origin);
 	return 0;
@@ -300,6 +323,7 @@ select_checker(struct path *pp)
 	char *origin, *checker_name;
 	struct checker * c = &pp->checker;
 
+	do_set(checker_name, conf->overrides, checker_name, "(overrides setting)");
 	do_set(checker_name, pp->hwe, checker_name, "(controller setting)");
 	do_set(checker_name, conf, checker_name, "(config file setting)");
 	do_default(checker_name, DEFAULT_CHECKER);
@@ -327,6 +351,8 @@ select_getuid (struct path * pp)
 {
 	char *origin;
 
+	pp_set_ovr(uid_attribute);
+	pp_set_ovr(getuid);
 	pp_set_hwe(uid_attribute);
 	pp_set_hwe(getuid);
 	pp_set_conf(uid_attribute);
@@ -383,6 +409,7 @@ select_prio (struct path * pp)
 	}
 	mpe = find_mpe(pp->wwid);
 	set_prio(mpe, "(LUN setting)");
+	set_prio(conf->overrides, "(overrides setting)");
 	set_prio(pp->hwe, "controller setting)");
 	set_prio(conf, "(config file default)");
 	prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
@@ -405,6 +432,7 @@ select_no_path_retry(struct multipath *mp)
 		return 0;
 	}
 	mp_set_mpe(no_path_retry);
+	mp_set_ovr(no_path_retry);
 	mp_set_hwe(no_path_retry);
 	mp_set_conf(no_path_retry);
 out:
@@ -427,6 +455,7 @@ select_minio_rq (struct multipath * mp)
 	char *origin;
 
 	do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
+	do_set(minio_rq, conf->overrides, mp->minio, "(overrides setting)");
 	do_set(minio_rq, mp->hwe, mp->minio, "(controller setting)");
 	do_set(minio_rq, conf, mp->minio, "(config file setting)");
 	do_default(mp->minio, DEFAULT_MINIO_RQ);
@@ -441,6 +470,7 @@ select_minio_bio (struct multipath * mp)
 	char *origin;
 
 	mp_set_mpe(minio);
+	mp_set_ovr(minio);
 	mp_set_hwe(minio);
 	mp_set_conf(minio);
 	mp_set_default(minio, DEFAULT_MINIO);
@@ -465,6 +495,7 @@ select_fast_io_fail(struct multipath *mp)
 {
 	char *origin, buff[12];
 
+	mp_set_ovr(fast_io_fail);
 	mp_set_hwe(fast_io_fail);
 	mp_set_conf(fast_io_fail);
 	mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
@@ -479,6 +510,7 @@ select_dev_loss(struct multipath *mp)
 {
 	char *origin, buff[12];
 
+	mp_set_ovr(dev_loss);
 	mp_set_hwe(dev_loss);
 	mp_set_conf(dev_loss);
 	mp->dev_loss = 0;
@@ -497,6 +529,7 @@ select_flush_on_last_del(struct multipath *mp)
 	if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
 		return 0;
 	mp_set_mpe(flush_on_last_del);
+	mp_set_ovr(flush_on_last_del);
 	mp_set_hwe(flush_on_last_del);
 	mp_set_conf(flush_on_last_del);
 	mp_set_default(flush_on_last_del, FLUSH_DISABLED);
@@ -532,6 +565,7 @@ select_retain_hwhandler (struct multipath * mp)
 		origin = "(requires kernel version >= 1.5.0)";
 		goto out;
 	}
+	mp_set_ovr(retain_hwhandler);
 	mp_set_hwe(retain_hwhandler);
 	mp_set_conf(retain_hwhandler);
 	mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
@@ -547,6 +581,7 @@ select_detect_prio (struct path * pp)
 {
 	char *origin;
 
+	pp_set_ovr(detect_prio);
 	pp_set_hwe(detect_prio);
 	pp_set_conf(detect_prio);
 	pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
index 30d247d..0538327 100644
--- a/libmultipath/structs.c
+++ b/libmultipath/structs.c
@@ -206,10 +206,7 @@ free_multipath_attributes (struct multipath * mpp)
 	if (!mpp)
 		return;
 
-	if (mpp->selector &&
-	    mpp->selector != conf->selector &&
-	    (!mpp->mpe || (mpp->mpe && mpp->selector != mpp->mpe->selector)) &&
-	    (!mpp->hwe || (mpp->hwe && mpp->selector != mpp->hwe->selector))) {
+	if (mpp->selector) {
 		FREE(mpp->selector);
 		mpp->selector = NULL;
 	}
@@ -219,9 +216,7 @@ free_multipath_attributes (struct multipath * mpp)
 		mpp->features = NULL;
 	}
 
-	if (mpp->hwhandler &&
-	    mpp->hwhandler != conf->hwhandler &&
-	    (!mpp->hwe || (mpp->hwe && mpp->hwhandler != mpp->hwe->hwhandler))) {
+	if (mpp->hwhandler) {
 		FREE(mpp->hwhandler);
 		mpp->hwhandler = NULL;
 	}
diff --git a/multipath.conf.annotated b/multipath.conf.annotated
index 0af1d4c..71afc0a 100644
--- a/multipath.conf.annotated
+++ b/multipath.conf.annotated
@@ -485,7 +485,8 @@
 ## scope : multipath & multipathd
 ## desc  : list of per storage controller settings
 ##	  overrides default settings (device_maps block)
-##         overriden by per multipath settings (multipaths block)
+##        overriden by per multipath settings (multipaths block)
+##	  and the overrides settings (overrides block)
 ##
 #devices {
 #	#
@@ -651,3 +652,18 @@
 #		rr_weight		priorities
 #	}
 #}
+#
+##
+## name  : devices
+## scope : multipath & multipathd
+## desc  : list of settings to override all hadware settings for all devices
+##	  overrides default settings (device_maps block)
+##	  and per device type settings (devices block)
+##        overriden by per multipath settings (multipaths block)
+##
+#	attributes and values are identical to the device block
+#
+#overrides {
+#	dev_loss_tmo		60
+#	no_path_retry		fail
+#}
diff --git a/multipath.conf.defaults b/multipath.conf.defaults
index 654be97..1c65e02 100644
--- a/multipath.conf.defaults
+++ b/multipath.conf.defaults
@@ -912,3 +912,5 @@
 #}
 #multipaths {
 #}
+#overrides {
+#}
diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
index bda1b75..f7b9b8a 100644
--- a/multipath.conf.synthetic
+++ b/multipath.conf.synthetic
@@ -72,3 +72,6 @@
 #		path_grouping_policy	multibus
 #	}
 #}
+#overrides {
+#	no_path_retry			fail
+#}
diff --git a/multipath/main.c b/multipath/main.c
index fd6262f..ea453b4 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -405,6 +405,12 @@ dump_config (void)
 			reply = REALLOC(reply, maxlen *= 2);
 			continue;
 		}
+		c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
+		again = ((c - reply) == maxlen);
+		if (again) {
+			reply = REALLOC(reply, maxlen *= 2);
+			continue;
+		}
 		c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
 		again = ((c - reply) == maxlen);
 		if (again)
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index cadb34d..b823990 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -61,6 +61,10 @@ the udev attribute given by the
 .TP
 .B devices
 This section defines the device-specific settings.
+.TP
+.B overrides
+This section defines values for attributes that should override the
+device-specific settings for all devices.
 .RE
 .LP
 .SH "defaults section"
@@ -629,6 +633,59 @@ section:
 .RE
 .PD
 .LP
+.SH "overrides section"
+The overrides section recognizes the following optional attributes; if not set
+the values are taken from the
+.I devices
+or
+.I defaults
+sections:
+.sp 1
+.PD .1v
+.RS
+.TP 18
+.B path_grouping_policy
+.TP
+.B uid_attribute
+.TP
+.B getuid_callout
+.TP
+.B path_selector
+.TP
+.B path_checker
+.TP
+.B alias_prefix
+.TP
+.B features
+.TP
+.B prio
+.TP
+.B prio_args
+.TP
+.B failback
+.TP
+.B rr_weight
+.TP
+.B no_path_retry
+.TP
+.B rr_min_io
+.TP
+.B rr_min_io_rq
+.TP
+.B flush_on_last_del
+.TP
+.B fast_io_fail_tmo
+.TP
+.B dev_loss_tmo
+.TP
+.B user_friendly_names
+.TP
+.B retain_attached_hw_handler
+.TP
+.B detect_prio
+.RE
+.PD
+.LP
 .SH "KNOWN ISSUES"
 The usage of
 .B queue_if_no_path
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index b086340..0ce1408 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -190,6 +190,16 @@ show_config (char ** r, int * len)
 			maxlen *= 2;
 			continue;
 		}
+		c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
+		again = ((c - reply) == maxlen);
+		if (again) {
+			reply = REALLOC(reply, maxlen * 2);
+			if (!reply)
+				return 1;
+			memset(reply + maxlen, 0, maxlen);
+			maxlen *= 2;
+			continue;
+		}
 		c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
 		again = ((c - reply) == maxlen);
 		REALLOC_REPLY(reply, again, maxlen);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/6] add find_multipaths option
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
                   ` (2 preceding siblings ...)
  2014-11-19  6:17 ` [PATCH 3/6] libmultipath: add overrides section to multipath.conf Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 5/6] correctly set partition delimiter on rename Benjamin Marzinski
  2014-11-19  6:17 ` [PATCH 6/6] libmultipath: only add uninitialized paths in check_path Benjamin Marzinski
  5 siblings, 0 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

This patch adds a new option (find_multipaths) to the defaults section
of multipath.conf.  This is used to keep multipath from simply creating
multipath devices on top of any non-blacklisted device.  When this is
set to "yes", multipath will only create multipath devices when there
are actually multiple paths to the storage.  This means that in most
setups where find_multipaths is set, users don't need to bother with the
editting the blacklist, because multipath will do the work for them.
The only case where blacklisting is still necessary is if user want to
disable multipathing on LUNs that actually have multiple paths.

One of the issues with only grabbing devices with multiple paths is that
multipath can't know when it first sees a path device whether a second
path device will appear. This could be a problem, because if multipath
doesn't claim the device, something else might. For instance, a
filesystem could be automounted on a path device before the second path
device appeared.

Multipath deals with this by using the /etc/multipaths/wwids file.  If
the device wwid is listed in this file, multipath knows that it is a
path device, and can create a multipath device on it as soon as it
appears.  This means that after multipath has created a multipath device
once, it will automatically create it in the future as soon as the first
path is discovered.

In general, there are three conditions for find_multipaths to allow the
creation of a device. After passing all the checks that multipath
currently does to allow device creation, one of these three conditions
must also be true for device creation, if find_multipaths is enabled.

1. There are at least two non-blacklisted paths with the same wwid
2. The creation was manually forced, by specifying the device with the
   multipath command
3. The path's wwid is in the wwids file, which means that multipath has
   previously created a multipath device with that wwid.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/config.c    |  1 +
 libmultipath/config.h    |  1 +
 libmultipath/configure.c | 11 +++++++++++
 libmultipath/defaults.h  |  1 +
 libmultipath/dict.c      |  4 ++++
 libmultipath/wwids.c     | 26 ++++++++++++++++++++++++++
 libmultipath/wwids.h     |  1 +
 multipath/main.c         | 27 +++++++++++++++++++++++++--
 multipathd/main.c        |  6 ++++++
 9 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 7f7bd5a..3c72b59 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -563,6 +563,7 @@ load_config (char * file, struct udev *udev)
 	conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
 	conf->detect_prio = DEFAULT_DETECT_PRIO;
 	conf->force_sync = 0;
+	conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
 
 	/*
 	 * preload default hwtable
diff --git a/libmultipath/config.h b/libmultipath/config.h
index ef1d7c3..801387c 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -116,6 +116,7 @@ struct config {
 	unsigned int dev_loss;
 	int log_checker_err;
 	int allow_queueing;
+	int find_multipaths;
 	uid_t uid;
 	gid_t gid;
 	mode_t mode;
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 1068a0a..2a7ef55 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -740,6 +740,10 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
 
 	memset(empty_buff, 0, WWID_SIZE);
 
+	/* ignore refwwid if it's empty */
+	if (refwwid && !strlen(refwwid))
+		refwwid = NULL;
+
 	if (force_reload) {
 		vector_foreach_slot (pathvec, pp1, k) {
 			pp1->mpp = NULL;
@@ -769,6 +773,13 @@ coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid, int force_r
 		if (refwwid && strncmp(pp1->wwid, refwwid, WWID_SIZE))
 			continue;
 
+		/* If find_multipaths was selected check if the path is valid */
+		if (conf->find_multipaths && !refwwid &&
+		    !should_multipath(pp1, pathvec)) {
+			orphan_path(pp1, "only one path");
+			continue;
+		}
+
 		/*
 		 * at this point, we know we really got a new mp
 		 */
diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h
index 99cf4b1..de6cec6 100644
--- a/libmultipath/defaults.h
+++ b/libmultipath/defaults.h
@@ -13,6 +13,7 @@
 #define DEFAULT_NO_PATH_RETRY  NO_PATH_RETRY_UNDEF
 #define DEFAULT_VERBOSITY	2
 #define DEFAULT_REASSIGN_MAPS	1
+#define DEFAULT_FIND_MULTIPATHS	0
 #define DEFAULT_FAST_IO_FAIL	5
 #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
 #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index 737c9b0..d1e2e96 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -230,6 +230,9 @@ declare_def_snprint(reassign_maps, print_yes_no)
 declare_def_handler(multipath_dir, set_str)
 declare_def_snprint(multipath_dir, print_str)
 
+declare_def_handler(find_multipaths, set_yes_no)
+declare_def_snprint(find_multipaths, print_yes_no)
+
 declare_def_handler(selector, set_str)
 declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
 declare_hw_handler(selector, set_str)
@@ -1242,6 +1245,7 @@ init_keywords(void)
 	install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler);
 	install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
 	install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
+	install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths);
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c
index eca1799..f6f8ea8 100644
--- a/libmultipath/wwids.c
+++ b/libmultipath/wwids.c
@@ -261,6 +261,32 @@ out:
 }
 
 int
+should_multipath(struct path *pp1, vector pathvec)
+{
+	int i;
+	struct path *pp2;
+
+	condlog(4, "checking if %s should be multipathed", pp1->dev);
+	vector_foreach_slot(pathvec, pp2, i) {
+		if (pp1->dev == pp2->dev)
+			continue;
+		if (strncmp(pp1->wwid, pp2->wwid, WWID_SIZE) == 0) {
+			condlog(3, "found multiple paths with wwid %s, "
+				"multipathing %s", pp1->wwid, pp1->dev);
+			return 1;
+		}
+	}
+	if (check_wwids_file(pp1->wwid, 0) < 0) {
+		condlog(3, "wwid %s not in wwids file, skipping %s",
+			pp1->wwid, pp1->dev);
+		return 0;
+	}
+	condlog(3, "found wwid %s in wwids file, multipathing %s", pp1->wwid,
+		pp1->dev);
+	return 1;
+}
+
+int
 remember_wwid(char *wwid)
 {
 	int ret = check_wwids_file(wwid, 1);
diff --git a/libmultipath/wwids.h b/libmultipath/wwids.h
index f3b21fa..9527012 100644
--- a/libmultipath/wwids.h
+++ b/libmultipath/wwids.h
@@ -12,6 +12,7 @@
 "#\n" \
 "# Valid WWIDs:\n"
 
+int should_multipath(struct path *pp, vector pathvec);
 int remember_wwid(char *wwid);
 int check_wwids_file(char *wwid, int write_wwid);
 int remove_wwid(char *wwid);
diff --git a/multipath/main.c b/multipath/main.c
index ea453b4..d085f64 100644
--- a/multipath/main.c
+++ b/multipath/main.c
@@ -197,6 +197,9 @@ get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
 			continue;
 		}
 
+		if (conf->cmd == CMD_VALID_PATH)
+			continue;
+
 		dm_get_map(mpp->alias, &mpp->size, params);
 		condlog(3, "params = %s", params);
 		dm_get_status(mpp->alias, status);
@@ -307,7 +310,13 @@ configure (void)
 			goto out;
 		}
 		condlog(3, "scope limited to %s", refwwid);
-		if (conf->cmd == CMD_VALID_PATH) {
+		/* If you are ignoring the wwids file and find_multipaths is
+		 * set, you need to actually check if there are two available
+		 * paths to determine if this path should be multipathed. To
+		 * do this, we put off the check until after discovering all
+		 * the paths */
+		if (conf->cmd == CMD_VALID_PATH &&
+		    (!conf->find_multipaths || !conf->ignore_wwids)) {
 			if (conf->ignore_wwids ||
 			    check_wwids_file(refwwid, 0) == 0)
 				r = 0;
@@ -347,6 +356,20 @@ configure (void)
 
 	filter_pathvec(pathvec, refwwid);
 
+
+	if (conf->cmd == CMD_VALID_PATH) {
+		/* This only happens if find_multipaths is and
+		 * ignore_wwids is set.
+		 * If there is currently a multipath device matching
+		 * the refwwid, or there is more than one path matching
+		 * the refwwid, then the path is valid */
+		if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
+			r = 0;
+		printf("%s %s a valid multipath device path\n",
+		       conf->dev, r == 0 ? "is" : "is not");
+		goto out;
+	}
+
 	if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
 		r = 0;
 		goto out;
@@ -355,7 +378,7 @@ configure (void)
 	/*
 	 * core logic entry point
 	 */
-	r = coalesce_paths(&vecs, NULL, NULL, conf->force_reload);
+	r = coalesce_paths(&vecs, NULL, refwwid, conf->force_reload);
 
 out:
 	if (refwwid)
diff --git a/multipathd/main.c b/multipathd/main.c
index 3afed62..e697897 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -54,6 +54,7 @@
 #include <print.h>
 #include <configure.h>
 #include <prio.h>
+#include <wwids.h>
 #include <pgpolicies.h>
 #include <uevent.h>
 #include <log.h>
@@ -496,6 +497,11 @@ rescan:
 			return 1;
 		}
 
+		if (conf->find_multipaths &&
+		    !should_multipath(pp, vecs->pathvec)) {
+			orphan_path(pp, "only one path");
+			return 0;
+		}
 		condlog(4,"%s: creating new map", pp->dev);
 		if ((mpp = add_map_with_path(vecs, pp, 1))) {
 			mpp->action = ACT_CREATE;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/6] correctly set partition delimiter on rename
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
                   ` (3 preceding siblings ...)
  2014-11-19  6:17 ` [PATCH 4/6] add find_multipaths option Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  2015-01-08 22:51   ` Christophe Varoqui
  2014-11-19  6:17 ` [PATCH 6/6] libmultipath: only add uninitialized paths in check_path Benjamin Marzinski
  5 siblings, 1 reply; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

When multipath renames a device and the name switches from ending in a
number to ending in a letter or vice versa, it currently just keeps any
existing delimiter between the device name and partition number.
However the default behaviour in kpartx is to only use the 'p' delimiter
when the name ends in a number. Unfortunately, without adding a
kpartx.conf that kpartx uses to set the delimiter behavior, there's no
way for multipath to know how kpartx was run for certain device names
(ones ending in a number with a 'p' delimiter).

The patch adds a new multipath.conf defaults parameter,
"partition_delimiter". If this value is not set, when multipath renames
a device, it will act just like the kpartx default does, only adding a
'p' to names ending in a number.  If this parameter is set, multipath
will act like kpartx does with the -p option is used, and always add
delimiter.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/config.c    |  3 +++
 libmultipath/config.h    |  1 +
 libmultipath/devmapper.c | 14 ++++++++++++--
 libmultipath/dict.c      |  4 ++++
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 3c72b59..701e177 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -502,6 +502,8 @@ free_config (struct config * conf)
 
 	if (conf->alias_prefix)
 		FREE(conf->alias_prefix);
+	if (conf->partition_delim)
+		FREE(conf->partition_delim);
 
 	if (conf->prio_args)
 		FREE(conf->prio_args);
@@ -564,6 +566,7 @@ load_config (char * file, struct udev *udev)
 	conf->detect_prio = DEFAULT_DETECT_PRIO;
 	conf->force_sync = 0;
 	conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
+	conf->partition_delim = NULL;
 
 	/*
 	 * preload default hwtable
diff --git a/libmultipath/config.h b/libmultipath/config.h
index 801387c..a6205ee 100644
--- a/libmultipath/config.h
+++ b/libmultipath/config.h
@@ -141,6 +141,7 @@ struct config {
 	char * prio_args;
 	char * checker_name;
 	char * alias_prefix;
+	char * partition_delim;
 	unsigned char * reservation_key;
 
 	vector keywords;
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 3d4c111..9e585f9 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -1142,6 +1142,8 @@ dm_rename_partmaps (char * old, char * new)
 	unsigned long long size;
 	char dev_t[32];
 	int r = 1;
+	int offset;
+	char *delim;
 
 	if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
 		return 1;
@@ -1162,6 +1164,13 @@ dm_rename_partmaps (char * old, char * new)
 	if (dm_dev_t(old, &dev_t[0], 32))
 		goto out;
 
+	if (conf->partition_delim)
+		delim = conf->partition_delim;
+	if (isdigit(new[strlen(new)-1]))
+		delim = "p";
+	else
+		delim = "";
+
 	do {
 		if (
 		    /*
@@ -1189,8 +1198,9 @@ dm_rename_partmaps (char * old, char * new)
 				 * then it's a kpartx generated partition.
 				 * Rename it.
 				 */
-				snprintf(buff, PARAMS_SIZE, "%s%s",
-					 new, names->name + strlen(old));
+				for (offset = strlen(old); names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do nothing */
+				snprintf(buff, PARAMS_SIZE, "%s%s%s",
+					 new, delim, names->name + offset);
 				dm_rename(names->name, buff);
 				condlog(4, "partition map %s renamed",
 					names->name);
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
index d1e2e96..f95f30c 100644
--- a/libmultipath/dict.c
+++ b/libmultipath/dict.c
@@ -233,6 +233,9 @@ declare_def_snprint(multipath_dir, print_str)
 declare_def_handler(find_multipaths, set_yes_no)
 declare_def_snprint(find_multipaths, print_yes_no)
 
+declare_def_handler(partition_delim, set_str)
+declare_def_snprint(partition_delim, print_str)
+
 declare_def_handler(selector, set_str)
 declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
 declare_hw_handler(selector, set_str)
@@ -1246,6 +1249,7 @@ init_keywords(void)
 	install_keyword("detect_prio", &def_detect_prio_handler, &snprint_def_detect_prio);
 	install_keyword("force_sync", &def_force_sync_handler, &snprint_def_force_sync);
 	install_keyword("find_multipaths", &def_find_multipaths_handler, &snprint_def_find_multipaths);
+	install_keyword("partition_delimiter", &def_partition_delim_handler, &snprint_def_partition_delim);
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/6] libmultipath: only add uninitialized paths in check_path
  2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
                   ` (4 preceding siblings ...)
  2014-11-19  6:17 ` [PATCH 5/6] correctly set partition delimiter on rename Benjamin Marzinski
@ 2014-11-19  6:17 ` Benjamin Marzinski
  5 siblings, 0 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2014-11-19  6:17 UTC (permalink / raw)
  To: device-mapper development; +Cc: Christophe Varoqui

With find_multipaths enabled, there can be non-blacklisted paths that
are not supposed to be part of any multipath device. To make sure that
check_path doesn't keep checking them, this patch marks paths which are
fully initialized. Only uninitialized paths are checked, if they don't
belong to a multipath device.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/discovery.c | 2 ++
 libmultipath/structs.h   | 1 +
 multipathd/main.c        | 3 +++
 3 files changed, 6 insertions(+)

diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index af2aa20..91eab74 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -1250,6 +1250,7 @@ pathinfo (struct path *pp, vector hwtable, int mask)
 		}
 	}
 
+	pp->initialized = 1;
 	return 0;
 
 blank:
@@ -1258,6 +1259,7 @@ blank:
 	 */
 	memset(pp->wwid, 0, WWID_SIZE);
 	pp->chkrstate = pp->state = PATH_DOWN;
+	pp->initialized = 0;
 
 	return 0;
 }
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
index 15e7e19..abd1c29 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -186,6 +186,7 @@ struct path {
 	struct checker checker;
 	struct multipath * mpp;
 	int fd;
+	int initialized;
 
 	/* configlet pointers */
 	struct hwentry * hwe;
diff --git a/multipathd/main.c b/multipathd/main.c
index e697897..5da31bb 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1124,6 +1124,9 @@ check_path (struct vectors * vecs, struct path * pp)
 	int chkr_new_path_up = 0;
 	int oldchkrstate = pp->chkrstate;
 
+	if (pp->initialized && !pp->mpp)
+		return 0;
+
 	if (pp->tick && --pp->tick)
 		return 0; /* don't check this path yet */
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/6] correctly set partition delimiter on rename
  2014-11-19  6:17 ` [PATCH 5/6] correctly set partition delimiter on rename Benjamin Marzinski
@ 2015-01-08 22:51   ` Christophe Varoqui
  0 siblings, 0 replies; 16+ messages in thread
From: Christophe Varoqui @ 2015-01-08 22:51 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development


[-- Attachment #1.1: Type: text/plain, Size: 5566 bytes --]

Ben,

I'm willing to apply this one.
Care to rebase it.

Best regards,
Christophe

On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <bmarzins@redhat.com>
wrote:

> When multipath renames a device and the name switches from ending in a
> number to ending in a letter or vice versa, it currently just keeps any
> existing delimiter between the device name and partition number.
> However the default behaviour in kpartx is to only use the 'p' delimiter
> when the name ends in a number. Unfortunately, without adding a
> kpartx.conf that kpartx uses to set the delimiter behavior, there's no
> way for multipath to know how kpartx was run for certain device names
> (ones ending in a number with a 'p' delimiter).
>
> The patch adds a new multipath.conf defaults parameter,
> "partition_delimiter". If this value is not set, when multipath renames
> a device, it will act just like the kpartx default does, only adding a
> 'p' to names ending in a number.  If this parameter is set, multipath
> will act like kpartx does with the -p option is used, and always add
> delimiter.
>
> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/config.c    |  3 +++
>  libmultipath/config.h    |  1 +
>  libmultipath/devmapper.c | 14 ++++++++++++--
>  libmultipath/dict.c      |  4 ++++
>  4 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/libmultipath/config.c b/libmultipath/config.c
> index 3c72b59..701e177 100644
> --- a/libmultipath/config.c
> +++ b/libmultipath/config.c
> @@ -502,6 +502,8 @@ free_config (struct config * conf)
>
>         if (conf->alias_prefix)
>                 FREE(conf->alias_prefix);
> +       if (conf->partition_delim)
> +               FREE(conf->partition_delim);
>
>         if (conf->prio_args)
>                 FREE(conf->prio_args);
> @@ -564,6 +566,7 @@ load_config (char * file, struct udev *udev)
>         conf->detect_prio = DEFAULT_DETECT_PRIO;
>         conf->force_sync = 0;
>         conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
> +       conf->partition_delim = NULL;
>
>         /*
>          * preload default hwtable
> diff --git a/libmultipath/config.h b/libmultipath/config.h
> index 801387c..a6205ee 100644
> --- a/libmultipath/config.h
> +++ b/libmultipath/config.h
> @@ -141,6 +141,7 @@ struct config {
>         char * prio_args;
>         char * checker_name;
>         char * alias_prefix;
> +       char * partition_delim;
>         unsigned char * reservation_key;
>
>         vector keywords;
> diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
> index 3d4c111..9e585f9 100644
> --- a/libmultipath/devmapper.c
> +++ b/libmultipath/devmapper.c
> @@ -1142,6 +1142,8 @@ dm_rename_partmaps (char * old, char * new)
>         unsigned long long size;
>         char dev_t[32];
>         int r = 1;
> +       int offset;
> +       char *delim;
>
>         if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
>                 return 1;
> @@ -1162,6 +1164,13 @@ dm_rename_partmaps (char * old, char * new)
>         if (dm_dev_t(old, &dev_t[0], 32))
>                 goto out;
>
> +       if (conf->partition_delim)
> +               delim = conf->partition_delim;
> +       if (isdigit(new[strlen(new)-1]))
> +               delim = "p";
> +       else
> +               delim = "";
> +
>         do {
>                 if (
>                     /*
> @@ -1189,8 +1198,9 @@ dm_rename_partmaps (char * old, char * new)
>                                  * then it's a kpartx generated partition.
>                                  * Rename it.
>                                  */
> -                               snprintf(buff, PARAMS_SIZE, "%s%s",
> -                                        new, names->name + strlen(old));
> +                               for (offset = strlen(old);
> names->name[offset] && !(isdigit(names->name[offset])); offset++); /* do
> nothing */
> +                               snprintf(buff, PARAMS_SIZE, "%s%s%s",
> +                                        new, delim, names->name + offset);
>                                 dm_rename(names->name, buff);
>                                 condlog(4, "partition map %s renamed",
>                                         names->name);
> diff --git a/libmultipath/dict.c b/libmultipath/dict.c
> index d1e2e96..f95f30c 100644
> --- a/libmultipath/dict.c
> +++ b/libmultipath/dict.c
> @@ -233,6 +233,9 @@ declare_def_snprint(multipath_dir, print_str)
>  declare_def_handler(find_multipaths, set_yes_no)
>  declare_def_snprint(find_multipaths, print_yes_no)
>
> +declare_def_handler(partition_delim, set_str)
> +declare_def_snprint(partition_delim, print_str)
> +
>  declare_def_handler(selector, set_str)
>  declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
>  declare_hw_handler(selector, set_str)
> @@ -1246,6 +1249,7 @@ init_keywords(void)
>         install_keyword("detect_prio", &def_detect_prio_handler,
> &snprint_def_detect_prio);
>         install_keyword("force_sync", &def_force_sync_handler,
> &snprint_def_force_sync);
>         install_keyword("find_multipaths", &def_find_multipaths_handler,
> &snprint_def_find_multipaths);
> +       install_keyword("partition_delimiter",
> &def_partition_delim_handler, &snprint_def_partition_delim);
>         __deprecated install_keyword("default_selector",
> &def_selector_handler, NULL);
>         __deprecated install_keyword("default_path_grouping_policy",
> &def_pgpolicy_handler, NULL);
>         __deprecated install_keyword("default_uid_attribute",
> &def_uid_attribute_handler, NULL);
> --
> 1.8.3.1
>
>

[-- Attachment #1.2: Type: text/html, Size: 7089 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2014-11-19  6:17 ` [PATCH 3/6] libmultipath: add overrides section to multipath.conf Benjamin Marzinski
@ 2015-01-08 23:06   ` Christophe Varoqui
  2015-01-11 23:15     ` Sebastian Herbszt
  2015-01-12 18:05     ` Benjamin Marzinski
  0 siblings, 2 replies; 16+ messages in thread
From: Christophe Varoqui @ 2015-01-08 23:06 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development


[-- Attachment #1.1: Type: text/plain, Size: 31865 bytes --]

I have no strong opinion on this one : I feel like the complexity of the
parameter inheritance system is already quite complicated ... but this
addition of a new layer would likely and safely be ignored by users who
don't need it. Those who need it are surely ready to pay the price.

Does someone have objection to my applying this patch ?

Best regards,
Christophe



On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <bmarzins@redhat.com>
wrote:

> Sometimes users want to be able to set a configuration value for all their
> devices (for instance, they may want all devices to set no_path_retry to
> fail). The builtin device configurations make this tricky, since users need
> to change each device configuration individually. To avoid that, this patch
> adds a new section to multipath.conf, "overrides".  This section has all of
> the attributes that are in both the devices and defaults section.
> Attributes set in the overrides section have a higher priority that those
> in the devices section. With this section added, the multipath
> configuration order now goes:
>
> multipaths > overrides > devices > defaults
>
> I also made want_user_friendly_names print out where the configuration came
> from, and I made made select_hwhandler and select_selector always strdup
> the string, instead of only on the defaults.  Since multipathd will update
> the device strings from the kernel anyway, the old way just added
> complexity without saving any memory.
>
> To store the overrides configuration, I used a hwentry structure. We may
> want to make a new overrides structure, so that we set any of the defaults
> values in overrides.  That way, users could skip using defaults and just
> use overrides if they wanted. However, this would take some additional
> changes to make sure that all the defaults options can undefined, which
> they can't currently be.
>
> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/config.c      |  1 +
>  libmultipath/config.h      |  1 +
>  libmultipath/dict.c        | 98
> ++++++++++++++++++++++++++++++++++++++++++++++
>  libmultipath/print.c       | 30 ++++++++++++++
>  libmultipath/print.h       |  1 +
>  libmultipath/propsel.c     | 55 +++++++++++++++++++++-----
>  libmultipath/structs.c     |  9 +----
>  multipath.conf.annotated   | 18 ++++++++-
>  multipath.conf.defaults    |  2 +
>  multipath.conf.synthetic   |  3 ++
>  multipath/main.c           |  6 +++
>  multipath/multipath.conf.5 | 57 +++++++++++++++++++++++++++
>  multipathd/cli_handlers.c  | 10 +++++
>  13 files changed, 273 insertions(+), 18 deletions(-)
>
> diff --git a/libmultipath/config.c b/libmultipath/config.c
> index bfd8ee8..7f7bd5a 100644
> --- a/libmultipath/config.c
> +++ b/libmultipath/config.c
> @@ -523,6 +523,7 @@ free_config (struct config * conf)
>
>         free_mptable(conf->mptable);
>         free_hwtable(conf->hwtable);
> +       free_hwe(conf->overrides);
>         free_keywords(conf->keywords);
>         FREE(conf);
>  }
> diff --git a/libmultipath/config.h b/libmultipath/config.h
> index c57ab31..ef1d7c3 100644
> --- a/libmultipath/config.h
> +++ b/libmultipath/config.h
> @@ -145,6 +145,7 @@ struct config {
>         vector keywords;
>         vector mptable;
>         vector hwtable;
> +       struct hwentry *overrides;
>
>         vector blist_devnode;
>         vector blist_wwid;
> diff --git a/libmultipath/dict.c b/libmultipath/dict.c
> index 98cbe48..737c9b0 100644
> --- a/libmultipath/dict.c
> +++ b/libmultipath/dict.c
> @@ -181,6 +181,22 @@ snprint_hw_ ## option (char * buff, int len, void *
> data)          \
>         return function (buff, len, &hwe->option);                      \
>  }
>
> +#define declare_ovr_handler(option, function)                          \
> +static int                                                             \
> +ovr_ ## option ## _handler (vector strvec)                             \
> +{                                                                      \
> +       if (!conf->overrides)                                           \
> +               return 1;                                               \
> +       return function (strvec, &conf->overrides->option);             \
> +}
> +
> +#define declare_ovr_snprint(option, function)                          \
> +static int                                                             \
> +snprint_ovr_ ## option (char * buff, int len, void * data)             \
> +{                                                                      \
> +       return function (buff, len, &conf->overrides->option);          \
> +}
> +
>  #define declare_mp_handler(option, function)                           \
>  static int                                                             \
>  mp_ ## option ## _handler (vector strvec)                              \
> @@ -218,21 +234,29 @@ declare_def_handler(selector, set_str)
>  declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
>  declare_hw_handler(selector, set_str)
>  declare_hw_snprint(selector, print_str)
> +declare_ovr_handler(selector, set_str)
> +declare_ovr_snprint(selector, print_str)
>  declare_mp_handler(selector, set_str)
>  declare_mp_snprint(selector, print_str)
>
>  declare_def_handler(uid_attribute, set_str)
>  declare_def_snprint_defstr(uid_attribute, print_str,
> DEFAULT_UID_ATTRIBUTE)
> +declare_ovr_handler(uid_attribute, set_str)
> +declare_ovr_snprint(uid_attribute, print_str)
>  declare_hw_handler(uid_attribute, set_str)
>  declare_hw_snprint(uid_attribute, print_str)
>
>  declare_def_handler(getuid, set_str)
>  declare_def_snprint(getuid, print_str)
> +declare_ovr_handler(getuid, set_str)
> +declare_ovr_snprint(getuid, print_str)
>  declare_hw_handler(getuid, set_str)
>  declare_hw_snprint(getuid, print_str)
>
>  declare_def_handler(prio_name, set_str)
>  declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
> +declare_ovr_handler(prio_name, set_str)
> +declare_ovr_snprint(prio_name, print_str)
>  declare_hw_handler(prio_name, set_str)
>  declare_hw_snprint(prio_name, print_str)
>  declare_mp_handler(prio_name, set_str)
> @@ -240,11 +264,15 @@ declare_mp_snprint(prio_name, print_str)
>
>  declare_def_handler(alias_prefix, set_str)
>  declare_def_snprint_defstr(alias_prefix, print_str, DEFAULT_ALIAS_PREFIX)
> +declare_ovr_handler(alias_prefix, set_str)
> +declare_ovr_snprint(alias_prefix, print_str)
>  declare_hw_handler(alias_prefix, set_str)
>  declare_hw_snprint(alias_prefix, print_str)
>
>  declare_def_handler(prio_args, set_str)
>  declare_def_snprint_defstr(prio_args, print_str, DEFAULT_PRIO_ARGS)
> +declare_ovr_handler(prio_args, set_str)
> +declare_ovr_snprint(prio_args, print_str)
>  declare_hw_handler(prio_args, set_str)
>  declare_hw_snprint(prio_args, print_str)
>  declare_mp_handler(prio_args, set_str)
> @@ -252,6 +280,8 @@ declare_mp_snprint(prio_args, print_str)
>
>  declare_def_handler(features, set_str)
>  declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
> +declare_ovr_handler(features, set_str)
> +declare_ovr_snprint(features, print_str)
>  declare_hw_handler(features, set_str)
>  declare_hw_snprint(features, print_str)
>  declare_mp_handler(features, set_str)
> @@ -259,11 +289,15 @@ declare_mp_snprint(features, print_str)
>
>  declare_def_handler(checker_name, set_str)
>  declare_def_snprint_defstr(checker_name, print_str, DEFAULT_CHECKER)
> +declare_ovr_handler(checker_name, set_str)
> +declare_ovr_snprint(checker_name, print_str)
>  declare_hw_handler(checker_name, set_str)
>  declare_hw_snprint(checker_name, print_str)
>
>  declare_def_handler(minio, set_int)
>  declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
> +declare_ovr_handler(minio, set_int)
> +declare_ovr_snprint(minio, print_nonzero)
>  declare_hw_handler(minio, set_int)
>  declare_hw_snprint(minio, print_nonzero)
>  declare_mp_handler(minio, set_int)
> @@ -271,6 +305,8 @@ declare_mp_snprint(minio, print_nonzero)
>
>  declare_def_handler(minio_rq, set_int)
>  declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
> +declare_ovr_handler(minio_rq, set_int)
> +declare_ovr_snprint(minio_rq, print_nonzero)
>  declare_hw_handler(minio_rq, set_int)
>  declare_hw_snprint(minio_rq, print_nonzero)
>  declare_mp_handler(minio_rq, set_int)
> @@ -296,6 +332,8 @@ declare_def_snprint(checker_timeout, print_nonzero)
>
>  declare_def_handler(flush_on_last_del, set_yes_no_undef)
>  declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, YNU_NO)
> +declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
> +declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
>  declare_hw_handler(flush_on_last_del, set_yes_no_undef)
>  declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
>  declare_mp_handler(flush_on_last_del, set_yes_no_undef)
> @@ -303,6 +341,8 @@ declare_mp_snprint(flush_on_last_del,
> print_yes_no_undef)
>
>  declare_def_handler(user_friendly_names, set_yes_no_undef)
>  declare_def_snprint_defint(user_friendly_names, print_yes_no_undef,
> YNU_NO)
> +declare_ovr_handler(user_friendly_names, set_yes_no_undef)
> +declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
>  declare_hw_handler(user_friendly_names, set_yes_no_undef)
>  declare_hw_snprint(user_friendly_names, print_yes_no_undef)
>  declare_mp_handler(user_friendly_names, set_yes_no_undef)
> @@ -316,11 +356,15 @@ declare_def_snprint(wwids_file, print_str)
>
>  declare_def_handler(retain_hwhandler, set_yes_no_undef)
>  declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, YNU_NO)
> +declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
> +declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
>  declare_hw_handler(retain_hwhandler, set_yes_no_undef)
>  declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
>
>  declare_def_handler(detect_prio, set_yes_no_undef)
>  declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
> +declare_ovr_handler(detect_prio, set_yes_no_undef)
> +declare_ovr_snprint(detect_prio, print_yes_no_undef)
>  declare_hw_handler(detect_prio, set_yes_no_undef)
>  declare_hw_snprint(detect_prio, print_yes_no_undef)
>
> @@ -512,6 +556,8 @@ print_fast_io_fail(char * buff, int len, void *ptr)
>
>  declare_def_handler(fast_io_fail, set_fast_io_fail)
>  declare_def_snprint(fast_io_fail, print_fast_io_fail)
> +declare_ovr_handler(fast_io_fail, set_fast_io_fail)
> +declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
>  declare_hw_handler(fast_io_fail, set_fast_io_fail)
>  declare_hw_snprint(fast_io_fail, print_fast_io_fail)
>
> @@ -548,6 +594,8 @@ print_dev_loss(char * buff, int len, void *ptr)
>
>  declare_def_handler(dev_loss, set_dev_loss)
>  declare_def_snprint(dev_loss, print_dev_loss)
> +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)
>
> @@ -583,6 +631,8 @@ print_pgpolicy(char * buff, int len, void *ptr)
>
>  declare_def_handler(pgpolicy, set_pgpolicy)
>  declare_def_snprint_defint(pgpolicy, print_pgpolicy, DEFAULT_PGPOLICY)
> +declare_ovr_handler(pgpolicy, set_pgpolicy)
> +declare_ovr_snprint(pgpolicy, print_pgpolicy)
>  declare_hw_handler(pgpolicy, set_pgpolicy)
>  declare_hw_snprint(pgpolicy, print_pgpolicy)
>  declare_mp_handler(pgpolicy, set_pgpolicy)
> @@ -700,6 +750,8 @@ print_rr_weight (char * buff, int len, void *ptr)
>
>  declare_def_handler(rr_weight, set_rr_weight)
>  declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
> +declare_ovr_handler(rr_weight, set_rr_weight)
> +declare_ovr_snprint(rr_weight, print_rr_weight)
>  declare_hw_handler(rr_weight, set_rr_weight)
>  declare_hw_snprint(rr_weight, print_rr_weight)
>  declare_mp_handler(rr_weight, set_rr_weight)
> @@ -748,6 +800,8 @@ print_pgfailback (char * buff, int len, void *ptr)
>
>  declare_def_handler(pgfailback, set_pgfailback)
>  declare_def_snprint_defint(pgfailback, print_pgfailback, DEFAULT_FAILBACK)
> +declare_ovr_handler(pgfailback, set_pgfailback)
> +declare_ovr_snprint(pgfailback, print_pgfailback)
>  declare_hw_handler(pgfailback, set_pgfailback)
>  declare_hw_snprint(pgfailback, print_pgfailback)
>  declare_mp_handler(pgfailback, set_pgfailback)
> @@ -793,6 +847,8 @@ print_no_path_retry(char * buff, int len, void *ptr)
>
>  declare_def_handler(no_path_retry, set_no_path_retry)
>  declare_def_snprint(no_path_retry, print_no_path_retry)
> +declare_ovr_handler(no_path_retry, set_no_path_retry)
> +declare_ovr_snprint(no_path_retry, print_no_path_retry)
>  declare_hw_handler(no_path_retry, set_no_path_retry)
>  declare_hw_snprint(no_path_retry, print_no_path_retry)
>  declare_mp_handler(no_path_retry, set_no_path_retry)
> @@ -1061,6 +1117,25 @@ declare_hw_handler(hwhandler, set_str)
>  declare_hw_snprint(hwhandler, print_str)
>
>  /*
> + * overrides handlers
> + */
> +static int
> +overrides_handler(vector strvec)
> +{
> +       struct hwentry * overrides;
> +
> +       overrides = alloc_hwe();
> +
> +       if (!overrides)
> +               return 1;
> +
> +       conf->overrides = overrides;
> +       return 0;
> +}
> +
> +
> +
> +/*
>   * multipaths block handlers
>   */
>  static int
> @@ -1236,6 +1311,29 @@ init_keywords(void)
>         install_keyword("detect_prio", &hw_detect_prio_handler,
> &snprint_hw_detect_prio);
>         install_sublevel_end();
>
> +       install_keyword_root("overrides", &overrides_handler);
> +       install_keyword("path_grouping_policy", &ovr_pgpolicy_handler,
> &snprint_ovr_pgpolicy);
> +       install_keyword("uid_attribute", &ovr_uid_attribute_handler,
> &snprint_ovr_uid_attribute);
> +       install_keyword("getuid_callout", &ovr_getuid_handler,
> &snprint_ovr_getuid);
> +       install_keyword("path_selector", &ovr_selector_handler,
> &snprint_ovr_selector);
> +       install_keyword("path_checker", &ovr_checker_name_handler,
> &snprint_ovr_checker_name);
> +       install_keyword("checker", &ovr_checker_name_handler, NULL);
> +       install_keyword("alias_prefix", &ovr_alias_prefix_handler,
> &snprint_ovr_alias_prefix);
> +       install_keyword("features", &ovr_features_handler,
> &snprint_ovr_features);
> +       install_keyword("prio", &ovr_prio_name_handler,
> &snprint_ovr_prio_name);
> +       install_keyword("prio_args", &ovr_prio_args_handler,
> &snprint_ovr_prio_args);
> +       install_keyword("failback", &ovr_pgfailback_handler,
> &snprint_ovr_pgfailback);
> +       install_keyword("rr_weight", &ovr_rr_weight_handler,
> &snprint_ovr_rr_weight);
> +       install_keyword("no_path_retry", &ovr_no_path_retry_handler,
> &snprint_ovr_no_path_retry);
> +       install_keyword("rr_min_io", &ovr_minio_handler,
> &snprint_ovr_minio);
> +       install_keyword("rr_min_io_rq", &ovr_minio_rq_handler,
> &snprint_ovr_minio_rq);
> +       install_keyword("flush_on_last_del",
> &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
> +       install_keyword("fast_io_fail_tmo", &ovr_fast_io_fail_handler,
> &snprint_ovr_fast_io_fail);
> +       install_keyword("dev_loss_tmo", &ovr_dev_loss_handler,
> &snprint_ovr_dev_loss);
> +       install_keyword("user_friendly_names",
> &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
> +       install_keyword("retain_attached_hw_handler",
> &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
> +       install_keyword("detect_prio", &ovr_detect_prio_handler,
> &snprint_ovr_detect_prio);
> +
>         install_keyword_root("multipaths", &multipaths_handler);
>         install_keyword_multi("multipath", &multipath_handler, NULL);
>         install_sublevel();
> diff --git a/libmultipath/print.c b/libmultipath/print.c
> index 383eae4..ade3841 100644
> --- a/libmultipath/print.c
> +++ b/libmultipath/print.c
> @@ -1080,6 +1080,36 @@ snprint_mptable (char * buff, int len, vector
> mptable)
>  }
>
>  extern int
> +snprint_overrides (char * buff, int len, struct hwentry *overrides)
> +{
> +       int fwd = 0;
> +       int i;
> +       struct keyword *rootkw;
> +       struct keyword *kw;
> +
> +       rootkw = find_keyword(NULL, "overrides");
> +       if (!rootkw)
> +               return 0;
> +
> +       fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
> +       if (fwd > len)
> +               return len;
> +       if (!overrides)
> +               goto out;
> +       iterate_sub_keywords(rootkw, kw, i) {
> +               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
> +                                      kw, NULL);
> +               if (fwd > len)
> +                       return len;
> +       }
> +out:
> +       fwd += snprintf(buff + fwd, len - fwd, "}\n");
> +       if (fwd > len)
> +               return len;
> +       return fwd;
> +}
> +
> +extern int
>  snprint_defaults (char * buff, int len)
>  {
>         int fwd = 0;
> diff --git a/libmultipath/print.h b/libmultipath/print.h
> index aef182b..a3c3319 100644
> --- a/libmultipath/print.h
> +++ b/libmultipath/print.h
> @@ -50,6 +50,7 @@ int snprint_status (char *, int, struct vectors *);
>  int snprint_devices (char *, int, struct vectors *);
>  int snprint_hwtable (char *, int, vector);
>  int snprint_mptable (char *, int, vector);
> +int snprint_overrides (char *, int, struct hwentry *);
>
>  void print_multipath_topology (struct multipath * mpp, int verbosity);
>  void print_path (struct path * pp, char * style);
> diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
> index f2ab7d2..440802c 100644
> --- a/libmultipath/propsel.c
> +++ b/libmultipath/propsel.c
> @@ -48,6 +48,8 @@ do {
>               \
>  do_set(var, mp->mpe, mp->var, "(LUN setting)")
>  #define mp_set_hwe(var)
>       \
>  do_set(var, mp->hwe, mp->var, "(controller setting)")
> +#define mp_set_ovr(var)
>       \
> +do_set(var, conf->overrides, mp->var, "(overrides setting)")
>  #define mp_set_conf(var)                                               \
>  do_set(var, conf, mp->var, "(config file default)")
>  #define mp_set_default(var, value)                                     \
> @@ -59,6 +61,8 @@ do_set(var, mpe, pp->var, "(LUN setting)")
>  do_set(var, pp->hwe, pp->var, "(controller setting)")
>  #define pp_set_conf(var)                                               \
>  do_set(var, conf, pp->var, "(config file default)")
> +#define pp_set_ovr(var)
>       \
> +do_set(var, conf->overrides, pp->var, "(overrides setting)")
>  #define pp_set_default(var, value)                                     \
>  do_default(pp->var, value)
>
> @@ -130,6 +134,7 @@ select_rr_weight (struct multipath * mp)
>         char *origin, buff[13];
>
>         mp_set_mpe(rr_weight);
> +       mp_set_ovr(rr_weight);
>         mp_set_hwe(rr_weight);
>         mp_set_conf(rr_weight);
>         mp_set_default(rr_weight, RR_WEIGHT_NONE);
> @@ -145,6 +150,7 @@ select_pgfailback (struct multipath * mp)
>         char *origin, buff[13];
>
>         mp_set_mpe(pgfailback);
> +       mp_set_ovr(pgfailback);
>         mp_set_hwe(pgfailback);
>         mp_set_conf(pgfailback);
>         mp_set_default(pgfailback, DEFAULT_FAILBACK);
> @@ -165,6 +171,7 @@ select_pgpolicy (struct multipath * mp)
>                 goto out;
>         }
>         mp_set_mpe(pgpolicy);
> +       mp_set_ovr(pgpolicy);
>         mp_set_hwe(pgpolicy);
>         mp_set_conf(pgpolicy);
>         mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
> @@ -181,10 +188,12 @@ select_selector (struct multipath * mp)
>         char *origin;
>
>         mp_set_mpe(selector);
> +       mp_set_ovr(selector);
>         mp_set_hwe(selector);
>         mp_set_conf(selector);
> -       mp_set_default(selector, set_default(DEFAULT_SELECTOR));
> +       mp_set_default(selector, DEFAULT_SELECTOR);
>  out:
> +       mp->selector = STRDUP(mp->selector);
>         condlog(3, "%s: path_selector = \"%s\" %s", mp->alias,
> mp->selector,
>                 origin);
>         return 0;
> @@ -195,6 +204,7 @@ select_alias_prefix (struct multipath * mp)
>  {
>         char *origin;
>
> +       mp_set_ovr(alias_prefix);
>         mp_set_hwe(alias_prefix);
>         mp_set_conf(alias_prefix);
>         mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
> @@ -206,19 +216,30 @@ out:
>  static int
>  want_user_friendly_names(struct multipath * mp)
>  {
> -       if (mp->mpe &&
> -           mp->mpe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
> -               return (mp->mpe->user_friendly_names ==
> USER_FRIENDLY_NAMES_ON);
> -       if (mp->hwe &&
> -           mp->hwe->user_friendly_names != USER_FRIENDLY_NAMES_UNDEF)
> -               return (mp->hwe->user_friendly_names ==
> USER_FRIENDLY_NAMES_ON);
> -       return (conf->user_friendly_names  == USER_FRIENDLY_NAMES_ON);
> +
> +       char *origin;
> +       int user_friendly_names;
> +
> +       do_set(user_friendly_names, mp->mpe, user_friendly_names,
> +              "(LUN setting)");
> +       do_set(user_friendly_names, conf->overrides, user_friendly_names,
> +              "(overrides setting)");
> +       do_set(user_friendly_names, mp->hwe, user_friendly_names,
> +              "(controller setting)");
> +       do_set(user_friendly_names, conf, user_friendly_names,
> +              "(config file setting)");
> +       do_default(user_friendly_names, USER_FRIENDLY_NAMES_OFF);
> +out:
> +       condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
> +               (user_friendly_names == USER_FRIENDLY_NAMES_ON)? "yes" :
> "no",
> +               origin);
> +       return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
>  }
>
>  extern int
>  select_alias (struct multipath * mp)
>  {
> -       char *origin;
> +       char *origin = NULL;
>
>         if (mp->mpe && mp->mpe->alias) {
>                 mp->alias = STRDUP(mp->mpe->alias);
> @@ -261,6 +282,7 @@ select_features (struct multipath * mp)
>         char *origin;
>
>         mp_set_mpe(features);
> +       mp_set_ovr(features);
>         mp_set_hwe(features);
>         mp_set_conf(features);
>         mp_set_default(features, DEFAULT_FEATURES);
> @@ -287,8 +309,9 @@ select_hwhandler (struct multipath * mp)
>
>         mp_set_hwe(hwhandler);
>         mp_set_conf(hwhandler);
> -       mp_set_default(hwhandler, set_default(DEFAULT_HWHANDLER));
> +       mp_set_default(hwhandler, DEFAULT_HWHANDLER);
>  out:
> +       mp->hwhandler = STRDUP(mp->hwhandler);
>         condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias,
> mp->hwhandler,
>                 origin);
>         return 0;
> @@ -300,6 +323,7 @@ select_checker(struct path *pp)
>         char *origin, *checker_name;
>         struct checker * c = &pp->checker;
>
> +       do_set(checker_name, conf->overrides, checker_name, "(overrides
> setting)");
>         do_set(checker_name, pp->hwe, checker_name, "(controller
> setting)");
>         do_set(checker_name, conf, checker_name, "(config file setting)");
>         do_default(checker_name, DEFAULT_CHECKER);
> @@ -327,6 +351,8 @@ select_getuid (struct path * pp)
>  {
>         char *origin;
>
> +       pp_set_ovr(uid_attribute);
> +       pp_set_ovr(getuid);
>         pp_set_hwe(uid_attribute);
>         pp_set_hwe(getuid);
>         pp_set_conf(uid_attribute);
> @@ -383,6 +409,7 @@ select_prio (struct path * pp)
>         }
>         mpe = find_mpe(pp->wwid);
>         set_prio(mpe, "(LUN setting)");
> +       set_prio(conf->overrides, "(overrides setting)");
>         set_prio(pp->hwe, "controller setting)");
>         set_prio(conf, "(config file default)");
>         prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
> @@ -405,6 +432,7 @@ select_no_path_retry(struct multipath *mp)
>                 return 0;
>         }
>         mp_set_mpe(no_path_retry);
> +       mp_set_ovr(no_path_retry);
>         mp_set_hwe(no_path_retry);
>         mp_set_conf(no_path_retry);
>  out:
> @@ -427,6 +455,7 @@ select_minio_rq (struct multipath * mp)
>         char *origin;
>
>         do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
> +       do_set(minio_rq, conf->overrides, mp->minio, "(overrides
> setting)");
>         do_set(minio_rq, mp->hwe, mp->minio, "(controller setting)");
>         do_set(minio_rq, conf, mp->minio, "(config file setting)");
>         do_default(mp->minio, DEFAULT_MINIO_RQ);
> @@ -441,6 +470,7 @@ select_minio_bio (struct multipath * mp)
>         char *origin;
>
>         mp_set_mpe(minio);
> +       mp_set_ovr(minio);
>         mp_set_hwe(minio);
>         mp_set_conf(minio);
>         mp_set_default(minio, DEFAULT_MINIO);
> @@ -465,6 +495,7 @@ select_fast_io_fail(struct multipath *mp)
>  {
>         char *origin, buff[12];
>
> +       mp_set_ovr(fast_io_fail);
>         mp_set_hwe(fast_io_fail);
>         mp_set_conf(fast_io_fail);
>         mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
> @@ -479,6 +510,7 @@ select_dev_loss(struct multipath *mp)
>  {
>         char *origin, buff[12];
>
> +       mp_set_ovr(dev_loss);
>         mp_set_hwe(dev_loss);
>         mp_set_conf(dev_loss);
>         mp->dev_loss = 0;
> @@ -497,6 +529,7 @@ select_flush_on_last_del(struct multipath *mp)
>         if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
>                 return 0;
>         mp_set_mpe(flush_on_last_del);
> +       mp_set_ovr(flush_on_last_del);
>         mp_set_hwe(flush_on_last_del);
>         mp_set_conf(flush_on_last_del);
>         mp_set_default(flush_on_last_del, FLUSH_DISABLED);
> @@ -532,6 +565,7 @@ select_retain_hwhandler (struct multipath * mp)
>                 origin = "(requires kernel version >= 1.5.0)";
>                 goto out;
>         }
> +       mp_set_ovr(retain_hwhandler);
>         mp_set_hwe(retain_hwhandler);
>         mp_set_conf(retain_hwhandler);
>         mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
> @@ -547,6 +581,7 @@ select_detect_prio (struct path * pp)
>  {
>         char *origin;
>
> +       pp_set_ovr(detect_prio);
>         pp_set_hwe(detect_prio);
>         pp_set_conf(detect_prio);
>         pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
> diff --git a/libmultipath/structs.c b/libmultipath/structs.c
> index 30d247d..0538327 100644
> --- a/libmultipath/structs.c
> +++ b/libmultipath/structs.c
> @@ -206,10 +206,7 @@ free_multipath_attributes (struct multipath * mpp)
>         if (!mpp)
>                 return;
>
> -       if (mpp->selector &&
> -           mpp->selector != conf->selector &&
> -           (!mpp->mpe || (mpp->mpe && mpp->selector !=
> mpp->mpe->selector)) &&
> -           (!mpp->hwe || (mpp->hwe && mpp->selector !=
> mpp->hwe->selector))) {
> +       if (mpp->selector) {
>                 FREE(mpp->selector);
>                 mpp->selector = NULL;
>         }
> @@ -219,9 +216,7 @@ free_multipath_attributes (struct multipath * mpp)
>                 mpp->features = NULL;
>         }
>
> -       if (mpp->hwhandler &&
> -           mpp->hwhandler != conf->hwhandler &&
> -           (!mpp->hwe || (mpp->hwe && mpp->hwhandler !=
> mpp->hwe->hwhandler))) {
> +       if (mpp->hwhandler) {
>                 FREE(mpp->hwhandler);
>                 mpp->hwhandler = NULL;
>         }
> diff --git a/multipath.conf.annotated b/multipath.conf.annotated
> index 0af1d4c..71afc0a 100644
> --- a/multipath.conf.annotated
> +++ b/multipath.conf.annotated
> @@ -485,7 +485,8 @@
>  ## scope : multipath & multipathd
>  ## desc  : list of per storage controller settings
>  ##       overrides default settings (device_maps block)
> -##         overriden by per multipath settings (multipaths block)
> +##        overriden by per multipath settings (multipaths block)
> +##       and the overrides settings (overrides block)
>  ##
>  #devices {
>  #      #
> @@ -651,3 +652,18 @@
>  #              rr_weight               priorities
>  #      }
>  #}
> +#
> +##
> +## name  : devices
> +## scope : multipath & multipathd
> +## desc  : list of settings to override all hadware settings for all
> devices
> +##       overrides default settings (device_maps block)
> +##       and per device type settings (devices block)
> +##        overriden by per multipath settings (multipaths block)
> +##
> +#      attributes and values are identical to the device block
> +#
> +#overrides {
> +#      dev_loss_tmo            60
> +#      no_path_retry           fail
> +#}
> diff --git a/multipath.conf.defaults b/multipath.conf.defaults
> index 654be97..1c65e02 100644
> --- a/multipath.conf.defaults
> +++ b/multipath.conf.defaults
> @@ -912,3 +912,5 @@
>  #}
>  #multipaths {
>  #}
> +#overrides {
> +#}
> diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
> index bda1b75..f7b9b8a 100644
> --- a/multipath.conf.synthetic
> +++ b/multipath.conf.synthetic
> @@ -72,3 +72,6 @@
>  #              path_grouping_policy    multibus
>  #      }
>  #}
> +#overrides {
> +#      no_path_retry                   fail
> +#}
> diff --git a/multipath/main.c b/multipath/main.c
> index fd6262f..ea453b4 100644
> --- a/multipath/main.c
> +++ b/multipath/main.c
> @@ -405,6 +405,12 @@ dump_config (void)
>                         reply = REALLOC(reply, maxlen *= 2);
>                         continue;
>                 }
> +               c += snprint_overrides(c, reply + maxlen - c,
> conf->overrides);
> +               again = ((c - reply) == maxlen);
> +               if (again) {
> +                       reply = REALLOC(reply, maxlen *= 2);
> +                       continue;
> +               }
>                 c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
>                 again = ((c - reply) == maxlen);
>                 if (again)
> diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
> index cadb34d..b823990 100644
> --- a/multipath/multipath.conf.5
> +++ b/multipath/multipath.conf.5
> @@ -61,6 +61,10 @@ the udev attribute given by the
>  .TP
>  .B devices
>  This section defines the device-specific settings.
> +.TP
> +.B overrides
> +This section defines values for attributes that should override the
> +device-specific settings for all devices.
>  .RE
>  .LP
>  .SH "defaults section"
> @@ -629,6 +633,59 @@ section:
>  .RE
>  .PD
>  .LP
> +.SH "overrides section"
> +The overrides section recognizes the following optional attributes; if
> not set
> +the values are taken from the
> +.I devices
> +or
> +.I defaults
> +sections:
> +.sp 1
> +.PD .1v
> +.RS
> +.TP 18
> +.B path_grouping_policy
> +.TP
> +.B uid_attribute
> +.TP
> +.B getuid_callout
> +.TP
> +.B path_selector
> +.TP
> +.B path_checker
> +.TP
> +.B alias_prefix
> +.TP
> +.B features
> +.TP
> +.B prio
> +.TP
> +.B prio_args
> +.TP
> +.B failback
> +.TP
> +.B rr_weight
> +.TP
> +.B no_path_retry
> +.TP
> +.B rr_min_io
> +.TP
> +.B rr_min_io_rq
> +.TP
> +.B flush_on_last_del
> +.TP
> +.B fast_io_fail_tmo
> +.TP
> +.B dev_loss_tmo
> +.TP
> +.B user_friendly_names
> +.TP
> +.B retain_attached_hw_handler
> +.TP
> +.B detect_prio
> +.RE
> +.PD
> +.LP
>  .SH "KNOWN ISSUES"
>  The usage of
>  .B queue_if_no_path
> diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
> index b086340..0ce1408 100644
> --- a/multipathd/cli_handlers.c
> +++ b/multipathd/cli_handlers.c
> @@ -190,6 +190,16 @@ show_config (char ** r, int * len)
>                         maxlen *= 2;
>                         continue;
>                 }
> +               c += snprint_overrides(c, reply + maxlen - c,
> conf->overrides);
> +               again = ((c - reply) == maxlen);
> +               if (again) {
> +                       reply = REALLOC(reply, maxlen * 2);
> +                       if (!reply)
> +                               return 1;
> +                       memset(reply + maxlen, 0, maxlen);
> +                       maxlen *= 2;
> +                       continue;
> +               }
>                 c += snprint_mptable(c, reply + maxlen - c, conf->mptable);
>                 again = ((c - reply) == maxlen);
>                 REALLOC_REPLY(reply, again, maxlen);
> --
> 1.8.3.1
>
>

[-- Attachment #1.2: Type: text/html, Size: 38322 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-08 23:06   ` Christophe Varoqui
@ 2015-01-11 23:15     ` Sebastian Herbszt
  2015-01-11 23:37       ` Christophe Varoqui
  2015-01-12 18:05     ` Benjamin Marzinski
  1 sibling, 1 reply; 16+ messages in thread
From: Sebastian Herbszt @ 2015-01-11 23:15 UTC (permalink / raw)
  To: device-mapper development; +Cc: Sebastian Herbszt

Christophe Varoqui wrote:
> I have no strong opinion on this one : I feel like the complexity of the
> parameter inheritance system is already quite complicated ... but this
> addition of a new layer would likely and safely be ignored by users who
> don't need it. Those who need it are surely ready to pay the price.
> 
> Does someone have objection to my applying this patch ?
> 
> Best regards,
> Christophe
> 
> 
> 
> On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <bmarzins@redhat.com>
> wrote:
> 
> > Sometimes users want to be able to set a configuration value for all their
> > devices (for instance, they may want all devices to set no_path_retry to
> > fail). The builtin device configurations make this tricky, since users need
> > to change each device configuration individually. To avoid that, this patch
> > adds a new section to multipath.conf, "overrides".  This section has all of
> > the attributes that are in both the devices and defaults section.
> > Attributes set in the overrides section have a higher priority that those
> > in the devices section. With this section added, the multipath
> > configuration order now goes:
> >
> > multipaths > overrides > devices > defaults
> >
> > I also made want_user_friendly_names print out where the configuration came
> > from, and I made made select_hwhandler and select_selector always strdup
> > the string, instead of only on the defaults.  Since multipathd will update
> > the device strings from the kernel anyway, the old way just added
> > complexity without saving any memory.
> >
> > To store the overrides configuration, I used a hwentry structure. We may
> > want to make a new overrides structure, so that we set any of the defaults
> > values in overrides.  That way, users could skip using defaults and just
> > use overrides if they wanted. However, this would take some additional
> > changes to make sure that all the defaults options can undefined, which
> > they can't currently be.
> >

What's the current precedence of the configuration sections? I don't think
the manual pages document this (sufficiently). I guess the precedence is:

multipaths > devices > defaults

But where do the built-in device configurations fit in? It seems those are
somehow merged with the user supplied entries from the configuration file.

Would changing the precedence to

multipaths > devices > defaults > built-in devices

fix the issue at hand?

Sebastian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-11 23:15     ` Sebastian Herbszt
@ 2015-01-11 23:37       ` Christophe Varoqui
  2015-01-13  0:01         ` Sebastian Herbszt
  0 siblings, 1 reply; 16+ messages in thread
From: Christophe Varoqui @ 2015-01-11 23:37 UTC (permalink / raw)
  To: Sebastian Herbszt; +Cc: device-mapper development


[-- Attachment #1.1: Type: text/plain, Size: 3218 bytes --]

Hi,

the precedence chain is :

multipaths > user-specified per-device > default per-device > default

The issue adressed by Ben's patch would not be solved by your suggestion,
as far as I can see. The proposed override section is just a way not repeat
a per-device in each multipath (insane) or device (tedious) section.

I personnaly implement the tedious device configuration using a
configuration manager (shameless plug: opensvc). But I can see the value of
an override section for those not using a such config management tools.

Best regards,
Christophe Varoqui
OpenSVC

On Mon, Jan 12, 2015 at 12:15 AM, Sebastian Herbszt <herbszt@gmx.de> wrote:

> Christophe Varoqui wrote:
> > I have no strong opinion on this one : I feel like the complexity of the
> > parameter inheritance system is already quite complicated ... but this
> > addition of a new layer would likely and safely be ignored by users who
> > don't need it. Those who need it are surely ready to pay the price.
> >
> > Does someone have objection to my applying this patch ?
> >
> > Best regards,
> > Christophe
> >
> >
> >
> > On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <bmarzins@redhat.com
> >
> > wrote:
> >
> > > Sometimes users want to be able to set a configuration value for all
> their
> > > devices (for instance, they may want all devices to set no_path_retry
> to
> > > fail). The builtin device configurations make this tricky, since users
> need
> > > to change each device configuration individually. To avoid that, this
> patch
> > > adds a new section to multipath.conf, "overrides".  This section has
> all of
> > > the attributes that are in both the devices and defaults section.
> > > Attributes set in the overrides section have a higher priority that
> those
> > > in the devices section. With this section added, the multipath
> > > configuration order now goes:
> > >
> > > multipaths > overrides > devices > defaults
> > >
> > > I also made want_user_friendly_names print out where the configuration
> came
> > > from, and I made made select_hwhandler and select_selector always
> strdup
> > > the string, instead of only on the defaults.  Since multipathd will
> update
> > > the device strings from the kernel anyway, the old way just added
> > > complexity without saving any memory.
> > >
> > > To store the overrides configuration, I used a hwentry structure. We
> may
> > > want to make a new overrides structure, so that we set any of the
> defaults
> > > values in overrides.  That way, users could skip using defaults and
> just
> > > use overrides if they wanted. However, this would take some additional
> > > changes to make sure that all the defaults options can undefined, which
> > > they can't currently be.
> > >
>
> What's the current precedence of the configuration sections? I don't think
> the manual pages document this (sufficiently). I guess the precedence is:
>
> multipaths > devices > defaults
>
> But where do the built-in device configurations fit in? It seems those are
> somehow merged with the user supplied entries from the configuration file.
>
> Would changing the precedence to
>
> multipaths > devices > defaults > built-in devices
>
> fix the issue at hand?
>
> Sebastian
>

[-- Attachment #1.2: Type: text/html, Size: 4209 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-08 23:06   ` Christophe Varoqui
  2015-01-11 23:15     ` Sebastian Herbszt
@ 2015-01-12 18:05     ` Benjamin Marzinski
  2015-01-12 20:27       ` Christophe Varoqui
  1 sibling, 1 reply; 16+ messages in thread
From: Benjamin Marzinski @ 2015-01-12 18:05 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: device-mapper development

On Fri, Jan 09, 2015 at 12:06:29AM +0100, Christophe Varoqui wrote:
>    I have no strong opinion on this one : I feel like the complexity of the
>    parameter inheritance system is already quite complicated ... but this
>    addition of a new layer would likely and safely be ignored by users who
>    don't need it. Those who need it are surely ready to pay the price.
>    Does someone have objection to my applying this patch ?

Christophe, I wrote this patch because you thought an "overrides"
section would be more intuitive than my previous solution of a
specialized "all_devs" devices section option to overwrite options on
all the devices.

http://www.redhat.com/archives/dm-devel/2014-September/msg00047.html

Maybe this isn't exactly what you had in mind.  At any rate, I'd like to
have some method inside of multipath to accomplish this.

-Ben 

>    Best regards,
>    Christophe
>    On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <bmarzins@redhat.com>
>    wrote:
> 
>      Sometimes users want to be able to set a configuration value for all
>      their
>      devices (for instance, they may want all devices to set no_path_retry to
>      fail). The builtin device configurations make this tricky, since users
>      need
>      to change each device configuration individually. To avoid that, this
>      patch
>      adds a new section to multipath.conf, "overrides".A  This section has
>      all of
>      the attributes that are in both the devices and defaults section.
>      Attributes set in the overrides section have a higher priority that
>      those
>      in the devices section. With this section added, the multipath
>      configuration order now goes:
> 
>      multipaths > overrides > devices > defaults
> 
>      I also made want_user_friendly_names print out where the configuration
>      came
>      from, and I made made select_hwhandler and select_selector always strdup
>      the string, instead of only on the defaults.A  Since multipathd will
>      update
>      the device strings from the kernel anyway, the old way just added
>      complexity without saving any memory.
> 
>      To store the overrides configuration, I used a hwentry structure. We may
>      want to make a new overrides structure, so that we set any of the
>      defaults
>      values in overrides.A  That way, users could skip using defaults and
>      just
>      use overrides if they wanted. However, this would take some additional
>      changes to make sure that all the defaults options can undefined, which
>      they can't currently be.
> 
>      Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
>      ---
>      A libmultipath/config.cA  A  A  |A  1 +
>      A libmultipath/config.hA  A  A  |A  1 +
>      A libmultipath/dict.cA  A  A  A  | 98
>      ++++++++++++++++++++++++++++++++++++++++++++++
>      A libmultipath/print.cA  A  A  A | 30 ++++++++++++++
>      A libmultipath/print.hA  A  A  A |A  1 +
>      A libmultipath/propsel.cA  A  A | 55 +++++++++++++++++++++-----
>      A libmultipath/structs.cA  A  A |A  9 +----
>      A multipath.conf.annotatedA  A | 18 ++++++++-
>      A multipath.conf.defaultsA  A  |A  2 +
>      A multipath.conf.syntheticA  A |A  3 ++
>      A multipath/main.cA  A  A  A  A  A |A  6 +++
>      A multipath/multipath.conf.5 | 57 +++++++++++++++++++++++++++
>      A multipathd/cli_handlers.cA  | 10 +++++
>      A 13 files changed, 273 insertions(+), 18 deletions(-)
> 
>      diff --git a/libmultipath/config.c b/libmultipath/config.c
>      index bfd8ee8..7f7bd5a 100644
>      --- a/libmultipath/config.c
>      +++ b/libmultipath/config.c
>      @@ -523,6 +523,7 @@ free_config (struct config * conf)
> 
>      A  A  A  A  free_mptable(conf->mptable);
>      A  A  A  A  free_hwtable(conf->hwtable);
>      +A  A  A  A free_hwe(conf->overrides);
>      A  A  A  A  free_keywords(conf->keywords);
>      A  A  A  A  FREE(conf);
>      A }
>      diff --git a/libmultipath/config.h b/libmultipath/config.h
>      index c57ab31..ef1d7c3 100644
>      --- a/libmultipath/config.h
>      +++ b/libmultipath/config.h
>      @@ -145,6 +145,7 @@ struct config {
>      A  A  A  A  vector keywords;
>      A  A  A  A  vector mptable;
>      A  A  A  A  vector hwtable;
>      +A  A  A  A struct hwentry *overrides;
> 
>      A  A  A  A  vector blist_devnode;
>      A  A  A  A  vector blist_wwid;
>      diff --git a/libmultipath/dict.c b/libmultipath/dict.c
>      index 98cbe48..737c9b0 100644
>      --- a/libmultipath/dict.c
>      +++ b/libmultipath/dict.c
>      @@ -181,6 +181,22 @@ snprint_hw_ ## option (char * buff, int len, void *
>      data)A  A  A  A  A  \
>      A  A  A  A  return function (buff, len, &hwe->option);A  A  A  A  A  A 
>      A  A  A  A  A  \
>      A }
> 
>      +#define declare_ovr_handler(option, function)A  A  A  A  A  A  A  A  A 
>      A  A  A  A  \
>      +static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A \
>      +ovr_ ## option ## _handler (vector strvec)A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A \
>      +{A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  \
>      +A  A  A  A if (!conf->overrides)A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A \
>      +A  A  A  A  A  A  A  A return 1;A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A \
>      +A  A  A  A return function (strvec, &conf->overrides->option);A  A  A 
>      A  A  A  A \
>      +}
>      +
>      +#define declare_ovr_snprint(option, function)A  A  A  A  A  A  A  A  A 
>      A  A  A  A  \
>      +static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A \
>      +snprint_ovr_ ## option (char * buff, int len, void * data)A  A  A  A 
>      A  A  A \
>      +{A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  \
>      +A  A  A  A return function (buff, len, &conf->overrides->option);A  A 
>      A  A  A  \
>      +}
>      +
>      A #define declare_mp_handler(option, function)A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A \
>      A static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A \
>      A mp_ ## option ## _handler (vector strvec)A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  \
>      @@ -218,21 +234,29 @@ declare_def_handler(selector, set_str)
>      A declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
>      A declare_hw_handler(selector, set_str)
>      A declare_hw_snprint(selector, print_str)
>      +declare_ovr_handler(selector, set_str)
>      +declare_ovr_snprint(selector, print_str)
>      A declare_mp_handler(selector, set_str)
>      A declare_mp_snprint(selector, print_str)
> 
>      A declare_def_handler(uid_attribute, set_str)
>      A declare_def_snprint_defstr(uid_attribute, print_str,
>      DEFAULT_UID_ATTRIBUTE)
>      +declare_ovr_handler(uid_attribute, set_str)
>      +declare_ovr_snprint(uid_attribute, print_str)
>      A declare_hw_handler(uid_attribute, set_str)
>      A declare_hw_snprint(uid_attribute, print_str)
> 
>      A declare_def_handler(getuid, set_str)
>      A declare_def_snprint(getuid, print_str)
>      +declare_ovr_handler(getuid, set_str)
>      +declare_ovr_snprint(getuid, print_str)
>      A declare_hw_handler(getuid, set_str)
>      A declare_hw_snprint(getuid, print_str)
> 
>      A declare_def_handler(prio_name, set_str)
>      A declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
>      +declare_ovr_handler(prio_name, set_str)
>      +declare_ovr_snprint(prio_name, print_str)
>      A declare_hw_handler(prio_name, set_str)
>      A declare_hw_snprint(prio_name, print_str)
>      A declare_mp_handler(prio_name, set_str)
>      @@ -240,11 +264,15 @@ declare_mp_snprint(prio_name, print_str)
> 
>      A declare_def_handler(alias_prefix, set_str)
>      A declare_def_snprint_defstr(alias_prefix, print_str,
>      DEFAULT_ALIAS_PREFIX)
>      +declare_ovr_handler(alias_prefix, set_str)
>      +declare_ovr_snprint(alias_prefix, print_str)
>      A declare_hw_handler(alias_prefix, set_str)
>      A declare_hw_snprint(alias_prefix, print_str)
> 
>      A declare_def_handler(prio_args, set_str)
>      A declare_def_snprint_defstr(prio_args, print_str, DEFAULT_PRIO_ARGS)
>      +declare_ovr_handler(prio_args, set_str)
>      +declare_ovr_snprint(prio_args, print_str)
>      A declare_hw_handler(prio_args, set_str)
>      A declare_hw_snprint(prio_args, print_str)
>      A declare_mp_handler(prio_args, set_str)
>      @@ -252,6 +280,8 @@ declare_mp_snprint(prio_args, print_str)
> 
>      A declare_def_handler(features, set_str)
>      A declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
>      +declare_ovr_handler(features, set_str)
>      +declare_ovr_snprint(features, print_str)
>      A declare_hw_handler(features, set_str)
>      A declare_hw_snprint(features, print_str)
>      A declare_mp_handler(features, set_str)
>      @@ -259,11 +289,15 @@ declare_mp_snprint(features, print_str)
> 
>      A declare_def_handler(checker_name, set_str)
>      A declare_def_snprint_defstr(checker_name, print_str, DEFAULT_CHECKER)
>      +declare_ovr_handler(checker_name, set_str)
>      +declare_ovr_snprint(checker_name, print_str)
>      A declare_hw_handler(checker_name, set_str)
>      A declare_hw_snprint(checker_name, print_str)
> 
>      A declare_def_handler(minio, set_int)
>      A declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
>      +declare_ovr_handler(minio, set_int)
>      +declare_ovr_snprint(minio, print_nonzero)
>      A declare_hw_handler(minio, set_int)
>      A declare_hw_snprint(minio, print_nonzero)
>      A declare_mp_handler(minio, set_int)
>      @@ -271,6 +305,8 @@ declare_mp_snprint(minio, print_nonzero)
> 
>      A declare_def_handler(minio_rq, set_int)
>      A declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
>      +declare_ovr_handler(minio_rq, set_int)
>      +declare_ovr_snprint(minio_rq, print_nonzero)
>      A declare_hw_handler(minio_rq, set_int)
>      A declare_hw_snprint(minio_rq, print_nonzero)
>      A declare_mp_handler(minio_rq, set_int)
>      @@ -296,6 +332,8 @@ declare_def_snprint(checker_timeout, print_nonzero)
> 
>      A declare_def_handler(flush_on_last_del, set_yes_no_undef)
>      A declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef,
>      YNU_NO)
>      +declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
>      +declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
>      A declare_hw_handler(flush_on_last_del, set_yes_no_undef)
>      A declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
>      A declare_mp_handler(flush_on_last_del, set_yes_no_undef)
>      @@ -303,6 +341,8 @@ declare_mp_snprint(flush_on_last_del,
>      print_yes_no_undef)
> 
>      A declare_def_handler(user_friendly_names, set_yes_no_undef)
>      A declare_def_snprint_defint(user_friendly_names, print_yes_no_undef,
>      YNU_NO)
>      +declare_ovr_handler(user_friendly_names, set_yes_no_undef)
>      +declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
>      A declare_hw_handler(user_friendly_names, set_yes_no_undef)
>      A declare_hw_snprint(user_friendly_names, print_yes_no_undef)
>      A declare_mp_handler(user_friendly_names, set_yes_no_undef)
>      @@ -316,11 +356,15 @@ declare_def_snprint(wwids_file, print_str)
> 
>      A declare_def_handler(retain_hwhandler, set_yes_no_undef)
>      A declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef,
>      YNU_NO)
>      +declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
>      +declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
>      A declare_hw_handler(retain_hwhandler, set_yes_no_undef)
>      A declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
> 
>      A declare_def_handler(detect_prio, set_yes_no_undef)
>      A declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
>      +declare_ovr_handler(detect_prio, set_yes_no_undef)
>      +declare_ovr_snprint(detect_prio, print_yes_no_undef)
>      A declare_hw_handler(detect_prio, set_yes_no_undef)
>      A declare_hw_snprint(detect_prio, print_yes_no_undef)
> 
>      @@ -512,6 +556,8 @@ print_fast_io_fail(char * buff, int len, void *ptr)
> 
>      A declare_def_handler(fast_io_fail, set_fast_io_fail)
>      A declare_def_snprint(fast_io_fail, print_fast_io_fail)
>      +declare_ovr_handler(fast_io_fail, set_fast_io_fail)
>      +declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
>      A declare_hw_handler(fast_io_fail, set_fast_io_fail)
>      A declare_hw_snprint(fast_io_fail, print_fast_io_fail)
> 
>      @@ -548,6 +594,8 @@ print_dev_loss(char * buff, int len, void *ptr)
> 
>      A declare_def_handler(dev_loss, set_dev_loss)
>      A declare_def_snprint(dev_loss, print_dev_loss)
>      +declare_ovr_handler(dev_loss, set_dev_loss)
>      +declare_ovr_snprint(dev_loss, print_dev_loss)
>      A declare_hw_handler(dev_loss, set_dev_loss)
>      A declare_hw_snprint(dev_loss, print_dev_loss)
> 
>      @@ -583,6 +631,8 @@ print_pgpolicy(char * buff, int len, void *ptr)
> 
>      A declare_def_handler(pgpolicy, set_pgpolicy)
>      A declare_def_snprint_defint(pgpolicy, print_pgpolicy, DEFAULT_PGPOLICY)
>      +declare_ovr_handler(pgpolicy, set_pgpolicy)
>      +declare_ovr_snprint(pgpolicy, print_pgpolicy)
>      A declare_hw_handler(pgpolicy, set_pgpolicy)
>      A declare_hw_snprint(pgpolicy, print_pgpolicy)
>      A declare_mp_handler(pgpolicy, set_pgpolicy)
>      @@ -700,6 +750,8 @@ print_rr_weight (char * buff, int len, void *ptr)
> 
>      A declare_def_handler(rr_weight, set_rr_weight)
>      A declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
>      +declare_ovr_handler(rr_weight, set_rr_weight)
>      +declare_ovr_snprint(rr_weight, print_rr_weight)
>      A declare_hw_handler(rr_weight, set_rr_weight)
>      A declare_hw_snprint(rr_weight, print_rr_weight)
>      A declare_mp_handler(rr_weight, set_rr_weight)
>      @@ -748,6 +800,8 @@ print_pgfailback (char * buff, int len, void *ptr)
> 
>      A declare_def_handler(pgfailback, set_pgfailback)
>      A declare_def_snprint_defint(pgfailback, print_pgfailback,
>      DEFAULT_FAILBACK)
>      +declare_ovr_handler(pgfailback, set_pgfailback)
>      +declare_ovr_snprint(pgfailback, print_pgfailback)
>      A declare_hw_handler(pgfailback, set_pgfailback)
>      A declare_hw_snprint(pgfailback, print_pgfailback)
>      A declare_mp_handler(pgfailback, set_pgfailback)
>      @@ -793,6 +847,8 @@ print_no_path_retry(char * buff, int len, void *ptr)
> 
>      A declare_def_handler(no_path_retry, set_no_path_retry)
>      A declare_def_snprint(no_path_retry, print_no_path_retry)
>      +declare_ovr_handler(no_path_retry, set_no_path_retry)
>      +declare_ovr_snprint(no_path_retry, print_no_path_retry)
>      A declare_hw_handler(no_path_retry, set_no_path_retry)
>      A declare_hw_snprint(no_path_retry, print_no_path_retry)
>      A declare_mp_handler(no_path_retry, set_no_path_retry)
>      @@ -1061,6 +1117,25 @@ declare_hw_handler(hwhandler, set_str)
>      A declare_hw_snprint(hwhandler, print_str)
> 
>      A /*
>      + * overrides handlers
>      + */
>      +static int
>      +overrides_handler(vector strvec)
>      +{
>      +A  A  A  A struct hwentry * overrides;
>      +
>      +A  A  A  A overrides = alloc_hwe();
>      +
>      +A  A  A  A if (!overrides)
>      +A  A  A  A  A  A  A  A return 1;
>      +
>      +A  A  A  A conf->overrides = overrides;
>      +A  A  A  A return 0;
>      +}
>      +
>      +
>      +
>      +/*
>      A  * multipaths block handlers
>      A  */
>      A static int
>      @@ -1236,6 +1311,29 @@ init_keywords(void)
>      A  A  A  A  install_keyword("detect_prio", &hw_detect_prio_handler,
>      &snprint_hw_detect_prio);
>      A  A  A  A  install_sublevel_end();
> 
>      +A  A  A  A install_keyword_root("overrides", &overrides_handler);
>      +A  A  A  A install_keyword("path_grouping_policy",
>      &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy);
>      +A  A  A  A install_keyword("uid_attribute", &ovr_uid_attribute_handler,
>      &snprint_ovr_uid_attribute);
>      +A  A  A  A install_keyword("getuid_callout", &ovr_getuid_handler,
>      &snprint_ovr_getuid);
>      +A  A  A  A install_keyword("path_selector", &ovr_selector_handler,
>      &snprint_ovr_selector);
>      +A  A  A  A install_keyword("path_checker", &ovr_checker_name_handler,
>      &snprint_ovr_checker_name);
>      +A  A  A  A install_keyword("checker", &ovr_checker_name_handler, NULL);
>      +A  A  A  A install_keyword("alias_prefix", &ovr_alias_prefix_handler,
>      &snprint_ovr_alias_prefix);
>      +A  A  A  A install_keyword("features", &ovr_features_handler,
>      &snprint_ovr_features);
>      +A  A  A  A install_keyword("prio", &ovr_prio_name_handler,
>      &snprint_ovr_prio_name);
>      +A  A  A  A install_keyword("prio_args", &ovr_prio_args_handler,
>      &snprint_ovr_prio_args);
>      +A  A  A  A install_keyword("failback", &ovr_pgfailback_handler,
>      &snprint_ovr_pgfailback);
>      +A  A  A  A install_keyword("rr_weight", &ovr_rr_weight_handler,
>      &snprint_ovr_rr_weight);
>      +A  A  A  A install_keyword("no_path_retry", &ovr_no_path_retry_handler,
>      &snprint_ovr_no_path_retry);
>      +A  A  A  A install_keyword("rr_min_io", &ovr_minio_handler,
>      &snprint_ovr_minio);
>      +A  A  A  A install_keyword("rr_min_io_rq", &ovr_minio_rq_handler,
>      &snprint_ovr_minio_rq);
>      +A  A  A  A install_keyword("flush_on_last_del",
>      &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
>      +A  A  A  A install_keyword("fast_io_fail_tmo",
>      &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail);
>      +A  A  A  A install_keyword("dev_loss_tmo", &ovr_dev_loss_handler,
>      &snprint_ovr_dev_loss);
>      +A  A  A  A install_keyword("user_friendly_names",
>      &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
>      +A  A  A  A install_keyword("retain_attached_hw_handler",
>      &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
>      +A  A  A  A install_keyword("detect_prio", &ovr_detect_prio_handler,
>      &snprint_ovr_detect_prio);
>      +
>      A  A  A  A  install_keyword_root("multipaths", &multipaths_handler);
>      A  A  A  A  install_keyword_multi("multipath", &multipath_handler,
>      NULL);
>      A  A  A  A  install_sublevel();
>      diff --git a/libmultipath/print.c b/libmultipath/print.c
>      index 383eae4..ade3841 100644
>      --- a/libmultipath/print.c
>      +++ b/libmultipath/print.c
>      @@ -1080,6 +1080,36 @@ snprint_mptable (char * buff, int len, vector
>      mptable)
>      A }
> 
>      A extern int
>      +snprint_overrides (char * buff, int len, struct hwentry *overrides)
>      +{
>      +A  A  A  A int fwd = 0;
>      +A  A  A  A int i;
>      +A  A  A  A struct keyword *rootkw;
>      +A  A  A  A struct keyword *kw;
>      +
>      +A  A  A  A rootkw = find_keyword(NULL, "overrides");
>      +A  A  A  A if (!rootkw)
>      +A  A  A  A  A  A  A  A return 0;
>      +
>      +A  A  A  A fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
>      +A  A  A  A if (fwd > len)
>      +A  A  A  A  A  A  A  A return len;
>      +A  A  A  A if (!overrides)
>      +A  A  A  A  A  A  A  A goto out;
>      +A  A  A  A iterate_sub_keywords(rootkw, kw, i) {
>      +A  A  A  A  A  A  A  A fwd += snprint_keyword(buff + fwd, len - fwd,
>      "\t%k %v\n",
>      +A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  kw, NULL);
>      +A  A  A  A  A  A  A  A if (fwd > len)
>      +A  A  A  A  A  A  A  A  A  A  A  A return len;
>      +A  A  A  A }
>      +out:
>      +A  A  A  A fwd += snprintf(buff + fwd, len - fwd, "}\n");
>      +A  A  A  A if (fwd > len)
>      +A  A  A  A  A  A  A  A return len;
>      +A  A  A  A return fwd;
>      +}
>      +
>      +extern int
>      A snprint_defaults (char * buff, int len)
>      A {
>      A  A  A  A  int fwd = 0;
>      diff --git a/libmultipath/print.h b/libmultipath/print.h
>      index aef182b..a3c3319 100644
>      --- a/libmultipath/print.h
>      +++ b/libmultipath/print.h
>      @@ -50,6 +50,7 @@ int snprint_status (char *, int, struct vectors *);
>      A int snprint_devices (char *, int, struct vectors *);
>      A int snprint_hwtable (char *, int, vector);
>      A int snprint_mptable (char *, int, vector);
>      +int snprint_overrides (char *, int, struct hwentry *);
> 
>      A void print_multipath_topology (struct multipath * mpp, int verbosity);
>      A void print_path (struct path * pp, char * style);
>      diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
>      index f2ab7d2..440802c 100644
>      --- a/libmultipath/propsel.c
>      +++ b/libmultipath/propsel.c
>      @@ -48,6 +48,8 @@ do {A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  \
>      A do_set(var, mp->mpe, mp->var, "(LUN setting)")
>      A #define mp_set_hwe(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  \
>      A do_set(var, mp->hwe, mp->var, "(controller setting)")
>      +#define mp_set_ovr(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  \
>      +do_set(var, conf->overrides, mp->var, "(overrides setting)")
>      A #define mp_set_conf(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A \
>      A do_set(var, conf, mp->var, "(config file default)")
>      A #define mp_set_default(var, value)A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A \
>      @@ -59,6 +61,8 @@ do_set(var, mpe, pp->var, "(LUN setting)")
>      A do_set(var, pp->hwe, pp->var, "(controller setting)")
>      A #define pp_set_conf(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A \
>      A do_set(var, conf, pp->var, "(config file default)")
>      +#define pp_set_ovr(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A  A  A  A  A  A  \
>      +do_set(var, conf->overrides, pp->var, "(overrides setting)")
>      A #define pp_set_default(var, value)A  A  A  A  A  A  A  A  A  A  A  A 
>      A  A  A  A  A  A  A \
>      A do_default(pp->var, value)
> 
>      @@ -130,6 +134,7 @@ select_rr_weight (struct multipath * mp)
>      A  A  A  A  char *origin, buff[13];
> 
>      A  A  A  A  mp_set_mpe(rr_weight);
>      +A  A  A  A mp_set_ovr(rr_weight);
>      A  A  A  A  mp_set_hwe(rr_weight);
>      A  A  A  A  mp_set_conf(rr_weight);
>      A  A  A  A  mp_set_default(rr_weight, RR_WEIGHT_NONE);
>      @@ -145,6 +150,7 @@ select_pgfailback (struct multipath * mp)
>      A  A  A  A  char *origin, buff[13];
> 
>      A  A  A  A  mp_set_mpe(pgfailback);
>      +A  A  A  A mp_set_ovr(pgfailback);
>      A  A  A  A  mp_set_hwe(pgfailback);
>      A  A  A  A  mp_set_conf(pgfailback);
>      A  A  A  A  mp_set_default(pgfailback, DEFAULT_FAILBACK);
>      @@ -165,6 +171,7 @@ select_pgpolicy (struct multipath * mp)
>      A  A  A  A  A  A  A  A  goto out;
>      A  A  A  A  }
>      A  A  A  A  mp_set_mpe(pgpolicy);
>      +A  A  A  A mp_set_ovr(pgpolicy);
>      A  A  A  A  mp_set_hwe(pgpolicy);
>      A  A  A  A  mp_set_conf(pgpolicy);
>      A  A  A  A  mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
>      @@ -181,10 +188,12 @@ select_selector (struct multipath * mp)
>      A  A  A  A  char *origin;
> 
>      A  A  A  A  mp_set_mpe(selector);
>      +A  A  A  A mp_set_ovr(selector);
>      A  A  A  A  mp_set_hwe(selector);
>      A  A  A  A  mp_set_conf(selector);
>      -A  A  A  A mp_set_default(selector, set_default(DEFAULT_SELECTOR));
>      +A  A  A  A mp_set_default(selector, DEFAULT_SELECTOR);
>      A out:
>      +A  A  A  A mp->selector = STRDUP(mp->selector);
>      A  A  A  A  condlog(3, "%s: path_selector = \"%s\" %s", mp->alias,
>      mp->selector,
>      A  A  A  A  A  A  A  A  origin);
>      A  A  A  A  return 0;
>      @@ -195,6 +204,7 @@ select_alias_prefix (struct multipath * mp)
>      A {
>      A  A  A  A  char *origin;
> 
>      +A  A  A  A mp_set_ovr(alias_prefix);
>      A  A  A  A  mp_set_hwe(alias_prefix);
>      A  A  A  A  mp_set_conf(alias_prefix);
>      A  A  A  A  mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
>      @@ -206,19 +216,30 @@ out:
>      A static int
>      A want_user_friendly_names(struct multipath * mp)
>      A {
>      -A  A  A  A if (mp->mpe &&
>      -A  A  A  A  A  A mp->mpe->user_friendly_names !=
>      USER_FRIENDLY_NAMES_UNDEF)
>      -A  A  A  A  A  A  A  A return (mp->mpe->user_friendly_names ==
>      USER_FRIENDLY_NAMES_ON);
>      -A  A  A  A if (mp->hwe &&
>      -A  A  A  A  A  A mp->hwe->user_friendly_names !=
>      USER_FRIENDLY_NAMES_UNDEF)
>      -A  A  A  A  A  A  A  A return (mp->hwe->user_friendly_names ==
>      USER_FRIENDLY_NAMES_ON);
>      -A  A  A  A return (conf->user_friendly_namesA  ==
>      USER_FRIENDLY_NAMES_ON);
>      +
>      +A  A  A  A char *origin;
>      +A  A  A  A int user_friendly_names;
>      +
>      +A  A  A  A do_set(user_friendly_names, mp->mpe, user_friendly_names,
>      +A  A  A  A  A  A  A  "(LUN setting)");
>      +A  A  A  A do_set(user_friendly_names, conf->overrides,
>      user_friendly_names,
>      +A  A  A  A  A  A  A  "(overrides setting)");
>      +A  A  A  A do_set(user_friendly_names, mp->hwe, user_friendly_names,
>      +A  A  A  A  A  A  A  "(controller setting)");
>      +A  A  A  A do_set(user_friendly_names, conf, user_friendly_names,
>      +A  A  A  A  A  A  A  "(config file setting)");
>      +A  A  A  A do_default(user_friendly_names, USER_FRIENDLY_NAMES_OFF);
>      +out:
>      +A  A  A  A condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
>      +A  A  A  A  A  A  A  A (user_friendly_names == USER_FRIENDLY_NAMES_ON)?
>      "yes" : "no",
>      +A  A  A  A  A  A  A  A origin);
>      +A  A  A  A return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
>      A }
> 
>      A extern int
>      A select_alias (struct multipath * mp)
>      A {
>      -A  A  A  A char *origin;
>      +A  A  A  A char *origin = NULL;
> 
>      A  A  A  A  if (mp->mpe && mp->mpe->alias) {
>      A  A  A  A  A  A  A  A  mp->alias = STRDUP(mp->mpe->alias);
>      @@ -261,6 +282,7 @@ select_features (struct multipath * mp)
>      A  A  A  A  char *origin;
> 
>      A  A  A  A  mp_set_mpe(features);
>      +A  A  A  A mp_set_ovr(features);
>      A  A  A  A  mp_set_hwe(features);
>      A  A  A  A  mp_set_conf(features);
>      A  A  A  A  mp_set_default(features, DEFAULT_FEATURES);
>      @@ -287,8 +309,9 @@ select_hwhandler (struct multipath * mp)
> 
>      A  A  A  A  mp_set_hwe(hwhandler);
>      A  A  A  A  mp_set_conf(hwhandler);
>      -A  A  A  A mp_set_default(hwhandler, set_default(DEFAULT_HWHANDLER));
>      +A  A  A  A mp_set_default(hwhandler, DEFAULT_HWHANDLER);
>      A out:
>      +A  A  A  A mp->hwhandler = STRDUP(mp->hwhandler);
>      A  A  A  A  condlog(3, "%s: hardware_handler = \"%s\" %s", mp->alias,
>      mp->hwhandler,
>      A  A  A  A  A  A  A  A  origin);
>      A  A  A  A  return 0;
>      @@ -300,6 +323,7 @@ select_checker(struct path *pp)
>      A  A  A  A  char *origin, *checker_name;
>      A  A  A  A  struct checker * c = &pp->checker;
> 
>      +A  A  A  A do_set(checker_name, conf->overrides, checker_name,
>      "(overrides setting)");
>      A  A  A  A  do_set(checker_name, pp->hwe, checker_name, "(controller
>      setting)");
>      A  A  A  A  do_set(checker_name, conf, checker_name, "(config file
>      setting)");
>      A  A  A  A  do_default(checker_name, DEFAULT_CHECKER);
>      @@ -327,6 +351,8 @@ select_getuid (struct path * pp)
>      A {
>      A  A  A  A  char *origin;
> 
>      +A  A  A  A pp_set_ovr(uid_attribute);
>      +A  A  A  A pp_set_ovr(getuid);
>      A  A  A  A  pp_set_hwe(uid_attribute);
>      A  A  A  A  pp_set_hwe(getuid);
>      A  A  A  A  pp_set_conf(uid_attribute);
>      @@ -383,6 +409,7 @@ select_prio (struct path * pp)
>      A  A  A  A  }
>      A  A  A  A  mpe = find_mpe(pp->wwid);
>      A  A  A  A  set_prio(mpe, "(LUN setting)");
>      +A  A  A  A set_prio(conf->overrides, "(overrides setting)");
>      A  A  A  A  set_prio(pp->hwe, "controller setting)");
>      A  A  A  A  set_prio(conf, "(config file default)");
>      A  A  A  A  prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
>      @@ -405,6 +432,7 @@ select_no_path_retry(struct multipath *mp)
>      A  A  A  A  A  A  A  A  return 0;
>      A  A  A  A  }
>      A  A  A  A  mp_set_mpe(no_path_retry);
>      +A  A  A  A mp_set_ovr(no_path_retry);
>      A  A  A  A  mp_set_hwe(no_path_retry);
>      A  A  A  A  mp_set_conf(no_path_retry);
>      A out:
>      @@ -427,6 +455,7 @@ select_minio_rq (struct multipath * mp)
>      A  A  A  A  char *origin;
> 
>      A  A  A  A  do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
>      +A  A  A  A do_set(minio_rq, conf->overrides, mp->minio, "(overrides
>      setting)");
>      A  A  A  A  do_set(minio_rq, mp->hwe, mp->minio, "(controller
>      setting)");
>      A  A  A  A  do_set(minio_rq, conf, mp->minio, "(config file setting)");
>      A  A  A  A  do_default(mp->minio, DEFAULT_MINIO_RQ);
>      @@ -441,6 +470,7 @@ select_minio_bio (struct multipath * mp)
>      A  A  A  A  char *origin;
> 
>      A  A  A  A  mp_set_mpe(minio);
>      +A  A  A  A mp_set_ovr(minio);
>      A  A  A  A  mp_set_hwe(minio);
>      A  A  A  A  mp_set_conf(minio);
>      A  A  A  A  mp_set_default(minio, DEFAULT_MINIO);
>      @@ -465,6 +495,7 @@ select_fast_io_fail(struct multipath *mp)
>      A {
>      A  A  A  A  char *origin, buff[12];
> 
>      +A  A  A  A mp_set_ovr(fast_io_fail);
>      A  A  A  A  mp_set_hwe(fast_io_fail);
>      A  A  A  A  mp_set_conf(fast_io_fail);
>      A  A  A  A  mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
>      @@ -479,6 +510,7 @@ select_dev_loss(struct multipath *mp)
>      A {
>      A  A  A  A  char *origin, buff[12];
> 
>      +A  A  A  A mp_set_ovr(dev_loss);
>      A  A  A  A  mp_set_hwe(dev_loss);
>      A  A  A  A  mp_set_conf(dev_loss);
>      A  A  A  A  mp->dev_loss = 0;
>      @@ -497,6 +529,7 @@ select_flush_on_last_del(struct multipath *mp)
>      A  A  A  A  if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
>      A  A  A  A  A  A  A  A  return 0;
>      A  A  A  A  mp_set_mpe(flush_on_last_del);
>      +A  A  A  A mp_set_ovr(flush_on_last_del);
>      A  A  A  A  mp_set_hwe(flush_on_last_del);
>      A  A  A  A  mp_set_conf(flush_on_last_del);
>      A  A  A  A  mp_set_default(flush_on_last_del, FLUSH_DISABLED);
>      @@ -532,6 +565,7 @@ select_retain_hwhandler (struct multipath * mp)
>      A  A  A  A  A  A  A  A  origin = "(requires kernel version >= 1.5.0)";
>      A  A  A  A  A  A  A  A  goto out;
>      A  A  A  A  }
>      +A  A  A  A mp_set_ovr(retain_hwhandler);
>      A  A  A  A  mp_set_hwe(retain_hwhandler);
>      A  A  A  A  mp_set_conf(retain_hwhandler);
>      A  A  A  A  mp_set_default(retain_hwhandler, DEFAULT_RETAIN_HWHANDLER);
>      @@ -547,6 +581,7 @@ select_detect_prio (struct path * pp)
>      A {
>      A  A  A  A  char *origin;
> 
>      +A  A  A  A pp_set_ovr(detect_prio);
>      A  A  A  A  pp_set_hwe(detect_prio);
>      A  A  A  A  pp_set_conf(detect_prio);
>      A  A  A  A  pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
>      diff --git a/libmultipath/structs.c b/libmultipath/structs.c
>      index 30d247d..0538327 100644
>      --- a/libmultipath/structs.c
>      +++ b/libmultipath/structs.c
>      @@ -206,10 +206,7 @@ free_multipath_attributes (struct multipath * mpp)
>      A  A  A  A  if (!mpp)
>      A  A  A  A  A  A  A  A  return;
> 
>      -A  A  A  A if (mpp->selector &&
>      -A  A  A  A  A  A mpp->selector != conf->selector &&
>      -A  A  A  A  A  A (!mpp->mpe || (mpp->mpe && mpp->selector !=
>      mpp->mpe->selector)) &&
>      -A  A  A  A  A  A (!mpp->hwe || (mpp->hwe && mpp->selector !=
>      mpp->hwe->selector))) {
>      +A  A  A  A if (mpp->selector) {
>      A  A  A  A  A  A  A  A  FREE(mpp->selector);
>      A  A  A  A  A  A  A  A  mpp->selector = NULL;
>      A  A  A  A  }
>      @@ -219,9 +216,7 @@ free_multipath_attributes (struct multipath * mpp)
>      A  A  A  A  A  A  A  A  mpp->features = NULL;
>      A  A  A  A  }
> 
>      -A  A  A  A if (mpp->hwhandler &&
>      -A  A  A  A  A  A mpp->hwhandler != conf->hwhandler &&
>      -A  A  A  A  A  A (!mpp->hwe || (mpp->hwe && mpp->hwhandler !=
>      mpp->hwe->hwhandler))) {
>      +A  A  A  A if (mpp->hwhandler) {
>      A  A  A  A  A  A  A  A  FREE(mpp->hwhandler);
>      A  A  A  A  A  A  A  A  mpp->hwhandler = NULL;
>      A  A  A  A  }
>      diff --git a/multipath.conf.annotated b/multipath.conf.annotated
>      index 0af1d4c..71afc0a 100644
>      --- a/multipath.conf.annotated
>      +++ b/multipath.conf.annotated
>      @@ -485,7 +485,8 @@
>      A ## scope : multipath & multipathd
>      A ## descA  : list of per storage controller settings
>      A ##A  A  A  A overrides default settings (device_maps block)
>      -##A  A  A  A  A overriden by per multipath settings (multipaths block)
>      +##A  A  A  A  overriden by per multipath settings (multipaths block)
>      +##A  A  A  A and the overrides settings (overrides block)
>      A ##
>      A #devices {
>      A #A  A  A  #
>      @@ -651,3 +652,18 @@
>      A #A  A  A  A  A  A  A  rr_weightA  A  A  A  A  A  A  A priorities
>      A #A  A  A  }
>      A #}
>      +#
>      +##
>      +## nameA  : devices
>      +## scope : multipath & multipathd
>      +## descA  : list of settings to override all hadware settings for all
>      devices
>      +##A  A  A  A overrides default settings (device_maps block)
>      +##A  A  A  A and per device type settings (devices block)
>      +##A  A  A  A  overriden by per multipath settings (multipaths block)
>      +##
>      +#A  A  A  attributes and values are identical to the device block
>      +#
>      +#overrides {
>      +#A  A  A  dev_loss_tmoA  A  A  A  A  A  60
>      +#A  A  A  no_path_retryA  A  A  A  A  A fail
>      +#}
>      diff --git a/multipath.conf.defaults b/multipath.conf.defaults
>      index 654be97..1c65e02 100644
>      --- a/multipath.conf.defaults
>      +++ b/multipath.conf.defaults
>      @@ -912,3 +912,5 @@
>      A #}
>      A #multipaths {
>      A #}
>      +#overrides {
>      +#}
>      diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
>      index bda1b75..f7b9b8a 100644
>      --- a/multipath.conf.synthetic
>      +++ b/multipath.conf.synthetic
>      @@ -72,3 +72,6 @@
>      A #A  A  A  A  A  A  A  path_grouping_policyA  A  multibus
>      A #A  A  A  }
>      A #}
>      +#overrides {
>      +#A  A  A  no_path_retryA  A  A  A  A  A  A  A  A  A fail
>      +#}
>      diff --git a/multipath/main.c b/multipath/main.c
>      index fd6262f..ea453b4 100644
>      --- a/multipath/main.c
>      +++ b/multipath/main.c
>      @@ -405,6 +405,12 @@ dump_config (void)
>      A  A  A  A  A  A  A  A  A  A  A  A  reply = REALLOC(reply, maxlen *= 2);
>      A  A  A  A  A  A  A  A  A  A  A  A  continue;
>      A  A  A  A  A  A  A  A  }
>      +A  A  A  A  A  A  A  A c += snprint_overrides(c, reply + maxlen - c,
>      conf->overrides);
>      +A  A  A  A  A  A  A  A again = ((c - reply) == maxlen);
>      +A  A  A  A  A  A  A  A if (again) {
>      +A  A  A  A  A  A  A  A  A  A  A  A reply = REALLOC(reply, maxlen *= 2);
>      +A  A  A  A  A  A  A  A  A  A  A  A continue;
>      +A  A  A  A  A  A  A  A }
>      A  A  A  A  A  A  A  A  c += snprint_mptable(c, reply + maxlen - c,
>      conf->mptable);
>      A  A  A  A  A  A  A  A  again = ((c - reply) == maxlen);
>      A  A  A  A  A  A  A  A  if (again)
>      diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
>      index cadb34d..b823990 100644
>      --- a/multipath/multipath.conf.5
>      +++ b/multipath/multipath.conf.5
>      @@ -61,6 +61,10 @@ the udev attribute given by the
>      A .TP
>      A .B devices
>      A This section defines the device-specific settings.
>      +.TP
>      +.B overrides
>      +This section defines values for attributes that should override the
>      +device-specific settings for all devices.
>      A .RE
>      A .LP
>      A .SH "defaults section"
>      @@ -629,6 +633,59 @@ section:
>      A .RE
>      A .PD
>      A .LP
>      +.SH "overrides section"
>      +The overrides section recognizes the following optional attributes; if
>      not set
>      +the values are taken from the
>      +.I devices
>      +or
>      +.I defaults
>      +sections:
>      +.sp 1
>      +.PD .1v
>      +.RS
>      +.TP 18
>      +.B path_grouping_policy
>      +.TP
>      +.B uid_attribute
>      +.TP
>      +.B getuid_callout
>      +.TP
>      +.B path_selector
>      +.TP
>      +.B path_checker
>      +.TP
>      +.B alias_prefix
>      +.TP
>      +.B features
>      +.TP
>      +.B prio
>      +.TP
>      +.B prio_args
>      +.TP
>      +.B failback
>      +.TP
>      +.B rr_weight
>      +.TP
>      +.B no_path_retry
>      +.TP
>      +.B rr_min_io
>      +.TP
>      +.B rr_min_io_rq
>      +.TP
>      +.B flush_on_last_del
>      +.TP
>      +.B fast_io_fail_tmo
>      +.TP
>      +.B dev_loss_tmo
>      +.TP
>      +.B user_friendly_names
>      +.TP
>      +.B retain_attached_hw_handler
>      +.TP
>      +.B detect_prio
>      +.RE
>      +.PD
>      +.LP
>      A .SH "KNOWN ISSUES"
>      A The usage of
>      A .B queue_if_no_path
>      diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
>      index b086340..0ce1408 100644
>      --- a/multipathd/cli_handlers.c
>      +++ b/multipathd/cli_handlers.c
>      @@ -190,6 +190,16 @@ show_config (char ** r, int * len)
>      A  A  A  A  A  A  A  A  A  A  A  A  maxlen *= 2;
>      A  A  A  A  A  A  A  A  A  A  A  A  continue;
>      A  A  A  A  A  A  A  A  }
>      +A  A  A  A  A  A  A  A c += snprint_overrides(c, reply + maxlen - c,
>      conf->overrides);
>      +A  A  A  A  A  A  A  A again = ((c - reply) == maxlen);
>      +A  A  A  A  A  A  A  A if (again) {
>      +A  A  A  A  A  A  A  A  A  A  A  A reply = REALLOC(reply, maxlen * 2);
>      +A  A  A  A  A  A  A  A  A  A  A  A if (!reply)
>      +A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A return 1;
>      +A  A  A  A  A  A  A  A  A  A  A  A memset(reply + maxlen, 0, maxlen);
>      +A  A  A  A  A  A  A  A  A  A  A  A maxlen *= 2;
>      +A  A  A  A  A  A  A  A  A  A  A  A continue;
>      +A  A  A  A  A  A  A  A }
>      A  A  A  A  A  A  A  A  c += snprint_mptable(c, reply + maxlen - c,
>      conf->mptable);
>      A  A  A  A  A  A  A  A  again = ((c - reply) == maxlen);
>      A  A  A  A  A  A  A  A  REALLOC_REPLY(reply, again, maxlen);
>      --
>      1.8.3.1

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-12 18:05     ` Benjamin Marzinski
@ 2015-01-12 20:27       ` Christophe Varoqui
  0 siblings, 0 replies; 16+ messages in thread
From: Christophe Varoqui @ 2015-01-12 20:27 UTC (permalink / raw)
  To: Benjamin Marzinski; +Cc: device-mapper development


[-- Attachment #1.1: Type: text/plain, Size: 41133 bytes --]

Ben,

I have no complaints about this patch iteration, and acknowledged the need
for some users. As nobody voiced against it, I will apply the patch.

Thanks,
Christophe Varoqui
OpenSVC


On Mon, Jan 12, 2015 at 7:05 PM, Benjamin Marzinski <bmarzins@redhat.com>
wrote:

> On Fri, Jan 09, 2015 at 12:06:29AM +0100, Christophe Varoqui wrote:
> >    I have no strong opinion on this one : I feel like the complexity of
> the
> >    parameter inheritance system is already quite complicated ... but this
> >    addition of a new layer would likely and safely be ignored by users
> who
> >    don't need it. Those who need it are surely ready to pay the price.
> >    Does someone have objection to my applying this patch ?
>
> Christophe, I wrote this patch because you thought an "overrides"
> section would be more intuitive than my previous solution of a
> specialized "all_devs" devices section option to overwrite options on
> all the devices.
>
> http://www.redhat.com/archives/dm-devel/2014-September/msg00047.html
>
> Maybe this isn't exactly what you had in mind.  At any rate, I'd like to
> have some method inside of multipath to accomplish this.
>
> -Ben
>
> >    Best regards,
> >    Christophe
> >    On Wed, Nov 19, 2014 at 7:17 AM, Benjamin Marzinski <
> bmarzins@redhat.com>
> >    wrote:
> >
> >      Sometimes users want to be able to set a configuration value for all
> >      their
> >      devices (for instance, they may want all devices to set
> no_path_retry to
> >      fail). The builtin device configurations make this tricky, since
> users
> >      need
> >      to change each device configuration individually. To avoid that,
> this
> >      patch
> >      adds a new section to multipath.conf, "overrides".A  This section
> has
> >      all of
> >      the attributes that are in both the devices and defaults section.
> >      Attributes set in the overrides section have a higher priority that
> >      those
> >      in the devices section. With this section added, the multipath
> >      configuration order now goes:
> >
> >      multipaths > overrides > devices > defaults
> >
> >      I also made want_user_friendly_names print out where the
> configuration
> >      came
> >      from, and I made made select_hwhandler and select_selector always
> strdup
> >      the string, instead of only on the defaults.A  Since multipathd will
> >      update
> >      the device strings from the kernel anyway, the old way just added
> >      complexity without saving any memory.
> >
> >      To store the overrides configuration, I used a hwentry structure.
> We may
> >      want to make a new overrides structure, so that we set any of the
> >      defaults
> >      values in overrides.A  That way, users could skip using defaults and
> >      just
> >      use overrides if they wanted. However, this would take some
> additional
> >      changes to make sure that all the defaults options can undefined,
> which
> >      they can't currently be.
> >
> >      Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
> >      ---
> >      A libmultipath/config.cA  A  A  |A  1 +
> >      A libmultipath/config.hA  A  A  |A  1 +
> >      A libmultipath/dict.cA  A  A  A  | 98
> >      ++++++++++++++++++++++++++++++++++++++++++++++
> >      A libmultipath/print.cA  A  A  A | 30 ++++++++++++++
> >      A libmultipath/print.hA  A  A  A |A  1 +
> >      A libmultipath/propsel.cA  A  A | 55 +++++++++++++++++++++-----
> >      A libmultipath/structs.cA  A  A |A  9 +----
> >      A multipath.conf.annotatedA  A | 18 ++++++++-
> >      A multipath.conf.defaultsA  A  |A  2 +
> >      A multipath.conf.syntheticA  A |A  3 ++
> >      A multipath/main.cA  A  A  A  A  A |A  6 +++
> >      A multipath/multipath.conf.5 | 57 +++++++++++++++++++++++++++
> >      A multipathd/cli_handlers.cA  | 10 +++++
> >      A 13 files changed, 273 insertions(+), 18 deletions(-)
> >
> >      diff --git a/libmultipath/config.c b/libmultipath/config.c
> >      index bfd8ee8..7f7bd5a 100644
> >      --- a/libmultipath/config.c
> >      +++ b/libmultipath/config.c
> >      @@ -523,6 +523,7 @@ free_config (struct config * conf)
> >
> >      A  A  A  A  free_mptable(conf->mptable);
> >      A  A  A  A  free_hwtable(conf->hwtable);
> >      +A  A  A  A free_hwe(conf->overrides);
> >      A  A  A  A  free_keywords(conf->keywords);
> >      A  A  A  A  FREE(conf);
> >      A }
> >      diff --git a/libmultipath/config.h b/libmultipath/config.h
> >      index c57ab31..ef1d7c3 100644
> >      --- a/libmultipath/config.h
> >      +++ b/libmultipath/config.h
> >      @@ -145,6 +145,7 @@ struct config {
> >      A  A  A  A  vector keywords;
> >      A  A  A  A  vector mptable;
> >      A  A  A  A  vector hwtable;
> >      +A  A  A  A struct hwentry *overrides;
> >
> >      A  A  A  A  vector blist_devnode;
> >      A  A  A  A  vector blist_wwid;
> >      diff --git a/libmultipath/dict.c b/libmultipath/dict.c
> >      index 98cbe48..737c9b0 100644
> >      --- a/libmultipath/dict.c
> >      +++ b/libmultipath/dict.c
> >      @@ -181,6 +181,22 @@ snprint_hw_ ## option (char * buff, int len,
> void *
> >      data)A  A  A  A  A  \
> >      A  A  A  A  return function (buff, len, &hwe->option);A  A  A  A
> A  A
> >      A  A  A  A  A  \
> >      A }
> >
> >      +#define declare_ovr_handler(option, function)A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  \
> >      +static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A  A  A \
> >      +ovr_ ## option ## _handler (vector strvec)A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A \
> >      +{A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A  A  A  A  \
> >      +A  A  A  A if (!conf->overrides)A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A \
> >      +A  A  A  A  A  A  A  A return 1;A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A \
> >      +A  A  A  A return function (strvec, &conf->overrides->option);A
> A  A
> >      A  A  A  A \
> >      +}
> >      +
> >      +#define declare_ovr_snprint(option, function)A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  \
> >      +static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A  A  A \
> >      +snprint_ovr_ ## option (char * buff, int len, void * data)A  A  A
> A
> >      A  A  A \
> >      +{A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A  A  A  A  \
> >      +A  A  A  A return function (buff, len,
> &conf->overrides->option);A  A
> >      A  A  A  \
> >      +}
> >      +
> >      A #define declare_mp_handler(option, function)A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A \
> >      A static intA  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A \
> >      A mp_ ## option ## _handler (vector strvec)A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  \
> >      @@ -218,21 +234,29 @@ declare_def_handler(selector, set_str)
> >      A declare_def_snprint_defstr(selector, print_str, DEFAULT_SELECTOR)
> >      A declare_hw_handler(selector, set_str)
> >      A declare_hw_snprint(selector, print_str)
> >      +declare_ovr_handler(selector, set_str)
> >      +declare_ovr_snprint(selector, print_str)
> >      A declare_mp_handler(selector, set_str)
> >      A declare_mp_snprint(selector, print_str)
> >
> >      A declare_def_handler(uid_attribute, set_str)
> >      A declare_def_snprint_defstr(uid_attribute, print_str,
> >      DEFAULT_UID_ATTRIBUTE)
> >      +declare_ovr_handler(uid_attribute, set_str)
> >      +declare_ovr_snprint(uid_attribute, print_str)
> >      A declare_hw_handler(uid_attribute, set_str)
> >      A declare_hw_snprint(uid_attribute, print_str)
> >
> >      A declare_def_handler(getuid, set_str)
> >      A declare_def_snprint(getuid, print_str)
> >      +declare_ovr_handler(getuid, set_str)
> >      +declare_ovr_snprint(getuid, print_str)
> >      A declare_hw_handler(getuid, set_str)
> >      A declare_hw_snprint(getuid, print_str)
> >
> >      A declare_def_handler(prio_name, set_str)
> >      A declare_def_snprint_defstr(prio_name, print_str, DEFAULT_PRIO)
> >      +declare_ovr_handler(prio_name, set_str)
> >      +declare_ovr_snprint(prio_name, print_str)
> >      A declare_hw_handler(prio_name, set_str)
> >      A declare_hw_snprint(prio_name, print_str)
> >      A declare_mp_handler(prio_name, set_str)
> >      @@ -240,11 +264,15 @@ declare_mp_snprint(prio_name, print_str)
> >
> >      A declare_def_handler(alias_prefix, set_str)
> >      A declare_def_snprint_defstr(alias_prefix, print_str,
> >      DEFAULT_ALIAS_PREFIX)
> >      +declare_ovr_handler(alias_prefix, set_str)
> >      +declare_ovr_snprint(alias_prefix, print_str)
> >      A declare_hw_handler(alias_prefix, set_str)
> >      A declare_hw_snprint(alias_prefix, print_str)
> >
> >      A declare_def_handler(prio_args, set_str)
> >      A declare_def_snprint_defstr(prio_args, print_str,
> DEFAULT_PRIO_ARGS)
> >      +declare_ovr_handler(prio_args, set_str)
> >      +declare_ovr_snprint(prio_args, print_str)
> >      A declare_hw_handler(prio_args, set_str)
> >      A declare_hw_snprint(prio_args, print_str)
> >      A declare_mp_handler(prio_args, set_str)
> >      @@ -252,6 +280,8 @@ declare_mp_snprint(prio_args, print_str)
> >
> >      A declare_def_handler(features, set_str)
> >      A declare_def_snprint_defstr(features, print_str, DEFAULT_FEATURES)
> >      +declare_ovr_handler(features, set_str)
> >      +declare_ovr_snprint(features, print_str)
> >      A declare_hw_handler(features, set_str)
> >      A declare_hw_snprint(features, print_str)
> >      A declare_mp_handler(features, set_str)
> >      @@ -259,11 +289,15 @@ declare_mp_snprint(features, print_str)
> >
> >      A declare_def_handler(checker_name, set_str)
> >      A declare_def_snprint_defstr(checker_name, print_str,
> DEFAULT_CHECKER)
> >      +declare_ovr_handler(checker_name, set_str)
> >      +declare_ovr_snprint(checker_name, print_str)
> >      A declare_hw_handler(checker_name, set_str)
> >      A declare_hw_snprint(checker_name, print_str)
> >
> >      A declare_def_handler(minio, set_int)
> >      A declare_def_snprint_defint(minio, print_int, DEFAULT_MINIO)
> >      +declare_ovr_handler(minio, set_int)
> >      +declare_ovr_snprint(minio, print_nonzero)
> >      A declare_hw_handler(minio, set_int)
> >      A declare_hw_snprint(minio, print_nonzero)
> >      A declare_mp_handler(minio, set_int)
> >      @@ -271,6 +305,8 @@ declare_mp_snprint(minio, print_nonzero)
> >
> >      A declare_def_handler(minio_rq, set_int)
> >      A declare_def_snprint_defint(minio_rq, print_int, DEFAULT_MINIO_RQ)
> >      +declare_ovr_handler(minio_rq, set_int)
> >      +declare_ovr_snprint(minio_rq, print_nonzero)
> >      A declare_hw_handler(minio_rq, set_int)
> >      A declare_hw_snprint(minio_rq, print_nonzero)
> >      A declare_mp_handler(minio_rq, set_int)
> >      @@ -296,6 +332,8 @@ declare_def_snprint(checker_timeout,
> print_nonzero)
> >
> >      A declare_def_handler(flush_on_last_del, set_yes_no_undef)
> >      A declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef,
> >      YNU_NO)
> >      +declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
> >      +declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
> >      A declare_hw_handler(flush_on_last_del, set_yes_no_undef)
> >      A declare_hw_snprint(flush_on_last_del, print_yes_no_undef)
> >      A declare_mp_handler(flush_on_last_del, set_yes_no_undef)
> >      @@ -303,6 +341,8 @@ declare_mp_snprint(flush_on_last_del,
> >      print_yes_no_undef)
> >
> >      A declare_def_handler(user_friendly_names, set_yes_no_undef)
> >      A declare_def_snprint_defint(user_friendly_names,
> print_yes_no_undef,
> >      YNU_NO)
> >      +declare_ovr_handler(user_friendly_names, set_yes_no_undef)
> >      +declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
> >      A declare_hw_handler(user_friendly_names, set_yes_no_undef)
> >      A declare_hw_snprint(user_friendly_names, print_yes_no_undef)
> >      A declare_mp_handler(user_friendly_names, set_yes_no_undef)
> >      @@ -316,11 +356,15 @@ declare_def_snprint(wwids_file, print_str)
> >
> >      A declare_def_handler(retain_hwhandler, set_yes_no_undef)
> >      A declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef,
> >      YNU_NO)
> >      +declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
> >      +declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
> >      A declare_hw_handler(retain_hwhandler, set_yes_no_undef)
> >      A declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
> >
> >      A declare_def_handler(detect_prio, set_yes_no_undef)
> >      A declare_def_snprint_defint(detect_prio, print_yes_no_undef,
> YNU_NO)
> >      +declare_ovr_handler(detect_prio, set_yes_no_undef)
> >      +declare_ovr_snprint(detect_prio, print_yes_no_undef)
> >      A declare_hw_handler(detect_prio, set_yes_no_undef)
> >      A declare_hw_snprint(detect_prio, print_yes_no_undef)
> >
> >      @@ -512,6 +556,8 @@ print_fast_io_fail(char * buff, int len, void
> *ptr)
> >
> >      A declare_def_handler(fast_io_fail, set_fast_io_fail)
> >      A declare_def_snprint(fast_io_fail, print_fast_io_fail)
> >      +declare_ovr_handler(fast_io_fail, set_fast_io_fail)
> >      +declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
> >      A declare_hw_handler(fast_io_fail, set_fast_io_fail)
> >      A declare_hw_snprint(fast_io_fail, print_fast_io_fail)
> >
> >      @@ -548,6 +594,8 @@ print_dev_loss(char * buff, int len, void *ptr)
> >
> >      A declare_def_handler(dev_loss, set_dev_loss)
> >      A declare_def_snprint(dev_loss, print_dev_loss)
> >      +declare_ovr_handler(dev_loss, set_dev_loss)
> >      +declare_ovr_snprint(dev_loss, print_dev_loss)
> >      A declare_hw_handler(dev_loss, set_dev_loss)
> >      A declare_hw_snprint(dev_loss, print_dev_loss)
> >
> >      @@ -583,6 +631,8 @@ print_pgpolicy(char * buff, int len, void *ptr)
> >
> >      A declare_def_handler(pgpolicy, set_pgpolicy)
> >      A declare_def_snprint_defint(pgpolicy, print_pgpolicy,
> DEFAULT_PGPOLICY)
> >      +declare_ovr_handler(pgpolicy, set_pgpolicy)
> >      +declare_ovr_snprint(pgpolicy, print_pgpolicy)
> >      A declare_hw_handler(pgpolicy, set_pgpolicy)
> >      A declare_hw_snprint(pgpolicy, print_pgpolicy)
> >      A declare_mp_handler(pgpolicy, set_pgpolicy)
> >      @@ -700,6 +750,8 @@ print_rr_weight (char * buff, int len, void
> *ptr)
> >
> >      A declare_def_handler(rr_weight, set_rr_weight)
> >      A declare_def_snprint_defint(rr_weight, print_rr_weight,
> RR_WEIGHT_NONE)
> >      +declare_ovr_handler(rr_weight, set_rr_weight)
> >      +declare_ovr_snprint(rr_weight, print_rr_weight)
> >      A declare_hw_handler(rr_weight, set_rr_weight)
> >      A declare_hw_snprint(rr_weight, print_rr_weight)
> >      A declare_mp_handler(rr_weight, set_rr_weight)
> >      @@ -748,6 +800,8 @@ print_pgfailback (char * buff, int len, void
> *ptr)
> >
> >      A declare_def_handler(pgfailback, set_pgfailback)
> >      A declare_def_snprint_defint(pgfailback, print_pgfailback,
> >      DEFAULT_FAILBACK)
> >      +declare_ovr_handler(pgfailback, set_pgfailback)
> >      +declare_ovr_snprint(pgfailback, print_pgfailback)
> >      A declare_hw_handler(pgfailback, set_pgfailback)
> >      A declare_hw_snprint(pgfailback, print_pgfailback)
> >      A declare_mp_handler(pgfailback, set_pgfailback)
> >      @@ -793,6 +847,8 @@ print_no_path_retry(char * buff, int len, void
> *ptr)
> >
> >      A declare_def_handler(no_path_retry, set_no_path_retry)
> >      A declare_def_snprint(no_path_retry, print_no_path_retry)
> >      +declare_ovr_handler(no_path_retry, set_no_path_retry)
> >      +declare_ovr_snprint(no_path_retry, print_no_path_retry)
> >      A declare_hw_handler(no_path_retry, set_no_path_retry)
> >      A declare_hw_snprint(no_path_retry, print_no_path_retry)
> >      A declare_mp_handler(no_path_retry, set_no_path_retry)
> >      @@ -1061,6 +1117,25 @@ declare_hw_handler(hwhandler, set_str)
> >      A declare_hw_snprint(hwhandler, print_str)
> >
> >      A /*
> >      + * overrides handlers
> >      + */
> >      +static int
> >      +overrides_handler(vector strvec)
> >      +{
> >      +A  A  A  A struct hwentry * overrides;
> >      +
> >      +A  A  A  A overrides = alloc_hwe();
> >      +
> >      +A  A  A  A if (!overrides)
> >      +A  A  A  A  A  A  A  A return 1;
> >      +
> >      +A  A  A  A conf->overrides = overrides;
> >      +A  A  A  A return 0;
> >      +}
> >      +
> >      +
> >      +
> >      +/*
> >      A  * multipaths block handlers
> >      A  */
> >      A static int
> >      @@ -1236,6 +1311,29 @@ init_keywords(void)
> >      A  A  A  A  install_keyword("detect_prio", &hw_detect_prio_handler,
> >      &snprint_hw_detect_prio);
> >      A  A  A  A  install_sublevel_end();
> >
> >      +A  A  A  A install_keyword_root("overrides", &overrides_handler);
> >      +A  A  A  A install_keyword("path_grouping_policy",
> >      &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy);
> >      +A  A  A  A install_keyword("uid_attribute",
> &ovr_uid_attribute_handler,
> >      &snprint_ovr_uid_attribute);
> >      +A  A  A  A install_keyword("getuid_callout", &ovr_getuid_handler,
> >      &snprint_ovr_getuid);
> >      +A  A  A  A install_keyword("path_selector", &ovr_selector_handler,
> >      &snprint_ovr_selector);
> >      +A  A  A  A install_keyword("path_checker",
> &ovr_checker_name_handler,
> >      &snprint_ovr_checker_name);
> >      +A  A  A  A install_keyword("checker", &ovr_checker_name_handler,
> NULL);
> >      +A  A  A  A install_keyword("alias_prefix",
> &ovr_alias_prefix_handler,
> >      &snprint_ovr_alias_prefix);
> >      +A  A  A  A install_keyword("features", &ovr_features_handler,
> >      &snprint_ovr_features);
> >      +A  A  A  A install_keyword("prio", &ovr_prio_name_handler,
> >      &snprint_ovr_prio_name);
> >      +A  A  A  A install_keyword("prio_args", &ovr_prio_args_handler,
> >      &snprint_ovr_prio_args);
> >      +A  A  A  A install_keyword("failback", &ovr_pgfailback_handler,
> >      &snprint_ovr_pgfailback);
> >      +A  A  A  A install_keyword("rr_weight", &ovr_rr_weight_handler,
> >      &snprint_ovr_rr_weight);
> >      +A  A  A  A install_keyword("no_path_retry",
> &ovr_no_path_retry_handler,
> >      &snprint_ovr_no_path_retry);
> >      +A  A  A  A install_keyword("rr_min_io", &ovr_minio_handler,
> >      &snprint_ovr_minio);
> >      +A  A  A  A install_keyword("rr_min_io_rq", &ovr_minio_rq_handler,
> >      &snprint_ovr_minio_rq);
> >      +A  A  A  A install_keyword("flush_on_last_del",
> >      &ovr_flush_on_last_del_handler, &snprint_ovr_flush_on_last_del);
> >      +A  A  A  A install_keyword("fast_io_fail_tmo",
> >      &ovr_fast_io_fail_handler, &snprint_ovr_fast_io_fail);
> >      +A  A  A  A install_keyword("dev_loss_tmo", &ovr_dev_loss_handler,
> >      &snprint_ovr_dev_loss);
> >      +A  A  A  A install_keyword("user_friendly_names",
> >      &ovr_user_friendly_names_handler, &snprint_ovr_user_friendly_names);
> >      +A  A  A  A install_keyword("retain_attached_hw_handler",
> >      &ovr_retain_hwhandler_handler, &snprint_ovr_retain_hwhandler);
> >      +A  A  A  A install_keyword("detect_prio", &ovr_detect_prio_handler,
> >      &snprint_ovr_detect_prio);
> >      +
> >      A  A  A  A  install_keyword_root("multipaths", &multipaths_handler);
> >      A  A  A  A  install_keyword_multi("multipath", &multipath_handler,
> >      NULL);
> >      A  A  A  A  install_sublevel();
> >      diff --git a/libmultipath/print.c b/libmultipath/print.c
> >      index 383eae4..ade3841 100644
> >      --- a/libmultipath/print.c
> >      +++ b/libmultipath/print.c
> >      @@ -1080,6 +1080,36 @@ snprint_mptable (char * buff, int len, vector
> >      mptable)
> >      A }
> >
> >      A extern int
> >      +snprint_overrides (char * buff, int len, struct hwentry *overrides)
> >      +{
> >      +A  A  A  A int fwd = 0;
> >      +A  A  A  A int i;
> >      +A  A  A  A struct keyword *rootkw;
> >      +A  A  A  A struct keyword *kw;
> >      +
> >      +A  A  A  A rootkw = find_keyword(NULL, "overrides");
> >      +A  A  A  A if (!rootkw)
> >      +A  A  A  A  A  A  A  A return 0;
> >      +
> >      +A  A  A  A fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
> >      +A  A  A  A if (fwd > len)
> >      +A  A  A  A  A  A  A  A return len;
> >      +A  A  A  A if (!overrides)
> >      +A  A  A  A  A  A  A  A goto out;
> >      +A  A  A  A iterate_sub_keywords(rootkw, kw, i) {
> >      +A  A  A  A  A  A  A  A fwd += snprint_keyword(buff + fwd, len -
> fwd,
> >      "\t%k %v\n",
> >      +A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  kw, NULL);
> >      +A  A  A  A  A  A  A  A if (fwd > len)
> >      +A  A  A  A  A  A  A  A  A  A  A  A return len;
> >      +A  A  A  A }
> >      +out:
> >      +A  A  A  A fwd += snprintf(buff + fwd, len - fwd, "}\n");
> >      +A  A  A  A if (fwd > len)
> >      +A  A  A  A  A  A  A  A return len;
> >      +A  A  A  A return fwd;
> >      +}
> >      +
> >      +extern int
> >      A snprint_defaults (char * buff, int len)
> >      A {
> >      A  A  A  A  int fwd = 0;
> >      diff --git a/libmultipath/print.h b/libmultipath/print.h
> >      index aef182b..a3c3319 100644
> >      --- a/libmultipath/print.h
> >      +++ b/libmultipath/print.h
> >      @@ -50,6 +50,7 @@ int snprint_status (char *, int, struct vectors
> *);
> >      A int snprint_devices (char *, int, struct vectors *);
> >      A int snprint_hwtable (char *, int, vector);
> >      A int snprint_mptable (char *, int, vector);
> >      +int snprint_overrides (char *, int, struct hwentry *);
> >
> >      A void print_multipath_topology (struct multipath * mpp, int
> verbosity);
> >      A void print_path (struct path * pp, char * style);
> >      diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
> >      index f2ab7d2..440802c 100644
> >      --- a/libmultipath/propsel.c
> >      +++ b/libmultipath/propsel.c
> >      @@ -48,6 +48,8 @@ do {A  A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  \
> >      A do_set(var, mp->mpe, mp->var, "(LUN setting)")
> >      A #define mp_set_hwe(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A  A  \
> >      A do_set(var, mp->hwe, mp->var, "(controller setting)")
> >      +#define mp_set_ovr(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A  A  \
> >      +do_set(var, conf->overrides, mp->var, "(overrides setting)")
> >      A #define mp_set_conf(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A \
> >      A do_set(var, conf, mp->var, "(config file default)")
> >      A #define mp_set_default(var, value)A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A \
> >      @@ -59,6 +61,8 @@ do_set(var, mpe, pp->var, "(LUN setting)")
> >      A do_set(var, pp->hwe, pp->var, "(controller setting)")
> >      A #define pp_set_conf(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A
> >      A  A  A  A  A  A  A  A  A \
> >      A do_set(var, conf, pp->var, "(config file default)")
> >      +#define pp_set_ovr(var)A  A  A  A  A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A  A  A  A  A  A  \
> >      +do_set(var, conf->overrides, pp->var, "(overrides setting)")
> >      A #define pp_set_default(var, value)A  A  A  A  A  A  A  A  A  A
> A  A
> >      A  A  A  A  A  A  A \
> >      A do_default(pp->var, value)
> >
> >      @@ -130,6 +134,7 @@ select_rr_weight (struct multipath * mp)
> >      A  A  A  A  char *origin, buff[13];
> >
> >      A  A  A  A  mp_set_mpe(rr_weight);
> >      +A  A  A  A mp_set_ovr(rr_weight);
> >      A  A  A  A  mp_set_hwe(rr_weight);
> >      A  A  A  A  mp_set_conf(rr_weight);
> >      A  A  A  A  mp_set_default(rr_weight, RR_WEIGHT_NONE);
> >      @@ -145,6 +150,7 @@ select_pgfailback (struct multipath * mp)
> >      A  A  A  A  char *origin, buff[13];
> >
> >      A  A  A  A  mp_set_mpe(pgfailback);
> >      +A  A  A  A mp_set_ovr(pgfailback);
> >      A  A  A  A  mp_set_hwe(pgfailback);
> >      A  A  A  A  mp_set_conf(pgfailback);
> >      A  A  A  A  mp_set_default(pgfailback, DEFAULT_FAILBACK);
> >      @@ -165,6 +171,7 @@ select_pgpolicy (struct multipath * mp)
> >      A  A  A  A  A  A  A  A  goto out;
> >      A  A  A  A  }
> >      A  A  A  A  mp_set_mpe(pgpolicy);
> >      +A  A  A  A mp_set_ovr(pgpolicy);
> >      A  A  A  A  mp_set_hwe(pgpolicy);
> >      A  A  A  A  mp_set_conf(pgpolicy);
> >      A  A  A  A  mp_set_default(pgpolicy, DEFAULT_PGPOLICY);
> >      @@ -181,10 +188,12 @@ select_selector (struct multipath * mp)
> >      A  A  A  A  char *origin;
> >
> >      A  A  A  A  mp_set_mpe(selector);
> >      +A  A  A  A mp_set_ovr(selector);
> >      A  A  A  A  mp_set_hwe(selector);
> >      A  A  A  A  mp_set_conf(selector);
> >      -A  A  A  A mp_set_default(selector, set_default(DEFAULT_SELECTOR));
> >      +A  A  A  A mp_set_default(selector, DEFAULT_SELECTOR);
> >      A out:
> >      +A  A  A  A mp->selector = STRDUP(mp->selector);
> >      A  A  A  A  condlog(3, "%s: path_selector = \"%s\" %s", mp->alias,
> >      mp->selector,
> >      A  A  A  A  A  A  A  A  origin);
> >      A  A  A  A  return 0;
> >      @@ -195,6 +204,7 @@ select_alias_prefix (struct multipath * mp)
> >      A {
> >      A  A  A  A  char *origin;
> >
> >      +A  A  A  A mp_set_ovr(alias_prefix);
> >      A  A  A  A  mp_set_hwe(alias_prefix);
> >      A  A  A  A  mp_set_conf(alias_prefix);
> >      A  A  A  A  mp_set_default(alias_prefix, DEFAULT_ALIAS_PREFIX);
> >      @@ -206,19 +216,30 @@ out:
> >      A static int
> >      A want_user_friendly_names(struct multipath * mp)
> >      A {
> >      -A  A  A  A if (mp->mpe &&
> >      -A  A  A  A  A  A mp->mpe->user_friendly_names !=
> >      USER_FRIENDLY_NAMES_UNDEF)
> >      -A  A  A  A  A  A  A  A return (mp->mpe->user_friendly_names ==
> >      USER_FRIENDLY_NAMES_ON);
> >      -A  A  A  A if (mp->hwe &&
> >      -A  A  A  A  A  A mp->hwe->user_friendly_names !=
> >      USER_FRIENDLY_NAMES_UNDEF)
> >      -A  A  A  A  A  A  A  A return (mp->hwe->user_friendly_names ==
> >      USER_FRIENDLY_NAMES_ON);
> >      -A  A  A  A return (conf->user_friendly_namesA  ==
> >      USER_FRIENDLY_NAMES_ON);
> >      +
> >      +A  A  A  A char *origin;
> >      +A  A  A  A int user_friendly_names;
> >      +
> >      +A  A  A  A do_set(user_friendly_names, mp->mpe,
> user_friendly_names,
> >      +A  A  A  A  A  A  A  "(LUN setting)");
> >      +A  A  A  A do_set(user_friendly_names, conf->overrides,
> >      user_friendly_names,
> >      +A  A  A  A  A  A  A  "(overrides setting)");
> >      +A  A  A  A do_set(user_friendly_names, mp->hwe,
> user_friendly_names,
> >      +A  A  A  A  A  A  A  "(controller setting)");
> >      +A  A  A  A do_set(user_friendly_names, conf, user_friendly_names,
> >      +A  A  A  A  A  A  A  "(config file setting)");
> >      +A  A  A  A do_default(user_friendly_names,
> USER_FRIENDLY_NAMES_OFF);
> >      +out:
> >      +A  A  A  A condlog(3, "%s: user_friendly_names = %s %s", mp->wwid,
> >      +A  A  A  A  A  A  A  A (user_friendly_names ==
> USER_FRIENDLY_NAMES_ON)?
> >      "yes" : "no",
> >      +A  A  A  A  A  A  A  A origin);
> >      +A  A  A  A return (user_friendly_names == USER_FRIENDLY_NAMES_ON);
> >      A }
> >
> >      A extern int
> >      A select_alias (struct multipath * mp)
> >      A {
> >      -A  A  A  A char *origin;
> >      +A  A  A  A char *origin = NULL;
> >
> >      A  A  A  A  if (mp->mpe && mp->mpe->alias) {
> >      A  A  A  A  A  A  A  A  mp->alias = STRDUP(mp->mpe->alias);
> >      @@ -261,6 +282,7 @@ select_features (struct multipath * mp)
> >      A  A  A  A  char *origin;
> >
> >      A  A  A  A  mp_set_mpe(features);
> >      +A  A  A  A mp_set_ovr(features);
> >      A  A  A  A  mp_set_hwe(features);
> >      A  A  A  A  mp_set_conf(features);
> >      A  A  A  A  mp_set_default(features, DEFAULT_FEATURES);
> >      @@ -287,8 +309,9 @@ select_hwhandler (struct multipath * mp)
> >
> >      A  A  A  A  mp_set_hwe(hwhandler);
> >      A  A  A  A  mp_set_conf(hwhandler);
> >      -A  A  A  A mp_set_default(hwhandler,
> set_default(DEFAULT_HWHANDLER));
> >      +A  A  A  A mp_set_default(hwhandler, DEFAULT_HWHANDLER);
> >      A out:
> >      +A  A  A  A mp->hwhandler = STRDUP(mp->hwhandler);
> >      A  A  A  A  condlog(3, "%s: hardware_handler = \"%s\" %s",
> mp->alias,
> >      mp->hwhandler,
> >      A  A  A  A  A  A  A  A  origin);
> >      A  A  A  A  return 0;
> >      @@ -300,6 +323,7 @@ select_checker(struct path *pp)
> >      A  A  A  A  char *origin, *checker_name;
> >      A  A  A  A  struct checker * c = &pp->checker;
> >
> >      +A  A  A  A do_set(checker_name, conf->overrides, checker_name,
> >      "(overrides setting)");
> >      A  A  A  A  do_set(checker_name, pp->hwe, checker_name, "(controller
> >      setting)");
> >      A  A  A  A  do_set(checker_name, conf, checker_name, "(config file
> >      setting)");
> >      A  A  A  A  do_default(checker_name, DEFAULT_CHECKER);
> >      @@ -327,6 +351,8 @@ select_getuid (struct path * pp)
> >      A {
> >      A  A  A  A  char *origin;
> >
> >      +A  A  A  A pp_set_ovr(uid_attribute);
> >      +A  A  A  A pp_set_ovr(getuid);
> >      A  A  A  A  pp_set_hwe(uid_attribute);
> >      A  A  A  A  pp_set_hwe(getuid);
> >      A  A  A  A  pp_set_conf(uid_attribute);
> >      @@ -383,6 +409,7 @@ select_prio (struct path * pp)
> >      A  A  A  A  }
> >      A  A  A  A  mpe = find_mpe(pp->wwid);
> >      A  A  A  A  set_prio(mpe, "(LUN setting)");
> >      +A  A  A  A set_prio(conf->overrides, "(overrides setting)");
> >      A  A  A  A  set_prio(pp->hwe, "controller setting)");
> >      A  A  A  A  set_prio(conf, "(config file default)");
> >      A  A  A  A  prio_get(p, DEFAULT_PRIO, DEFAULT_PRIO_ARGS);
> >      @@ -405,6 +432,7 @@ select_no_path_retry(struct multipath *mp)
> >      A  A  A  A  A  A  A  A  return 0;
> >      A  A  A  A  }
> >      A  A  A  A  mp_set_mpe(no_path_retry);
> >      +A  A  A  A mp_set_ovr(no_path_retry);
> >      A  A  A  A  mp_set_hwe(no_path_retry);
> >      A  A  A  A  mp_set_conf(no_path_retry);
> >      A out:
> >      @@ -427,6 +455,7 @@ select_minio_rq (struct multipath * mp)
> >      A  A  A  A  char *origin;
> >
> >      A  A  A  A  do_set(minio_rq, mp->mpe, mp->minio, "(LUN setting)");
> >      +A  A  A  A do_set(minio_rq, conf->overrides, mp->minio, "(overrides
> >      setting)");
> >      A  A  A  A  do_set(minio_rq, mp->hwe, mp->minio, "(controller
> >      setting)");
> >      A  A  A  A  do_set(minio_rq, conf, mp->minio, "(config file
> setting)");
> >      A  A  A  A  do_default(mp->minio, DEFAULT_MINIO_RQ);
> >      @@ -441,6 +470,7 @@ select_minio_bio (struct multipath * mp)
> >      A  A  A  A  char *origin;
> >
> >      A  A  A  A  mp_set_mpe(minio);
> >      +A  A  A  A mp_set_ovr(minio);
> >      A  A  A  A  mp_set_hwe(minio);
> >      A  A  A  A  mp_set_conf(minio);
> >      A  A  A  A  mp_set_default(minio, DEFAULT_MINIO);
> >      @@ -465,6 +495,7 @@ select_fast_io_fail(struct multipath *mp)
> >      A {
> >      A  A  A  A  char *origin, buff[12];
> >
> >      +A  A  A  A mp_set_ovr(fast_io_fail);
> >      A  A  A  A  mp_set_hwe(fast_io_fail);
> >      A  A  A  A  mp_set_conf(fast_io_fail);
> >      A  A  A  A  mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
> >      @@ -479,6 +510,7 @@ select_dev_loss(struct multipath *mp)
> >      A {
> >      A  A  A  A  char *origin, buff[12];
> >
> >      +A  A  A  A mp_set_ovr(dev_loss);
> >      A  A  A  A  mp_set_hwe(dev_loss);
> >      A  A  A  A  mp_set_conf(dev_loss);
> >      A  A  A  A  mp->dev_loss = 0;
> >      @@ -497,6 +529,7 @@ select_flush_on_last_del(struct multipath *mp)
> >      A  A  A  A  if (mp->flush_on_last_del == FLUSH_IN_PROGRESS)
> >      A  A  A  A  A  A  A  A  return 0;
> >      A  A  A  A  mp_set_mpe(flush_on_last_del);
> >      +A  A  A  A mp_set_ovr(flush_on_last_del);
> >      A  A  A  A  mp_set_hwe(flush_on_last_del);
> >      A  A  A  A  mp_set_conf(flush_on_last_del);
> >      A  A  A  A  mp_set_default(flush_on_last_del, FLUSH_DISABLED);
> >      @@ -532,6 +565,7 @@ select_retain_hwhandler (struct multipath * mp)
> >      A  A  A  A  A  A  A  A  origin = "(requires kernel version >=
> 1.5.0)";
> >      A  A  A  A  A  A  A  A  goto out;
> >      A  A  A  A  }
> >      +A  A  A  A mp_set_ovr(retain_hwhandler);
> >      A  A  A  A  mp_set_hwe(retain_hwhandler);
> >      A  A  A  A  mp_set_conf(retain_hwhandler);
> >      A  A  A  A  mp_set_default(retain_hwhandler,
> DEFAULT_RETAIN_HWHANDLER);
> >      @@ -547,6 +581,7 @@ select_detect_prio (struct path * pp)
> >      A {
> >      A  A  A  A  char *origin;
> >
> >      +A  A  A  A pp_set_ovr(detect_prio);
> >      A  A  A  A  pp_set_hwe(detect_prio);
> >      A  A  A  A  pp_set_conf(detect_prio);
> >      A  A  A  A  pp_set_default(detect_prio, DEFAULT_DETECT_PRIO);
> >      diff --git a/libmultipath/structs.c b/libmultipath/structs.c
> >      index 30d247d..0538327 100644
> >      --- a/libmultipath/structs.c
> >      +++ b/libmultipath/structs.c
> >      @@ -206,10 +206,7 @@ free_multipath_attributes (struct multipath *
> mpp)
> >      A  A  A  A  if (!mpp)
> >      A  A  A  A  A  A  A  A  return;
> >
> >      -A  A  A  A if (mpp->selector &&
> >      -A  A  A  A  A  A mpp->selector != conf->selector &&
> >      -A  A  A  A  A  A (!mpp->mpe || (mpp->mpe && mpp->selector !=
> >      mpp->mpe->selector)) &&
> >      -A  A  A  A  A  A (!mpp->hwe || (mpp->hwe && mpp->selector !=
> >      mpp->hwe->selector))) {
> >      +A  A  A  A if (mpp->selector) {
> >      A  A  A  A  A  A  A  A  FREE(mpp->selector);
> >      A  A  A  A  A  A  A  A  mpp->selector = NULL;
> >      A  A  A  A  }
> >      @@ -219,9 +216,7 @@ free_multipath_attributes (struct multipath *
> mpp)
> >      A  A  A  A  A  A  A  A  mpp->features = NULL;
> >      A  A  A  A  }
> >
> >      -A  A  A  A if (mpp->hwhandler &&
> >      -A  A  A  A  A  A mpp->hwhandler != conf->hwhandler &&
> >      -A  A  A  A  A  A (!mpp->hwe || (mpp->hwe && mpp->hwhandler !=
> >      mpp->hwe->hwhandler))) {
> >      +A  A  A  A if (mpp->hwhandler) {
> >      A  A  A  A  A  A  A  A  FREE(mpp->hwhandler);
> >      A  A  A  A  A  A  A  A  mpp->hwhandler = NULL;
> >      A  A  A  A  }
> >      diff --git a/multipath.conf.annotated b/multipath.conf.annotated
> >      index 0af1d4c..71afc0a 100644
> >      --- a/multipath.conf.annotated
> >      +++ b/multipath.conf.annotated
> >      @@ -485,7 +485,8 @@
> >      A ## scope : multipath & multipathd
> >      A ## descA  : list of per storage controller settings
> >      A ##A  A  A  A overrides default settings (device_maps block)
> >      -##A  A  A  A  A overriden by per multipath settings (multipaths
> block)
> >      +##A  A  A  A  overriden by per multipath settings (multipaths
> block)
> >      +##A  A  A  A and the overrides settings (overrides block)
> >      A ##
> >      A #devices {
> >      A #A  A  A  #
> >      @@ -651,3 +652,18 @@
> >      A #A  A  A  A  A  A  A  rr_weightA  A  A  A  A  A  A  A priorities
> >      A #A  A  A  }
> >      A #}
> >      +#
> >      +##
> >      +## nameA  : devices
> >      +## scope : multipath & multipathd
> >      +## descA  : list of settings to override all hadware settings for
> all
> >      devices
> >      +##A  A  A  A overrides default settings (device_maps block)
> >      +##A  A  A  A and per device type settings (devices block)
> >      +##A  A  A  A  overriden by per multipath settings (multipaths
> block)
> >      +##
> >      +#A  A  A  attributes and values are identical to the device block
> >      +#
> >      +#overrides {
> >      +#A  A  A  dev_loss_tmoA  A  A  A  A  A  60
> >      +#A  A  A  no_path_retryA  A  A  A  A  A fail
> >      +#}
> >      diff --git a/multipath.conf.defaults b/multipath.conf.defaults
> >      index 654be97..1c65e02 100644
> >      --- a/multipath.conf.defaults
> >      +++ b/multipath.conf.defaults
> >      @@ -912,3 +912,5 @@
> >      A #}
> >      A #multipaths {
> >      A #}
> >      +#overrides {
> >      +#}
> >      diff --git a/multipath.conf.synthetic b/multipath.conf.synthetic
> >      index bda1b75..f7b9b8a 100644
> >      --- a/multipath.conf.synthetic
> >      +++ b/multipath.conf.synthetic
> >      @@ -72,3 +72,6 @@
> >      A #A  A  A  A  A  A  A  path_grouping_policyA  A  multibus
> >      A #A  A  A  }
> >      A #}
> >      +#overrides {
> >      +#A  A  A  no_path_retryA  A  A  A  A  A  A  A  A  A fail
> >      +#}
> >      diff --git a/multipath/main.c b/multipath/main.c
> >      index fd6262f..ea453b4 100644
> >      --- a/multipath/main.c
> >      +++ b/multipath/main.c
> >      @@ -405,6 +405,12 @@ dump_config (void)
> >      A  A  A  A  A  A  A  A  A  A  A  A  reply = REALLOC(reply, maxlen
> *= 2);
> >      A  A  A  A  A  A  A  A  A  A  A  A  continue;
> >      A  A  A  A  A  A  A  A  }
> >      +A  A  A  A  A  A  A  A c += snprint_overrides(c, reply + maxlen -
> c,
> >      conf->overrides);
> >      +A  A  A  A  A  A  A  A again = ((c - reply) == maxlen);
> >      +A  A  A  A  A  A  A  A if (again) {
> >      +A  A  A  A  A  A  A  A  A  A  A  A reply = REALLOC(reply, maxlen
> *= 2);
> >      +A  A  A  A  A  A  A  A  A  A  A  A continue;
> >      +A  A  A  A  A  A  A  A }
> >      A  A  A  A  A  A  A  A  c += snprint_mptable(c, reply + maxlen - c,
> >      conf->mptable);
> >      A  A  A  A  A  A  A  A  again = ((c - reply) == maxlen);
> >      A  A  A  A  A  A  A  A  if (again)
> >      diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
> >      index cadb34d..b823990 100644
> >      --- a/multipath/multipath.conf.5
> >      +++ b/multipath/multipath.conf.5
> >      @@ -61,6 +61,10 @@ the udev attribute given by the
> >      A .TP
> >      A .B devices
> >      A This section defines the device-specific settings.
> >      +.TP
> >      +.B overrides
> >      +This section defines values for attributes that should override the
> >      +device-specific settings for all devices.
> >      A .RE
> >      A .LP
> >      A .SH "defaults section"
> >      @@ -629,6 +633,59 @@ section:
> >      A .RE
> >      A .PD
> >      A .LP
> >      +.SH "overrides section"
> >      +The overrides section recognizes the following optional
> attributes; if
> >      not set
> >      +the values are taken from the
> >      +.I devices
> >      +or
> >      +.I defaults
> >      +sections:
> >      +.sp 1
> >      +.PD .1v
> >      +.RS
> >      +.TP 18
> >      +.B path_grouping_policy
> >      +.TP
> >      +.B uid_attribute
> >      +.TP
> >      +.B getuid_callout
> >      +.TP
> >      +.B path_selector
> >      +.TP
> >      +.B path_checker
> >      +.TP
> >      +.B alias_prefix
> >      +.TP
> >      +.B features
> >      +.TP
> >      +.B prio
> >      +.TP
> >      +.B prio_args
> >      +.TP
> >      +.B failback
> >      +.TP
> >      +.B rr_weight
> >      +.TP
> >      +.B no_path_retry
> >      +.TP
> >      +.B rr_min_io
> >      +.TP
> >      +.B rr_min_io_rq
> >      +.TP
> >      +.B flush_on_last_del
> >      +.TP
> >      +.B fast_io_fail_tmo
> >      +.TP
> >      +.B dev_loss_tmo
> >      +.TP
> >      +.B user_friendly_names
> >      +.TP
> >      +.B retain_attached_hw_handler
> >      +.TP
> >      +.B detect_prio
> >      +.RE
> >      +.PD
> >      +.LP
> >      A .SH "KNOWN ISSUES"
> >      A The usage of
> >      A .B queue_if_no_path
> >      diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
> >      index b086340..0ce1408 100644
> >      --- a/multipathd/cli_handlers.c
> >      +++ b/multipathd/cli_handlers.c
> >      @@ -190,6 +190,16 @@ show_config (char ** r, int * len)
> >      A  A  A  A  A  A  A  A  A  A  A  A  maxlen *= 2;
> >      A  A  A  A  A  A  A  A  A  A  A  A  continue;
> >      A  A  A  A  A  A  A  A  }
> >      +A  A  A  A  A  A  A  A c += snprint_overrides(c, reply + maxlen -
> c,
> >      conf->overrides);
> >      +A  A  A  A  A  A  A  A again = ((c - reply) == maxlen);
> >      +A  A  A  A  A  A  A  A if (again) {
> >      +A  A  A  A  A  A  A  A  A  A  A  A reply = REALLOC(reply, maxlen *
> 2);
> >      +A  A  A  A  A  A  A  A  A  A  A  A if (!reply)
> >      +A  A  A  A  A  A  A  A  A  A  A  A  A  A  A  A return 1;
> >      +A  A  A  A  A  A  A  A  A  A  A  A memset(reply + maxlen, 0,
> maxlen);
> >      +A  A  A  A  A  A  A  A  A  A  A  A maxlen *= 2;
> >      +A  A  A  A  A  A  A  A  A  A  A  A continue;
> >      +A  A  A  A  A  A  A  A }
> >      A  A  A  A  A  A  A  A  c += snprint_mptable(c, reply + maxlen - c,
> >      conf->mptable);
> >      A  A  A  A  A  A  A  A  again = ((c - reply) == maxlen);
> >      A  A  A  A  A  A  A  A  REALLOC_REPLY(reply, again, maxlen);
> >      --
> >      1.8.3.1
>

[-- Attachment #1.2: Type: text/html, Size: 54085 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-11 23:37       ` Christophe Varoqui
@ 2015-01-13  0:01         ` Sebastian Herbszt
  2015-01-13 15:56           ` Marian Csontos
  2015-01-13 17:08           ` Benjamin Marzinski
  0 siblings, 2 replies; 16+ messages in thread
From: Sebastian Herbszt @ 2015-01-13  0:01 UTC (permalink / raw)
  To: Christophe Varoqui; +Cc: device-mapper development, Sebastian Herbszt

Hello Christophe,

Christophe Varoqui wrote:
> Hi,
> 
> the precedence chain is :
> 
> multipaths > user-specified per-device > default per-device > default
> 
> The issue adressed by Ben's patch would not be solved by your suggestion,
> as far as I can see. The proposed override section is just a way not repeat
> a per-device in each multipath (insane) or device (tedious) section.

care to explain why setting the precedence to

multipaths > user-specified per-device > default > default per-device

would not fix the issue?

Lets assume the following default device and user configuration:

.vendor        = "COMPELNT",
.product       = "Compellent Vol",
.pgpolicy      = MULTIBUS,
.pgfailback    = -FAILBACK_IMMEDIATE
.no_path_retry = NO_PATH_RETRY_QUEUE,
.checker_name  = TUR

defaults {
	no_path_retry fail
}

devices {
        device {
                vendor "COMPELNT"
                product "Compellent Vol"
		path_grouping_policy "group_by_prio"
	}
}

multipaths {
	multipath {
		wwid 1234
		failback 15
	}
}

The default section should change no_path_retry from "queue" to "fail".
The device section should change path_grouping_policy from "multibus"
to "group_by_prio" for "COMPELNT/Compellent Vol".
The multipath section should change failback from "immediate" to 15
for wwid 1234.
The path_checker would still be "tur".

Is this not what the "overrides" patch intended?

Sebastian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-13  0:01         ` Sebastian Herbszt
@ 2015-01-13 15:56           ` Marian Csontos
  2015-01-13 17:08           ` Benjamin Marzinski
  1 sibling, 0 replies; 16+ messages in thread
From: Marian Csontos @ 2015-01-13 15:56 UTC (permalink / raw)
  To: device-mapper development, Christophe Varoqui; +Cc: Sebastian Herbszt

On 01/13/2015 01:01 AM, Sebastian Herbszt wrote:
> Hello Christophe,
>
> Christophe Varoqui wrote:
>> Hi,
>>
>> the precedence chain is :
>>
>> multipaths > user-specified per-device > default per-device > default
>>
>> The issue adressed by Ben's patch would not be solved by your suggestion,
>> as far as I can see. The proposed override section is just a way not repeat
>> a per-device in each multipath (insane) or device (tedious) section.
>
> care to explain why setting the precedence to
>
> multipaths > user-specified per-device > default > default per-device
>
> would not fix the issue?

It may very well "fix" the issue but having global default overriding 
drive-specific default seems to me as wrong as breaking compatibility by 
such change which would likely introduce more issues.

-- Martian

>
> Lets assume the following default device and user configuration:
>
> .vendor        = "COMPELNT",
> .product       = "Compellent Vol",
> .pgpolicy      = MULTIBUS,
> .pgfailback    = -FAILBACK_IMMEDIATE
> .no_path_retry = NO_PATH_RETRY_QUEUE,
> .checker_name  = TUR
>
> defaults {
> 	no_path_retry fail
> }
>
> devices {
>          device {
>                  vendor "COMPELNT"
>                  product "Compellent Vol"
> 		path_grouping_policy "group_by_prio"
> 	}
> }
>
> multipaths {
> 	multipath {
> 		wwid 1234
> 		failback 15
> 	}
> }
>
> The default section should change no_path_retry from "queue" to "fail".
> The device section should change path_grouping_policy from "multibus"
> to "group_by_prio" for "COMPELNT/Compellent Vol".
> The multipath section should change failback from "immediate" to 15
> for wwid 1234.
> The path_checker would still be "tur".
>
> Is this not what the "overrides" patch intended?
>
> Sebastian
>
> --
> dm-devel mailing list
> dm-devel@redhat.com
> https://www.redhat.com/mailman/listinfo/dm-devel
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] libmultipath: add overrides section to multipath.conf
  2015-01-13  0:01         ` Sebastian Herbszt
  2015-01-13 15:56           ` Marian Csontos
@ 2015-01-13 17:08           ` Benjamin Marzinski
  1 sibling, 0 replies; 16+ messages in thread
From: Benjamin Marzinski @ 2015-01-13 17:08 UTC (permalink / raw)
  To: Sebastian Herbszt; +Cc: device-mapper development

On Tue, Jan 13, 2015 at 01:01:58AM +0100, Sebastian Herbszt wrote:
> Hello Christophe,
> 
> Christophe Varoqui wrote:
> > Hi,
> > 
> > the precedence chain is :
> > 
> > multipaths > user-specified per-device > default per-device > default
> > 
> > The issue adressed by Ben's patch would not be solved by your suggestion,
> > as far as I can see. The proposed override section is just a way not repeat
> > a per-device in each multipath (insane) or device (tedious) section.
> 
> care to explain why setting the precedence to
> 
> multipaths > user-specified per-device > default > default per-device
> 
> would not fix the issue?

I don't think the issue is that it wouldn't solve my problem.  The issue
is that it isn't as simple as it looks, and causes a large impact to
existing users.

First off, I assume you mean

multipaths > user per-device > user default > builtin per-device >
builtin default

What happens when users modify a builtin device configuration.  Does the
whole device configuration move up in presidence, or only the user
modified parts?  If the whole device does, This will cause lots of
unexpected effects.  If not, there will often be two devices sections
controlling a multipath device along with two defaults sections, making
the configuration output that much harder to read (I admit that the
overrides section is basically a second devices section, but I assume
that this feature will be rarely used. My original all_devs patch had
the benefit that it adjusted all the device configurations directly, so
users sill just needed to look in three sections to understand their
configuration, instead of five with your method)

Also, adding a new section doesn't impact existing user configurations
or user's existing understanding of how the multipath tools work.  Your
solution would cause a lot of broken configurations and relearning. This
last point is my biggest objection.  If we were starting from scratch
your method would have probably made configuration enough more
inituitive to justify the extra work of dealing with and displaying the
two extra configuration sections. As it stands, I don't think it adds
enough benefit to be worth the pain.

-Ben

> 
> Lets assume the following default device and user configuration:
> 
> .vendor        = "COMPELNT",
> .product       = "Compellent Vol",
> .pgpolicy      = MULTIBUS,
> .pgfailback    = -FAILBACK_IMMEDIATE
> .no_path_retry = NO_PATH_RETRY_QUEUE,
> .checker_name  = TUR
> 
> defaults {
> 	no_path_retry fail
> }
> 
> devices {
>         device {
>                 vendor "COMPELNT"
>                 product "Compellent Vol"
> 		path_grouping_policy "group_by_prio"
> 	}
> }
> 
> multipaths {
> 	multipath {
> 		wwid 1234
> 		failback 15
> 	}
> }
> 
> The default section should change no_path_retry from "queue" to "fail".
> The device section should change path_grouping_policy from "multibus"
> to "group_by_prio" for "COMPELNT/Compellent Vol".
> The multipath section should change failback from "immediate" to 15
> for wwid 1234.
> The path_checker would still be "tur".
> 
> Is this not what the "overrides" patch intended?
> 
> Sebastian

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-01-13 17:08 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-19  6:17 [PATCH 0/6][RESEND] configuration overhaul and find_multipaths Benjamin Marzinski
2014-11-19  6:17 ` [PATCH 1/6] libmultipath: rewrite dict.c with function generation macros Benjamin Marzinski
2014-11-19  6:17 ` [PATCH 2/6] libmultipath: cleanup propsel.c with macros for common actions Benjamin Marzinski
2014-11-19  6:17 ` [PATCH 3/6] libmultipath: add overrides section to multipath.conf Benjamin Marzinski
2015-01-08 23:06   ` Christophe Varoqui
2015-01-11 23:15     ` Sebastian Herbszt
2015-01-11 23:37       ` Christophe Varoqui
2015-01-13  0:01         ` Sebastian Herbszt
2015-01-13 15:56           ` Marian Csontos
2015-01-13 17:08           ` Benjamin Marzinski
2015-01-12 18:05     ` Benjamin Marzinski
2015-01-12 20:27       ` Christophe Varoqui
2014-11-19  6:17 ` [PATCH 4/6] add find_multipaths option Benjamin Marzinski
2014-11-19  6:17 ` [PATCH 5/6] correctly set partition delimiter on rename Benjamin Marzinski
2015-01-08 22:51   ` Christophe Varoqui
2014-11-19  6:17 ` [PATCH 6/6] libmultipath: only add uninitialized paths in check_path Benjamin Marzinski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.