diff -arup linux-2.6.7-rc2/drivers/md/dm-mpath.c linux-2.6.7-rc2-pg/drivers/md/dm-mpath.c --- linux-2.6.7-rc2/drivers/md/dm-mpath.c 2004-06-04 03:58:47.000000000 -0700 +++ linux-2.6.7-rc2-pg/drivers/md/dm-mpath.c 2004-06-04 22:02:51.000000000 -0700 @@ -100,6 +100,7 @@ static struct priority_group *alloc_prio memset(pg, 0, sizeof(*pg)); INIT_LIST_HEAD(&pg->paths); + pg->failed = 0; return pg; } @@ -171,28 +172,33 @@ static void free_multipath(struct multip kfree(m); } -static void __pg_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); -} +static int select_group(struct multipath *m); -void dm_pg_init_complete(struct priority_group *pg) +void dm_pg_init_complete(struct priority_group *pg, int error) { unsigned long flags; struct multipath *m = pg->m; spin_lock_irqsave(&m->lock, flags); - __pg_init_complete(m, pg); + + if (error == DM_PG_FAILED) { + pg->failed = 1; + if (select_group(m) == DM_PG_INITIALIZING) + goto done; + } else if (error == DM_PG_SUCCESS) { + m->initializing_pg = 0; + m->current_pg = pg; + } + + complete_all(&m->init_pg_wait); + schedule_work(&m->dispatch_failed); + done: spin_unlock_irqrestore(&m->lock, flags); } EXPORT_SYMBOL(dm_pg_init_complete); -static int select_group(struct multipath *m, struct mpath_io *mpio, - struct bio *bio) +static int select_group(struct multipath *m) { struct priority_group *pg = NULL; int err; @@ -202,26 +208,23 @@ static int select_group(struct multipath init_completion(&m->init_pg_wait); list_for_each_entry (pg, &m->priority_groups, list) { + if (pg->failed) + continue; if (pg->type->init) { - spin_unlock_irq(&m->lock); err = pg->type->init(pg); - spin_lock_irq(&m->lock); - if (err == DM_PG_INITIALIZING) - return DM_PG_INITIALIZING; - else if (err == DM_PG_FAILED) + return err; + else if (err == DM_PG_FAILED) { + pg->failed = 1; continue; + } } - - mpio->path = pg->ps.type->select_path(&pg->ps, bio, - &mpio->info); - if (mpio->path) - break; } - __pg_init_complete(m, mpio->path ? pg : NULL); - return mpio->path ? DM_PG_SUCCESS : DM_PG_FAILED; + m->current_pg = (pg->failed ? NULL : pg); + m->initializing_pg = 0; + return m->current_pg ? DM_PG_SUCCESS : DM_PG_FAILED; } static int select_path(struct multipath *m, struct mpath_io *mpio, @@ -249,13 +252,11 @@ static int select_path(struct multipath 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_PG_INITIALIZING)) - /* - * while the lock was dropped the - * initialization might have completed. - */ - goto retest; + if (!mpio->path) { + m->current_pg->failed = 1; + if (select_group(m) != DM_PG_FAILED) + goto retest; + } } return mpio->path ? 0 : -EIO; diff -arup linux-2.6.7-rc2/drivers/md/dm-priority-group.c linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.c --- linux-2.6.7-rc2/drivers/md/dm-priority-group.c 2004-06-04 04:04:17.000000000 -0700 +++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.c 2004-06-04 13:54:28.000000000 -0700 @@ -109,7 +109,7 @@ static struct pg_internal *_alloc_priori return pgi; } -int dm_register_priority_group(struct priority_group_type *pgt) +int dm_register_priority_group_type(struct priority_group_type *pgt) { int r = 0; struct pg_internal *pgi = _alloc_priority_group(pgt); @@ -129,9 +129,9 @@ int dm_register_priority_group(struct pr return r; } -EXPORT_SYMBOL(dm_register_priority_group); +EXPORT_SYMBOL(dm_register_priority_group_type); -int dm_unregister_priority_group(struct priority_group_type *pgt) +int dm_unregister_priority_group_type(struct priority_group_type *pgt) { struct pg_internal *pgi; @@ -156,7 +156,7 @@ int dm_unregister_priority_group(struct return 0; } -EXPORT_SYMBOL(dm_unregister_priority_group); +EXPORT_SYMBOL(dm_unregister_priority_group_type); /* @@ -345,10 +345,10 @@ static struct priority_group_type gen_pg int __init dm_register_generic_group(void) { - return dm_register_priority_group(&gen_pg); + return dm_register_priority_group_type(&gen_pg); } void __exit dm_unregister_generic_group(void) { - dm_unregister_priority_group(&gen_pg); + dm_unregister_priority_group_type(&gen_pg); } diff -arup linux-2.6.7-rc2/drivers/md/dm-priority-group.h linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.h --- linux-2.6.7-rc2/drivers/md/dm-priority-group.h 2004-06-04 04:04:17.000000000 -0700 +++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.h 2004-06-04 21:01:40.000000000 -0700 @@ -49,6 +49,8 @@ struct priority_group { struct list_head paths; struct list_head list; + + int failed; }; /* @@ -61,7 +63,8 @@ typedef void (*pg_dtr_fn) (struct priori * Allows the pg to initialize itself. It should return one * of the following return values. If DM_PG_INITIALIZING is * returned the priority_group must call dm_pg_init_complete - * when the initializtion has completed. + * with either DM_PG_SUCCESS or DM_PG_FAILED when the + * initializtion has completed */ enum { DM_PG_SUCCESS, @@ -69,7 +72,7 @@ enum { DM_PG_INITIALIZING, }; -void dm_pg_init_complete(struct priority_group *pg); +void dm_pg_init_complete(struct priority_group *pg, int error); typedef int (*pg_init_fn) (struct priority_group *pg); @@ -112,8 +115,8 @@ struct priority_group_type { }; -int dm_unregister_priority_group(struct priority_group_type *pgt); -int dm_register_priority_group(struct priority_group_type *pgt); +int dm_unregister_priority_group_type(struct priority_group_type *pgt); +int dm_register_priority_group_type(struct priority_group_type *pgt); void dm_put_priority_group(struct priority_group_type *pgt); struct priority_group_type *dm_get_priority_group(const char *name);