All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch] leastpending_io load balancing policy
@ 2008-11-12 14:17 Balasubramanian, Vijayakumar (STSD)
  2008-11-13 17:53 ` [patch] multipath-tools weighted path priority routine Balasubramanian, Vijayakumar (STSD)
  2008-12-03 22:08 ` [patch] leastpending_io load balancing policy Alasdair G Kergon
  0 siblings, 2 replies; 9+ messages in thread
From: Balasubramanian, Vijayakumar (STSD) @ 2008-11-12 14:17 UTC (permalink / raw)
  To: dm-devel@redhat.com

[-- Attachment #1: Type: text/plain, Size: 582 bytes --]

Hi,
Attached patch provides "Least pending IO" dynamic load balancing policy for bio based device mapper multipath. This load balancing policy considers the number of unserviced requests pending on a path and selects the path with least count for pending service request.

We find this policy more useful especially when the SAN environment has heterogeneous components. Ex, when there is one 8GB HBA and one 2GB HBA connected to the same server, 8GB HBA could be utilized better with this algorithm.

Can we have this patch included into the source tree?

Thanks,
Vijay


[-- Attachment #2: leastpending_io.patch --]
[-- Type: application/octet-stream, Size: 7948 bytes --]

diff -pNaur md-org//Makefile md//Makefile
--- md-org//Makefile	2008-11-12 17:08:29.000000000 +0530
+++ md//Makefile	2008-11-12 15:14:22.000000000 +0530
@@ -32,7 +32,7 @@ obj-$(CONFIG_BLK_DEV_MD)	+= md-mod.o
 obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
 obj-$(CONFIG_DM_DELAY)		+= dm-delay.o
-obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o
+obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o dm-leastpending-path.o 
 obj-$(CONFIG_DM_SNAPSHOT)	+= dm-snapshot.o
 obj-$(CONFIG_DM_MIRROR)		+= dm-mirror.o dm-log.o
 obj-$(CONFIG_DM_ZERO)		+= dm-zero.o
diff -pNaur md-org//dm-leastpending-path.c md//dm-leastpending-path.c
--- md-org//dm-leastpending-path.c	1970-01-01 05:30:00.000000000 +0530
+++ md//dm-leastpending-path.c	2008-11-12 15:19:11.000000000 +0530
@@ -0,0 +1,272 @@
+/*
+  *****************************************************************************
+ *                                                                           *
+ *     (C)  Copyright 2008 Hewlett-Packard Development Company, L.P          *
+ *                                                                           *
+ * This program is free software; you can redistribute it and/or modify it   *
+ * under the terms of the GNU General Public License as published by the Free*
+ * Software  Foundation; either version 2 of the License, or (at your option)*
+ * any later version.                                                        *
+ *                                                                           *
+ * This program is distributed in the hope that it will be useful, but       *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY*
+ * or FITNESS FOR  A PARTICULAR PURPOSE. See the GNU General Public License  *
+ * for more details.                                                         *
+ *                                                                           *
+ * You should have received a copy of the GNU General Public License along   *
+ * with this program; if not, write to the Free Software Foundation, Inc.,   *
+ * 675 Mass Ave, Cambridge, MA 02139, USA.                                   *
+ *                                                                           *
+ *                                                                           *
+ *****************************************************************************
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+
+
+#define RR_MIN_IO	-1
+
+#define DM_MSG_PREFIX "multipath leastpendingio-path"
+	
+/*-----------------------------------------------------------------
+ * Path-handling code, paths are held in lists
+ *---------------------------------------------------------------*/
+struct path_info {
+	struct list_head list;
+	struct dm_path *path;
+	unsigned repeat_count;
+	unsigned io_count;
+};
+
+static void free_paths(struct list_head *paths)
+{
+	struct path_info *pi, *next;
+
+	list_for_each_entry_safe(pi, next, paths, list) {
+		list_del(&pi->list);
+		kfree(pi);
+	}
+}
+
+/*-----------------------------------------------------------------
+ * leastpendingio-path selector
+ *---------------------------------------------------------------*/
+
+struct selector {
+	struct list_head valid_paths;
+	struct list_head invalid_paths;
+};
+
+static struct selector *alloc_selector(void)
+{
+	struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (s) {
+		INIT_LIST_HEAD(&s->valid_paths);
+		INIT_LIST_HEAD(&s->invalid_paths);
+	}
+
+	return s;
+}
+
+static int lpp_create(struct path_selector *ps, unsigned argc, char **argv)
+{
+	struct selector *s;
+
+	s = alloc_selector();
+	if (!s)
+		return -ENOMEM;
+
+	ps->context = s;
+	return 0;
+}
+
+static void lpp_destroy(struct path_selector *ps)
+{
+	struct selector *s = (struct selector *) ps->context;
+
+	free_paths(&s->valid_paths);
+	free_paths(&s->invalid_paths);
+	kfree(s);
+	ps->context = NULL;
+}
+
+static int lpp_status(struct path_selector *ps, struct dm_path *path,
+		     status_type_t type, char *result, unsigned int maxlen)
+{
+	struct path_info *pi;
+	int sz = 0;
+
+	if (!path)
+		DMEMIT("0 ");
+	else {
+		switch(type) {
+		case STATUSTYPE_INFO:
+			break;
+		case STATUSTYPE_TABLE:
+			pi = path->pscontext;
+			DMEMIT("%u ", pi->repeat_count);
+			break;
+		}
+	}
+
+	return sz;
+}
+
+/*
+ * Called during initialisation to register each path with an
+ * optional repeat_count.
+ */
+static int lpp_add_path(struct path_selector *ps, struct dm_path *path,
+		       int argc, char **argv, char **error)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi;
+	unsigned repeat_count = RR_MIN_IO;
+
+	if (argc > 1) {
+		*error = "leastpendingio-path ps: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+	/* First path argument is number of I/Os before switching path */
+	if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+		*error = "leastpendingio-path ps: invalid repeat count";
+		return -EINVAL;
+	}
+
+	/* allocate the path */
+	pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+	if (!pi) {
+		*error = "leastpendingio-path ps: Error allocating path context";
+		return -ENOMEM;
+	}
+
+	pi->path = path;
+	pi->repeat_count = repeat_count;
+	pi->io_count = 0;
+
+	path->pscontext = pi;
+
+	list_add(&pi->list, &s->valid_paths);
+
+	return 0;
+}
+
+static void lpp_fail_path(struct path_selector *ps, struct dm_path *p)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = p->pscontext;
+
+	pi->io_count = 0;
+
+	list_move(&pi->list, &s->invalid_paths);
+}
+
+static int lpp_reinstate_path(struct path_selector *ps, struct dm_path *p)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = p->pscontext;
+
+	pi->io_count = 0;
+
+	list_move(&pi->list, &s->valid_paths);
+
+	return 0;
+}
+
+static struct dm_path* lpp_find_least_pending_io_path(struct selector *s)
+{
+	struct path_info *pi = NULL,*next = NULL,*least_io_path = NULL;
+	struct list_head *paths = NULL;
+
+	if(list_empty(&s->valid_paths)){
+		return NULL;
+	}
+	paths = &s->valid_paths;
+	list_for_each_entry_safe(pi, next, paths, list) {
+		if(least_io_path == NULL)
+			least_io_path = pi;
+		if(least_io_path->io_count < pi->io_count) {
+			least_io_path = pi;
+		}
+		if(least_io_path->io_count == 0)
+			break;
+
+	}
+	if(least_io_path){
+		least_io_path->io_count ++;
+		return least_io_path->path;
+	}
+
+	return NULL;
+}
+
+static struct dm_path *lpp_select_path(struct path_selector *ps,
+				   unsigned *repeat_count)
+{
+	struct selector *s = (struct selector *) ps->context;
+	return lpp_find_least_pending_io_path(s);
+}
+
+static int lpp_end_io(struct path_selector *ps,struct dm_path *path)
+{
+	struct path_info *pi = NULL;
+
+	DMINFO("leastpendingio-path: lpp_end_io");
+	
+	pi = path->pscontext;
+	if(pi == NULL)
+		return 1;
+	
+	pi->io_count--;
+
+	return 0;
+}
+
+static struct path_selector_type lpp_ps = {
+	.name = "leastpendingio-path",
+	.module = THIS_MODULE,
+	.table_args = 1,
+	.info_args = 0,
+	.create = lpp_create,
+	.destroy = lpp_destroy,
+	.status = lpp_status,
+	.add_path = lpp_add_path,
+	.fail_path = lpp_fail_path,
+	.reinstate_path = lpp_reinstate_path,
+	.select_path = lpp_select_path,
+	.end_io	= lpp_end_io,
+};
+
+
+
+static int __init dm_lpp_init(void)
+{
+	int r = dm_register_path_selector(&lpp_ps);
+
+	if (r < 0)
+		DMERR("leastpendingio-path: register failed %d", r);
+
+	DMINFO("dm-leastpendingio-path version 1.0.0 loaded");
+
+	return r;
+}
+
+static void __exit dm_lpp_exit(void)
+{
+	int r = dm_unregister_path_selector(&lpp_ps);
+
+	if (r < 0)
+		DMERR("leastpendingio-path: unregister failed %d", r);
+}
+
+module_init(dm_lpp_init);
+module_exit(dm_lpp_exit);
+
+MODULE_DESCRIPTION(DM_NAME " leastpendingio-path multipath path selector");
+MODULE_AUTHOR("Sakshi Chaitanya Veni <vsakshi@hp.com>");
+MODULE_LICENSE("GPL");

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



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

