[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