- dm-bio-record.h - change multipath target to use dm-bio-record.h --- diff/drivers/md/dm-mpath.c 2004-02-25 11:11:23.000000000 +0000 +++ source/drivers/md/dm-mpath.c 2004-02-25 11:13:46.000000000 +0000 @@ -7,6 +7,7 @@ #include "dm.h" #include "dm-path-selector.h" #include "dm-bio-list.h" +#include "dm-bio-record.h" #include #include @@ -77,8 +78,22 @@ struct multipath { struct bio_list failed_ios; struct work_struct trigger_event; + + /* + * We must use a mempool of mpath_io structs so that we + * can resubmit bios on error. + */ + mempool_t *details_pool; +}; + +struct mpath_io { + struct path *path; + struct dm_bio_details details; }; +#define MIN_IOS 256 +static kmem_cache_t *_details_cache; + static void dispatch_failed_ios(void *data); static void trigger_event(void *data); @@ -159,6 +174,12 @@ static struct multipath *alloc_multipath m->lock = SPIN_LOCK_UNLOCKED; INIT_WORK(&m->dispatch_failed, dispatch_failed_ios, m); INIT_WORK(&m->trigger_event, trigger_event, m); + m->details_pool = mempool_create(MIN_IOS, mempool_alloc_slab, + mempool_free_slab, _details_cache); + if (!m->details_pool) { + kfree(m); + return NULL; + } } return m; @@ -173,6 +194,7 @@ static void free_multipath(struct multip free_priority_group(pg, m->ti); } + mempool_destroy(m->details_pool); kfree(m); } @@ -219,15 +241,13 @@ static struct path *get_current_path(str return path; } -static int map_io(struct multipath *m, struct bio *bio) +static int map_io(struct multipath *m, struct bio *bio, struct path **chosen) { - struct path *path; - - path = get_current_path(m); - if (!path) + *chosen = get_current_path(m); + if (!*chosen) return -EIO; - bio->bi_bdev = path->dev->bdev; + bio->bi_bdev = (*chosen)->dev->bdev; return 0; } @@ -235,7 +255,6 @@ static void dispatch_failed_ios(void *da { struct multipath *m = (struct multipath *) data; - int r; unsigned long flags; struct bio *bio = NULL, *next; @@ -246,18 +265,7 @@ static void dispatch_failed_ios(void *da while (bio) { next = bio->bi_next; bio->bi_next = NULL; - - r = map_io(m, bio); - if (r) - /* - * This wont loop forever because the - * end_io function will fail the ios if - * we've no valid paths left. - */ - bio_io_error(bio, bio->bi_size); - else - generic_make_request(bio); - + generic_make_request(bio); bio = next; } @@ -514,32 +522,23 @@ static int multipath_map(struct dm_targe union map_info *map_context) { int r; + struct mpath_io *io; struct multipath *m = (struct multipath *) ti->private; + io = mempool_alloc(m->details_pool, GFP_NOIO); + dm_bio_record(&io->details, bio); + bio->bi_rw |= (1 << BIO_RW_FAILFAST); - r = map_io(m, bio); - if (r) + r = map_io(m, bio, &io->path); + if (r) { + mempool_free(io, m->details_pool); return r; + } + map_context->ptr = io; return 1; } -/* - * Only called on the error path. - */ -static struct path *find_path(struct multipath *m, struct block_device *bdev) -{ - struct path *p; - struct priority_group *pg; - - list_for_each_entry (pg, &m->priority_groups, list) - list_for_each_entry (p, &pg->paths, list) - if (p->dev->bdev == bdev) - return p; - - return NULL; -} - static void fail_path(struct path *path) { unsigned long flags; @@ -567,11 +566,10 @@ static void fail_path(struct path *path) spin_unlock_irqrestore(&path->failed_lock, flags); } -static int multipath_end_io(struct dm_target *ti, struct bio *bio, - int error, union map_info *map_context) +static int do_end_io(struct multipath *m, struct bio *bio, + int error, struct mpath_io *io) { - struct path *path; - struct multipath *m = (struct multipath *) ti->private; + int r; if (error) { spin_lock(&m->lock); @@ -581,8 +579,14 @@ static int multipath_end_io(struct dm_ta } spin_unlock(&m->lock); - path = find_path(m, bio->bi_bdev); - fail_path(path); + fail_path(io->path); + + /* remap */ + dm_bio_restore(&io->details, bio); + r = map_io(m, bio, &io->path); + if (r) + /* no paths left */ + return -EIO; /* queue for the daemon to resubmit */ spin_lock(&m->lock); @@ -596,6 +600,20 @@ static int multipath_end_io(struct dm_ta return 0; } +static int multipath_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + struct multipath *m = (struct multipath *) ti->private; + struct mpath_io *io = (struct mpath_io *) map_context->ptr; + int r; + + r = do_end_io(m, bio, error, io); + if (r <= 0) + mempool_free(io, m->details_pool); + + return r; +} + /* * Info string has the following format: * num_groups [num_paths num_selector_args [path_dev A|F fail_count [selector_args]* ]+ ]+ @@ -686,15 +704,23 @@ int __init dm_multipath_init(void) { int r; + /* allocate a slab for the dm_ios */ + _details_cache = kmem_cache_create("dm_mpath", sizeof(struct mpath_io), + 0, 0, NULL, NULL); + if (!_details_cache) + return -ENOMEM; + r = dm_register_target(&multipath_target); if (r < 0) { DMERR("%s: register failed %d", multipath_target.name, r); + kmem_cache_destroy(_details_cache); return -EINVAL; } r = dm_register_path_selectors(); if (r && r != -EEXIST) { dm_unregister_target(&multipath_target); + kmem_cache_destroy(_details_cache); return r; } @@ -703,6 +729,7 @@ int __init dm_multipath_init(void) /* FIXME: remove this */ dm_unregister_path_selectors(); dm_unregister_target(&multipath_target); + kmem_cache_destroy(_details_cache); } else DMINFO("dm_multipath v0.2.0"); @@ -719,6 +746,7 @@ void __exit dm_multipath_exit(void) if (r < 0) DMERR("%s: target unregister failed %d", multipath_target.name, r); + kmem_cache_destroy(_details_cache); } module_init(dm_multipath_init); --- diff/drivers/md/dm-bio-record.h 1970-01-01 01:00:00.000000000 +0100 +++ source/drivers/md/dm-bio-record.h 2004-02-25 11:09:11.000000000 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004 Red Hat UK Ltd. + * + * This file is released under the GPL. + */ + +#ifndef DM_BIO_RECORD_H +#define DM_BIO_RECORD_H + +#include + +/* + * There are lots of mutable fields in the bio struct that get + * changed by the lower levels of the block layer. Some targets, + * such as multipath, may wish to resubmit a bio on error. The + * functions in this file help the target record and restore the + * original bio state. + */ +struct dm_bio_details { + sector_t bi_sector; + struct block_device *bi_bdev; + unsigned int bi_size; + unsigned short bi_idx; +}; + +static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) +{ + bd->bi_sector = bio->bi_sector; + bd->bi_bdev = bio->bi_bdev; + bd->bi_size = bio->bi_size; + bd->bi_idx = bio->bi_idx; +} + +static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) +{ + bio->bi_sector = bd->bi_sector; + bio->bi_bdev = bd->bi_bdev; + bio->bi_size = bd->bi_size; + bio->bi_idx = bd->bi_idx; +} + +#endif