diff --git a/driver/device-mapper/device-mapper.h b/driver/device-mapper/device-mapper.h index efcfc689a..257dac566 100644 --- a/driver/device-mapper/device-mapper.h +++ b/driver/device-mapper/device-mapper.h @@ -28,8 +28,6 @@ #ifndef DEVICE_MAPPER_H #define DEVICE_MAPPER_H -#ifdef __KERNEL__ - #include /* FIXME: Use value from local range for now, for co-existence with LVM 1 */ @@ -50,8 +48,21 @@ typedef int (*dm_ctr_fn)(struct dm_table *t, typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); typedef int (*dm_map_fn)(struct buffer_head *bh, void *context); -int dm_register_target(const char *name, dm_ctr_fn ctr, dm_dtr_fn dtr, - dm_map_fn map); +/* + * information about a target type + */ +struct target_type { + struct list_head list; + const char *name; + long use; + struct module *module; + dm_ctr_fn ctr; + dm_dtr_fn dtr; + dm_map_fn map; +}; + +int dm_register_target(struct target_type *t); +int dm_unregister_target(struct target_type *t); /* contructors should call this to make sure any @@ -62,8 +73,7 @@ int dm_table_lookup_device(const char *path, kdev_t *d); int dm_table_add_device(struct dm_table *t, kdev_t dev); void dm_table_remove_device(struct dm_table *t, kdev_t dev); -#endif -#endif +#endif /* DEVICE_MAPPER_H */ /* * Local variables: diff --git a/driver/device-mapper/dm-linear.c b/driver/device-mapper/dm-linear.c new file mode 100644 index 000000000..588d8813e --- /dev/null +++ b/driver/device-mapper/dm-linear.c @@ -0,0 +1,140 @@ +/* + * dm-linear.c + * + * Copyright (C) 2001 Sistina Software + * + * This software 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, or (at + * your option) any later version. + * + * This software 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "dm.h" /* going away soon */ + +/* + * linear: maps a linear range of a device. + */ +struct linear_c { + kdev_t dev; + long delta; /* FIXME: we need a signed offset type */ +}; + +/* + * construct a linear mapping. + * + */ +static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, + struct text_region *args, void **result, + dm_error_fn fn, void *private) +{ + struct linear_c *lc; + unsigned int start; + kdev_t dev; + int r; + char path[256]; + struct text_region word; + + if (!dm_get_word(args, &word)) { + fn("couldn't get device path", private); + return -EINVAL; + } + + dm_txt_copy(path, sizeof(path) - 1, &word); + + if ((r = dm_table_lookup_device(path, &dev))) { + fn("no such device", private); + return r; + } + + if (!dm_get_number(args, &start)) { + fn("destination start not given", private); + return -EINVAL; + } + + if (!(lc = kmalloc(sizeof(lc), GFP_KERNEL))) { + fn("couldn't allocate memory for linear context\n", private); + return -ENOMEM; + } + + lc->dev = dev; + lc->delta = (int) start - (int) b; + + if ((r = dm_table_add_device(t, lc->dev))) { + fn("failed to add destination device to list", private); + kfree(lc); + return r; + } + + *result = lc; + return 0; +} + +static void linear_dtr(struct dm_table *t, void *c) +{ + struct linear_c *lc = (struct linear_c *) c; + dm_table_remove_device(t, lc->dev); + kfree(c); +} + +static int linear_map(struct buffer_head *bh, void *context) +{ + struct linear_c *lc = (struct linear_c *) context; + + bh->b_rdev = lc->dev; + bh->b_rsector = bh->b_rsector + lc->delta; + return 1; +} + +static struct target_type linear_target = { + name: "linear", + ctr: linear_ctr, + dtr: linear_dtr, + map: linear_map, +}; + +static int __init linear_init(void) +{ + int rv; + + rv = dm_register_target(&linear_target); + if (rv < 0) { + printk(KERN_ERR "Device mapper: Linear: register failed %d\n", rv); + } + + return rv; +} + +static void __exit linear_exit(void) +{ + int rv; + + rv = dm_unregister_target(&linear_target); + + if (rv < 0) { + printk(KERN_ERR "Device mapper: Linear: unregister failed %d\n", rv); + } +} + +module_init(linear_init); +module_exit(linear_exit); + +MODULE_AUTHOR("Joe Thornber "); +MODULE_DESCRIPTION("Device Mapper: Linear mapping"); + diff --git a/driver/device-mapper/dm-target.c b/driver/device-mapper/dm-target.c index b10662742..90770ab84 100644 --- a/driver/device-mapper/dm-target.c +++ b/driver/device-mapper/dm-target.c @@ -24,62 +24,97 @@ */ #include "dm.h" +#include -static struct target_type *_targets; -static spinlock_t _lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(dm_targets); +static rwlock_t dm_targets_lock = RW_LOCK_UNLOCKED; -struct target_type *__get_target(const char *name) -{ - struct target_type *t; - for (t = _targets; t && strcmp(t->name, name); t = t->next) - ; - return t; -} +#define DM_MOD_NAME_SIZE 32 struct target_type *dm_get_target_type(const char *name) { + struct list_head *tmp, *head; struct target_type *t; + int try = 0; - spin_lock(&_lock); - t = __get_target(name); - spin_unlock(&_lock); + /* Length check for strcat() below */ + if (strlen(name) > (DM_MOD_NAME_SIZE - 4)) + return NULL; - return t; -} +try_again: + read_lock(&dm_targets_lock); + tmp = head = &dm_targets; + for(;;) { + tmp = tmp->next; + if (tmp == head) + break; + t = list_entry(tmp, struct target_type, list); + if (strcmp(name, t->name) == 0) { + if (t->use == 0 && t->module) + __MOD_INC_USE_COUNT(t->module); + t->use++; + read_unlock(&dm_targets_lock); + return t; + } + } + read_unlock(&dm_targets_lock); -/* - * register a new target_type. - */ -int dm_register_target(const char *name, dm_ctr_fn ctr, - dm_dtr_fn dtr, dm_map_fn map) -{ - struct target_type *t = - kmalloc(sizeof(*t) + strlen(name) + 1, GFP_KERNEL); - - if (!t) - return -ENOMEM; - - spin_lock(&_lock); - if (__get_target(name)) { - WARN("mapper(%s) already registered\n", name); - spin_unlock(&_lock); - return -1; /* FIXME: what's a good return value ? */ + if (try++ == 0) { + char module_name[DM_MOD_NAME_SIZE] = "dm-"; + /* strcat() is only safe due to length check above */ + strcat(module_name, name); + request_module(module_name); + goto try_again; } - t->name = (char *) (t + 1); - strcpy(t->name, name); - - t->ctr = ctr; - t->dtr = dtr; - t->map = map; - - t->next = _targets; - _targets = t; - - spin_unlock(&_lock); - return 0; + return NULL; } +void dm_put_target_type(struct target_type *t) +{ + read_lock(&dm_targets_lock); + if (--t->use == 0 && t->module) + __MOD_DEC_USE_COUNT(t->module); + if (t->use < 0) + BUG(); + read_unlock(&dm_targets_lock); +} + +int dm_register_target(struct target_type *t) +{ + struct list_head *tmp, *head; + struct target_type *t2; + int rv = 0; + write_lock(&dm_targets_lock); + tmp = head = &dm_targets; + for(;;) { + if (tmp == head) + break; + t2 = list_entry(tmp, struct target_type, list); + if (strcmp(t->name, t2->name) != 0) + continue; + rv = -EEXIST; + break; + } + if (rv == 0) + list_add(&t->list, &dm_targets); + write_unlock(&dm_targets_lock); + return rv; +} + +int dm_unregister_target(struct target_type *t) +{ + int rv = -ETXTBSY; + + write_lock(&dm_targets_lock); + if (t->use == 0) { + list_del(&t->list); + rv = 0; + } + write_unlock(&dm_targets_lock); + + return rv; +} /* * io-err: always fails an io, useful for bringing @@ -105,96 +140,19 @@ static int io_err_map(struct buffer_head *bh, void *context) return 0; } -/* - * linear: maps a linear range of a device. - */ -struct linear_c { - kdev_t dev; - int delta; /* FIXME: we need a signed offset type */ +static struct target_type error_target = { + name: "error", + ctr: io_err_ctr, + dtr: io_err_dtr, + map: io_err_map }; -/* - * construct a linear mapping. - * - */ -static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, - struct text_region *args, void **result, - dm_error_fn fn, void *private) -{ - struct linear_c *lc; - unsigned int start; - kdev_t dev; - int r; - char path[256]; - struct text_region word; - if (!dm_get_word(args, &word)) { - fn("couldn't get device path", private); - return -EINVAL; - } - - dm_txt_copy(path, sizeof(path) - 1, &word); - - if ((r = dm_table_lookup_device(path, &dev))) { - fn("no such device", private); - return r; - } - - if (!dm_get_number(args, &start)) { - fn("destination start not given", private); - return -EINVAL; - } - - if (!(lc = kmalloc(sizeof(lc), GFP_KERNEL))) { - fn("couldn't allocate memory for linear context\n", private); - return -ENOMEM; - } - - lc->dev = dev; - lc->delta = (int) start - (int) b; - - if ((r = dm_table_add_device(t, lc->dev))) { - fn("failed to add destination device to list", private); - kfree(lc); - return r; - } - - *result = lc; - return 0; -} - -static void linear_dtr(struct dm_table *t, void *c) -{ - struct linear_c *lc = (struct linear_c *) c; - dm_table_remove_device(t, lc->dev); - kfree(c); -} - -static int linear_map(struct buffer_head *bh, void *context) -{ - struct linear_c *lc = (struct linear_c *) context; - - bh->b_rdev = lc->dev; - bh->b_rsector = bh->b_rsector + lc->delta; - return 1; -} - -/* - * registers io-err and linear targets - */ int dm_target_init(void) { - int ret; - -#define xx(n, fn) \ - if ((ret = dm_register_target(n, \ - fn ## _ctr, fn ## _dtr, fn ## _map) < 0)) return ret - - xx("io-err", io_err); - xx("linear", linear); -#undef xx - - return 0; + return dm_register_target(&error_target); } EXPORT_SYMBOL(dm_register_target); +EXPORT_SYMBOL(dm_unregister_target); + diff --git a/driver/device-mapper/dm.h b/driver/device-mapper/dm.h index e12a01b00..9893094e7 100644 --- a/driver/device-mapper/dm.h +++ b/driver/device-mapper/dm.h @@ -131,6 +131,7 @@ #include #include #include +#include #define MAX_DEPTH 16 #define NODE_SIZE L1_CACHE_BYTES @@ -166,18 +167,6 @@ struct deferred_io { struct deferred_io *next; }; -/* - * information about a target type - */ -struct target_type { - char *name; - dm_ctr_fn ctr; - dm_dtr_fn dtr; - dm_map_fn map; - - struct target_type *next; -}; - /* * btree leaf, these do the actual mapping */ @@ -231,9 +220,9 @@ extern struct block_device_operations dm_blk_dops; /* dm-target.c */ -int dm_target_init(void); struct target_type *dm_get_target_type(const char *name); - +void dm_put_target_type(struct target_type *t); +int dm_target_init(void); /* dm.c */ struct mapped_device *dm_find_by_name(const char *name); diff --git a/driver/device-mapper/patches/00_config b/driver/device-mapper/patches/00_config index 7a6a4eb26..0d64c4dd8 100644 --- a/driver/device-mapper/patches/00_config +++ b/driver/device-mapper/patches/00_config @@ -1,10 +1,10 @@ ---- linux/drivers/md/Config.in.orig Tue Aug 21 14:18:30 2001 -+++ linux/drivers/md/Config.in Tue Aug 21 14:19:08 2001 -@@ -14,4 +14,6 @@ +--- linux-2.4.9-ac5/drivers/md/Config.in Sun Mar 11 13:33:24 2001 ++++ linux/drivers/md/Config.in Thu Sep 13 18:02:17 2001 +@@ -13,5 +13,7 @@ + dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD - +dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD -+ ++dep_tristate ' Device mapper linear target' CONFIG_BLK_DEV_DM_LINEAR $CONFIG_BLK_DEV_DM + endmenu - diff --git a/driver/device-mapper/patches/00_makefile b/driver/device-mapper/patches/00_makefile index 36a59f019..ae58807f2 100644 --- a/driver/device-mapper/patches/00_makefile +++ b/driver/device-mapper/patches/00_makefile @@ -1,19 +1,19 @@ -diff -ruNX /home/joe/packages/2.4/dontdiff linux/drivers/md/Makefile linux-dm/drivers/md/Makefile ---- linux/drivers/md/Makefile Fri Dec 29 22:07:22 2000 -+++ linux-dm/drivers/md/Makefile Thu Aug 30 13:51:44 2001 +--- linux-2.4.9-ac5/drivers/md/Makefile Sat Sep 1 16:24:46 2001 ++++ linux/drivers/md/Makefile Thu Sep 13 18:00:10 2001 @@ -7,6 +7,7 @@ export-objs := md.o xor.o list-multi := lvm-mod.o - lvm-mod-objs := lvm.o lvm-snap.o + lvm-mod-objs := lvm.o lvm-snap.o lvm-fs.o +dm-mod-objs := dm.o dm-table.o dm-target.o dm-fs.o # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise -@@ -19,8 +20,12 @@ +@@ -19,8 +20,14 @@ obj-$(CONFIG_MD_RAID5) += raid5.o xor.o obj-$(CONFIG_BLK_DEV_MD) += md.o obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o +obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o ++obj-$(CONFIG_BLK_DEV_DM_LINEAR) += dm-linear.o include $(TOPDIR)/Rules.make @@ -22,3 +22,4 @@ diff -ruNX /home/joe/packages/2.4/dontdiff linux/drivers/md/Makefile linux-dm/dr + +dm-mod.o: $(dm-mod-objs) + $(LD) -r -o $@ $(dm-mod-objs) ++