--- /dev/null
+---
+ libmultipath/config.c | 10 ++
+ libmultipath/config.h | 4 +
+ libmultipath/dict.c | 92 ++++++++++++++++++++---
+ libmultipath/discovery.c | 56 +++++++-------
+ libmultipath/prio.h | 1
+ libmultipath/prioritizers/Makefile | 3
+ libmultipath/prioritizers/weighted.c | 139 +++++++++++++++++++++++++++++++++++
+ libmultipath/prioritizers/weighted.h | 8 ++
+ libmultipath/propsel.c | 11 ++
+ libmultipath/structs.h | 1
+ 10 files changed, 286 insertions(+), 39 deletions(-)
+
+Index: multipath-tools/libmultipath/config.c
+===================================================================
+--- multipath-tools.orig/libmultipath/config.c
++++ multipath-tools/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/libmultipath/config.h
+===================================================================
+--- multipath-tools.orig/libmultipath/config.h
++++ multipath-tools/libmultipath/config.h
+@@ -25,6 +25,7 @@ struct hwentry {
+ char * selector;
+ char * checker_name;
+ char * prio_name;
++ char * prio_args;
+
+ int pgpolicy;
+ int pgfailback;
+@@ -43,6 +44,8 @@ struct mpentry {
+ char * alias;
+ char * getuid;
+ char * selector;
++ char * prio_name;
++ char * prio_args;
+
+ int pgpolicy;
+ int pgfailback;
+@@ -97,6 +100,7 @@ struct config {
+ char * hwhandler;
+ char * bindings_file;
+ char * prio_name;
++ char * prio_args;
+ char * checker_name;
+
+ vector keywords;
+Index: multipath-tools/libmultipath/dict.c
+===================================================================
+--- multipath-tools.orig/libmultipath/dict.c
++++ multipath-tools/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/libmultipath/discovery.c
+===================================================================
+--- multipath-tools.orig/libmultipath/discovery.c
++++ multipath-tools/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/libmultipath/prio.h
+===================================================================
+--- multipath-tools.orig/libmultipath/prio.h
++++ multipath-tools/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/libmultipath/prioritizers/Makefile
+===================================================================
+--- multipath-tools.orig/libmultipath/prioritizers/Makefile
++++ multipath-tools/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/libmultipath/prioritizers/weighted.c
+===================================================================
+--- /dev/null
++++ multipath-tools/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 <regex> <prio> [<regex> <prio>]
++ * prio "weighted devname <regex> <prio> [<regex> <prio>]
++ *
++ * Examples:
++ * prio "weighted hbtl 4:* 2 3:.:.:. 1"
++ * prio "weighted devname sda 2 sde 1"
++ *
++ */
++
++#include <string.h>
++#include <prio.h>
++#include <debug.h>
++#include <regex.h>
++
++#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/libmultipath/propsel.c
+===================================================================
+--- multipath-tools.orig/libmultipath/propsel.c
++++ multipath-tools/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/libmultipath/structs.h
+===================================================================
+--- multipath-tools.orig/libmultipath/structs.h
++++ multipath-tools/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/libmultipath/prioritizers/weighted.h
+===================================================================
+--- /dev/null
++++ multipath-tools/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