Index: multipath-tools-091020/libmultipath/config.c =================================================================== --- multipath-tools-091020.orig/libmultipath/config.c +++ multipath-tools-091020/libmultipath/config.c @@ -156,6 +156,9 @@ free_hwe (struct hwentry * hwe) if (hwe->prio_name) FREE(hwe->prio_name); + if (hwe->prio_args) + FREE(hwe->prio_args); + if (hwe->bl_product) FREE(hwe->bl_product); @@ -195,6 +198,12 @@ free_mpe (struct mpentry * mpe) if (mpe->alias) FREE(mpe->alias); + if (mpe->prio_name) + FREE(mpe->prio_name); + + if (mpe->prio_args) + FREE(mpe->prio_args); + FREE(mpe); } @@ -279,6 +288,7 @@ merge_hwe (struct hwentry * hwe1, struct merge_str(selector); merge_str(checker_name); merge_str(prio_name); + merge_str(prio_args); merge_str(bl_product); merge_num(pgpolicy); merge_num(pgfailback); Index: multipath-tools-091020/libmultipath/config.h =================================================================== --- multipath-tools-091020.orig/libmultipath/config.h +++ multipath-tools-091020/libmultipath/config.h @@ -24,6 +24,7 @@ struct hwentry { char * selector; char * checker_name; char * prio_name; + char * prio_args; int pgpolicy; int pgfailback; @@ -42,6 +43,8 @@ struct mpentry { char * alias; char * getuid; char * selector; + char * prio_name; + char * prio_args; int pgpolicy; int pgfailback; @@ -95,6 +98,7 @@ struct config { char * hwhandler; char * bindings_file; char * prio_name; + char * prio_args; char * checker_name; vector keywords; Index: multipath-tools-091020/libmultipath/dict.c =================================================================== --- multipath-tools-091020.orig/libmultipath/dict.c +++ multipath-tools-091020/libmultipath/dict.c @@ -139,11 +139,23 @@ def_getuid_callout_handler(vector strvec static int def_prio_handler(vector strvec) { - conf->prio_name = set_value(strvec); + char *name, *args; - if (!conf->prio_name) + name = set_value(strvec); + if (!name) return 1; + args = strpbrk(name, " \t"); + if (args) { + *args = 0; + while(*++args && isblank(*args)); /* Do nothing */ + } + + conf->prio_name = STRDUP(name); + if (args && *args) + conf->prio_args = STRDUP(args); + + FREE(name); return 0; } @@ -806,16 +818,27 @@ hw_handler_handler(vector strvec) static int hw_prio_handler(vector strvec) { + char *name, *args; struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable); if (!hwe) return 1; - hwe->prio_name = set_value(strvec); - - if (!hwe->prio_name) + name = set_value(strvec); + if (!name) return 1; + args = strpbrk(name, " \t"); + if (args) { + *args = 0; + while(*++args && isblank(*args)); /* Do nothing */ + } + + hwe->prio_name = STRDUP(name); + if (args && *args) + hwe->prio_args = STRDUP(args); + + FREE(name); return 0; } @@ -1293,6 +1316,33 @@ mp_flush_on_last_del_handler(vector strv return 0; } +static int +mp_prio_handler(vector strvec) +{ + char *name, *args; + struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable); + + if (!mpe) + return 1; + + name = set_value(strvec); + if (!name) + return 1; + + args = strpbrk(name, " \t"); + if (args) { + *args = 0; + while(*++args && isblank(*args)); /* Do nothing */ + } + + mpe->prio_name = STRDUP(name); + if (args && *args) + mpe->prio_args = STRDUP(args); + + FREE(name); + return 0; +} + /* * config file keywords printing */ @@ -1472,6 +1522,20 @@ snprint_mp_flush_on_last_del (char * buf } static int +snprint_mp_prio (char * buff, int len, void * data) +{ + struct mpentry * mpe = (struct mpentry *)data; + + if (!mpe->prio_name) + return 0; + if (!strcmp(mpe->prio_name, conf->prio_name) && !mpe->prio_args) + return 0; + if (!mpe->prio_args) + return snprintf(buff, len, "%s", mpe->prio_name); + return snprintf(buff, len, "%s %s", mpe->prio_name, mpe->prio_args); +} + +static int snprint_hw_fast_io_fail(char * buff, int len, void * data) { struct hwentry * hwe = (struct hwentry *)data; @@ -1545,10 +1609,11 @@ snprint_hw_prio (char * buff, int len, v if (!hwe->prio_name) return 0; - if (!strcmp(hwe->prio_name, conf->prio_name)) + if (!strcmp(hwe->prio_name, conf->prio_name) && !hwe->prio_args) return 0; - - return snprintf(buff, len, "%s", hwe->prio_name); + if (!hwe->prio_args) + return snprintf(buff, len, "%s", hwe->prio_name); + return snprintf(buff, len, "%s %s", hwe->prio_name, hwe->prio_args); } static int @@ -1837,10 +1902,14 @@ snprint_def_prio (char * buff, int len, return 0; if (strlen(conf->prio_name) == strlen(DEFAULT_PRIO) && - !strcmp(conf->prio_name, DEFAULT_PRIO)) + !strcmp(conf->prio_name, DEFAULT_PRIO) && !conf->prio_args) return 0; - - return snprintf(buff, len, "%s", conf->prio_name); + + if (!conf->prio_args) + return snprintf(buff, len, "%s", conf->prio_name); + else + return snprintf(buff, len, "%s %s", conf->prio_name, + conf->prio_args); } static int @@ -2146,5 +2215,6 @@ init_keywords(void) 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("prio", &mp_prio_handler, &snprint_mp_prio); install_sublevel_end(); } Index: multipath-tools-091020/libmultipath/discovery.c =================================================================== --- multipath-tools-091020.orig/libmultipath/discovery.c +++ multipath-tools-091020/libmultipath/discovery.c @@ -800,30 +800,6 @@ get_state (struct path * pp, int daemon) } static int -get_prio (struct path * pp) -{ - if (!pp) - return 0; - - if (!pp->prio) { - select_prio(pp); - if (!pp->prio) { - condlog(3, "%s: no prio selected", pp->dev); - return 1; - } - } - pp->priority = prio_getprio(pp->prio, pp); - if (pp->priority < 0) { - condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio)); - pp->priority = PRIO_UNDEF; - return 1; - } - condlog(3, "%s: %s prio = %u", - pp->dev, prio_name(pp->prio), pp->priority); - return 0; -} - -static int get_uid (struct path * pp) { char buff[CALLOUT_MAX_SIZE]; @@ -850,6 +826,32 @@ get_uid (struct path * pp) return 0; } +static int +get_prio (struct path * pp) +{ + if (!pp) + return 0; + + if (!pp->prio) { + if (!strlen(pp->wwid)) + get_uid(pp); + select_prio(pp); + if (!pp->prio) { + condlog(3, "%s: no prio selected", pp->dev); + return 1; + } + } + pp->priority = prio_getprio(pp->prio, pp); + if (pp->priority < 0) { + condlog(3, "%s: %s prio error", pp->dev, prio_name(pp->prio)); + pp->priority = PRIO_UNDEF; + return 1; + } + condlog(3, "%s: %s prio = %u", + pp->dev, prio_name(pp->prio), pp->priority); + return 0; +} + extern int pathinfo (struct path *pp, vector hwtable, int mask) { @@ -887,6 +889,9 @@ pathinfo (struct path *pp, vector hwtabl goto blank; } + if (mask & DI_WWID && !strlen(pp->wwid)) + get_uid(pp); + /* * Retrieve path priority, even for PATH_DOWN paths if it has never * been successfully obtained before. @@ -895,9 +900,6 @@ pathinfo (struct path *pp, vector hwtabl (pp->state != PATH_DOWN || pp->priority == PRIO_UNDEF)) get_prio(pp); - if (mask & DI_WWID && !strlen(pp->wwid)) - get_uid(pp); - return 0; blank: Index: multipath-tools-091020/libmultipath/prio.h =================================================================== --- multipath-tools-091020.orig/libmultipath/prio.h +++ multipath-tools-091020/libmultipath/prio.h @@ -24,6 +24,7 @@ #define PRIO_NETAPP "netapp" #define PRIO_RANDOM "random" #define PRIO_RDAC "rdac" +#define PRIO_WEIGHTED "weighted" /* * Value used to mark the fact prio was not defined Index: multipath-tools-091020/libmultipath/prioritizers/Makefile =================================================================== --- multipath-tools-091020.orig/libmultipath/prioritizers/Makefile +++ multipath-tools-091020/libmultipath/prioritizers/Makefile @@ -13,7 +13,8 @@ LIBS = \ libprioalua.so \ libpriotpg_pref.so \ libprionetapp.so \ - libpriohds.so + libpriohds.so \ + libprioweighted.so \ CFLAGS += -I.. Index: multipath-tools-091020/libmultipath/prioritizers/weighted.c =================================================================== --- /dev/null +++ multipath-tools-091020/libmultipath/prioritizers/weighted.c @@ -0,0 +1,139 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright (C) 2009 Red Hat, Inc. All rights reserved. +** +** This copyrighted material is made available to anyone wishing to use, +** modify, copy, or redistribute it subject to the terms and conditions +** of the GNU General Public License v.2. +** +******************************************************************************* +******************************************************************************/ + +/* This prioritizer is based on a path's device name or its H:T:B:L. Both of + * these can change when the node is rebooted, and can differ from node to + * node. (i.e. there is no guarantee that sda will point to the same device + * after a reboot) If you use this prioritizer, it may be necessary to + * manually edit /etc/multipath.conf after any reboot + * + * Format: + * prio "weighted hbtl [ ] + * prio "weighted devname [ ] + * + * Examples: + * prio "weighted hbtl 4:* 2 3:.:.:. 1" + * prio "weighted devname sda 2 sde 1" + * + */ + +#include +#include +#include +#include + +#include "weighted.h" + +#define DEFAULT_WEIGHTED_PRIO 0 + +#define pp_weighted_log(prio, fmt, args...) \ + condlog(prio, "%s: weighted prio: " fmt, dev, ##args) + +static char * +next_str(char **str) +{ + char *next; + + do { + next = strsep(str, " \t"); + } while (next && strcmp(next, "") == 0); + return next; +} + + +static int +match (char *dev, char *target, char *regex_str, char *prio_str, + unsigned int *prio) +{ + + regex_t regex; + int err, ret = 0; + char *errbuf; + size_t errbuf_size; + unsigned int prio_match; + + if (sscanf(prio_str, "%u", &prio_match) != 1) { + condlog(0, "%s: weighted prio: invalid prio '%s'", dev, + prio_str); + return 0; + } + err = regcomp(®ex, regex_str, REG_EXTENDED|REG_NOSUB); + if (err) { + errbuf_size = regerror(err, ®ex, NULL, 0); + errbuf = malloc(errbuf_size); + regerror(err, ®ex, errbuf, errbuf_size); + condlog(0, "%s: weighted prio: cannot compile regex '%s' : %s", + dev, regex_str, errbuf); + free(errbuf); + return 0; + } + if (regexec(®ex, target, 0, NULL, 0) == 0) { + *prio = prio_match; + ret = 1; + } + + regfree(®ex); + return ret; +} + +int +prio_weighted(struct path * pp) +{ + char target[FILE_NAME_SIZE]; + char *buff, *args, *ptr, *prio_str; + unsigned int prio = DEFAULT_WEIGHTED_PRIO; + char *regex_str = NULL; + int regex_size = 0; + + if (!pp->prio_args) + return DEFAULT_WEIGHTED_PRIO; + buff = args = strdup(pp->prio_args); + ptr = next_str(&args); + + if (strcasecmp(ptr, "hbtl") == 0) + sprintf(target, "%d:%d:%d:%d", pp->sg_id.host_no, + pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun); + else if (strcasecmp(ptr, "devname") == 0) + strcpy(target, pp->dev); + else { + condlog(0, "%s: weighted prio: invalid argument. Want 'hbtl' or 'devname'. Got '%s'", pp->dev, ptr); + goto out; + } + + while ((ptr = next_str(&args)) != NULL) { + + prio_str = next_str(&args); + if (!prio_str) { + condlog(0, "%s weighted prio: missing prio for regex '%s'", pp->dev, ptr); + goto out; + } + if (!regex_str || regex_size < strlen(ptr) + 3){ + regex_size = strlen(ptr) + 3; + regex_str = realloc(regex_str, regex_size); + } + sprintf(regex_str, "%s%s%s", (ptr[0] == '^')? "" : "^", + ptr, (ptr[strlen(ptr)-1] == '$')? "" : "$"); + if (match(pp->dev, target, regex_str, prio_str, &prio)) + break; + } +out: + free(buff); + if (regex_str) + free(regex_str); + return prio; +} + +int +getprio(struct path * pp) +{ + return prio_weighted(pp); +} Index: multipath-tools-091020/libmultipath/propsel.c =================================================================== --- multipath-tools-091020.orig/libmultipath/propsel.c +++ multipath-tools-091020/libmultipath/propsel.c @@ -312,14 +312,25 @@ select_getuid (struct path * pp) extern int select_prio (struct path * pp) { + struct mpentry * mpe; + + if ((mpe = find_mpe(pp->wwid)) && mpe->prio_name) { + pp->prio = prio_lookup(mpe->prio_name); + pp->prio_args = mpe->prio_args; + condlog(3, "%s: prio = %s (LUN setting)", + pp->dev, mpe->prio_name); + return 0; + } if (pp->hwe && pp->hwe->prio_name) { pp->prio = prio_lookup(pp->hwe->prio_name); + pp->prio_args = pp->hwe->prio_args; 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_args = conf->prio_args; condlog(3, "%s: prio = %s (config file default)", pp->dev, conf->prio_name); return 0; Index: multipath-tools-091020/libmultipath/structs.h =================================================================== --- multipath-tools-091020.orig/libmultipath/structs.h +++ multipath-tools-091020/libmultipath/structs.h @@ -142,6 +142,7 @@ struct path { int priority; int pgindex; char * getuid; + char * prio_args; struct prio * prio; struct checker checker; struct multipath * mpp; Index: multipath-tools-091020/libmultipath/prioritizers/weighted.h =================================================================== --- /dev/null +++ multipath-tools-091020/libmultipath/prioritizers/weighted.h @@ -0,0 +1,8 @@ +#ifndef _WEIGHTED_H +#define _WEIGHTED_H + +#define PRIO_WEIGHTED "weighted" + +int prio_weighted(struct path *pp); + +#endif