Separate out round-robin path selector.
--- diff/drivers/md/Makefile	2004-09-28 16:39:34.000000000 +0100
+++ source/drivers/md/Makefile	2004-09-28 16:21:50.000000000 +0100
@@ -4,7 +4,7 @@
 
 dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
 		   dm-ioctl.o dm-io.o kcopyd.o
-dm-multipath-objs := dm-path-selector.o dm-mpath.o
+dm-multipath-objs := dm-path-selector.o dm-mpath.o dm-roundrobin.o
 dm-snapshot-objs := dm-snap.o dm-exception-store.o
 dm-mirror-objs	:= dm-log.o dm-raid1.o
 raid6-objs	:= raid6main.o raid6algos.o raid6recov.o raid6tables.o \
--- diff/drivers/md/dm-mpath.c	2004-09-28 16:39:34.000000000 +0100
+++ source/drivers/md/dm-mpath.c	2004-09-28 16:38:40.000000000 +0100
@@ -678,13 +678,6 @@
 		return -EINVAL;
 	}
 
-	r = dm_register_path_selectors();
-	if (r && r != -EEXIST) {
-		dm_unregister_target(&multipath_target);
-		kmem_cache_destroy(_mpio_cache);
-		return r;
-	}
-
 	DMINFO("dm_multipath v0.2.0");
 	return r;
 }
