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

[dm-devel] [PATCH RFC 2/3] async path-selector initialization



hehe numbering on the subject was messed up on previous mails. sorry.

02-async-ps-init-RFC.patch - Basically, for incoming IO the map
function will simply sleep until the ps has been activated. For failed
IO that can not be mapped becuase the ps is initializing the map or
end_io function will just place the bio on the on the dispatched_failed
list and set things up so that work is not dequeued until the ps has been
initialized.


dm-mpath.c | 173 ++++++++++++++++++++++++++++++++--------------------- dm-path-selector.h | 17 ++++- 2 files changed, 119 insertions(+), 71 deletions(-)
diff -aurp linux-2.6.5-orig/drivers/md/dm-mpath.c linux-2.6.5-rdac/drivers/md/dm-mpath.c
--- linux-2.6.5-orig/drivers/md/dm-mpath.c	2004-04-20 23:20:29.254721055 -0700
+++ linux-2.6.5-rdac/drivers/md/dm-mpath.c	2004-04-20 23:42:27.492963026 -0700
@@ -53,12 +53,14 @@ 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;
@@ -96,6 +98,7 @@ struct mpath_io {
 #define MIN_IOS 256
 static kmem_cache_t *_details_cache;
 
+struct workqueue_struct *kmultipathd;
 static void dispatch_failed_ios(void *data);
 static void trigger_event(void *data);
 
@@ -121,13 +124,7 @@ static struct priority_group *alloc_prio
 	pg = kmalloc(sizeof(*pg), GFP_KERNEL);
 	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);
 
@@ -148,14 +145,13 @@ 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);
 	}
 
 	free_paths(&pg->paths, ti);
@@ -199,93 +195,117 @@ static void free_multipath(struct multip
 	kfree(m);
 }
 
-static struct path *__choose_path(struct multipath *m)
+void dm_ps_init_done(struct path_selector *ps)
 {
-	struct priority_group *pg, *orig_pg = m->current_pg;
-	struct path *path = NULL;
+	struct multipath *m = ps_to_pg(ps)->m;
 
-	m->current_pg = NULL;
+	spin_lock_irq(&m->lock);
+	m->initializing_pg = 0;
+	complete_all(&m->init_pg_wait);
+	queue_work(kmultipathd, &m->dispatch_failed);
+	spin_unlock_irq(&m->lock);
+}
 
