--- linux-2.6.7-rc2/drivers/md/dm-mpath.c 2004-06-04 03:52:23.332727408 -0700 +++ linux-2.6.7-rc2-pg/drivers/md/dm-mpath.c 2004-06-04 03:37:30.871140637 -0700 @@ -1,11 +1,16 @@ /* + * dm-mpath.c - maps/remaps IO by interfacing with DM + * priority_groups and path_selectors. + * * Copyright (C) 2003 Sistina Software Limited. + * Copyright (C) 2004 IBM Corporation * * This file is released under the GPL. */ #include "dm.h" #include "dm-path-selector.h" +#include "dm-priority-group.h" #include "dm-bio-list.h" #include "dm-bio-record.h" @@ -30,20 +35,9 @@ struct path { inline struct block_device *dm_path_to_bdev(struct path *path) { - return path->dev->bdev; + return (path ? path->dev->bdev : NULL); } - -struct priority_group { - struct list_head list; - - struct multipath *m; - struct path_selector ps; - - unsigned nr_paths; - struct list_head paths; -}; - -#define ps_to_pg(__ps) container_of((__ps), struct priority_group, ps) +EXPORT_SYMBOL(dm_path_to_bdev); /* Multipath context */ struct multipath { @@ -126,6 +120,11 @@ static void free_priority_group(struct p { struct path_selector *ps = &pg->ps; + if (pg->type) { + pg->type->dtr(pg); + dm_put_priority_group(pg->type); + } + if (ps->type) { ps->type->dtr(ps); dm_put_path_selector(ps->type); @@ -172,8 +171,7 @@ static void free_multipath(struct multip kfree(m); } -static void __ps_init_complete(struct multipath *m, - struct priority_group *pg) +static void __pg_init_complete(struct multipath *m, struct priority_group *pg) { m->initializing_pg = 0; m->current_pg = pg; @@ -181,18 +179,17 @@ static void __ps_init_complete(struct mu schedule_work(&m->dispatch_failed); } -void dm_ps_init_complete(struct path_selector *ps) +void dm_pg_init_complete(struct priority_group *pg) { unsigned long flags; - struct priority_group *pg = ps_to_pg(ps); struct multipath *m = pg->m; spin_lock_irqsave(&m->lock, flags); - __ps_init_complete(m, pg); + __pg_init_complete(m, pg); spin_unlock_irqrestore(&m->lock, flags); } -EXPORT_SYMBOL(dm_ps_init_complete); +EXPORT_SYMBOL(dm_pg_init_complete); static int select_group(struct multipath *m, struct mpath_io *mpio, struct bio *bio) @@ -206,14 +203,14 @@ static int select_group(struct multipath list_for_each_entry (pg, &m->priority_groups, list) { - if (pg->ps.type->init) { + if (pg->type->init) { spin_unlock_irq(&m->lock); - err = pg->ps.type->init(&pg->ps); + err = pg->type->init(pg); spin_lock_irq(&m->lock); - if (err == DM_PS_INITIALIZING) - return DM_PS_INITIALIZING; - else if (err == DM_PS_FAILED) + if (err == DM_PG_INITIALIZING) + return DM_PG_INITIALIZING; + else if (err == DM_PG_FAILED) continue; } @@ -223,11 +220,11 @@ static int select_group(struct multipath break; } - __ps_init_complete(m, mpio->path ? pg : NULL); - return mpio->path ? DM_PS_SUCCESS : DM_PS_FAILED; + __pg_init_complete(m, mpio->path ? pg : NULL); + return mpio->path ? DM_PG_SUCCESS : DM_PG_FAILED; } -static int select_path1(struct multipath *m, struct mpath_io *mpio, +static int select_path(struct multipath *m, struct mpath_io *mpio, struct bio *bio, int wait) { mpio->path = NULL; @@ -253,7 +250,7 @@ static int select_path1(struct multipath mpio->path = ps->type->select_path(ps, bio, &mpio->info); if (!mpio->path && - (select_group(m, mpio, bio) == DM_PS_INITIALIZING)) + (select_group(m, mpio, bio) == DM_PG_INITIALIZING)) /* * while the lock was dropped the * initialization might have completed. @@ -270,7 +267,7 @@ static int map_io(struct multipath *m, s int err; spin_lock_irq(&m->lock); - err = select_path1(m, mpio, bio, wait); + err = select_path(m, mpio, bio, wait); if (err == -EWOULDBLOCK) /* * when the ps init is completed it will @@ -383,40 +380,56 @@ static void consume(struct arg_set *as, as->argv += n; } -static struct path *parse_path(struct arg_set *as, struct path_selector *ps, - struct dm_target *ti) +static int parse_paths(struct arg_set *as, struct priority_group *pg, + int nr_pg_args, int nr_ps_args, struct dm_target *ti) { - int r; struct path *p; + struct path_selector *ps = &pg->ps; + int i, r, nr_params = nr_pg_args + nr_ps_args + 1; - /* we need at least a path arg */ - if (as->argc < 1) { - ti->error = ESTR("no device given"); - return NULL; - } + for (i = 0; i < pg->nr_paths; i++) { + + if (as->argc < nr_params) + return -EINVAL; - p = alloc_path(); - if (!p) - return NULL; + /* we need at least a path arg */ + if (as->argc < 1) { + ti->error = ESTR("no device given"); + return -EINVAL; + } - r = dm_get_device(ti, shift(as), ti->begin, ti->len, - dm_table_get_mode(ti->table), &p->dev); - if (r) { - ti->error = ESTR("error getting device"); - goto bad; - } + p = alloc_path(); + if (!p) + return -EINVAL; + + r = dm_get_device(ti, shift(as), ti->begin, ti->len, + dm_table_get_mode(ti->table), &p->dev); + if (r) { + ti->error = ESTR("error getting device"); + goto free_path; + } - r = ps->type->add_path(ps, p, as->argc, as->argv, &ti->error); - if (r) { - dm_put_device(ti, p->dev); - goto bad; + r = pg->type->add_path(pg, p, nr_pg_args, as->argv, &ti->error); + if (r) + goto put_dev; + consume(as, nr_pg_args); + + r = ps->type->add_path(ps, p, nr_ps_args, as->argv, &ti->error); + if (r) + goto put_dev; + consume(as, nr_ps_args); + + p->pg = pg; + list_add_tail(&p->list, &pg->paths); } - return p; + return 0; - bad: + put_dev: + dm_put_device(ti, p->dev); + free_path: free_path(p); - return NULL; + return -EINVAL; } static struct priority_group *parse_priority_group(struct arg_set *as, @@ -424,16 +437,18 @@ static struct priority_group *parse_prio struct dm_target *ti) { static struct param _params[] = { + {0, 1024, ESTR("invalid number of group args")}, + {0, 1024, ESTR("invalid number of selector args")}, {1, 1024, ESTR("invalid number of paths")}, - {0, 1024, ESTR("invalid number of selector args")} }; int r; - unsigned i, nr_selector_args, nr_params; + unsigned nr_selector_args, nr_group_args; struct priority_group *pg; struct path_selector_type *pst; + struct priority_group_type *pgt; - if (as->argc < 2) { + if (as->argc < 3) { as->argc = 0; ti->error = ESTR("not enough priority group aruments"); return NULL; @@ -446,6 +461,29 @@ static struct priority_group *parse_prio } pg->m = m; + /* setup group */ + pgt = dm_get_priority_group(shift(as)); + if (!pgt) { + ti->error = ESTR("unknown priority group type"); + goto bad; + } + + r = pgt->ctr(pg); + if (r) { + dm_put_priority_group(pgt); + goto bad; + } + pg->type = pgt; + + /* + * get num pg args per path. We might need + * per group args too? + */ + r = read_param(_params, shift(as), &nr_group_args, &ti->error); + if (r) + goto bad; + + /* setup selector */ pst = dm_get_path_selector(shift(as)); if (!pst) { ti->error = ESTR("unknown path selector type"); @@ -459,38 +497,20 @@ static struct priority_group *parse_prio } pg->ps.type = pst; - /* - * read the paths - */ - r = read_param(_params, shift(as), &pg->nr_paths, &ti->error); + /* num selector args */ + r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); if (r) goto bad; - r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); + /* + * read the paths + */ + r = read_param(_params + 2, shift(as), &pg->nr_paths, &ti->error); if (r) goto bad; - nr_params = 1 + nr_selector_args; - for (i = 0; i < pg->nr_paths; i++) { - struct path *path; - struct arg_set path_args; - - if (as->argc < nr_params) - goto bad; - - path_args.argc = nr_params; - path_args.argv = as->argv; - - path = parse_path(&path_args, &pg->ps, ti); - if (!path) - goto bad; - - path->pg = pg; - list_add_tail(&path->list, &pg->paths); - consume(as, nr_params); - } - - return pg; + if (!parse_paths(as, pg, nr_group_args, nr_selector_args, ti)) + return pg; bad: free_priority_group(pg, ti); @@ -573,10 +593,16 @@ static int multipath_map(struct dm_targe static int do_end_io(struct multipath *m, struct bio *bio, int error, struct mpath_io *mpio) { - struct path_selector *ps = &mpio->path->pg->ps; + struct priority_group *pg = mpio->path->pg; + + if (pg->ps.type->end_io) + pg->ps.type->end_io(&pg->ps, bio, error, &mpio->info); - ps->type->end_io(ps, bio, error, &mpio->info); if (error) { + struct path *path = mpio->path; + + if (pg->type->update_path(pg, path, error)) + pg->ps.type->update_path(&pg->ps, path, error); dm_bio_restore(&mpio->details, bio); @@ -625,10 +651,11 @@ static int multipath_end_io(struct dm_ta /* * Info string has the following format: - * num_groups [num_paths num_selector_args [path_dev A|F fail_count [selector_args]* ]+ ]+ + * num_groups [num_paths [path_dev num_group_args A|F fail_count [group_args]* [num_selector_args [selector_args]* ]+ ]+ * * Table string has the following format (identical to the constructor string): - * num_groups [priority selector-name num_paths num_selector_args [path_dev [selector_args]* ]+ ]+ + * num_groups [group-name num_group_args [selector-name num_selector_arg num_paths [path_dev [path args (group args then selector args)]* ]+ ]+ ]+ + * */ static int multipath_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) @@ -647,13 +674,24 @@ static int multipath_status(struct dm_ta EMIT("%u ", m->nr_priority_groups); list_for_each_entry(pg, &m->priority_groups, list) { - EMIT("%u %u ", pg->nr_paths, pg->ps.type->info_args); + EMIT("%u ", pg->nr_paths); list_for_each_entry(p, &pg->paths, list) { format_dev_t(buffer, p->dev->bdev->bd_dev); EMIT("%s ", buffer); - sz += pg->ps.type->status(&pg->ps, p, type, - result + sz, maxlen - sz); + + /* pg stat */ + EMIT("%u ", pg->type->info_args); + sz += pg->type->status(pg, p, type, + result + sz, + maxlen - sz); + /* ps stat */ + EMIT("%u ", pg->ps.type->info_args); + if (pg->ps.type->status) + sz += pg->ps.type->status(&pg->ps, p, + type, + result + sz, + maxlen - sz); } } break; @@ -662,14 +700,23 @@ static int multipath_status(struct dm_ta EMIT("%u ", m->nr_priority_groups); list_for_each_entry(pg, &m->priority_groups, list) { - EMIT("%s %u %u ", pg->ps.type->name, - pg->nr_paths, pg->ps.type->table_args); + EMIT("%s %u %s %u %u ", pg->type->name, + pg->type->table_args, pg->ps.type->name, + pg->ps.type->table_args, pg->nr_paths); list_for_each_entry(p, &pg->paths, list) { format_dev_t(buffer, p->dev->bdev->bd_dev); EMIT("%s ", buffer); - sz += pg->ps.type->status(&pg->ps, p, type, - result + sz, maxlen - sz); + /* pg stat */ + sz += pg->type->status(pg, p, type, + result + sz, + maxlen - sz); + /* ps stat */ + if (pg->ps.type->status) + sz += pg->ps.type->status(&pg->ps, p, + type, + result + sz, + maxlen - sz); } } @@ -706,18 +753,27 @@ static int __init dm_multipath_init(void r = dm_register_target(&multipath_target); if (r < 0) { DMERR("%s: register failed %d", multipath_target.name, r); - kmem_cache_destroy(_mpio_cache); - return -EINVAL; + r = -EINVAL; + goto destroy_cache; } r = dm_register_path_selectors(); - if (r && r != -EEXIST) { - dm_unregister_target(&multipath_target); - kmem_cache_destroy(_mpio_cache); - return r; - } + if (r && r != -EEXIST) + goto unreg_tgt; + + r = dm_register_generic_group(); + if (r && r != -EEXIST) + goto unreg_ps; DMINFO("dm_multipath v0.2.0"); + return 0; + +unreg_ps: + dm_unregister_path_selectors(); +unreg_tgt: + dm_unregister_target(&multipath_target); +destroy_cache: + kmem_cache_destroy(_mpio_cache); return r; } @@ -725,6 +781,7 @@ static void __exit dm_multipath_exit(voi { int r; + dm_unregister_generic_group(); dm_unregister_path_selectors(); r = dm_unregister_target(&multipath_target); if (r < 0)