* [patch] multipath-tools weighted path priority routine
  2008-11-12 14:17 [patch] leastpending_io load balancing policy Balasubramanian, Vijayakumar (STSD)
@ 2008-11-13 17:53 ` Balasubramanian, Vijayakumar (STSD)
  2008-11-21  7:51   ` Kiyoshi Ueda
  2008-12-03 22:08 ` [patch] leastpending_io load balancing policy Alasdair G Kergon
  1 sibling, 1 reply; 9+ messages in thread
From: Balasubramanian, Vijayakumar (STSD) @ 2008-11-13 17:53 UTC (permalink / raw)
  To: device-mapper development

[-- Attachment #1: Type: text/plain, Size: 19081 bytes --]

Hi,
'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.


The below patch
Allows 'prio' parameter to be set in "multipath" section,
Allows 'prio' priority routine to take arguments in multipath.conf file,
Adds 'weightedpath' priority routine.

Can we have this patch included in the source tree?

Thanks,
Vijay


-----------------------------------------------------------------------------------

Patch to implement weighted path priority routine in multipath-tools.

Signed-off-by:
                Veena T S <veena-s.t@hp.com>
                Sakshi Chaitanya Veni <sakshi-chaitanya.veni@hp.com>
                Vijayakumar Balasubramanian <vijayakumar@hp.com>

diff -pNur multipath-tools-0.4.8.org/libmultipath/config.c multipath-tools-0.4.8/libmultipath/config.c
--- multipath-tools-0.4.8.org/libmultipath/config.c     2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/config.c 2008-11-12 10:26:55.000000000 +0530
@@ -201,6 +201,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);
 }

@@ -285,6 +291,7 @@ merge_hwe (struct hwentry * hwe1, struct
        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);
@@ -333,6 +340,9 @@ store_hwe (vector hwtable, struct hwentr
        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;
@@ -547,8 +557,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 -pNur multipath-tools-0.4.8.org/libmultipath/config.h multipath-tools-0.4.8/libmultipath/config.h
--- multipath-tools-0.4.8.org/libmultipath/config.h     2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/config.h 2008-11-12 10:23:28.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/dict.c multipath-tools-0.4.8/libmultipath/dict.c
--- multipath-tools-0.4.8.org/libmultipath/dict.c       2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/dict.c   2008-11-13 20:03:10.000000000 +0530
@@ -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"
@@ -95,11 +96,29 @@ 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 (temp) {
+               result = strsep(&temp, split_char);
+               if (strcmp(result, "")) {
+                       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;
 }

@@ -602,15 +621,32 @@ 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 (temp) {
+               result = strsep(&temp, split_char);
+               if (strcmp(result, "")) {
+                       if (prio_lookup(result)) {
+                               hwe->prio_name = STRDUP(result);
+                               if (temp)
+                                       hwe->prio_arg = STRDUP(temp);
+                               else
+                                       hwe->prio_arg = NULL;
+                               break;
+                       }
+               }
+       }
+
+       FREE(buff);
        return 0;
 }

@@ -956,6 +992,41 @@ 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 (temp) {
+               result = strsep(&temp, split_char);
+               if (strcmp(result, "")) {
+                       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
  */
@@ -1091,6 +1162,17 @@ snprint_mp_pg_timeout (char * buff, int
 }

 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;
@@ -1652,6 +1734,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 -pNur multipath-tools-0.4.8.org/libmultipath/discovery.c multipath-tools-0.4.8/libmultipath/discovery.c
--- multipath-tools-0.4.8.org/libmultipath/discovery.c  2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/discovery.c      2008-11-13 19:43:55.000000000 +0530
@@ -759,8 +759,11 @@ pathinfo (struct path *pp, vector hwtabl
          * 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 -pNur multipath-tools-0.4.8.org/libmultipath/prio.h multipath-tools-0.4.8/libmultipath/prio.h
--- multipath-tools-0.4.8.org/libmultipath/prio.h       2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prio.h   2008-11-13 22:41:11.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/Makefile multipath-tools-0.4.8/libmultipath/prioritizers/Makefile
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/Makefile        2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/Makefile    2008-11-11 18:11:07.000000000 +0530
@@ -12,7 +12,8 @@ LIBS = \
        libpriordac.so \
        libprioalua.so \
        libprioontap.so \
-       libpriohds.so
+       libpriohds.so \
+       libprioweightedpath.so

 CFLAGS += -I..

diff -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.c multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.c
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.c  1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.c      2008-11-13 20:04:47.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.h multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.h
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.h  1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.h      2008-11-13 19:56:10.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/propsel.c multipath-tools-0.4.8/libmultipath/propsel.c
--- multipath-tools-0.4.8.org/libmultipath/propsel.c    2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/propsel.c        2008-11-13 19:58:58.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/structs.h multipath-tools-0.4.8/libmultipath/structs.h
--- multipath-tools-0.4.8.org/libmultipath/structs.h    2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/structs.h        2008-11-11 18:11:07.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/multipath/multipath.conf.5 multipath-tools-0.4.8/multipath/multipath.conf.5
--- multipath-tools-0.4.8.org/multipath/multipath.conf.5        2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/multipath/multipath.conf.5    2008-11-13 22:36:05.000000000 +0530
@@ -146,6 +146,24 @@ Generate the path priority for Hitachi H
 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
@@ -322,6 +340,8 @@ section:
 .TP
 .B path_selector
 .TP
+.B prio
+.TP
 .B failback
 .TP
 .B no_path_retry
@@ -375,6 +395,8 @@ section:
 .TP
 .B path_checker
 .TP
+.B prio
+.TP
 .B features
 .TP
 .B prio_callout
diff -pNur multipath-tools-0.4.8.org/multipath.conf.annotated multipath-tools-0.4.8/multipath.conf.annotated
--- multipath-tools-0.4.8.org/multipath.conf.annotated  2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/multipath.conf.annotated      2008-11-12 18:29:01.000000000 +0530
@@ -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

[-- Attachment #2: multipath-tools-add-weightedpath.patch --]
[-- Type: application/octet-stream, Size: 14467 bytes --]

Patch to implement weighted path priority routine in multipath-tools.

Signed-off-by:
                Veena T S <veena-s.t@hp.com>
                Sakshi Chaitanya Veni <sakshi-chaitanya.veni@hp.com>
                Vijayakumar Balasubramanian <vijayakumar@hp.com>

diff -pNur multipath-tools-0.4.8.org/libmultipath/config.c multipath-tools-0.4.8/libmultipath/config.c
--- multipath-tools-0.4.8.org/libmultipath/config.c	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/config.c	2008-11-12 10:26:55.000000000 +0530
@@ -201,6 +201,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);
 }
 
@@ -285,6 +291,7 @@ merge_hwe (struct hwentry * hwe1, struct
 	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);
@@ -333,6 +340,9 @@ store_hwe (vector hwtable, struct hwentr
 	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;
@@ -547,8 +557,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 -pNur multipath-tools-0.4.8.org/libmultipath/config.h multipath-tools-0.4.8/libmultipath/config.h
--- multipath-tools-0.4.8.org/libmultipath/config.h	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/config.h	2008-11-12 10:23:28.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/dict.c multipath-tools-0.4.8/libmultipath/dict.c
--- multipath-tools-0.4.8.org/libmultipath/dict.c	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/dict.c	2008-11-13 20:03:10.000000000 +0530
@@ -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"
@@ -95,11 +96,29 @@ 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 (temp) {
+		result = strsep(&temp, split_char);
+		if (strcmp(result, "")) {
+			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;
 }
 
@@ -602,15 +621,32 @@ 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 (temp) {
+		result = strsep(&temp, split_char);
+		if (strcmp(result, "")) {
+			if (prio_lookup(result)) {
+				hwe->prio_name = STRDUP(result);
+				if (temp)
+					hwe->prio_arg = STRDUP(temp);
+				else
+					hwe->prio_arg = NULL;
+				break;
+			}
+		}
+	}
+
+	FREE(buff);
 	return 0;
 }
 
@@ -956,6 +992,41 @@ 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 (temp) {
+		result = strsep(&temp, split_char);
+		if (strcmp(result, "")) {
+			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
  */
@@ -1091,6 +1162,17 @@ snprint_mp_pg_timeout (char * buff, int
 }
 
 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;
@@ -1652,6 +1734,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 -pNur multipath-tools-0.4.8.org/libmultipath/discovery.c multipath-tools-0.4.8/libmultipath/discovery.c
--- multipath-tools-0.4.8.org/libmultipath/discovery.c	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/discovery.c	2008-11-13 19:43:55.000000000 +0530
@@ -759,8 +759,11 @@ pathinfo (struct path *pp, vector hwtabl
 	  * 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 -pNur multipath-tools-0.4.8.org/libmultipath/prio.h multipath-tools-0.4.8/libmultipath/prio.h
--- multipath-tools-0.4.8.org/libmultipath/prio.h	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prio.h	2008-11-13 22:41:11.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/Makefile multipath-tools-0.4.8/libmultipath/prioritizers/Makefile
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/Makefile	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/Makefile	2008-11-11 18:11:07.000000000 +0530
@@ -12,7 +12,8 @@ LIBS = \
 	libpriordac.so \
 	libprioalua.so \
 	libprioontap.so \
-	libpriohds.so
+	libpriohds.so \
+	libprioweightedpath.so
 
 CFLAGS += -I..
 
diff -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.c multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.c
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.c	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.c	2008-11-13 20:04:47.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.h multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.h
--- multipath-tools-0.4.8.org/libmultipath/prioritizers/weightedpath.h	1970-01-01 05:30:00.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/prioritizers/weightedpath.h	2008-11-13 19:56:10.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/propsel.c multipath-tools-0.4.8/libmultipath/propsel.c
--- multipath-tools-0.4.8.org/libmultipath/propsel.c	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/propsel.c	2008-11-13 19:58:58.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/libmultipath/structs.h multipath-tools-0.4.8/libmultipath/structs.h
--- multipath-tools-0.4.8.org/libmultipath/structs.h	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/libmultipath/structs.h	2008-11-11 18:11:07.000000000 +0530
@@ -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 -pNur multipath-tools-0.4.8.org/multipath/multipath.conf.5 multipath-tools-0.4.8/multipath/multipath.conf.5
--- multipath-tools-0.4.8.org/multipath/multipath.conf.5	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/multipath/multipath.conf.5	2008-11-13 22:36:05.000000000 +0530
@@ -146,6 +146,24 @@ Generate the path priority for Hitachi H
 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
@@ -322,6 +340,8 @@ section:
 .TP
 .B path_selector
 .TP
+.B prio
+.TP
 .B failback
 .TP
 .B no_path_retry
@@ -375,6 +395,8 @@ section:
 .TP
 .B path_checker
 .TP
+.B prio
+.TP
 .B features
 .TP
 .B prio_callout
diff -pNur multipath-tools-0.4.8.org/multipath.conf.annotated multipath-tools-0.4.8/multipath.conf.annotated
--- multipath-tools-0.4.8.org/multipath.conf.annotated	2008-11-11 18:11:56.000000000 +0530
+++ multipath-tools-0.4.8/multipath.conf.annotated	2008-11-12 18:29:01.000000000 +0530
@@ -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

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



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

* Re: [patch] multipath-tools weighted path priority routine
  2008-11-13 17:53 ` [patch] multipath-tools weighted path priority routine Balasubramanian, Vijayakumar (STSD)
