Add switch_group message.
--- diff/drivers/md/dm-mpath.c	2005-01-12 19:14:33.000000000 +0000
+++ source/drivers/md/dm-mpath.c	2005-01-12 19:14:55.000000000 +0000
@@ -67,6 +67,7 @@
 
 	struct pgpath *current_pgpath;
 	struct priority_group *current_pg;
+	struct priority_group *next_pg;	/* Switch to this PG if set */
 	unsigned current_count;
 
 	struct work_struct process_queued_ios;
@@ -239,6 +240,14 @@
 	if (!m->nr_valid_paths)
 		goto out;
 
+	/* Were we instructed to switch PG? */
+	if (m->next_pg) {
+		pgpath = __choose_path_in_pg(m, m->next_pg);
+		m->next_pg = NULL;
+		if (pgpath)
+			goto out;
+	}
+
 	/* Don't change PG until it has no remaining paths */
 	if (m->current_pg) {
 		pgpath = __choose_path_in_pg(m, m->current_pg);
@@ -823,6 +832,34 @@
 	schedule_work(&m->trigger_event);
 }
 
+static int switch_pg_num(struct multipath *m, const char *pgstr)
+{
+	struct priority_group *pg;
+	unsigned pgnum;
+	unsigned long flags;
+
+	if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+	    (pgnum > m->nr_priority_groups)) {
+		DMWARN("invalid PG number supplied to switch_pg_num");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&m->lock, flags);
+	list_for_each_entry(pg, &m->priority_groups, list) {
+		pg->bypassed = 0;
+		if (--pgnum)
+			continue;
+
+		m->current_pgpath = NULL;
+		m->current_pg = NULL;
+		m->next_pg = pg;
+	}
+	spin_unlock_irqrestore(&m->lock, flags);
+
+	schedule_work(&m->trigger_event);
+	return 0;
+}
+
 /*
  * Set/clear bypassed status of a PG.
  * PG numbering goes 1, 2, 3...
@@ -1072,6 +1109,8 @@
 		return bypass_pg_num(m, argv[1], 1);
 	else if (!strnicmp(argv[0], MESG_STR("enable_group")))
 		return bypass_pg_num(m, argv[1], 0);
+	else if (!strnicmp(argv[0], MESG_STR("switch_group")))
+		return switch_pg_num(m, argv[1]);
 	else if (!strnicmp(argv[0], MESG_STR("reinstate_path")))
 		action = reinstate_path;
 	else if (!strnicmp(argv[0], MESG_STR("fail_path")))