Change the multipath target interface yet again. --- diff/drivers/md/dm-mpath.c 2003-11-26 11:33:42.000000000 +0000 +++ source/drivers/md/dm-mpath.c 2003-12-03 15:28:55.000000000 +0000 @@ -1,12 +1,7 @@ /* * Copyright (C) 2003 Sistina Software Limited. * - * Module Author: Heinz Mauelshagen - * * This file is released under the GPL. - * - * device-mapper multipathing target - * */ #include "dm.h" @@ -27,25 +22,35 @@ struct list_head list; struct dm_dev *dev; - int fail_limit; + struct priority_group *pg; int has_failed; jiffy_t fail_time; atomic_t fail_count; atomic_t fail_total; - unsigned failback_interval; - sector_t test_sector; }; +struct priority_group { + struct list_head list; + + unsigned priority; + struct path_selector ps; + struct list_head valid_paths; + struct list_head invalid_paths; +}; + /* Multipath context */ struct multipath { struct list_head list; struct dm_target *ti; - struct path_selector ps; - struct list_head paths; + struct rw_semaphore path_lock; + struct list_head priority_groups; + struct path *current_path; + atomic_t count; + unsigned min_io; spinlock_t failed_lock; struct bio *failed_ios; @@ -73,38 +78,68 @@ kfree(p); } -static struct multipath *alloc_multipath(void) +static struct priority_group *alloc_priority_group(void) { - struct multipath *m; + struct priority_group *pg; - m = kmalloc(sizeof(*m), GFP_KERNEL); - if (m) { - memset(m, 0, sizeof(*m)); - INIT_LIST_HEAD(&m->paths); + pg = kmalloc(sizeof(*pg), GFP_KERNEL); + if (pg) { + INIT_LIST_HEAD(&pg->valid_paths); + INIT_LIST_HEAD(&pg->invalid_paths); } - return m; + return pg; } -static void free_multipath(struct multipath *m) +static void free_paths(struct list_head *paths, struct dm_target *ti) { - struct path_selector *ps; struct path *path, *tmp; - if (!m) - return; + list_for_each_entry_safe (path, tmp, paths, list) { + list_del(&path->list); + dm_put_device(ti, path->dev); + free_path(path); + } +} - ps = &m->ps; +static void free_priority_group(struct priority_group *pg, + struct dm_target *ti) +{ + struct path_selector *ps = &pg->ps; - if (ps) { +??? if (ps) { ps->type->dtr(ps); dm_put_path_selector(ps->type); } - list_for_each_entry_safe (path, tmp, &m->paths, list) { - list_del(&path->list); - dm_put_device(m->ti, path->dev); - free_path(path); + free_paths(&pg->valid_paths, ti); + free_paths(&pg->invalid_paths, ti); + kfree(pg); +} + +static struct multipath *alloc_multipath(void) +{ + struct multipath *m; + + m = kmalloc(sizeof(*m), GFP_KERNEL); + if (m) { + memset(m, 0, sizeof(*m)); + init_rwsem(&m->path_lock); + INIT_LIST_HEAD(&m->priority_groups); + m->failed_lock = SPIN_LOCK_UNLOCKED; + m->min_io = 1000; /* FIXME: arbitrary number */ + } + + return m; +} + +static void free_multipath(struct multipath *m) +{ + struct priority_group *pg, *tmp; + + list_for_each_entry_safe (pg, tmp, &m->priority_groups, list) { + list_del(&pg->list); + free_priority_group(pg, m->ti); } kfree(m); @@ -159,12 +194,9 @@ } /*----------------------------------------------------------------- - * Constructor/argument parsing - * - * - * [ - * {num_ps_parms} - * ]{nr path parms} + * Constructor/argument parsing: + * [ + * [ ]] *---------------------------------------------------------------*/ struct param { unsigned min; @@ -176,7 +208,8 @@ static int read_param(struct param *param, char *str, unsigned *v, char **error) { - if ((sscanf(str, "%u", v) != 1) || + if (!str || + (sscanf(str, "%u", v) != 1) || (*v < param->min) || (*v > param->max)) { *error = param->error; @@ -186,135 +219,208 @@ return 0; } -static int parse_path(struct multipath *m, int argc, char **argv, struct dm_target *ti) +struct arg_set { + unsigned argc; + char **argv; +}; + +static char *shift(struct arg_set *as) { - /* path parameters */ - static struct param _params[] = { - {0, 1024, ESTR("invalid path reactivation interval")}, - {0, 1024, ESTR("invalid io failures")} - }; + if (as->argc) { + as->argc--; + return *as->argv++; + } + + return NULL; +} +static void consume(struct arg_set *as, unsigned n) +{ + BUG_ON (as->argc < n); + as->argc -= n; + as->argv += n; +} +static struct path *parse_path(struct arg_set *as, struct path_selector *ps, + struct dm_target *ti) +{ int r; struct path *p; + /* we need at least a path arg */ + if (as->argc < 1) { + ti->error = ESTR("no device given"); + return NULL; + } + p = alloc_path(); if (!p) - return -ENOMEM; + return NULL; - r = dm_get_device(ti, argv[0], ti->begin, ti->len, + r = dm_get_device(ti, shift(as), ti->begin, ti->len, dm_table_get_mode(ti->table), &p->dev); if (r) { - ti->error = "dm-multipath: error getting device"; + ti->error = ESTR("error getting device"); goto bad; } - r = read_param(_params, argv[1], &p->failback_interval, &ti->error); - if (r) - goto bad; - - r = read_param(_params + 1, argv[2], &p->fail_limit, &ti->error); - if (r) + r = ps->type->add_path(ps, p, as->argc, as->argv, &ti->error); + if (r) { + dm_put_device(ti, p->dev); goto bad; - atomic_set(&p->fail_count, p->fail_limit); + } - r = m->ps.type->add_path(&m->ps, p, argc - 3, argv + 3, &ti->error); - if (r) - goto bad; - - list_add_tail(&p->list, &m->paths); - return 0; + return p; bad: free_path(p); - return r; + return NULL; } -#define MIN_PARMS 5 -static int multipath_ctr(struct dm_target *ti, unsigned int argc, - char **argv) +/* + * Returns the number of arguments consumed, or an error. + */ +static struct priority_group *parse_priority_group(struct arg_set *as, + struct multipath *m, + struct dm_target *ti) { - /* target parameters */ static struct param _params[] = { - {2, 1024, ESTR("invalid number of paths")}, - {2, 32, ESTR("invalid number of path parameters")}, - {1, 24*60*60, ESTR("invalid path test interval")}, - {0, 1024, ESTR("invalid path selector parameters")} + {0, 1024, ESTR("invalid priority")}, + {0, 1024, ESTR("invalid number of selector args")}, + {1, 1024, ESTR("invalid number of paths")} }; - int r, i; - struct multipath *m; + int r; + unsigned i, nr_paths, nr_selector_args, nr_params; + struct priority_group *pg; struct path_selector_type *pst; - unsigned nr_paths, nr_params, nr_ps_params; - - /* Check minimum argument count */ - if (argc < MIN_PARMS) { - ti->error = ESTR("not enough arguments"); - return -EINVAL; - } - - m = alloc_multipath(); - if (!m) { - ti->error = ESTR("can't allocate multipath context"); - return -EINVAL; - } - m->failed_lock = SPIN_LOCK_UNLOCKED; - - r = read_param(_params, argv[0], &nr_paths, &ti->error); - if (r) - goto bad; - /* there must be at least 2 paths */ - if (nr_paths < 2) { - ti->error = ESTR("not enough paths"); - goto bad; + if (as->argc < 3) { + ti->error = ESTR("not enough priority group aruments"); + return NULL; } - r = read_param(_params + 1, argv[1], &nr_params, &ti->error); - if (r) - goto bad; - - if (nr_params != 2) { - ti->error = ESTR("invalid number of path args"); - goto bad; + pg = alloc_priority_group(); + if (!pg) { + ti->error = ESTR("couldn't allocate priority group"); + return NULL; } - r = read_param(_params + 2, argv[2], &m->test_interval, &ti->error); + r = read_param(_params, shift(as), &pg->priority, &ti->error); if (r) goto bad; - pst = dm_get_path_selector(argv[3]); + pst = dm_get_path_selector(shift(as)); if (!pst) { ti->error = ESTR("unknown path selector type"); goto bad; } - m->ps.type = pst; + pg->ps.type = pst; - r = pst->ctr(&m->ps); + r = pst->ctr(&pg->ps); if (r) { - /* FIXME: put the pst ? */ + /* FIXME: need to put the pst ? fix after + * factoring out the register */ goto bad; } - r = read_param(_params + 3, argv[4], &nr_ps_params, &ti->error); + r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); + if (r) + goto bad; + + /* + * read the paths + */ + nr_params = 1 + nr_selector_args; + r = read_param(_params + 2, shift(as), &nr_paths, &ti->error); if (r) goto bad; - /* Loop through all paths parsing their parameters */ - argc -= 5; argv += 5; - nr_params += nr_ps_params + 1; for (i = 0; i < nr_paths; i++) { + struct path *path; + struct arg_set path_args; - if (argc < nr_params) { - ti->error = ESTR("insufficient arguments"); + if (as->argc < nr_params) goto bad; - } - r = parse_path(m, nr_params, argv, ti); - if (r) + path_args.argc = nr_params; + path_args.argv = as->argv; + + path = parse_path(&path_args, &pg->ps, ti); + if (!path) goto bad; - argc -= nr_params; argv += nr_params; + path->pg = pg; + list_add_tail(&path->list, &pg->valid_paths); + consume(as, nr_params); + } + + return pg; + + bad: + free_priority_group(pg, ti); + return NULL; +} + +/* + * Debug only. + */ +static void __check_ordered(struct list_head *head) +{ + struct priority_group *pg; + unsigned last = 0; + + list_for_each_entry (pg, head, list) { + BUG_ON (pg->priority < last); + last = pg->priority; + } +} + +static void __insert_priority_group(struct multipath *m, + struct priority_group *pg) +{ + struct priority_group *tmp; + + list_for_each_entry (tmp, &m->priority_groups, list) + if (tmp->priority > pg->priority) + break; + + list_add_tail(&pg->list, &tmp->list); + + /* FIXME: remove debug later */ + __check_ordered(&m->priority_groups); +} + +static int multipath_ctr(struct dm_target *ti, unsigned int argc, + char **argv) +{ + /* target parameters */ + static struct param _params[] = { + {1, 60 * 60, ESTR("invalid path test interval")}, + }; + + int r; + struct multipath *m; + struct arg_set as; + + as.argc = argc; + as.argv = argv; + + m = alloc_multipath(); + if (!m) { + ti->error = ESTR("can't allocate multipath"); + return -EINVAL; + } + + r = read_param(_params, shift(&as), &m->test_interval, &ti->error); + if (r) + goto bad; + + /* parse the priority groups */ + while (as.argc) { + struct priority_group *pg = parse_priority_group(&as, m, ti); + if (pg) + __insert_priority_group(m, pg); } ti->private = m; @@ -331,7 +437,6 @@ return -EINVAL; } -/* Destruct a multipath mapping */ static void multipath_dtr(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; @@ -344,103 +449,170 @@ free_multipath(m); } -/* Set a path to "failed" */ -static inline void set_failed(struct path_selector *ps, struct path *path, sector_t sector) +static struct priority_group *__find_priority_group(struct list_head *pgs) { - if (path->has_failed) - return; + struct priority_group *pg; - /* FIXME: need locking ? */ - path->fail_time = jiffies; - atomic_inc(&path->fail_total); - path->test_sector = sector; - ps->type->set_path_state(ps, path, 0); -// queue_table_event(io); + list_for_each_entry (pg, pgs, list) { + if (!list_empty(&pg->valid_paths)) + return pg; + } + + return NULL; +} + +static int __choose_path(struct multipath *m) +{ + struct priority_group *pg; + struct path *path; + + /* get the priority group */ + pg = __find_priority_group(&m->priority_groups); + if (!pg) + return -EIO; + + /* select a path */ + path = pg->ps.type->select_path(&pg->ps); + if (!path) + return -EIO; /* No valid path found */ + + m->current_path = path; + atomic_set(&m->count, m->min_io); + return 0; +} + +static int multipath_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + struct multipath *m = (struct multipath *) ti->private; + struct path *path; + + retry: + down_read(&m->path_lock); + + /* + * Do we need to choose a new path? + */ + if (m->current_path && atomic_dec_and_test(&m->count)) { + path = m->current_path; + up_read(&m->path_lock); + + } else { + /* promote to write lock */ + up_read(&m->path_lock); + down_write(&m->path_lock); + + if (m->current_path && atomic_read(&m->count)) { + up_write(&m->path_lock); + goto retry; + } + + if (__choose_path(m)) { + /* no paths */ + up_write(&m->path_lock); + return -EIO; + } + + path = m->current_path; + up_write(&m->path_lock); + } + + /* map */ + bio->bi_rw |= (1 << BIO_RW_FAILFAST); + bio->bi_bdev = path->dev->bdev; + return 1; } /* - * Only called on the slow, error path. + * Only called on the error path. */ -static struct path *find_path(struct multipath *m, struct block_device *bdev) +static struct path *__lookup_path(struct list_head *head, + struct block_device *bdev) { struct path *p; - list_for_each_entry(p, &m->paths, list) + list_for_each_entry (p, head, list) if (p->dev->bdev == bdev) return p; return NULL; } -static int multipath_end_io(struct dm_target *ti, struct bio *bio, - int error, union map_info *map_context) +static struct path *__find_path(struct multipath *m, struct block_device *bdev) { - struct multipath *m = (struct multipath *) ti->private; - struct path_selector *ps = &m->ps; - struct path_selector_type *pst = ps->type; - ps_endio_fn endio = pst->endio; - unsigned long flags; - - if (error) { - struct path *path = find_path(m, bio->bi_bdev); - - if (atomic_dec_and_test(&path->fail_count)) - set_failed(ps, path, bio->bi_sector); + struct path *p; + struct priority_group *pg; - /* choose a new path */ - path = pst->select_path(ps, bio, map_context); - if (path) { - bio->bi_bdev = path->dev->bdev; - spin_lock_irqsave(&m->failed_lock, flags); - bio->bi_next = m->failed_ios; - m->failed_ios = bio; - spin_unlock_irqrestore(&m->failed_lock, flags); + list_for_each_entry (pg, &m->priority_groups, list) { + p = __lookup_path(&pg->valid_paths, bdev); + if (p) + return p; - dm_daemon_wake(&_kmpathd); - return 1; /* io not complete */ - } + p = __lookup_path(&pg->invalid_paths, bdev); + if (p) + return p; } - if (endio) - endio(ps, bio, error, map_context); - - return 0; /* io complete */ + return NULL; } -/* Suspend */ -static void multipath_suspend(struct dm_target *ti) +static void __fail_path(struct path *path) { - struct multipath *m = (struct multipath *) ti->private; + if (path->has_failed) + return; - //atomic_set(&m->suspended, 1); - //wait_for_scrub_ios(m); + if (!atomic_dec_and_test(&path->fail_count)) + return; + + path->has_failed = 1; + path->fail_time = jiffies; + atomic_inc(&path->fail_total); +// path->test_sector = sector; + list_del(&path->list); + list_add(&path->list, &path->pg->invalid_paths); + path->pg->ps.type->set_path_state(&path->pg->ps, path, 0); } -/* Resume */ -static void multipath_resume(struct dm_target *ti) +static int __resubmit_io(struct multipath *m, struct bio *bio) { - struct multipath *m = (struct multipath *) ti->private; + int r; + unsigned long flags; + + r = __choose_path(m); + if (r) + return r; + + /* remap */ + bio->bi_bdev = m->current_path->dev->bdev; + + /* queue for the daemon to resubmit */ + spin_lock_irqsave(&m->failed_lock, flags); + bio->bi_next = m->failed_ios; + m->failed_ios = bio; + spin_unlock_irqrestore(&m->failed_lock, flags); - //atomic_set(&m->suspended, 0); dm_daemon_wake(&_kmpathd); + return 1; /* io not complete */ } -/* Multipath mapping */ -static int multipath_map(struct dm_target *ti, struct bio *bio, - union map_info *map_context) +static int multipath_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) { + int r = 0; struct multipath *m = (struct multipath *) ti->private; - struct path *path; - /* Ask path selector for a path */ - memset(map_context, 0, sizeof(*map_context)); - path = m->ps.type->select_path(&m->ps, bio, map_context); - if (!path) - return -1; /* No valid path found */ + if (error) { + struct path *path; - bio->bi_rw |= (1 << BIO_RW_FAILFAST); - bio->bi_bdev = path->dev->bdev; - return 1; + down_write(&m->path_lock); + path = __find_path(m, bio->bi_bdev); + __fail_path(path); + up_write(&m->path_lock); + + r = __resubmit_io(m, bio); + } + + return r; } /* Multipath status */ @@ -460,8 +632,6 @@ .dtr = multipath_dtr, .map = multipath_map, .end_io = multipath_end_io, - .suspend = multipath_suspend, - .resume = multipath_resume, .status = multipath_status, }; @@ -483,7 +653,8 @@ r = dm_daemon_start(&_kmpathd, "kpathd", do_work); if (r) { -// dm_unregister_path_selectors(); + /* FIXME: remove this */ + dm_unregister_path_selectors(); dm_unregister_target(&multipath_target); } else DMINFO("dm_multipath v0.2.0"); @@ -508,7 +679,7 @@ module_exit(dm_multipath_exit); MODULE_DESCRIPTION(DM_NAME " multipath target"); -MODULE_AUTHOR("Heinz Mauelshagen "); +MODULE_AUTHOR("Sistina software "); MODULE_LICENSE("GPL"); @@ -518,6 +689,12 @@ + + + + + + #ifdef SCRUB_STUFF /* Reset failure information on a path */ static inline void reset_failures(struct path *path) @@ -824,3 +1001,26 @@ return 0; #endif + + + +#if 0 +/* Suspend */ +static void multipath_suspend(struct dm_target *ti) +{ + struct multipath *m = (struct multipath *) ti->private; + + //atomic_set(&m->suspended, 1); + //wait_for_scrub_ios(m); +} + +/* Resume */ +static void multipath_resume(struct dm_target *ti) +{ + struct multipath *m = (struct multipath *) ti->private; + + //atomic_set(&m->suspended, 0); + dm_daemon_wake(&_kmpathd); +} + +#endif --- diff/drivers/md/dm-path-selector.c 2003-11-26 11:52:38.000000000 +0000 +++ source/drivers/md/dm-path-selector.c 2003-12-03 12:54:57.000000000 +0000 @@ -40,6 +40,9 @@ { struct path_selector_type *lb; + if (!name) + return NULL; + down(&_lock); lb = __find_path_selector_type(name); if (lb) { @@ -133,58 +136,13 @@ } /*----------------------------------------------------------------- - * Path handling code, paths are held in lists ordered by - * priority. + * Path handling code, paths are held in lists *---------------------------------------------------------------*/ struct path_info { struct list_head list; struct path *path; - - unsigned min_io; - unsigned priority; - - /* count how much has been sent to the path */ - atomic_t io_count; }; -/* - * Debug only. - */ -static void path_ordered(struct list_head *head, struct path_info *pi) -{ - struct path_info *cursor; - unsigned last = 0; - int seen = 0; - - list_for_each_entry (cursor, head, list) { - BUG_ON (cursor->priority < last); - - last = cursor->priority; - if (cursor == pi) - seen = 1; - } - - BUG_ON(!seen); -} - -/* - * IMPORTANT: we rely on this function inserting the new path at - * the _back_ of its priority group. - */ -static void path_insert(struct list_head *head, struct path_info *pi) -{ - struct path_info *cursor; - - list_for_each_entry (cursor, head, list) - if (cursor->priority > pi->priority) - break; - - list_add_tail(&pi->list, &cursor->list); - - /* FIXME: remove debug later */ - path_ordered(head, pi); -} - static struct path_info *path_lookup(struct list_head *head, struct path *p) { struct path_info *pi; @@ -257,24 +215,13 @@ { struct selector *s = (struct selector *) ps->context; struct path_info *pi; - unsigned priority, min_io; /* parse the path arguments */ - if (argc != 2) { + if (argc != 0) { *error = "round-robin ps: incorrect number of arguments"; return -EINVAL; } - if (sscanf(argv[0], "%u", &priority) != 1) { - *error = "round-robin ps: Invalid priority"; - return -EINVAL; - } - - if (sscanf(argv[1], "%u", &min_io) != 1) { - *error = "round-robin ps: Invalid min_io"; - return -EINVAL; - } - /* allocate the path */ pi = kmalloc(sizeof(*pi), GFP_KERNEL); if (!pi) { @@ -283,18 +230,14 @@ } pi->path = path; - pi->min_io = min_io; - pi->priority = priority; - atomic_set(&pi->io_count, min_io); spin_lock(&s->lock); - path_insert(&s->valid_paths, pi); + list_add(&pi->list, &s->valid_paths); spin_unlock(&s->lock); return 0; } - static void rr_set_path_state(struct path_selector *ps, struct path *p, int valid) { @@ -314,33 +257,26 @@ if (!pi) DMWARN("asked to change the state of an unknown path"); - else - path_insert(valid ? &s->valid_paths : &s->invalid_paths, pi); + else { + list_del(&pi->list); + list_add(&pi->list, valid ? &s->valid_paths : &s->invalid_paths); + } spin_unlock_irqrestore(&s->lock, flags); } /* Path selector */ -static struct path *rr_select_path(struct path_selector *ps, - struct bio *bio, - union map_info *map_context) +static struct path *rr_select_path(struct path_selector *ps) { unsigned long flags; struct selector *s = (struct selector *) ps->context; - struct list_head *list = &s->valid_paths; struct path_info *pi = NULL; spin_lock_irqsave(&s->lock, flags); - if (!list_empty(list)) - pi = list_entry(list->next, struct path_info, list); - - /* have we done enough io on this path? */ - if (pi && atomic_dec_and_test(&pi->io_count)) { + if (!list_empty(&s->valid_paths)) { + pi = list_entry(s->valid_paths.next, struct path_info, list); list_del(&pi->list); - atomic_set(&pi->io_count, pi->min_io); - - /* move to the back of its priority group */ - path_insert(&s->valid_paths, pi); + list_add_tail(&pi->list, &s->valid_paths); } spin_unlock_irqrestore(&s->lock, flags); @@ -354,8 +290,6 @@ .add_path = rr_add_path, .set_path_state = rr_set_path_state, .select_path = rr_select_path, - .endio = NULL, - .status = NULL, }; int dm_register_rr_ps(void) --- diff/drivers/md/dm-path-selector.h 2003-11-26 10:21:50.000000000 +0000 +++ source/drivers/md/dm-path-selector.h 2003-12-02 15:33:26.000000000 +0000 @@ -49,18 +49,7 @@ * reused or reallocated because an endio call (which needs to free it) * might happen after a couple of select calls. */ -typedef struct path *(*ps_select_path_fn) (struct path_selector *ps, - struct bio *bio, - union map_info *map_context); - -/* - * Hook the end of the io, path throughput/failure can be - * detected through this. Must ensure, that any dynamically allocated - * IO context gets freed. - */ -typedef void (*ps_endio_fn) (struct path_selector *ps, - struct bio *bio, int error, - union map_info *map_context); +typedef struct path *(*ps_select_path_fn) (struct path_selector *ps); /* * Notify the selector that a path has failed. @@ -85,10 +74,7 @@ ps_add_path_fn add_path; ps_set_path_state_fn set_path_state; - ps_select_path_fn select_path; - ps_endio_fn endio; - ps_status_fn status; }; @@ -117,3 +103,26 @@ void dm_unregister_latency_ps(void); #endif + + + +#if 0 +/* + * An optional function usd if the selector wishes to record the + * start of every io to a path. + */ +typedef struct path *(*path_startio_fn) (struct path_selector *ps, + struct path *path, + struct bio *bio, + union map_info *map_context); + +/* + * Hook the end of the io, path throughput/failure can be + * detected through this. Must ensure, that any dynamically allocated + * IO context gets freed. + */ +typedef void (*ps_endio_fn) (struct path_selector *ps, + const struct bio *bio, int error, + union map_info *map_context); +#endif + --- diff/drivers/md/dm.h 2003-11-26 10:20:45.000000000 +0000 +++ source/drivers/md/dm.h 2003-12-02 16:14:19.000000000 +0000 @@ -123,6 +123,24 @@ void dm_table_resume_targets(struct dm_table *t); /*----------------------------------------------------------------- + * Gerneral purpose registry code + *---------------------------------------------------------------*/ +struct dm_registry; +struct dm_registry_entry { + const char *name; + struct module *m; +}; + +struct dm_register *dm_registry_create(void); +void dm_registry_destroy(struct dm_register *reg); + +int dm_registry_add(struct dm_register *reg, struct dm_registry_entry *re); +int dm_registry_remove(struct dm_register *reg, struct dm_registry_entry *re); + +struct dm_registry_entry *dm_register_get(struct dm_register *reg, const char *name); +void dm_register_put(struct dm_register *reg, struct dm_registry_entry *re); + +/*----------------------------------------------------------------- * A registry of target types. *---------------------------------------------------------------*/ int dm_target_init(void); @@ -130,7 +148,6 @@ struct target_type *dm_get_target_type(const char *name); void dm_put_target_type(struct target_type *t); - /*----------------------------------------------------------------- * Useful inlines. *---------------------------------------------------------------*/ --- diff/drivers/md/kcopyd.c 2003-11-26 10:18:32.000000000 +0000 +++ source/drivers/md/kcopyd.c 2003-12-03 12:55:19.000000000 +0000 @@ -398,7 +398,7 @@ /* * kcopyd does this every time it's woken up. */ -static void do_work(void) +static jiffy_t do_work(void) { /* * The order that these are called is *very* important. @@ -412,6 +412,7 @@ process_jobs(&_io_jobs, run_io_job); blk_run_queues(); + return (jiffy_t) 0; } /* --- diff/drivers/md/dm-register.h 1970-01-01 01:00:00.000000000 +0100 +++ source/drivers/md/dm-register.h 2003-12-02 15:41:59.000000000 +0000 @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2003 Sistina Software (UK) Limited + * + * This file is released under the GPL. + */ + +#ifndef DM_REGISTER_H +#define DM_REGISTER_H + +struct dm_register; + + +#endif