[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[dm-devel] [PATCH 3/3] add path-selector init function




03-ps-init-fn.patch - this adds the ps-init function.


 drivers/md/dm-mpath.c         |  246 ++++++++++++++++++++++++++++++------------
 drivers/md/dm-path-selector.c |    8 -
 drivers/md/dm-path-selector.h |   23 +++
 drivers/md/dm.c               |    9 +
 include/linux/device-mapper.h |    2
 5 files changed, 211 insertions(+), 77 deletions(-)


-- Mike Christie mikenc us ibm com
diff -aurp linux-2.6.6/drivers/md/dm.c linux-2.6.6-work/drivers/md/dm.c
--- linux-2.6.6/drivers/md/dm.c	2004-05-22 21:26:49.000000000 -0700
+++ linux-2.6.6-work/drivers/md/dm.c	2004-05-23 02:30:07.511500132 -0700
@@ -1078,6 +1078,15 @@ int dm_suspended(struct mapped_device *m
 	return test_bit(DMF_SUSPENDED, &md->flags);
 }
 
+inline union map_info *dm_get_mapinfo(struct bio *bio)
+{
+	if (bio && bio->bi_private)
+		return &((struct target_io *)bio->bi_private)->info;
+	return NULL;
+}
+
+EXPORT_SYMBOL(dm_get_mapinfo);
+
 struct block_device_operations dm_blk_dops = {
 	.open = dm_blk_open,
 	.release = dm_blk_close,
diff -aurp linux-2.6.6/drivers/md/dm-mpath.c linux-2.6.6-work/drivers/md/dm-mpath.c
--- linux-2.6.6/drivers/md/dm-mpath.c	2004-05-23 02:29:58.781624421 -0700
+++ linux-2.6.6-work/drivers/md/dm-mpath.c	2004-05-23 02:30:07.597489058 -0700
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/workqueue.h>
+#include <linux/completion.h>
 #include <asm/atomic.h>
 
 /* Path properties */
@@ -27,27 +28,36 @@ struct path {
 	struct priority_group *pg;
 };
 
+inline struct block_device *dm_path_to_bdev(struct path *path)
+{
+	return path->dev->bdev;
+}
+
 struct priority_group {
 	struct list_head list;
 
 	struct multipath *m;
-	struct path_selector *ps;
+	struct path_selector ps;
 
 	unsigned nr_paths;
 	struct list_head paths;
 };
 
+#define ps_to_pg(__ps) container_of((__ps), struct priority_group, ps)
+
 /* Multipath context */
 struct multipath {
 	struct list_head list;
 	struct dm_target *ti;
 
+	spinlock_t lock;
+
 	unsigned nr_priority_groups;
 	struct list_head priority_groups;
+	int initializing_pg;
+	struct completion init_pg_wait;
 	struct priority_group *current_pg;
 
-	spinlock_t lock;
-
 	struct work_struct dispatch_failed;
 	struct bio_list failed_ios;
 
@@ -94,13 +104,7 @@ static struct priority_group *alloc_prio
 	if (!pg)
 		return NULL;
 
-	pg->ps = kmalloc(sizeof(*pg->ps), GFP_KERNEL);
-	if (!pg->ps) {
-		kfree(pg);
-		return NULL;
-	}
-	memset(pg->ps, 0, sizeof(*pg->ps));
-
+	memset(pg, 0, sizeof(*pg));
 	INIT_LIST_HEAD(&pg->paths);
 
 	return pg;
@@ -120,14 +124,11 @@ static void free_paths(struct list_head 
 static void free_priority_group(struct priority_group *pg,
 				struct dm_target *ti)
 {
-	struct path_selector *ps = pg->ps;
+	struct path_selector *ps = &pg->ps;
 
-	if (ps) {
-		if (ps->type) {
-			ps->type->dtr(ps);
-			dm_put_path_selector(ps->type);
-		}
-		kfree(ps);
+	if (ps->type) {
+		ps->type->dtr(ps);
+		dm_put_path_selector(ps->type);
 	}
 
 	free_paths(&pg->paths, ti);
@@ -142,6 +143,8 @@ static struct multipath *alloc_multipath
 	if (m) {
 		memset(m, 0, sizeof(*m));
 		INIT_LIST_HEAD(&m->priority_groups);
+		init_completion(&m->init_pg_wait);
+		m->initializing_pg = 0;
 		m->lock = SPIN_LOCK_UNLOCKED;
 		INIT_WORK(&m->dispatch_failed, dispatch_failed_ios, m);
 		INIT_WORK(&m->trigger_event, trigger_event, m);
@@ -169,45 +172,115 @@ static void free_multipath(struct multip
 	kfree(m);
 }
 
-/*-----------------------------------------------------------------
- * The multipath daemon is responsible for resubmitting failed ios.
- *---------------------------------------------------------------*/
-static struct path *select_path(struct multipath *m, struct bio *bio,
-				union map_info *info)
+static void __ps_init_complete(struct multipath *m,
+			       struct priority_group *pg)
+{
+	m->initializing_pg = 0;
+	m->current_pg = pg;
+	complete_all(&m->init_pg_wait);
+	schedule_work(&m->dispatch_failed);
+}
+
+void dm_ps_init_complete(struct path_selector *ps)
 {
-	struct priority_group *pg;
-	struct path *path = NULL;
 	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);
+	spin_unlock_irqrestore(&m->lock, flags);
+}
 
-	pg = m->current_pg;
-	if (pg && (path = pg->ps->type->select_path(pg->ps, bio, info)))
-		goto done;
+EXPORT_SYMBOL(dm_ps_init_complete);
+
+static int select_group(struct multipath *m, struct mpath_io *mpio,
+			struct bio *bio)
+{
+	struct priority_group *pg = NULL;
+	int err;
+
+	m->current_pg = NULL;
+	m->initializing_pg = 1;
+	init_completion(&m->init_pg_wait);
 
-	/*
-	 * loop through the priority groups until we
-	 * find a valid path.
-	 */
 	list_for_each_entry (pg, &m->priority_groups, list) {
-		path = pg->ps->type->select_path(pg->ps, bio, info);
-		if (path) {
-			m->current_pg = pg;
-			break;
+
+		if (pg->ps.type->init) {
+			spin_unlock_irq(&m->lock);
+			err = pg->ps.type->init(&pg->ps);
+			spin_lock_irq(&m->lock);
+
+			if (err == DM_PS_INITIALIZING)
+				return DM_PS_INITIALIZING;
+			else if (err == DM_PS_FAILED)
+				continue;
 		}
+
+		mpio->path = pg->ps.type->select_path(&pg->ps, bio,
+						      &mpio->info);
+		if (mpio->path)
+			break;
 	}
 
- done:
-	spin_unlock_irqrestore(&m->lock, flags);
+	__ps_init_complete(m, mpio->path ? pg : NULL);
+	return mpio->path ? DM_PS_SUCCESS : DM_PS_FAILED;
+}
+  
+static int select_path1(struct multipath *m, struct mpath_io *mpio,
+		       struct bio *bio, int wait)
+{
+	mpio->path = NULL;
 
-	return path;
+ retest:
+	/*
+	 * completion event, current_pg, initializing_pg and
+	 * in the case of wait=0 adding to the failed_ios list for
+	 * resubmission are protected under the m->lock to avoid races.
+	 */
+	if (unlikely(m->initializing_pg)) {
+		if (!wait)
+			return -EWOULDBLOCK;
+
+		spin_unlock_irq(&m->lock);
+		wait_for_completion(&m->init_pg_wait);
+		spin_lock_irq(&m->lock);
+		goto retest;
+	}
+
+	if (m->current_pg) {
+		struct path_selector *ps = &m->current_pg->ps;
+
+		mpio->path = ps->type->select_path(ps, bio, &mpio->info);
+		if (!mpio->path &&
+		    (select_group(m, mpio, bio) == DM_PS_INITIALIZING))
+			/*
+			 * while the lock was dropped the
+			 * initialization might have completed.
+			 */
+			goto retest;
+	}
+
+	return mpio->path ? 0 : -EIO;
 }
 
-static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio)
+static int map_io(struct multipath *m, struct mpath_io *mpio,
+		  struct bio *bio, int wait)
 {
-	mpio->path = select_path(m, bio, &mpio->info);
-	if (unlikely(!mpio->path))
-		return -EIO;
+	int err;
+
+	spin_lock_irq(&m->lock);
+	err = select_path1(m, mpio, bio, wait);
+	if (err == -EWOULDBLOCK)
+		/*
+		 * when the ps init is completed it will
+		 * remap and submit this bio
+		 */
+		bio_list_add(&m->failed_ios, bio);
+	spin_unlock_irq(&m->lock);
+
+	if (err)
+		return err;
 
 	bio->bi_bdev = mpio->path->dev->bdev;
 	return 0;
@@ -225,9 +298,29 @@ static void dispatch_failed_ios(void *da
 	spin_unlock_irqrestore(&m->lock, flags);
 
 	while (bio) {
+		int err;
+		struct mpath_io *mpio;
+		union map_info *info;
+
 		next = bio->bi_next;
 		bio->bi_next = NULL;
-		generic_make_request(bio);
+
+		info = dm_get_mapinfo(bio);
+		mpio = info->ptr;
+
+		/*
+		 * For -EWOULDBLOCK the bio could not be mapped
+		 * due to a ps initialization. The bio has been
+		 * requeued, and the work will be processed when
+		 * the initialization is completed.
+		 */
+		err = map_io(m, mpio, bio, 0);
+		if (!err)
+			generic_make_request(bio);
+		else if (err != -EWOULDBLOCK)
+			/* no paths left */
+			bio_endio(bio, bio->bi_size, -EIO);
+
 		bio = next;
 	}
 }
@@ -359,13 +452,12 @@ static struct priority_group *parse_prio
 		goto bad;
 	}
 
-	r = pst->ctr(pg->ps);
+	r = pst->ctr(&pg->ps);
 	if (r) {
-		/* FIXME: need to put the pst ? fix after
-		 * factoring out the register */
+		dm_put_path_selector(pst);
 		goto bad;
 	}
-	pg->ps->type = pst;
+	pg->ps.type = pst;
 
 	/*
 	 * read the paths
@@ -389,7 +481,7 @@ static struct priority_group *parse_prio
 		path_args.argc = nr_params;
 		path_args.argv = as->argv;
 
-		path = parse_path(&path_args, pg->ps, ti);
+		path = parse_path(&path_args, &pg->ps, ti);
 		if (!path)
 			goto bad;
 
@@ -461,42 +553,45 @@ static int multipath_map(struct dm_targe
 			 union map_info *info)
 {
 	int r;
-	struct mpath_io *io;
+	struct mpath_io *mpio;
 	struct multipath *m = (struct multipath *) ti->private;
 
-	io = mempool_alloc(m->mpio_pool, GFP_NOIO);
-	dm_bio_record(&io->details, bio);
+	mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
+	dm_bio_record(&mpio->details, bio);
 
 	bio->bi_rw |= (1 << BIO_RW_FAILFAST);
-	r = map_io(m, bio, io);
+	r = map_io(m, mpio, bio, 1);
 	if (unlikely(r)) {
-		mempool_free(io, m->mpio_pool);
+		mempool_free(mpio, m->mpio_pool);
 		return r;
 	}
 
-	info->ptr = io;
+	info->ptr = mpio;
 	return 1;
 }
 
 static int do_end_io(struct multipath *m, struct bio *bio,
-		     int error, struct mpath_io *io)
+		     int error, struct mpath_io *mpio)
 {
-	struct path_selector *ps = io->path->pg->ps;
+	struct path_selector *ps = &mpio->path->pg->ps;
 
-	error = ps->type->end_io(ps, bio, error, &io->info);
+	ps->type->end_io(ps, bio, error, &mpio->info);
 	if (error) {
-		/* remap */
-		dm_bio_restore(&io->details, bio);
-		if (map_io(m, bio, io))
-			/* no paths left */
-			return -EIO;
 
-		/* queue for the daemon to resubmit */
+		dm_bio_restore(&mpio->details, bio);
+
+		/* queue for the daemon to resubmit or fail */
 		spin_lock(&m->lock);
 		bio_list_add(&m->failed_ios, bio);
+		/*
+		 * If a ps is initializing we do not queue the work
+		 * becuase when the ps initialization has completed
+		 * it will queue the dispatch function to be run.
+		 */
+		if (!m->initializing_pg)
+			schedule_work(&m->dispatch_failed);
 		spin_unlock(&m->lock);
 
-		schedule_work(&m->dispatch_failed);
 		return 1;	/* io not complete */
 	}
 
@@ -510,7 +605,18 @@ static int multipath_end_io(struct dm_ta
 	struct mpath_io *io = (struct mpath_io *) info->ptr;
 	int r;
 
-	r  = do_end_io(m, bio, error, io);
+	/*
+	 * If we report to dm that we are going to retry the
+	 * bio, but that fails due to a pst->init failure
+	 * calling bio_endio from dm-mpath.c will end up
+	 * calling dm-mpath's endio fn, so this test catches
+	 * that case.
+	 */
+	if (io->path)
+		r = do_end_io(m, bio, error, io);
+	else
+		r = -EIO;
+
 	if (r <= 0)
 		mempool_free(io, m->mpio_pool);
 
@@ -541,12 +647,12 @@ 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 %u ", pg->nr_paths, pg->ps.type->info_args);
 
 			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,
+				sz += pg->ps.type->status(&pg->ps, p, type,
 						     result + sz, maxlen - sz);
 			}
 		}
@@ -556,13 +662,13 @@ 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 %u ", pg->ps.type->name,
+			     pg->nr_paths, pg->ps.type->table_args);
 
 			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,
+				sz += pg->ps.type->status(&pg->ps, p, type,
 						     result + sz, maxlen - sz);
 
 			}
diff -aurp linux-2.6.6/drivers/md/dm-path-selector.c linux-2.6.6-work/drivers/md/dm-path-selector.c
--- linux-2.6.6/drivers/md/dm-path-selector.c	2004-05-23 02:29:58.826618626 -0700
+++ linux-2.6.6-work/drivers/md/dm-path-selector.c	2004-05-23 02:30:07.626485324 -0700
@@ -254,15 +254,15 @@ static int rr_add_path(struct path_selec
 	return 0;
 }
 
-static int rr_end_io(struct path_selector *ps, struct bio *bio, int error,
-		     union map_info *info)
+static void rr_end_io(struct path_selector *ps, struct bio *bio, int error,
+		      union map_info *info)
 {
 	unsigned long flags;
 	struct selector *s = (struct selector *) ps->context;
 	struct path_info *pi = (struct path_info *)info->ptr;
 
 	if (likely(!error))
-		return 0;
+		return;
 
 	spin_lock_irqsave(&s->lock, flags);
 
@@ -274,8 +274,6 @@ static int rr_end_io(struct path_selecto
 	}
 
 	spin_unlock_irqrestore(&s->lock, flags);
-
-	return -EIO;
 }
 
 /* Path selector */
diff -aurp linux-2.6.6/drivers/md/dm-path-selector.h linux-2.6.6-work/drivers/md/dm-path-selector.h
--- linux-2.6.6/drivers/md/dm-path-selector.h	2004-05-23 02:29:58.828618369 -0700
+++ linux-2.6.6-work/drivers/md/dm-path-selector.h	2004-05-23 02:30:07.657481332 -0700
@@ -16,6 +16,8 @@
 
 struct path;
 
+struct block_device *dm_path_to_bdev(struct path *path);
+
 /*
  * We provide an abstraction for the code that chooses which path
  * to send some io down.
@@ -33,6 +35,22 @@ typedef int (*ps_ctr_fn) (struct path_se
 typedef void (*ps_dtr_fn) (struct path_selector *ps);
 
 /*
+ * Allows the ps to initialize itself. It should return one
+ * of the following return values. iif DM_PS_INITIALIZING is
+ * returned the path-selector must call dm_ps_init_complete
+ * when the initializtion has completed.
+ */
+enum {
+	DM_PS_SUCCESS,
+	DM_PS_FAILED,
+	DM_PS_INITIALIZING,
+};
+
+void dm_ps_init_complete(struct path_selector *ps);
+
+typedef int (*ps_init_fn) (struct path_selector *ps);
+
+/*
  * Add an opaque path object, along with some selector specific
  * path args (eg, path priority).
  */
@@ -52,8 +70,8 @@ typedef	int (*ps_add_path_fn) (struct pa
 typedef	struct path *(*ps_select_path_fn) (struct path_selector *ps,
 					   struct bio *bio,
 					   union map_info *info);
-typedef int (*ps_end_io) (struct path_selector *ps, struct bio *bio,
-			  int error, union map_info *info);
+typedef void (*ps_end_io) (struct path_selector *ps, struct bio *bio,
+			   int error, union map_info *info);
 
 /*
  * Table content based on parameters added in ps_add_path_fn
@@ -73,6 +91,7 @@ struct path_selector_type {
 	unsigned int info_args;
 	ps_ctr_fn ctr;
 	ps_dtr_fn dtr;
+	ps_init_fn init;
 
 	ps_add_path_fn add_path;
 	ps_select_path_fn select_path;
diff -aurp linux-2.6.6/include/linux/device-mapper.h linux-2.6.6-work/include/linux/device-mapper.h
--- linux-2.6.6/include/linux/device-mapper.h	2004-05-09 19:32:53.000000000 -0700
+++ linux-2.6.6-work/include/linux/device-mapper.h	2004-05-23 02:30:07.000000000 -0700
@@ -18,6 +18,8 @@ union map_info {
 	unsigned long long ll;
 };
 
+inline union map_info *dm_get_mapinfo(struct bio *bio);
+
 /*
  * In the constructor the target parameter will already have the
  * table, type, begin and len fields filled in.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]