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 + +/*----------------------------------------------------------------- + * 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 "); +MODULE_LICENSE("GPL");