-	init_completion(&m->init_pg_wait);
+static int __choose_path(struct multipath *m, struct path **path)
+{
+	struct priority_group *pg, *orig_pg;
+
+	orig_pg = m->current_pg;
+	m->current_pg = NULL;
 	m->initializing_pg = 1;
+	init_completion(&m->init_pg_wait);
 
 	list_for_each_entry (pg, &m->priority_groups, list) {
 		if (orig_pg == pg)
 			continue;
 
-		if (pg->ps->type->init) {
-			int err;
+		if (pg->ps.type->init) {
+			switch(pg->ps.type->init(&pg->ps, dm_ps_init_done)) {
 
-			spin_unlock_irq(&m->lock);
-			err = pg->ps->type->init(pg->ps);
-			spin_lock_irq(&m->lock);
-			if (err)
+			case DM_PS_INITIALIZING:
+				return DM_PS_INITIALIZING;
+			case DM_PS_FAILED:
 				continue;
+			}
 		}
 
-		path = pg->ps->type->select_path(pg->ps);
-		if (path) {
+		*path = pg->ps.type->select_path(&pg->ps);
+		if (*path) {
 			m->current_pg = pg;
 			break;
 		}
 	}
 
 	m->initializing_pg = 0;
-	complete_all(&m->init_pg_wait);
-
-	return path;
+	return (*path ? DM_PS_SUCCESS : DM_PS_FAILED);
 }
   
-static struct path *get_current_path(struct multipath *m)
+static int get_current_path(struct multipath *m, struct path **path, int wait)
 {
-	struct path *path = NULL;
+	*path = NULL;
 
  retry:
-	spin_lock_irq(&m->lock);
-
-	if (m->current_path && --m->current_count > 0)
-		goto done;
+	if (m->current_path && --m->current_count > 0) {
+		*path = m->current_path;
+		return 0;
+	}
 
 	/*
-	 * completion event, current_pg, and initializing_pg
-	 * are protected under the m->lock to avoid races.
+	 * 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)) {
-		spin_unlock_irq(&m->lock);
-		wait_for_completion(&m->init_pg_wait);
-		goto retry;
+
+	ps_init:
+		if (wait) {
+			spin_unlock_irq(&m->lock);
+			wait_for_completion(&m->init_pg_wait);
+			spin_lock_irq(&m->lock);
+			goto retry;
+		}
+		return -EWOULDBLOCK;
 	}
 
 	if (m->current_pg) {
-		path = m->current_pg->ps->type->select_path(m->current_pg->ps);
-		if (!path)
-			path = __choose_path(m);
+		*path = m->current_pg->ps.type->select_path(&m->current_pg->ps);
+		if (!*path && 
+		    (__choose_path(m, path) == DM_PS_INITIALIZING))
+			goto ps_init;
 	}
 
 	m->current_count = MPATH_MIN_IO;
-	m->current_path = path;
- done:
-	path = m->current_path;
+	m->current_path = *path;
 
-	spin_unlock_irq(&m->lock);
-
-	return path;
+	return *path ? 0 : -EIO;
 }
 
-static int map_io(struct multipath *m, struct bio *bio, struct path **chosen)
+static int map_io(struct multipath *m, struct bio *bio, int wait)
 {
-	*chosen = get_current_path(m);
-	if (!*chosen)
-		return -EIO;
+	int err;
+	struct mpath_io *io;
+	union map_info *info;
+
+	info = dm_get_mapinfo(bio);
+	io = info->ptr;
+
+	spin_lock_irq(&m->lock);
+	err = get_current_path(m, &io->path, wait);
+	if (err == -EWOULDBLOCK)
+		/* we will submit the bio later */
+		bio_list_add(&m->failed_ios, bio);
+	spin_unlock_irq(&m->lock);
 
-	bio->bi_bdev = (*chosen)->dev->bdev;
+	if (err)
+		return err;
+
+	bio->bi_bdev = io->path->dev->bdev;
 	return 0;
 }
 
 /*-----------------------------------------------------------------
  * The multipath daemon is responsible for resubmitting failed ios.
  *---------------------------------------------------------------*/
-struct workqueue_struct *kmultipathd;
 
 static void dispatch_failed_ios(void *data)
 {
@@ -307,7 +327,13 @@ static void dispatch_failed_ios(void *da
 		info = dm_get_mapinfo(bio);
 		io = info->ptr;
 
-		if (map_io(m, bio, &io->path))
+		/*
+		 * For -EWOULDBLOCK the bio could not be mapped
+		 * due to a ps initialization. That work has been
+		 * requeued and will be processed when the
+		 * initialization is completed.
+		 */
+		if (map_io(m, bio, 0) == -EIO)
 			/* no paths left */
 			bio_endio(bio, bio->bi_size, -EIO);
 		else
@@ -452,13 +478,13 @@ static struct priority_group *parse_prio
 	if (as->argc < nr_args)
 		goto bad;
 
-	r = pst->ctr(pg->ps, nr_args, as->argv, &ti->error);
+	r = pst->ctr(&pg->ps, nr_args, as->argv, &ti->error);
 	if (r) {
 		/* FIXME: need to put the pst ? fix after
 		 * factoring out the register */
 		goto bad;
 	}
-	pg->ps->type = pst;
+	pg->ps.type = pst;
 	consume(as, nr_args);
 
 	/*
@@ -486,7 +512,7 @@ static struct priority_group *parse_prio
 		path_args.argc = nr_args;
 		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;
 
@@ -563,17 +589,22 @@ static int multipath_map(struct dm_targe
 	struct multipath *m = (struct multipath *) ti->private;
 
 	io = mempool_alloc(m->details_pool, GFP_NOIO);
+	map_context->ptr = io;
 	dm_bio_record(&io->details, bio);
 
 	bio->bi_rw |= (1 << BIO_RW_FAILFAST);
-	r = map_io(m, bio, &io->path);
-	if (r) {
+	/*
+	 * For bios that could not be mapped because the ps was
+	 * initializing we pass wait=1 so map_io just blocks untill
+	 * the initialization is completed.
+	 */
+	r = map_io(m, bio, 1);
+	if (r < 0) {
 		mempool_free(io, m->details_pool);
 		return r;
 	}
 
-	map_context->ptr = io;
-	return 1;
+	return r;
 }
 
 static void update_path(struct path *path, int error)
@@ -581,7 +612,7 @@ static void update_path(struct path *pat
 	unsigned long flags;
 	struct multipath *m = path->pg->m;
 
-	path->pg->ps->type->update_path(path->pg->ps, path, error);
+	path->pg->ps.type->update_path(&path->pg->ps, path, error);
 
 	spin_lock_irqsave(&m->lock, flags);
 	if (path == m->current_path)
@@ -605,9 +636,15 @@ static int do_end_io(struct multipath *m
 		/* queue for the daemon to resubmit */
 		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)
+			queue_work(kmultipathd, &m->dispatch_failed);
 		spin_unlock(&m->lock);
 
-		queue_work(kmultipathd, &m->dispatch_failed);
 		return 1;	/* io not complete */
 	}
 
@@ -654,16 +691,16 @@ static int multipath_status(struct dm_ta
 		EMIT("%u ", m->nr_priority_groups);
 
 		list_for_each_entry(pg, &m->priority_groups, list) {
-			pst = pg->ps->type;
+			pst = pg->ps.type;
 
-			sz += pst->ps_status(pg->ps, type, result + sz,
+			sz += pst->ps_status(&pg->ps, type, result + sz,
 					     maxlen - sz);
 			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 += pst->path_status(pg->ps, p, type,
+				sz += pst->path_status(&pg->ps, p, type,
 						       result + sz,
 						       maxlen - sz);
 			}
@@ -674,17 +711,17 @@ static int multipath_status(struct dm_ta
 		EMIT("%u ", m->nr_priority_groups);
 
 		list_for_each_entry(pg, &m->priority_groups, list) {
-		        pst = pg->ps->type;
+		        pst = pg->ps.type;
 
 			EMIT("%s ", pst->name);
-			sz += pst->ps_status(pg->ps, type, result + sz,
+			sz += pst->ps_status(&pg->ps, type, result + sz,
 					     maxlen - sz);
 			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 += pst->path_status(pg->ps, p, type,
+				sz += pst->path_status(&pg->ps, p, type,
 						       result + sz,
 						       maxlen - sz);
 
diff -aurp linux-2.6.5-orig/drivers/md/dm-path-selector.h linux-2.6.5-rdac/drivers/md/dm-path-selector.h
--- linux-2.6.5-orig/drivers/md/dm-path-selector.h	2004-04-20 23:20:29.287716764 -0700
+++ linux-2.6.5-rdac/drivers/md/dm-path-selector.h	2004-04-20 23:40:46.054062030 -0700
@@ -36,10 +36,21 @@ typedef int (*ps_ctr_fn) (struct path_se
 typedef void (*ps_dtr_fn) (struct path_selector *ps);
 
 /*
- * Allows the ps to initialize itself. This fn may sleep.
- * The multipath context lock is not held.
+ * 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 ps_init_completion_fn.
+ *
+ * The Mulipath lock is held, so the init funtion should not sleep.
  */
-typedef	int (*ps_init_fn) (struct path_selector *ps);
+enum {
+	DM_PS_SUCCESS,
+	DM_PS_FAILED,
+	DM_PS_INITIALIZING,
+};
+
+typedef void (*ps_init_completion_fn)(struct path_selector *ps);
+typedef	int (*ps_init_fn) (struct path_selector *ps,
+			   ps_init_completion_fn done);
 
 /*
  * Add an opaque path object, along with some selector specific

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