Add pg_init capability. --- diff/drivers/md/dm-hw-handler.h 2004-10-29 15:38:04.000000000 +0100 +++ source/drivers/md/dm-hw-handler.h 2004-10-29 15:38:35.000000000 +0100 @@ -17,12 +17,16 @@ void *context; }; +struct path; + /* * Constructs a hardware handler object, takes custom arguments */ typedef int (*hwh_ctr_fn) (struct hw_handler *hwh, unsigned arc, char **argv); typedef void (*hwh_dtr_fn) (struct hw_handler *hwh); +typedef int (*hwh_pg_init_fn) (struct hw_handler *hwh, struct path *path, + struct block_device *bdev); typedef unsigned (*hwh_err_fn) (struct hw_handler *hwh, struct bio *bio); typedef int (*hwh_status_fn) (struct hw_handler *hwh, status_type_t type, @@ -36,6 +40,7 @@ hwh_ctr_fn ctr; hwh_dtr_fn dtr; + hwh_pg_init_fn pg_init; hwh_err_fn err; hwh_status_fn status; }; @@ -60,4 +65,8 @@ #define MP_BYPASS_PG 2 #define MP_RETRY_IO 4 +/* hwh_pg_init_fn return values */ +#define MP_PG_INITIALISING 1 +#define MP_PG_FAILED 2 + #endif --- diff/drivers/md/dm-mpath.c 2004-10-29 15:38:29.000000000 +0100 +++ source/drivers/md/dm-mpath.c 2004-10-29 15:38:35.000000000 +0100 @@ -59,6 +59,7 @@ unsigned nr_valid_paths; struct path *current_path; + struct priority_group *current_pg; unsigned current_count; struct work_struct dispatch_queued; @@ -187,24 +188,57 @@ /*----------------------------------------------------------------- * The multipath daemon is responsible for resubmitting queued ios. *---------------------------------------------------------------*/ + +/* + * Retuns 0 if pg switch failed else 1. + * Clears *path if it's not ready to be used. + */ +static int __switch_pg(struct multipath *m, struct path **path) +{ + int r; + struct hw_handler *hwh = &m->hw_handler; + + if (!hwh || !hwh->type->pg_init) + return 1; + + r = hwh->type->pg_init(hwh, *path, (*path)->dev->bdev); + if (r == MP_PG_INITIALISING) { + m->initialising_pg = 1; + *path = NULL; + return 1; + } else if (r == MP_PG_FAILED) { + (*path)->pg->bypass = 1; + return 0; + } + + return 1; +} + static int __choose_path(struct multipath *m) { struct priority_group *pg; struct path *path = NULL; if (m->nr_valid_paths) { - /* loop through the priority groups until we find a valid path. */ + /* loop through priority groups until we find a valid path. */ list_for_each_entry (pg, &m->priority_groups, list) { if (pg->bypass) continue; path = pg->ps.type->select_path(&pg->ps, &m->current_count); - if (path) - break; + if (!path) + continue; + + if (m->current_pg != pg && !__switch_pg(m, &path)) + continue; + + break; } } m->current_path = path; + if (path) + m->current_pg = path->pg; return 0; }