@ 2008-11-21  7:51   ` Kiyoshi Ueda
  0 siblings, 0 replies; 9+ messages in thread
From: Kiyoshi Ueda @ 2008-11-21  7:51 UTC (permalink / raw)
  To: device-mapper development

Hi Vijayakumar,

Balasubramanian, Vijayakumar (STSD) wrote:
> Hi,
> '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.

I think we can't specify a prefered path reliably in this way.
Device name, host number, etc may vary for each system reboot.
It's horrible to check and change the config file after every reboot.
We should use more persistent name.

If you'd like to specify a prefered host, you may be able to use
hosts's WWN like /sys/class/fc_host/host?/[node|port]_name.

Thanks,
Kiyoshi Ueda

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

* Re: [patch] leastpending_io load balancing policy
  2008-11-12 14:17 [patch] leastpending_io load balancing policy Balasubramanian, Vijayakumar (STSD)
  2008-11-13 17:53 ` [patch] multipath-tools weighted path priority routine Balasubramanian, Vijayakumar (STSD)
@ 2008-12-03 22:08 ` Alasdair G Kergon
  2008-12-03 23:01   ` Alasdair G Kergon
  2008-12-04 11:42   ` Balasubramanian, Vijayakumar (STSD)
  1 sibling, 2 replies; 9+ messages in thread
From: Alasdair G Kergon @ 2008-12-03 22:08 UTC (permalink / raw)
  To: Balasubramanian, Vijayakumar (STSD); +Cc: device-mapper development

On Wed, Nov 12, 2008 at 02:17:05PM +0000, Balasubramanian, Vijayakumar (STSD) wrote:
> Attached patch provides "Least pending IO" dynamic load balancing policy for
> bio based device mapper multipath. This load balancing policy considers the
> number of unserviced requests pending on a path and selects the path with
> least count for pending service request.

repeat_count is still accepted but does nothing so I've removed it.
(And how did it work with a default of (unsigned) -1 anyway - never
switch path?)

However, it might improve performance by reducing the amount of splitting
of consecutive contiguous I/Os, so I think you should consider putting
it back in and implementing it (either internally or by extending the
ps interface to separate choice of path from use of path).

Another alternative might be to use thresholds, and only switch path,
for example, when the amount of I/O outstanding down the current path is
X more than the amount down the least path or the amount down the least
path falls below Y.

There is useful status information (io_count) not returned to userspace, so
I've added that to lpp_status().

The wrapper function lpp_select_path call adds nothing so I've
collapsed it.

Is there some locking missing from the end_io function because it manipulates
io_count?  E.g. io_count atomic with memory barrier, or caller takes the
lock?  How does it interact with fail_path() in do_end_io() and the way
that the io_count can get reset to 0 when a path is reinstated (and in
general there could still be outstanding I/O down it)?  For now, I've
removed that resetting.  (I'm concerned that there may be some races in
this code.)

Also, now that there is more than one path selector, Kconfig should be
updated to make them separate modules and to require at least one to
be included.

Alasdair
-- 
agk@redhat.com

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

* Re: [patch] leastpending_io load balancing policy
  2008-12-03 22:08 ` [patch] leastpending_io load balancing policy Alasdair G Kergon
