commit 86bc28e5702babadf73a1c4395870da370efa257 Author: Hannes Reinecke 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 ... 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 Signed-off-by: Hannes Reinecke 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 #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 +#include + +#include +#include "weightedpath.h" +#include +#include +#include +#include +#include + +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 ... +.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