forked from pool/multipath-tools
530 lines
14 KiB
Plaintext
530 lines
14 KiB
Plaintext
commit 86bc28e5702babadf73a1c4395870da370efa257
|
|
Author: Hannes Reinecke <hare@suse.de>
|
|
Date: Fri Nov 21 14:03:38 2008 +0100
|
|
|
|
Static Load balancing prioritizer
|
|
|
|
'Weighted path' is a new path prioritizer for device mapper
|
|
multipath, where specific paths and the corresponding priority
|
|
values can be provided as arguments.
|
|
This prioritizer assigns the priority value provided in the
|
|
configuration file based on the comparison made between the
|
|
specified paths and the path instance for which this is called.
|
|
Paths can be specified as a regular expression of devname
|
|
of the path or as hbtl information of the path.
|
|
|
|
Syntax:
|
|
weightedpath <hbtl|devname> <regex1> <prio1> <regex2> <prio2> ...
|
|
|
|
Examples:
|
|
prio "weightedpath hbtl 1:.:.:. 2 4:.:.:. 4" #All paths through SCSI 'H' as
|
|
'1' will take prio 2 and all paths with SCSI 'H' as 4 will take prio as 4.
|
|
|
|
prio "weightedpath devname sda$ 10 sde$ 20" #Path sda takes prio 10 and
|
|
path sde takes prio 20. can be provided in multipath section.
|
|
|
|
This prioritizer allows user to set static load balancing
|
|
for devices. Useful when user has prior knowledge of path
|
|
performance difference or unavailability of certain paths.
|
|
|
|
References: 441007
|
|
|
|
Signed-off-by: Vijayakumar Balasubramanian <vijaykumar@hp.com>
|
|
Signed-off-by: Hannes Reinecke <hare@suse.de>
|
|
|
|
diff --git a/libmultipath/config.c b/libmultipath/config.c
|
|
index 908156d..83da6e7 100644
|
|
--- a/libmultipath/config.c
|
|
+++ b/libmultipath/config.c
|
|
@@ -207,6 +207,12 @@ free_mpe (struct mpentry * mpe)
|
|
if (mpe->alias)
|
|
FREE(mpe->alias);
|
|
|
|
+ if (mpe->prio_name)
|
|
+ FREE(mpe->prio_name);
|
|
+
|
|
+ if (mpe->prio_arg)
|
|
+ FREE(mpe->prio_arg);
|
|
+
|
|
FREE(mpe);
|
|
}
|
|
|
|
@@ -291,6 +297,7 @@ merge_hwe (struct hwentry * hwe1, struct hwentry * hwe2)
|
|
merge_str(selector);
|
|
merge_str(checker_name);
|
|
merge_str(prio_name);
|
|
+ merge_str(prio_arg);
|
|
merge_str(bl_product);
|
|
merge_num(pgpolicy);
|
|
merge_num(pgfailback);
|
|
@@ -339,6 +346,9 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
|
|
if (dhwe->prio_name && !(hwe->prio_name = set_param_str(dhwe->prio_name)))
|
|
goto out;
|
|
|
|
+ if (dhwe->prio_arg && !(hwe->prio_arg = set_param_str(dhwe->prio_arg)))
|
|
+ goto out;
|
|
+
|
|
hwe->pgpolicy = dhwe->pgpolicy;
|
|
hwe->pgfailback = dhwe->pgfailback;
|
|
hwe->rr_weight = dhwe->rr_weight;
|
|
@@ -559,8 +569,10 @@ load_config (char * file)
|
|
!conf->hwhandler || !conf->bindings_file)
|
|
goto out;
|
|
|
|
- if (!conf->prio_name)
|
|
+ if (!conf->prio_name) {
|
|
conf->prio_name = set_default(DEFAULT_PRIO);
|
|
+ conf->prio_arg = NULL;
|
|
+ }
|
|
|
|
if (!conf->checker_name)
|
|
conf->checker_name = set_default(DEFAULT_CHECKER);
|
|
diff --git a/libmultipath/config.h b/libmultipath/config.h
|
|
index fb917f4..fc0e22d 100644
|
|
--- a/libmultipath/config.h
|
|
+++ b/libmultipath/config.h
|
|
@@ -21,6 +21,7 @@ struct hwentry {
|
|
char * selector;
|
|
char * checker_name;
|
|
char * prio_name;
|
|
+ char * prio_arg;
|
|
|
|
int pgpolicy;
|
|
int pgfailback;
|
|
@@ -37,6 +38,8 @@ struct mpentry {
|
|
char * getuid;
|
|
char * selector;
|
|
|
|
+ char * prio_name;
|
|
+ char * prio_arg;
|
|
int pgpolicy;
|
|
int pgfailback;
|
|
int rr_weight;
|
|
@@ -75,6 +78,7 @@ struct config {
|
|
char * hwhandler;
|
|
char * bindings_file;
|
|
char * prio_name;
|
|
+ char * prio_arg;
|
|
char * checker_name;
|
|
|
|
vector keywords;
|
|
diff --git a/libmultipath/dict.c b/libmultipath/dict.c
|
|
index 5794b11..9ba3961 100644
|
|
--- a/libmultipath/dict.c
|
|
+++ b/libmultipath/dict.c
|
|
@@ -4,6 +4,7 @@
|
|
* Copyright (c) 2005 Benjamin Marzinski, Redhat
|
|
* Copyright (c) 2005 Kiyoshi Ueda, NEC
|
|
*/
|
|
+#include <string.h>
|
|
#include "checkers.h"
|
|
#include "vector.h"
|
|
#include "hwtable.h"
|
|
@@ -106,11 +107,26 @@ def_getuid_callout_handler(vector strvec)
|
|
static int
|
|
def_prio_handler(vector strvec)
|
|
{
|
|
- conf->prio_name = set_value(strvec);
|
|
+ char *buff, *result, *temp;
|
|
+ char split_char[] = " \t";
|
|
|
|
- if (!conf->prio_name)
|
|
+ buff = set_value(strvec);
|
|
+ if (!buff)
|
|
return 1;
|
|
+ temp = buff;
|
|
+
|
|
+ while ((result = strsep(&temp, split_char))) {
|
|
+ if (prio_lookup(result)) {
|
|
+ conf->prio_name = STRDUP(result);
|
|
+ if (temp)
|
|
+ conf->prio_arg = STRDUP(temp);
|
|
+ else
|
|
+ conf->prio_arg = NULL;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
|
|
+ FREE(buff);
|
|
return 0;
|
|
}
|
|
|
|
@@ -613,15 +629,29 @@ static int
|
|
hw_prio_handler(vector strvec)
|
|
{
|
|
struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
|
|
+ char *buff, *result, *temp;
|
|
+ char split_char[] = " \t";
|
|
|
|
if (!hwe)
|
|
return 1;
|
|
|
|
- hwe->prio_name = set_value(strvec);
|
|
-
|
|
- if (!hwe->prio_name)
|
|
+ buff = set_value(strvec);
|
|
+ if (!buff)
|
|
return 1;
|
|
+ temp = buff;
|
|
+
|
|
+ while ((result = strsep(&temp, split_char))) {
|
|
+ if (prio_lookup(result)) {
|
|
+ conf->prio_name = STRDUP(result);
|
|
+ if (temp)
|
|
+ conf->prio_arg = STRDUP(temp);
|
|
+ else
|
|
+ conf->prio_arg = NULL;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
|
|
+ FREE(buff);
|
|
return 0;
|
|
}
|
|
|
|
@@ -967,6 +997,38 @@ mp_pg_timeout_handler(vector strvec)
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+mp_prio_handler (vector strvec)
|
|
+{
|
|
+ struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
|
|
+ char *buff, *result, *temp;
|
|
+ char split_char[] = " \t";
|
|
+
|
|
+ if (!mpe)
|
|
+ return 1;
|
|
+
|
|
+ buff = set_value(strvec);
|
|
+
|
|
+ if (!buff)
|
|
+ return 1;
|
|
+
|
|
+ temp = buff;
|
|
+
|
|
+ while ((result = strsep(&temp, split_char))) {
|
|
+ if (prio_lookup(result)) {
|
|
+ mpe->prio_name = STRDUP(result);
|
|
+ if (temp)
|
|
+ mpe->prio_arg = STRDUP(temp);
|
|
+ else
|
|
+ mpe->prio_arg = NULL;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ FREE(buff);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* config file keywords printing
|
|
*/
|
|
@@ -1102,6 +1164,17 @@ snprint_mp_pg_timeout (char * buff, int len, void * data)
|
|
}
|
|
|
|
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_hw_vendor (char * buff, int len, void * data)
|
|
{
|
|
struct hwentry * hwe = (struct hwentry *)data;
|
|
@@ -1672,6 +1745,7 @@ init_keywords(void)
|
|
install_keyword("alias", &alias_handler, &snprint_mp_alias);
|
|
install_keyword("path_grouping_policy", &mp_pgpolicy_handler, &snprint_mp_path_grouping_policy);
|
|
install_keyword("path_selector", &mp_selector_handler, &snprint_mp_selector);
|
|
+ install_keyword("prio", &mp_prio_handler, &snprint_mp_prio);
|
|
install_keyword("failback", &mp_failback_handler, &snprint_mp_failback);
|
|
install_keyword("rr_weight", &mp_weight_handler, &snprint_mp_rr_weight);
|
|
install_keyword("no_path_retry", &mp_no_path_retry_handler, &snprint_mp_no_path_retry);
|
|
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
|
index 56186bd..c4a53ab 100644
|
|
--- a/libmultipath/discovery.c
|
|
+++ b/libmultipath/discovery.c
|
|
@@ -784,8 +784,11 @@ pathinfo (struct path *pp, vector hwtable, int mask)
|
|
* been successfully obtained before.
|
|
*/
|
|
if (mask & DI_PRIO &&
|
|
- (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF))
|
|
+ (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF)) {
|
|
+ if (!strlen(pp->wwid))
|
|
+ get_uid(pp);
|
|
get_prio(pp);
|
|
+ }
|
|
|
|
if (mask & DI_WWID && !strlen(pp->wwid))
|
|
get_uid(pp);
|
|
diff --git a/libmultipath/prio.h b/libmultipath/prio.h
|
|
index deef02d..1d00725 100644
|
|
--- a/libmultipath/prio.h
|
|
+++ b/libmultipath/prio.h
|
|
@@ -24,6 +24,7 @@
|
|
#define PRIO_ONTAP "ontap"
|
|
#define PRIO_RANDOM "random"
|
|
#define PRIO_RDAC "rdac"
|
|
+#define PRIO_WEIGHTED_PATH "weightedpath"
|
|
|
|
/*
|
|
* Value used to mark the fact prio was not defined
|
|
diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile
|
|
index df42145..a569321 100644
|
|
--- a/libmultipath/prioritizers/Makefile
|
|
+++ b/libmultipath/prioritizers/Makefile
|
|
@@ -12,7 +12,8 @@ LIBS = \
|
|
libpriordac.so \
|
|
libprioalua.so \
|
|
libprioontap.so \
|
|
- libpriohds.so
|
|
+ libpriohds.so \
|
|
+ libprioweightedpath.so
|
|
|
|
CFLAGS += -I..
|
|
|
|
diff --git a/libmultipath/prioritizers/weightedpath.c b/libmultipath/prioritizers/weightedpath.c
|
|
new file mode 100644
|
|
index 0000000..d04d91e
|
|
--- /dev/null
|
|
+++ b/libmultipath/prioritizers/weightedpath.c
|
|
@@ -0,0 +1,99 @@
|
|
+/*
|
|
+ *
|
|
+ * (C) Copyright 2008 Hewlett-Packard Development Company, L.P
|
|
+ *
|
|
+ * This file is released under the GPL
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Prioritizer for device mapper multipath, where specific paths and the
|
|
+ * corresponding priority values are provided as arguments.
|
|
+ *
|
|
+ * This prioritizer assigns the priority value provided in the configuration
|
|
+ * file based on the comparison made between the specified paths and the path
|
|
+ * instance for which this is called.
|
|
+ * Paths can be specified as a regular expression of devname of the path or
|
|
+ * as hbtl information of the path.
|
|
+ *
|
|
+ * Examples:
|
|
+ * prio "weightedpath hbtl 1:.:.:. 2 4:.:.:. 4"
|
|
+ * prio "weightedpath devname sda 10 sde 20"
|
|
+ *
|
|
+ * Returns zero as the default priority.
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <prio.h>
|
|
+#include "weightedpath.h"
|
|
+#include <config.h>
|
|
+#include <structs.h>
|
|
+#include <memory.h>
|
|
+#include <debug.h>
|
|
+#include <regex.h>
|
|
+
|
|
+char *get_next_string(char **temp, char *split_char)
|
|
+{
|
|
+ char *token = NULL;
|
|
+ token = strsep(temp, split_char);
|
|
+ while (token != NULL && !strcmp(token, ""))
|
|
+ token = strsep(temp, split_char);
|
|
+ return token;
|
|
+}
|
|
+
|
|
+/* main priority routine */
|
|
+int prio_path_weight(struct path *pp)
|
|
+{
|
|
+ char path[FILE_NAME_SIZE];
|
|
+ char *arg;
|
|
+ char *temp, *regex, *prio;
|
|
+ char split_char[] = " \t";
|
|
+ int priority = DEFAULT_PRIORITY, path_found = 0;
|
|
+ regex_t pathe;
|
|
+
|
|
+ /* Return default priority if there is no argument */
|
|
+ if (!pp->prio_arg)
|
|
+ return priority;
|
|
+
|
|
+ arg = temp = STRDUP(pp->prio_arg);
|
|
+
|
|
+ regex = get_next_string(&temp, split_char);
|
|
+
|
|
+ if (!strcmp(regex, HBTL)) {
|
|
+ sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no,
|
|
+ pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun);
|
|
+ } else if (!strcmp(regex, DEV_NAME)) {
|
|
+ strcpy(path, pp->dev);
|
|
+ } else {
|
|
+ condlog(0, "%s: %s - Invalid arguments", pp->dev,
|
|
+ pp->prio->name);
|
|
+ return priority;
|
|
+ }
|
|
+
|
|
+ while (!path_found) {
|
|
+ if (!temp)
|
|
+ break;
|
|
+ if (!(regex = get_next_string(&temp, split_char)))
|
|
+ break;
|
|
+ if (!(prio = get_next_string(&temp, split_char)))
|
|
+ break;
|
|
+
|
|
+ if (!regcomp(&pathe, regex, REG_EXTENDED|REG_NOSUB)) {
|
|
+ if (!regexec(&pathe, path, 0, NULL, 0)) {
|
|
+ path_found = 1;
|
|
+ priority = atoi(prio);
|
|
+ }
|
|
+ regfree(&pathe);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ FREE(arg);
|
|
+ return priority;
|
|
+}
|
|
+
|
|
+int getprio(struct path *pp)
|
|
+{
|
|
+ return prio_path_weight(pp);
|
|
+}
|
|
+
|
|
diff --git a/libmultipath/prioritizers/weightedpath.h b/libmultipath/prioritizers/weightedpath.h
|
|
new file mode 100644
|
|
index 0000000..141cdf7
|
|
--- /dev/null
|
|
+++ b/libmultipath/prioritizers/weightedpath.h
|
|
@@ -0,0 +1,11 @@
|
|
+#ifndef _WEIGHTED_PATH_H
|
|
+#define _WEIGHTED_PATH_H
|
|
+
|
|
+#define PRIO_WEIGHTED_PATH "weightedpath"
|
|
+#define HBTL "hbtl"
|
|
+#define DEV_NAME "devname"
|
|
+#define DEFAULT_PRIORITY 0
|
|
+
|
|
+int prio_path_weight(struct path *pp);
|
|
+
|
|
+#endif
|
|
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
|
index 5a16182..1fc7c40 100644
|
|
--- a/libmultipath/propsel.c
|
|
+++ b/libmultipath/propsel.c
|
|
@@ -258,14 +258,28 @@ select_getuid (struct path * pp)
|
|
extern int
|
|
select_prio (struct path * pp)
|
|
{
|
|
+ struct mpentry * mpe;
|
|
+
|
|
+ if ((mpe = find_mpe(pp->wwid))) {
|
|
+ if (mpe->prio_name) {
|
|
+ pp->prio = prio_lookup(mpe->prio_name);
|
|
+ pp->prio_arg = mpe->prio_arg;
|
|
+ condlog(3, "%s: prio = %s (LUN setting)",
|
|
+ pp->dev, pp->prio->name);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (pp->hwe && pp->hwe->prio_name) {
|
|
pp->prio = prio_lookup(pp->hwe->prio_name);
|
|
+ pp->prio_arg = pp->hwe->prio_arg;
|
|
condlog(3, "%s: prio = %s (controller setting)",
|
|
pp->dev, pp->hwe->prio_name);
|
|
return 0;
|
|
}
|
|
if (conf->prio_name) {
|
|
pp->prio = prio_lookup(conf->prio_name);
|
|
+ pp->prio_arg = conf->prio_arg;
|
|
condlog(3, "%s: prio = %s (config file default)",
|
|
pp->dev, conf->prio_name);
|
|
return 0;
|
|
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
|
index 658d6b2..75bd379 100644
|
|
--- a/libmultipath/structs.h
|
|
+++ b/libmultipath/structs.h
|
|
@@ -121,6 +121,7 @@ struct path {
|
|
int pgindex;
|
|
char * getuid;
|
|
struct prio * prio;
|
|
+ char * prio_arg;
|
|
struct checker checker;
|
|
struct multipath * mpp;
|
|
int fd;
|
|
diff --git a/multipath.conf.annotated b/multipath.conf.annotated
|
|
index a4c7e6a..740a334 100644
|
|
--- a/multipath.conf.annotated
|
|
+++ b/multipath.conf.annotated
|
|
@@ -261,6 +261,18 @@
|
|
# # default : 1000
|
|
# #
|
|
# rr_min_io 100
|
|
+#
|
|
+# #
|
|
+# #name : prio
|
|
+# #scope : multipath
|
|
+# #desc : the function to call to obtain a path weight.
|
|
+# # Weights are summed for each path group to
|
|
+# # determine the next PG to use case of failure.
|
|
+# #default : no callout, all paths equals
|
|
+# # Ex:
|
|
+# # prio alua
|
|
+# # prio "weightedpath devname sda 50 sde 10 sdc 50 sdf 10"
|
|
+# prio "weightedpath hbtl 1:.:.:. 2 4:.:.:. 4"
|
|
# }
|
|
# multipath {
|
|
# wwid 1DEC_____321816758474
|
|
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
|
index d3c37c8..8ac1f1c 100644
|
|
--- a/multipath/multipath.conf.5
|
|
+++ b/multipath/multipath.conf.5
|
|
@@ -151,6 +151,24 @@ Generate the path priority for Hitachi HDS Modular storage arrays.
|
|
Default value is \fBnone\fR.
|
|
.RE
|
|
.TP
|
|
+.B prio
|
|
+The default program and args to path priority routine. The specified
|
|
+routine should return a numeric value specifying the relative priority
|
|
+of this path. Higher number have a higher priority.
|
|
+.RS
|
|
+.TP 12
|
|
+.B alua
|
|
+Generate the path priority based on ALUA status of the path.
|
|
+.TP 12
|
|
+.B weightedpath <hbtl|devname> <regex1> <prio1> <regex2> <prio2> ...
|
|
+.I hbtl
|
|
+regex can be of SCSI H:B:T:L format Ex: 1:0:.:. , *:0:0:.
|
|
+.I devname
|
|
+regex can be of device name format Ex: sda , sd.e
|
|
+Generate the path priority based on the regular expression and the
|
|
+priority provided as argument.
|
|
+.RE
|
|
+.TP
|
|
.B features
|
|
Specify any device-mapper features to be used. Syntax is
|
|
.I num list
|
|
@@ -327,6 +345,8 @@ section:
|
|
.TP
|
|
.B path_selector
|
|
.TP
|
|
+.B prio
|
|
+.TP
|
|
.B failback
|
|
.TP
|
|
.B no_path_retry
|
|
@@ -380,6 +400,8 @@ section:
|
|
.TP
|
|
.B path_checker
|
|
.TP
|
|
+.B prio
|
|
+.TP
|
|
.B features
|
|
.TP
|
|
.B prio_callout
|