@@ -693,7 +686,6 @@
 {
 	int r;
 
-	dm_unregister_path_selectors();
 	r = dm_unregister_target(&multipath_target);
 	if (r < 0)
 		DMERR("%s: target unregister failed %d",
--- diff/drivers/md/dm-path-selector.c	2004-09-28 16:18:11.000000000 +0100
+++ source/drivers/md/dm-path-selector.c	2004-09-28 16:20:23.000000000 +0100
@@ -23,7 +23,7 @@
 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
 
 static LIST_HEAD(_path_selectors);
-static DECLARE_MUTEX(_lock);
+static DECLARE_RWSEM(_lock);
 
 struct path_selector_type *__find_path_selector_type(const char *name)
 {
@@ -44,17 +44,17 @@
 	if (!name)
 		return NULL;
 
-	down(&_lock);
+	down_read(&_lock);
 	pst = __find_path_selector_type(name);
 	if (pst) {
 		struct ps_internal *psi = pst_to_psi(pst);
 
-		if (psi->use == 0 && !try_module_get(pst->module))
+		if ((psi->use == 0) && !try_module_get(pst->module))
 			psi = NULL;
 		else
 			psi->use++;
 	}
-	up(&_lock);
+	up_read(&_lock);
 
 	return pst;
 }
@@ -63,7 +63,7 @@
 {
 	struct ps_internal *psi;
 
-	down(&_lock);
+	down_read(&_lock);
 	pst = __find_path_selector_type(pst->name);
 	if (!pst)
 		return;
@@ -74,7 +74,7 @@
 
 	if (psi->use < 0)
 		BUG();
-	up(&_lock);
+	up_read(&_lock);
 }
 
 static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
@@ -97,258 +97,43 @@
 	if (!psi)
 		return -ENOMEM;
 
-	down(&_lock);
+	down_write(&_lock);
+
 	if (__find_path_selector_type(pst->name)) {
 		kfree(psi);
 		r = -EEXIST;
 	} else
 		list_add(&psi->list, &_path_selectors);
 
-	up(&_lock);
+	up_write(&_lock);
 
 	return r;
 }
 
-EXPORT_SYMBOL(dm_register_path_selector);
-
 int dm_unregister_path_selector(struct path_selector_type *pst)
 {
 	struct ps_internal *psi;
 
-	down(&_lock);
+	down_write(&_lock);
 	pst = __find_path_selector_type(pst->name);
 	if (!pst) {
-		up(&_lock);
+		up_write(&_lock);
 		return -EINVAL;
 	}
 
 	psi = pst_to_psi(pst);
 	if (psi->use) {
-		up(&_lock);
+		up_write(&_lock);
 		return -ETXTBSY;
 	}
 
 	list_del(&psi->list);
-	up(&_lock);
+	up_write(&_lock);
 
 	kfree(psi);
 
 	return 0;
 }
 
+EXPORT_SYMBOL(dm_register_path_selector);
 EXPORT_SYMBOL(dm_unregister_path_selector);
-
-/*-----------------------------------------------------------------
- * Path handling code, paths are held in lists
- *---------------------------------------------------------------*/
-struct path_info {
-	struct list_head list;
-	struct path *path;
-};
-
-static struct path_info *path_lookup(struct list_head *head, struct path *p)
-{
-	struct path_info *pi;
-
-	list_for_each_entry (pi, head, list)
-		if (pi->path == p)
-			return pi;
-
-	return NULL;
-}
-
-/*-----------------------------------------------------------------
- * Round robin selector
- *---------------------------------------------------------------*/
-
-#define RR_MIN_IO		1000
-
-struct selector {
-	spinlock_t lock;
-
-	struct list_head valid_paths;
-	struct list_head invalid_paths;
-
-	unsigned repeat_count;
-};
-
-static struct selector *alloc_selector(unsigned repeat_count)
-{
-	struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
-	if (s) {
-		INIT_LIST_HEAD(&s->valid_paths);
-		INIT_LIST_HEAD(&s->invalid_paths);
-		s->lock = SPIN_LOCK_UNLOCKED;
-		s->repeat_count = repeat_count;
-	}
-
-	return s;
-}
-
-/* Path selector constructor */
-static int rr_ctr(struct path_selector *ps)
-{
-	struct selector *s;
-
-	/* FIXME Parameter passed in */
-	s = alloc_selector(RR_MIN_IO);
-	if (!s)
-		return -ENOMEM;
-
-	ps->context = s;
-	return 0;
-}
-
-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);
-	}
-}
-
-/* Path selector destructor */
-static void rr_dtr(struct path_selector *ps)
-{
-	struct selector *s = (struct selector *) ps->context;
-	free_paths(&s->valid_paths);
-	free_paths(&s->invalid_paths);
-	kfree(s);
-}
-
-/* Path add context */
-static int rr_add_path(struct path_selector *ps, struct path *path,
-		       int argc, char **argv, char **error)
-{
-	struct selector *s = (struct selector *) ps->context;
-	struct path_info *pi;
-
-	/* parse the path arguments */
-	if (argc != 0) {
-		*error = "round-robin ps: incorrect number of arguments";
-		return -EINVAL;
-	}
-
-	/* allocate the path */
-	pi = kmalloc(sizeof(*pi), GFP_KERNEL);
-	if (!pi) {
-		*error = "round-robin ps: Error allocating path context";
-		return -ENOMEM;
-	}
-
-	pi->path = path;
-
-	spin_lock(&s->lock);
-	list_add(&pi->list, &s->valid_paths);
-	spin_unlock(&s->lock);
-
-	return 0;
-}
-
-static void rr_fail_path(struct path_selector *ps, struct path *p)
-{
-	unsigned long flags;
-	struct selector *s = (struct selector *) ps->context;
-	struct path_info *pi;
-
-	/*
-	 * This function will be called infrequently so we don't
-	 * mind the expense of these searches.
-	 */
-	spin_lock_irqsave(&s->lock, flags);
-	pi = path_lookup(&s->valid_paths, p);
-	if (!pi)
-		pi = path_lookup(&s->invalid_paths, p);
-
-	if (!pi)
-		DMWARN("asked to change the state of an unknown path");
-
-	else
-		list_move(&pi->list, &s->invalid_paths);
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int rr_reinstate_path(struct path_selector *ps, struct path *p)
-{
-	int r = 0;
-	unsigned long flags;
-	struct selector *s = (struct selector *) ps->context;
-	struct path_info *pi;
-
-	/*
-	 * This function will be called infrequently so we don't
-	 * mind the expense of these searches.
-	 */
-	spin_lock_irqsave(&s->lock, flags);
-	pi = path_lookup(&s->invalid_paths, p);
-	if (!pi)
-		pi = path_lookup(&s->valid_paths, p);
-
-	if (pi)
-		list_move(&pi->list, &s->valid_paths);
-	else {
-		DMWARN("asked to change the state of an unknown path");
-		r = -EINVAL;
-	}
-
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	return r;
-}
-
-/* Path selector */
-static struct path *rr_select_path(struct path_selector *ps,
-				   unsigned *repeat_count)
-{
-	unsigned long flags;
-	struct selector *s = (struct selector *) ps->context;
-	struct path_info *pi = NULL;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!list_empty(&s->valid_paths)) {
-		pi = list_entry(s->valid_paths.next, struct path_info, list);
-		list_move_tail(&pi->list, &s->valid_paths);
-		*repeat_count = RR_MIN_IO;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	return pi ? pi->path : NULL;
-}
-
-/* Path status */
-static int rr_status(struct path_selector *ps, struct path *path,
-		     status_type_t type, char *result, unsigned int maxlen)
-{
-	return 0;
-}
-
-static struct path_selector_type rr_ps = {
-	.name = "round-robin",
-	.module = THIS_MODULE,
-	.table_args = 0,
-	.info_args = 0,
-	.ctr = rr_ctr,
-	.dtr = rr_dtr,
-	.add_path = rr_add_path,
-	.fail_path = rr_fail_path,
-	.reinstate_path = rr_reinstate_path,
-	.select_path = rr_select_path,
-	.status = rr_status,
-};
-
-/*
- * (Un)register all path selectors (FIXME: remove this after tests)
- */
-int dm_register_path_selectors(void)
-{
-	return dm_register_path_selector(&rr_ps);
-}
-
-void dm_unregister_path_selectors(void)
-{
-	dm_unregister_path_selector(&rr_ps);
-}
--- diff/drivers/md/dm-roundrobin.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-roundrobin.c	2004-09-28 16:20:23.000000000 +0100
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2003 Sistina Software.
+ *
+ * Module Author: Heinz Mauelshagen
+ *
+ * This file is released under the GPL.
+ *
+ * Round-robin path selector.
+ */
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+#include <linux/slab.h>
+
+/*-----------------------------------------------------------------
+ * Path handling code, paths are held in lists
+ *---------------------------------------------------------------*/
+struct path_info {
+	struct list_head list;
+	struct path *path;
+};
+
+static struct path_info *path_lookup(struct list_head *head, struct path *p)
+{
+	struct path_info *pi;
+
+	list_for_each_entry (pi, head, list)
+		if (pi->path == p)
+			return pi;
+
+	return NULL;
+}
+
+/*-----------------------------------------------------------------
+ * Round robin selector
+ *---------------------------------------------------------------*/
+
+#define RR_MIN_IO		1000
+
+struct selector {
+	spinlock_t lock;
+
+	struct list_head valid_paths;
+	struct list_head invalid_paths;
+
+	unsigned repeat_count;
+};
+
+static struct selector *alloc_selector(unsigned repeat_count)
+{
+	struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (s) {
+		INIT_LIST_HEAD(&s->valid_paths);
+		INIT_LIST_HEAD(&s->invalid_paths);
+		s->lock = SPIN_LOCK_UNLOCKED;
+		s->repeat_count = repeat_count;
+	}
+
+	return s;
+}
+
+/* Path selector constructor */
+static int rr_ctr(struct path_selector *ps)
+{
+	struct selector *s;
+
+	/* FIXME Parameter passed in */
+	s = alloc_selector(RR_MIN_IO);
+	if (!s)
+		return -ENOMEM;
+
+	ps->context = s;
+	return 0;
+}
+
+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);
+	}
+}
+
+/* Path selector destructor */
+static void rr_dtr(struct path_selector *ps)
+{
+	struct selector *s = (struct selector *) ps->context;
+	free_paths(&s->valid_paths);
+	free_paths(&s->invalid_paths);
+	kfree(s);
+}
+
+/* Path add context */
+static int rr_add_path(struct path_selector *ps, struct path *path,
+		       int argc, char **argv, char **error)
+{
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi;
+
+	/* parse the path arguments */
+	if (argc != 0) {
+		*error = "round-robin ps: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+	/* allocate the path */
+	pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+	if (!pi) {
+		*error = "round-robin ps: Error allocating path context";
+		return -ENOMEM;
+	}
+
+	pi->path = path;
+
+	spin_lock(&s->lock);
+	list_add(&pi->list, &s->valid_paths);
+	spin_unlock(&s->lock);
+
+	return 0;
+}
+
+static void rr_fail_path(struct path_selector *ps, struct path *p)
+{
+	unsigned long flags;
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi;
+
+	/*
+	 * This function will be called infrequently so we don't
+	 * mind the expense of these searches.
+	 */
+	spin_lock_irqsave(&s->lock, flags);
+	pi = path_lookup(&s->valid_paths, p);
+	if (!pi)
+		pi = path_lookup(&s->invalid_paths, p);
+
+	if (!pi)
+		DMWARN("asked to change the state of an unknown path");
+
+	else
+		list_move(&pi->list, &s->invalid_paths);
+
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static int rr_reinstate_path(struct path_selector *ps, struct path *p)
+{
+	int r = 0;
+	unsigned long flags;
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi;
+
+	/*
+	 * This function will be called infrequently so we don't
+	 * mind the expense of these searches.
+	 */
+	spin_lock_irqsave(&s->lock, flags);
+	pi = path_lookup(&s->invalid_paths, p);
+	if (!pi)
+		pi = path_lookup(&s->valid_paths, p);
+
+	if (pi)
+		list_move(&pi->list, &s->valid_paths);
+	else {
+		DMWARN("asked to change the state of an unknown path");
+		r = -EINVAL;
+	}
+
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return r;
+}
+
+/* Path selector */
+static struct path *rr_select_path(struct path_selector *ps,
+				   unsigned *repeat_count)
+{
+	unsigned long flags;
+	struct selector *s = (struct selector *) ps->context;
+	struct path_info *pi = NULL;
+
+	spin_lock_irqsave(&s->lock, flags);
+	if (!list_empty(&s->valid_paths)) {
+		pi = list_entry(s->valid_paths.next, struct path_info, list);
+		list_move_tail(&pi->list, &s->valid_paths);
+		*repeat_count = RR_MIN_IO;
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return pi ? pi->path : NULL;
+}
+
+/* Path status */
+static int rr_status(struct path_selector *ps, struct path *path,
+		     status_type_t type, char *result, unsigned int maxlen)
+{
+	return 0;
+}
+
+static struct path_selector_type rr_ps = {
+	.name = "round-robin",
+	.module = THIS_MODULE,
+	.table_args = 0,
+	.info_args = 0,
+	.ctr = rr_ctr,
+	.dtr = rr_dtr,
+	.add_path = rr_add_path,
+	.fail_path = rr_fail_path,
+	.reinstate_path = rr_reinstate_path,
+	.select_path = rr_select_path,
+	.status = rr_status,
+};
+
+static int __init dm_rr_init(void)
+{
+	int r = dm_register_path_selector(&rr_ps);
+
+	if (r < 0)
+		DMERR("round-robin: register failed %d", r);
+
+	return r;
+}
+
+static void __exit dm_rr_exit(void)
+{
+	int r = dm_unregister_path_selector(&rr_ps);
+
+	if (r < 0)
+		DMERR("round-robin: unregister failed %d", r);
+}
+
+module_init(dm_rr_init);
+module_exit(dm_rr_exit);
+
+MODULE_DESCRIPTION(DM_NAME " round-robin multipath path selector");
+MODULE_AUTHOR("Sistina software <dm@uk.sistina.com>");
+MODULE_LICENSE("GPL");
