[dm-devel] [Patch 2/2] record bios in dm-mpath.c
Joe Thornber
thornber at redhat.com
Wed Feb 25 07:43:02 UTC 2004
- 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 <linux/ctype.h>
#include <linux/init.h>
@@ -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 <linux/bio.h>
+
+/*
+ * 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
More information about the dm-devel
mailing list