Add outline hardware handler framework. --- diff/drivers/md/Makefile 2004-10-29 15:37:40.000000000 +0100 +++ source/drivers/md/Makefile 2004-10-29 15:37:46.000000000 +0100 @@ -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-hw-handler.o dm-path-selector.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 \ --- diff/drivers/md/dm-mpath.c 2004-10-29 15:37:28.000000000 +0100 +++ source/drivers/md/dm-mpath.c 2004-10-29 15:37:46.000000000 +0100 @@ -7,6 +7,7 @@ #include "dm.h" #include "dm-path-selector.h" +#include "dm-hw-handler.h" #include "dm-bio-list.h" #include "dm-bio-record.h" @@ -47,6 +48,8 @@ struct list_head list; struct dm_target *ti; + struct hw_handler hw_handler; + unsigned nr_priority_groups; struct list_head priority_groups; @@ -163,12 +166,18 @@ static void free_multipath(struct multipath *m) { struct priority_group *pg, *tmp; + struct hw_handler *hwh = &m->hw_handler; list_for_each_entry_safe (pg, tmp, &m->priority_groups, list) { list_del(&pg->list); free_priority_group(pg, m->ti); } + if (hwh->type) { + hwh->type->dtr(hwh); + dm_put_hw_handler(hwh->type); + } + mempool_destroy(m->mpio_pool); kfree(m); } @@ -251,6 +260,7 @@ /*----------------------------------------------------------------- * Constructor/argument parsing: + * [hw_handler []*] * [ * [ []* ]+ ]+ *---------------------------------------------------------------*/ @@ -418,6 +428,43 @@ return NULL; } +int parse_hw_handler(struct arg_set *as, struct multipath *m, + struct dm_target *ti) +{ + int r; + struct hw_handler_type *hwht; + unsigned hw_argc; + + static struct param _params[] = { + {0, 1024, ESTR("invalid number of hardware handler args")}, + }; + + r = read_param(_params, shift(as), &hw_argc, &ti->error); + if (r) + return -EINVAL; + + if (!hw_argc) + return 0; + + hwht = dm_get_hw_handler(shift(as)); + if (!hwht) { + ti->error = ESTR("unknown hardware handler type"); + return -EINVAL; + } + + r = hwht->ctr(&m->hw_handler, hw_argc - 1, as->argv); + if (r) { + dm_put_hw_handler(hwht); + ti->error = ESTR("hardware handler constructor failed"); + return r; + } + + m->hw_handler.type = hwht; + consume(as, hw_argc - 1); + + return 0; +} + static int multipath_ctr(struct dm_target *ti, unsigned int argc, char **argv) { @@ -439,6 +486,10 @@ return -EINVAL; } + r = parse_hw_handler(&as, m, ti); + if (r) + goto bad; + r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error); if (r) goto bad; @@ -447,8 +498,10 @@ while (as.argc) { struct priority_group *pg; pg = parse_priority_group(&as, m, ti); - if (!pg) + if (!pg) { + r = -EINVAL; goto bad; + } m->nr_valid_paths += pg->nr_paths; list_add_tail(&pg->list, &m->priority_groups); @@ -461,7 +514,7 @@ bad: free_multipath(m); - return -EINVAL; + return r; } static void multipath_dtr(struct dm_target *ti) --- diff/drivers/md/dm-hw-handler.c 1970-01-01 01:00:00.000000000 +0100 +++ source/drivers/md/dm-hw-handler.c 2004-10-29 15:37:46.000000000 +0100 @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + * + * Multipath hardware handler registration. + */ + +#include "dm.h" +#include "dm-hw-handler.h" + +#include + +struct hwh_internal { + struct hw_handler_type hwht; + + struct list_head list; + long use; +}; + +#define hwht_to_hwhi(__hwht) container_of((__hwht), struct hwh_internal, hwht) + +static LIST_HEAD(_hw_handlers); +static DECLARE_RWSEM(_hwh_lock); + +struct hwh_internal *__find_hw_handler_type(const char *name) +{ + struct hwh_internal *hwhi; + + list_for_each_entry (hwhi, &_hw_handlers, list) { + if (!strcmp(name, hwhi->hwht.name)) + return hwhi; + } + + return NULL; +} + +static struct hwh_internal *get_hw_handler(const char *name) +{ + struct hwh_internal *hwhi; + + down_read(&_hwh_lock); + hwhi = __find_hw_handler_type(name); + if (hwhi) { + if ((hwhi->use == 0) && !try_module_get(hwhi->hwht.module)) + hwhi = NULL; + else + hwhi->use++; + } + up_read(&_hwh_lock); + + return hwhi; +} + +struct hw_handler_type *dm_get_hw_handler(const char *name) +{ + struct hwh_internal *hwhi; + + if (!name) + return NULL; + + hwhi = get_hw_handler(name); + if (!hwhi) { + request_module("dm-%s", name); + hwhi = get_hw_handler(name); + } + + return hwhi ? &hwhi->hwht : NULL; +} + +void dm_put_hw_handler(struct hw_handler_type *hwht) +{ + struct hwh_internal *hwhi; + + if (!hwht) + return; + + down_read(&_hwh_lock); + hwhi = __find_hw_handler_type(hwht->name); + if (!hwhi) + goto out; + + if (--hwhi->use == 0) + module_put(hwhi->hwht.module); + + if (hwhi->use < 0) + BUG(); + +out: + up_read(&_hwh_lock); +} + +static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht) +{ + struct hwh_internal *hwhi = kmalloc(sizeof(*hwhi), GFP_KERNEL); + + if (hwhi) { + memset(hwhi, 0, sizeof(*hwhi)); + hwhi->hwht = *hwht; + } + + return hwhi; +} + +int dm_register_hw_handler(struct hw_handler_type *hwht) +{ + int r = 0; + struct hwh_internal *hwhi = _alloc_hw_handler(hwht); + + if (!hwhi) + return -ENOMEM; + + down_write(&_hwh_lock); + + if (__find_hw_handler_type(hwht->name)) { + kfree(hwhi); + r = -EEXIST; + } else + list_add(&hwhi->list, &_hw_handlers); + + up_write(&_hwh_lock); + + return r; +} + +int dm_unregister_hw_handler(struct hw_handler_type *hwht) +{ + struct hwh_internal *hwhi; + + down_write(&_hwh_lock); + + hwhi = __find_hw_handler_type(hwht->name); + if (!hwhi) { + up_write(&_hwh_lock); + return -EINVAL; + } + + if (hwhi->use) { + up_write(&_hwh_lock); + return -ETXTBSY; + } + + list_del(&hwhi->list); + + up_write(&_hwh_lock); + + kfree(hwhi); + + return 0; +} + +EXPORT_SYMBOL(dm_register_hw_handler); +EXPORT_SYMBOL(dm_unregister_hw_handler); --- diff/drivers/md/dm-hw-handler.h 1970-01-01 01:00:00.000000000 +0100 +++ source/drivers/md/dm-hw-handler.h 2004-10-29 15:37:46.000000000 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + * + * Multipath hardware handler registration. + */ + +#ifndef DM_HW_HANDLER_H +#define DM_HW_HANDLER_H + +#include + +struct hw_handler_type; +struct hw_handler { + struct hw_handler_type *type; + void *context; +}; + +/* + * 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_status_fn) (struct hw_handler *hwh, + status_type_t type, + char *result, unsigned int maxlen); + +/* Information about a hardware handler type */ +struct hw_handler_type { + char *name; + struct module *module; + + hwh_ctr_fn ctr; + hwh_dtr_fn dtr; + + hwh_status_fn status; +}; + +/* Register a hardware handler */ +int dm_register_hw_handler(struct hw_handler_type *type); + +/* Unregister a hardware handler */ +int dm_unregister_hw_handler(struct hw_handler_type *type); + +/* Returns a registered hardware handler type */ +struct hw_handler_type *dm_get_hw_handler(const char *name); + +/* Releases a hardware handler */ +void dm_put_hw_handler(struct hw_handler_type *hwht); + +#endif