@ 2008-12-03 23:01   ` Alasdair G Kergon
  2008-12-11  1:43     ` Kiyoshi Ueda
  2008-12-04 11:42   ` Balasubramanian, Vijayakumar (STSD)
  1 sibling, 1 reply; 9+ messages in thread
From: Alasdair G Kergon @ 2008-12-03 23:01 UTC (permalink / raw)
  To: Balasubramanian, Vijayakumar (STSD); +Cc: device-mapper development

Also look at request based multipath patch rqdm-dlb-02-queue-length-dlb.patch
which addresses some but not all of those points.

In particular I'd be interested in evidence as to whether repeat counts or 
thresholds work better.

Alasdair
-- 
agk@redhat.com

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

* RE: [patch] leastpending_io load balancing policy
  2008-12-03 22:08 ` [patch] leastpending_io load balancing policy Alasdair G Kergon
  2008-12-03 23:01   ` Alasdair G Kergon
@ 2008-12-04 11:42   ` Balasubramanian, Vijayakumar (STSD)
  1 sibling, 0 replies; 9+ messages in thread
From: Balasubramanian, Vijayakumar (STSD) @ 2008-12-04 11:42 UTC (permalink / raw)
  To: Alasdair G Kergon; +Cc: device-mapper development

Hi Alasdair,
I have inserted the response in the below mail. Let us know if it is OK, we can modify the patch accordingly.

Thanks,
Vijay


> -----Original Message-----
> From: Alasdair G Kergon [mailto:agk@redhat.com]
> Sent: Thursday, December 04, 2008 3:38 AM
> To: Balasubramanian, Vijayakumar (STSD)
> Cc: device-mapper development
> Subject: Re: [dm-devel] [patch] leastpending_io load balancing policy
>
> On Wed, Nov 12, 2008 at 02:17:05PM +0000, Balasubramanian,
> Vijayakumar (STSD) wrote:
> > Attached patch provides "Least pending IO" dynamic load balancing
> > policy for bio based device mapper multipath. This load balancing
> > policy considers the number of unserviced requests pending
> on a path
> > and selects the path with least count for pending service request.
>
> repeat_count is still accepted but does nothing so I've removed it.
> (And how did it work with a default of (unsigned) -1 anyway -
> never switch path?)
>
From multipath.conf user can set rr_min_io to 1 and that would be the default value [-1 needs to be replaced with 1]. However we could still provide the flexibility for user to change in case selector need to home on to a path for rr_min_io(s).

> However, it might improve performance by reducing the amount
> of splitting of consecutive contiguous I/Os, so I think you
> should consider putting it back in and implementing it
> (either internally or by extending the ps interface to
> separate choice of path from use of path).
>
Yes, It would be better to have repeat_count and have it user configurable.

> Another alternative might be to use thresholds, and only
> switch path, for example, when the amount of I/O outstanding
> down the current path is X more than the amount down the
> least path or the amount down the least path falls below Y.
>
> There is useful status information (io_count) not returned to
> userspace, so I've added that to lpp_status().
>
As we would be retaining repeat_count can we have the ":" separated information about repeat_count also.

> The wrapper function lpp_select_path call adds nothing so
> I've collapsed it.
>
This is fine.

> Is there some locking missing from the end_io function
> because it manipulates io_count?  E.g. io_count atomic with
> memory barrier, or caller takes the lock?  How does it
> interact with fail_path() in do_end_io() and the way that the
> io_count can get reset to 0 when a path is reinstated (and in
> general there could still be outstanding I/O down it)?  For
> now, I've removed that resetting.  (I'm concerned that there
> may be some races in this code.)
>
I guess we could have io_count as atomic_t and use atomic_* interfaces to avoid race conditions.

> Also, now that there is more than one path selector, Kconfig
> should be updated to make them separate modules and to
> require at least one to be included.
>
Kconfig can be modified to include the new path selector and leave the round-robin as default.

> Alasdair
> --
> agk@redhat.com
>

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

* Re: [patch] leastpending_io load balancing policy
  2008-12-03 23:01   ` Alasdair G Kergon
@ 2008-12-11  1:43     ` Kiyoshi Ueda
  2008-12-11 10:14       ` Balasubramanian, Vijayakumar (STSD)
  0 siblings, 1 reply; 9+ messages in thread
From: Kiyoshi Ueda @ 2008-12-11  1:43 UTC (permalink / raw)
  To: Balasubramanian, Vijayakumar (STSD), Alasdair G Kergon
  Cc: device-mapper development

Hi Alasdair, Vijayakumar,

Alasdair G Kergon wrote:
> Also look at request based multipath patch rqdm-dlb-02-queue-length-dlb.patch
> which addresses some but not all of those points.

FYI.
The rqdm-dlb-* patches don't depend on request-based dm-multipath,
so those can work on bio-based dm-multipath, too, with some cosmetic
changes.

Alasdair,
If you want to apply dynamic load balancer patches before request-based
dm-multipath patches, I can rebase my load balancer patches.

The reason why I've been posting those patches on top of request-based
patches is that load balancer doesn't work well in bio-based dm-multipath.
Bio-based dm-multipath is on top of the I/O scheduler, so I/O merging and
I/O sorting may occur after path switching.

Thanks,
Kiyoshi Ueda

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

* RE: [patch] leastpending_io load balancing policy
  2008-12-11  1:43     ` Kiyoshi Ueda
@ 2008-12-11 10:14       ` Balasubramanian, Vijayakumar (STSD)
  2008-12-12  2:51         ` Kiyoshi Ueda
  0 siblings, 1 reply; 9+ messages in thread
From: Balasubramanian, Vijayakumar (STSD) @ 2008-12-11 10:14 UTC (permalink / raw)
  To: Kiyoshi Ueda, Alasdair G Kergon; +Cc: device-mapper development

[-- Attachment #1: Type: text/plain, Size: 1229 bytes --]

Hi,
Attached is modified patch with the comments incorporated.

Thanks,
Vijay


> -----Original Message-----
> From: Kiyoshi Ueda [mailto:k-ueda@ct.jp.nec.com]
> Sent: Thursday, December 11, 2008 7:13 AM
> To: Balasubramanian, Vijayakumar (STSD); Alasdair G Kergon
> Cc: device-mapper development
> Subject: Re: [dm-devel] [patch] leastpending_io load balancing policy
>
> Hi Alasdair, Vijayakumar,
>
> Alasdair G Kergon wrote:
> > Also look at request based multipath patch
> > rqdm-dlb-02-queue-length-dlb.patch
> > which addresses some but not all of those points.
>
> FYI.
> The rqdm-dlb-* patches don't depend on request-based
> dm-multipath, so those can work on bio-based dm-multipath,
> too, with some cosmetic changes.
>
> Alasdair,
> If you want to apply dynamic load balancer patches before
> request-based dm-multipath patches, I can rebase my load
> balancer patches.
>
> The reason why I've been posting those patches on top of
> request-based patches is that load balancer doesn't work well
> in bio-based dm-multipath.
> Bio-based dm-multipath is on top of the I/O scheduler, so I/O
> merging and I/O sorting may occur after path switching.
>
> Thanks,
> Kiyoshi Ueda
>
>

[-- Attachment #2: dm-mpath-add-least-pending-path-selector.patch --]
[-- Type: application/octet-stream, Size: 8801 bytes --]

From: "Balasubramanian, Vijayakumar (STSD)" <vijayakumar@hp.com> 

This patch provides a "least pending IO" dynamic load balancing policy for
bio-based device-mapper multipath.

This load balancing policy considers the number of unserviced requests pending
on a path and selects the path with least count for pending service request.

We find this policy more useful especially when the SAN environment has
heterogeneous components. E.g. when there is one 8GB HBA and one 2GB HBA
connected to the same server, 8GB HBA could be utilized better with this
algorithm.

Signed-off-by: Sakshi Chaitanya Veni <vsakshi@hp.com>
Signed-off-by: Vijayakumar Balasubramanian <vijayakumar@hp.com>
Signed-off-by: Senthil Kumar V <senthil-kumar.veluswamy@hp.com>

---

diff -pNaur linux-2.6.28-rc7-org//drivers/md/Kconfig linux-2.6.28-rc7-mod//drivers/md/Kconfig
--- linux-2.6.28-rc7-org//drivers/md/Kconfig	2008-12-04 14:50:35.000000000 +0530
+++ linux-2.6.28-rc7-mod//drivers/md/Kconfig	2008-12-05 15:32:56.000000000 +0530
@@ -192,6 +192,16 @@ config MD_MULTIPATH
 
 	  If unsure, say N.
 
+config MD_MULTIPATH_LPP
+        tristate "Multipath - Least Pending IO Path Selector"
+        depends on MD_MULTIPATH
+        help
+          Least Pending IO Path Selector - This load balancing policy
+          considers the number of unserviced requests pending on a path
+          and selects the path with least count for pending service request.
+
+          If unsure, say N.
+
 config MD_FAULTY
 	tristate "Faulty test module for MD"
 	depends on BLK_DEV_MD
diff -pNaur linux-2.6.28-rc7-org//drivers/md/Makefile linux-2.6.28-rc7-mod//drivers/md/Makefile
--- linux-2.6.28-rc7-org//drivers/md/Makefile	2008-12-04 15:06:31.000000000 +0530
+++ linux-2.6.28-rc7-mod//drivers/md/Makefile	2008-12-05 15:33:22.000000000 +0530
@@ -33,6 +33,7 @@ obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
 obj-$(CONFIG_DM_DELAY)		+= dm-delay.o
 obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o
+obj-$(CONFIG_MD_MULTIPATH_LPP)	+= dm-least-pending.o
 obj-$(CONFIG_DM_SNAPSHOT)	+= dm-snapshot.o
 obj-$(CONFIG_DM_MIRROR)		+= dm-mirror.o dm-log.o dm-region-hash.o
 obj-$(CONFIG_DM_ZERO)		+= dm-zero.o
diff -pNaur linux-2.6.28-rc7-org//drivers/md/dm-least-pending.c linux-2.6.28-rc7-mod//drivers/md/dm-least-pending.c
--- linux-2.6.28-rc7-org//drivers/md/dm-least-pending.c	1970-01-01 05:30:00.000000000 +0530
+++ linux-2.6.28-rc7-mod//drivers/md/dm-least-pending.c	2008-12-05 15:33:09.000000000 +0530
@@ -0,0 +1,256 @@
+/*
+ * (C) Copyright 2008 Hewlett-Packard Development Company, L.P
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+
+#define DM_MSG_PREFIX "multipath least-pending"
+
+/*-----------------------------------------------------------------
+* Path-handling code, paths are held in lists
+*---------------------------------------------------------------*/
+struct path_info {
+       struct list_head list;
+       struct dm_path *path;
+       unsigned repeat_count;
+       atomic_t io_count;
+};
+
+static void free_paths(struct list_head *paths)
+{
+       struct path_info *pi, *next;
+
+       list_for_each_entry_safe(pi, next, paths, list) {
+		list_del(&pi->list);
+		kfree(pi);
+       }
+}
+
+/*-----------------------------------------------------------------
+ * Least-pending selector
+ *---------------------------------------------------------------*/
+
+#define LPP_MIN_IO     1
+
+struct selector {
+       struct list_head valid_paths;
+       struct list_head invalid_paths;
+};
+
+static struct selector *alloc_selector(void)
+{
+       struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (s) {
+		INIT_LIST_HEAD(&s->valid_paths);
+		INIT_LIST_HEAD(&s->invalid_paths);
+       }
+
+       return s;
+}
+
+static int lpp_create(struct path_selector *ps, unsigned argc, char **argv)
+{
+       struct selector *s;
+
+       s = alloc_selector();
+       if (!s)
+		return -ENOMEM;
+
+       ps->context = s;
+       return 0;
+}
+
+static void lpp_destroy(struct path_selector *ps)
+{
+       struct selector *s = ps->context;
+
+       free_paths(&s->valid_paths);
+       free_paths(&s->invalid_paths);
+       kfree(s);
+       ps->context = NULL;
+}
+
+static int lpp_status(struct path_selector *ps, struct dm_path *path,
+			status_type_t type, char *result, unsigned int maxlen)
+{
+       struct path_info *pi;
+       int sz = 0;
+
+       if (!path)
+		switch (type) {
+		case STATUSTYPE_INFO:
+			DMEMIT("1 ");
+		break;
+		case STATUSTYPE_TABLE:
+			DMEMIT("0 ");
+		break;
+		}
+       else {
+		pi = path->pscontext;
+		switch (type) {
+		case STATUSTYPE_INFO:
+			DMEMIT("%u:%u ", pi->repeat_count,
+					 atomic_read(&pi->io_count));
+		break;
+		case STATUSTYPE_TABLE:
+		break;
+		}
+	}
+
+       return sz;
+}
+
+/*
+ * Called during initialisation to register each path with an
+ * optional repeat_count.
+ */
+static int lpp_add_path(struct path_selector *ps, struct dm_path *path,
+			int argc, char **argv, char **error)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi;
+       unsigned repeat_count = LPP_MIN_IO;
+
+	if (argc > 1) {
+		*error = "least-pending ps: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+       /* First path argument is number of I/Os before switching path */
+       if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+		*error = "least-pending ps: invalid repeat count";
+		return -EINVAL;
+       }
+
+       /* allocate the path */
+       pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+       if (!pi) {
+		*error = "least-pending ps: Error allocating path context";
+		return -ENOMEM;
+       }
+
+       pi->path = path;
+       pi->repeat_count = repeat_count;
+       atomic_set(&pi->io_count, 0);
+
+       path->pscontext = pi;
+
+       list_add(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+static void lpp_fail_path(struct path_selector *ps, struct dm_path *p)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = p->pscontext;
+
+       if (!pi)
+	return;
+
+       atomic_set(&pi->io_count, 0);
+
+       list_move(&pi->list, &s->invalid_paths);
+}
+
+static int lpp_reinstate_path(struct path_selector *ps, struct dm_path *p)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi = p->pscontext;
+
+       if (!pi)
+	return 1;
+
+       list_move(&pi->list, &s->valid_paths);
+
+       return 0;
+}
+
+static struct dm_path *lpp_select_path(struct path_selector *ps,
+					unsigned *repeat_count)
+{
+       struct selector *s = ps->context;
+       struct path_info *pi, *next, *least_io_path = NULL;
+       struct list_head *paths;
+
+       if (list_empty(&s->valid_paths))
+		return NULL;
+
+       paths = &s->valid_paths;
+
+       list_for_each_entry_safe(pi, next, paths, list) {
+		if (!least_io_path || atomic_read(&least_io_path->io_count) < atomic_read(&pi->io_count))
+			least_io_path = pi;
+		if (!atomic_read(&least_io_path->io_count))
+			break;
+       }
+
+       if (!least_io_path)
+		return NULL;
+
+       atomic_inc(&least_io_path->io_count);
+       *repeat_count = pi->repeat_count;
+
+       return least_io_path->path;
+}
+
+static int lpp_end_io(struct path_selector *ps, struct dm_path *path)
+{
+       struct path_info *pi = NULL;
+
+       pi = path->pscontext;
+       if (!pi)
+	return 1;
+
+       atomic_dec(&pi->io_count);
+
+       return 0;
+}
+
+static struct path_selector_type lpp_ps = {
+       .name = "least-pending",
+       .module = THIS_MODULE,
+       .table_args = 1,
+       .info_args = 0,
+       .create = lpp_create,
+       .destroy = lpp_destroy,
+       .status = lpp_status,
+       .add_path = lpp_add_path,
+       .fail_path = lpp_fail_path,
+       .reinstate_path = lpp_reinstate_path,
+       .select_path = lpp_select_path,
+       .end_io = lpp_end_io,
+};
+
+static int __init dm_lpp_init(void)
+{
+       int r = dm_register_path_selector(&lpp_ps);
+
+       if (r < 0)
+		DMERR("register failed %d", r);
+
+       DMINFO("version 1.0.0 loaded");
+
+       return r;
+}
+
+static void __exit dm_lpp_exit(void)
+{
+       int r = dm_unregister_path_selector(&lpp_ps);
+
+       if (r < 0)
+		DMERR("unregister failed %d", r);
+}
+
+module_init(dm_lpp_init);
+module_exit(dm_lpp_exit);
+
+MODULE_DESCRIPTION(DM_NAME " least-pending multipath path selector");
+MODULE_AUTHOR("Sakshi Chaitanya Veni <vsakshi@hp.com>");
+MODULE_LICENSE("GPL");
+

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



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

* Re: [patch] leastpending_io load balancing policy
  2008-12-11 10:14       ` Balasubramanian, Vijayakumar (STSD)
@ 2008-12-12  2:51         ` Kiyoshi Ueda
  0 siblings, 0 replies; 9+ messages in thread
From: Kiyoshi Ueda @ 2008-12-12  2:51 UTC (permalink / raw)
  To: Balasubramanian, Vijayakumar (STSD)
  Cc: device-mapper development, Alasdair G Kergon

Hi Vijayakumar,

Balasubramanian, Vijayakumar (STSD) wrote:
> > Hi,
> > Attached is modified patch with the comments incorporated.

I think it doesn't work correctly if repeat_count is more than 1
because io_count is decremented for every end_io while it is
incremented only when the path is selected.


The 'leastpending_io' balancing is actually what our queue-length
based dynamic load balancer, which is originally posted by Stefan
Bader, is already doing.
Our patches work with repeat_count more than 1 by adding a hook
at starting I/O:
http://www.kernel.org/pub/linux/kernel/people/agk/patches/2.6/editing/rqdm-dlb-01-interface-change-for-queue-length-dlb.patch

So, please take a look at our patches and let's avoid the duplication
of efforts.  Comments are welcome.


Also, if you are interested in dynamic load balancing, you might
want to check the request-based dm-multipath, too.
Since necessary changes in the block layer and SCSI subsystem are
already included in Linus's tree, remaining patches are dm only.
The latest version is in the Alasdair's editing tree.

Thanks,
Kiyoshi Ueda

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

end of thread, other threads:[~2008-12-12  2:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-12 14:17 [patch] leastpending_io load balancing policy Balasubramanian, Vijayakumar (STSD)
2008-11-13 17:53 ` [patch] multipath-tools weighted path priority routine Balasubramanian, Vijayakumar (STSD)
2008-11-21  7:51   ` Kiyoshi Ueda
2008-12-03 22:08 ` [patch] leastpending_io load balancing policy Alasdair G Kergon
2008-12-03 23:01   ` Alasdair G Kergon
2008-12-11  1:43     ` Kiyoshi Ueda
2008-12-11 10:14       ` Balasubramanian, Vijayakumar (STSD)
2008-12-12  2:51         ` Kiyoshi Ueda
2008-12-04 11:42   ` Balasubramanian, Vijayakumar (STSD)

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.