Add code for the multipath_status() routine. The table string format is identical to the constructor string format. test_interval num_groups [priority selector-name num_paths num_selector_args [path_dev [selector_args]* ]+ ]+ The info string format is: num_groups [num_paths num_selector_args [path_dev A|F fail_count fail_total [selector_args]* ]+ ]+ where "A" means the path is active and "F" means the path has failed, fail_count is the number of I/O errors remaining before the path fails, and fail_total is the number of times the path has failed. Obviously the table string must match the constructor string, but the info string can be modified if we'd like to add more information. This format should provide a good starting point. --- diff/drivers/md/dm-mpath.c 2004-01-16 09:44:40.000000000 -0600 +++ source/drivers/md/dm-mpath.c 2004-01-16 10:03:40.000000000 -0600 @@ -746,9 +746,119 @@ iterate_paths(m, unlock_path); } +static inline int __pg_count(struct multipath *m) +{ + int count = 0; + struct priority_group *pg; + list_for_each_entry(pg, &m->priority_groups, list) count++; + return count; +} + +static inline int __path_count(struct priority_group *pg) +{ + int count = 0; + struct path *p; + list_for_each_entry(p, &pg->valid_paths, list) count++; + list_for_each_entry(p, &pg->invalid_paths, list) count++; + return count; +} + +/* + * Info string has the following format: + * num_groups [num_paths num_selector_args [path_dev A|F fail_count fail_total [selector_args]* ]+ ]+ + * + * Table string has the following format (identical to the constructor string): + * test_interval num_groups [priority selector-name num_paths num_selector_args [path_dev [selector_args]* ]+ ]+ + */ static int multipath_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { + int sz = 0; + unsigned long flags; + struct multipath *m = (struct multipath *) ti->private; + struct priority_group *pg; + struct path *p; + char buffer[32]; + + spin_lock_irqsave(&m->path_lock, flags); + + switch (type) { + case STATUSTYPE_INFO: + sz += snprintf(result + sz, maxlen - sz, "%u ", __pg_count(m)); + + list_for_each_entry(pg, &m->priority_groups, list) { + sz += snprintf(result + sz, maxlen - sz, "%u %u ", + __path_count(pg), + pg->ps->type->info_args); + + list_for_each_entry(p, &pg->valid_paths, list) { + format_dev_t(buffer, p->dev->bdev->bd_dev); + sz += snprintf(result + sz, maxlen - sz, + "%s A %u %u ", buffer, + atomic_read(&p->fail_count), + atomic_read(&p->fail_total)); + pg->ps->type->status(pg->ps, p, type, + result + sz, maxlen - sz); + + sz = strlen(result); + if (sz >= maxlen) + break; + } + list_for_each_entry(p, &pg->invalid_paths, list) { + format_dev_t(buffer, p->dev->bdev->bd_dev); + sz += snprintf(result + sz, maxlen - sz, + "%s F %u %u ", buffer, + atomic_read(&p->fail_count), + atomic_read(&p->fail_total)); + pg->ps->type->status(pg->ps, p, type, + result + sz, maxlen - sz); + + sz = strlen(result); + if (sz >= maxlen) + break; + } + } + + break; + + case STATUSTYPE_TABLE: + sz += snprintf(result + sz, maxlen - sz, "%u %u ", + m->test_interval, __pg_count(m)); + + list_for_each_entry(pg, &m->priority_groups, list) { + sz += snprintf(result + sz, maxlen - sz, "%u %s %u %u ", + pg->priority, pg->ps->type->name, + __path_count(pg), pg->ps->type->table_args); + + list_for_each_entry(p, &pg->valid_paths, list) { + format_dev_t(buffer, p->dev->bdev->bd_dev); + sz += snprintf(result + sz, maxlen - sz, + "%s ", buffer); + pg->ps->type->status(pg->ps, p, type, + result + sz, maxlen - sz); + + sz = strlen(result); + if (sz >= maxlen) + break; + } + list_for_each_entry(p, &pg->invalid_paths, list) { + format_dev_t(buffer, p->dev->bdev->bd_dev); + sz += snprintf(result + sz, maxlen - sz, + "%s ", buffer); + pg->ps->type->status(pg->ps, p, type, + result + sz, maxlen - sz); + + sz = strlen(result); + if (sz >= maxlen) + break; + } + } + + break; + } + + spin_unlock_irqrestore(&m->path_lock, flags); + return 0; } --- diff/drivers/md/dm-path-selector.c 2004-01-13 15:03:57.000000000 -0600 +++ source/drivers/md/dm-path-selector.c 2004-01-16 10:03:37.000000000 -0600 @@ -280,13 +280,23 @@ return pi ? pi->path : NULL; } +/* Path status */ +static int rr_status(struct path_selector *ps, struct path *path, + status_type_t type, char *result, unsigned int maxlen) +{ + return 0; +} + static struct path_selector_type rr_ps = { .name = "round-robin", + .table_args = 0, + .info_args = 0, .ctr = rr_ctr, .dtr = rr_dtr, .add_path = rr_add_path, .set_path_state = rr_set_path_state, .select_path = rr_select_path, + .status = rr_status, }; int dm_register_rr_ps(void) --- diff/drivers/md/dm-path-selector.h 2004-01-13 15:03:57.000000000 -0600 +++ source/drivers/md/dm-path-selector.h 2004-01-16 10:03:37.000000000 -0600 @@ -69,6 +69,8 @@ /* Information about a path selector type */ struct path_selector_type { char *name; + unsigned int table_args; + unsigned int info_args; ps_ctr_fn ctr; ps_dtr_fn dtr;