diff -Naurp 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 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.c 2004-06-04 03:37:39.938958278 -0700 @@ -0,0 +1,354 @@ +/* + * dm-priority-group.c - DM-mpath Priority Group - Priority Groups + * are generic way to group your paths together. PGs should init + * the paths if needed (implement ->init function to send a + * failover command) and decide when to fail a path (how to decode + * and/or pass dm-mpath vendor specific sense is unfinished). + * + * Copyright (C) IBM Corporation, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111s-1307, USA. + * + */ + +#include +#include + +#include "dm.h" +#include "dm-priority-group.h" + + +/* + * code to handle refcounting priority_group_type modules + */ +struct pg_internal { + struct priority_group_type pgt; + + struct list_head list; + long use; +}; + +#define pgt_to_pgi(__pgt) container_of((__pgt), struct pg_internal, pgt) + +static LIST_HEAD(priority_groups); +static DECLARE_MUTEX(priority_groups_lock); + +struct priority_group_type *__find_priority_group_type(const char *name) +{ + struct pg_internal *pgi; + + list_for_each_entry (pgi, &priority_groups, list) { + if (!strcmp(name, pgi->pgt.name)) + return &pgi->pgt; + } + + return NULL; +} + +struct priority_group_type *dm_get_priority_group(const char *name) +{ + struct priority_group_type *pgt; + + if (!name) + return NULL; + + down(&priority_groups_lock); + pgt = __find_priority_group_type(name); + if (pgt) { + struct pg_internal *pgi = pgt_to_pgi(pgt); + + if (pgi->use == 0 && !try_module_get(pgt->module)) + pgi = NULL; + else + pgi->use++; + } + up(&priority_groups_lock); + + return pgt; +} + +void dm_put_priority_group(struct priority_group_type *pgt) +{ + struct pg_internal *pgi; + + down(&priority_groups_lock); + pgt = __find_priority_group_type(pgt->name); + if (!pgt) + return; + + pgi = pgt_to_pgi(pgt); + if (--pgi->use == 0) + module_put(pgi->pgt.module); + + if (pgi->use < 0) + BUG(); + up(&priority_groups_lock); +} + +static struct pg_internal *_alloc_priority_group(struct priority_group_type *pt) +{ + struct pg_internal *pgi = kmalloc(sizeof(*pgi), GFP_KERNEL); + + if (pgi) { + memset(pgi, 0, sizeof(*pgi)); + memcpy(&pgi->pgt, pt, sizeof(*pt)); + } + + return pgi; +} + +int dm_register_priority_group(struct priority_group_type *pgt) +{ + int r = 0; + struct pg_internal *pgi = _alloc_priority_group(pgt); + + if (!pgi) + return -ENOMEM; + + down(&priority_groups_lock); + if (__find_priority_group_type(pgt->name)) { + kfree(pgi); + r = -EEXIST; + } else + list_add(&pgi->list, &priority_groups); + + up(&priority_groups_lock); + + return r; +} + +EXPORT_SYMBOL(dm_register_priority_group); + +int dm_unregister_priority_group(struct priority_group_type *pgt) +{ + struct pg_internal *pgi; + + down(&priority_groups_lock); + pgt = __find_priority_group_type(pgt->name); + if (!pgt) { + up(&priority_groups_lock); + return -EINVAL; + } + + pgi = pgt_to_pgi(pgt); + if (pgi->use) { + up(&priority_groups_lock); + return -ETXTBSY; + } + + list_del(&pgi->list); + up(&priority_groups_lock); + + kfree(pgi); + + return 0; +} + +EXPORT_SYMBOL(dm_unregister_priority_group); + + +/* + * Generic Priority Group - This handles basic HW or cases where we do + * not have any specs/info so we cannot support the devices special + * features. + */ + +/* FIXME: get rid of this */ +#define PG_FAIL_COUNT 1 + +struct path_info { + struct list_head list; + struct path *path; + unsigned fail_count; +}; + +/* + * bleh - we do not need this. put some sort of private memeber on the + * path struct along with nice accessor fns. This is only used in + * non critical code paths though. + */ +static struct path_info *path_lookup(struct list_head *head, struct path *p) +{ + struct path_info *pi; + + list_for_each_entry (pi, head, list) + if (pi->path == p) + return pi; + + return NULL; +} + +struct pgroup { + spinlock_t path_lock; + + struct list_head valid_paths; + struct list_head invalid_paths; +}; + +static struct pgroup *alloc_pgroup(void) +{ + struct pgroup *pgroup = kmalloc(sizeof(*pgroup), GFP_KERNEL); + + if (pgroup) { + memset(pgroup, 0, sizeof(*pgroup)); + INIT_LIST_HEAD(&pgroup->valid_paths); + INIT_LIST_HEAD(&pgroup->invalid_paths); + pgroup->path_lock = SPIN_LOCK_UNLOCKED; + } + + return pgroup; +} + +static int generic_group_ctr(struct priority_group *pg) +{ + struct pgroup *pgroup; + + pgroup = alloc_pgroup(); + if (!pgroup) + return -ENOMEM; + + pg->context = pgroup; + return 0; +} + +static void free_paths(struct list_head *paths) +{ + struct path_info *pi, *next; + + list_for_each_entry_safe (pi, next, paths, list) { + list_del(&pi->list); + kfree(pi); + } +} + +static void generic_group_dtr(struct priority_group *pg) +{ + struct pgroup *pgroup = (struct pgroup *)pg->context; + free_paths(&pgroup->valid_paths); + free_paths(&pgroup->invalid_paths); + kfree(pgroup); +} + +static int generic_group_add_path(struct priority_group *pg, struct path *path, + int argc, char **argv, char **error) +{ + struct pgroup *pgroup= (struct pgroup *) pg->context; + struct path_info *pi; + + if (argc != 0) { + *error = "generic-pg: incorrect number of arguments"; + return -EINVAL; + } + + pi = kmalloc(sizeof(*pi), GFP_KERNEL); + if (!pi) { + *error = "generic-pg: Error allocating path context"; + return -ENOMEM; + } + + pi->fail_count = 0; + pi->path = path; + + spin_lock(&pgroup->path_lock); + list_add_tail(&pi->list, &pgroup->valid_paths); + spin_unlock(&pgroup->path_lock); + + return 0; +} + +static int generic_group_update_path(struct priority_group *pg, + struct path *path, int status) +{ + unsigned long flags; + int r = 0; + struct path_info *pi; + struct pgroup *pgroup = (struct pgroup *) pg->context; + + spin_lock_irqsave(&pgroup->path_lock, flags); + + if (status) { + pi = path_lookup(&pgroup->valid_paths, path); + if (!pi) + goto done; + + if (++pi->fail_count == PG_FAIL_COUNT) { + list_move(&pi->list, &pgroup->invalid_paths); + + r = 1; + } + } else { + pi = path_lookup(&pgroup->invalid_paths, path); + if (!pi) + goto done; + + list_move(&pi->list, &pgroup->valid_paths); + } + + done: + spin_unlock_irqrestore(&pgroup->path_lock, flags); + + return r; +} + + +static int generic_group_status(struct priority_group *pg, struct path *path, + status_type_t type, char *result, + unsigned int maxlen) +{ + unsigned long flags; + int failed = 0; + struct path_info *pi; + int sz = 0; + struct pgroup *pgroup = (struct pgroup *) pg->context; + + if (type == STATUSTYPE_TABLE) + return 0; + + spin_lock_irqsave(&pgroup->path_lock, flags); + + pi = path_lookup(&pgroup->valid_paths, path); + if (!pi) { + failed = 1; + pi = path_lookup(&pgroup->invalid_paths, path); + } + + sz = scnprintf(result, maxlen, "%s %u ", failed ? "F" : "A", + pi->fail_count); + + spin_unlock_irqrestore(&pgroup->path_lock, flags); + + return sz; +} + +static struct priority_group_type gen_pg = { + .name = "generic", + .module = THIS_MODULE, + + .ctr = generic_group_ctr, + .dtr = generic_group_dtr, + .add_path = generic_group_add_path, + .update_path = generic_group_update_path, + .status = generic_group_status, +}; + +int __init dm_register_generic_group(void) +{ + return dm_register_priority_group(&gen_pg); +} + +void __exit dm_unregister_generic_group(void) +{ + dm_unregister_priority_group(&gen_pg); +} diff -Naurp 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 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.h 2004-06-04 01:55:44.000000000 -0700 @@ -0,0 +1,123 @@ +/* + * Copyright (C) IBM Corporation, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111s-1307, USA. + * + */ + +#ifndef DM_PRIORITY_GROUP_H +#define DM_PRIORITY_GROUP_H + +#include "dm-path-selector.h" + +struct path; + +struct block_device *dm_path_to_bdev(struct path *path); + +struct multipath; +struct priority_group_type; + +/* Priority Group */ +struct priority_group { + /* + * This can be set by priority_groups to store + * some private data. + */ + void *context; + + /* + * These should be considered private to + * dm-mpath.c + */ + struct priority_group_type *type; + struct path_selector ps; + struct multipath *m; + + unsigned nr_paths; + struct list_head paths; + + struct list_head list; +}; + +/* + * Constructs a priority group object, takes custom arguments + */ +typedef int (*pg_ctr_fn) (struct priority_group *pg); +typedef void (*pg_dtr_fn) (struct priority_group *pg); + +/* + * 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. + */ +enum { + DM_PG_SUCCESS, + DM_PG_FAILED, + DM_PG_INITIALIZING, +}; + +void dm_pg_init_complete(struct priority_group *pg); + +typedef int (*pg_init_fn) (struct priority_group *pg); + +/* + * Add a path object, along with some path args. + */ +typedef int (*pg_add_path_fn) (struct priority_group *pg, struct path *path, + int argc, char **argv, char **error); +/* + * Notify the pg that path status has changes. + * status should be an -Exxx value to indicate an error, + * 0 to indicatate reactivation. + * returns 1 if it determined the path should be + * marked as failed else 0. + */ +typedef int (*pg_update_path_fn) (struct priority_group *pg, + struct path *path, int status); + +/* + * Table content based on parameters added in pg_add_path_fn + * or path selector status + */ +typedef int (*pg_status_fn) (struct priority_group *pg, struct path *path, + status_type_t type, char *result, + unsigned int maxlen); + +/* Information about a priority group type */ +struct priority_group_type { + char *name; + struct module *module; + + unsigned int table_args; + unsigned int info_args; + pg_ctr_fn ctr; + pg_dtr_fn dtr; + pg_init_fn init; + pg_add_path_fn add_path; + pg_update_path_fn update_path; + pg_status_fn status; +}; + + +int dm_unregister_priority_group(struct priority_group_type *pgt); +int dm_register_priority_group(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); + +int dm_register_generic_group(void); +void dm_unregister_generic_group(void); + +#endif diff -Naurp linux-2.6.7-rc2/drivers/md/Makefile linux-2.6.7-rc2-pg/drivers/md/Makefile --- linux-2.6.7-rc2/drivers/md/Makefile 2004-06-04 03:52:23.168748837 -0700 +++ linux-2.6.7-rc2-pg/drivers/md/Makefile 2004-06-04 03:59:16.659899173 -0700 @@ -4,7 +4,7 @@ dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ dm-ioctl.o dm-io.o kcopyd.o -dm-multipath-objs := dm-path-selector.o dm-mpath.o +dm-multipath-objs := dm-path-selector.o dm-priority-group.o dm-mpath.o dm-snapshot-objs := dm-snap.o dm-exception-store.o dm-mirror-objs := dm-log.o dm-raid1.o raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \