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")))