From fd36a66ccc9c24762dd014aeba264a851e4adee4 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 14 Sep 2001 09:45:35 +0000 Subject: [PATCH] Changes to device handling; o Only one list of block devices for all tables o Locking to ensure that block devices only get opened once o Block device handling is now in dm-blkdev.c o We open block devices when we create the tables and hold them open until the table is destroyed (this prevents the module for the device being unloaded after table parsing and before the table is used) o We compute the hardsect size when the table is created rather than when someone requests it. Still to fix/change: o Probably want to hash the device lists in dm-blkdev.c and also remove refs to struct dm_bdev outside this file. o Need to ensure that hardsect_size doesn't change when new tables are swapped in (maybe this ought to be a per volume parameter and the tables will only parse if they match the value for the volume?). Things are changing fast here, so if you want a stable version of thic code try checking out yesterdays. --- driver/device-mapper/device-mapper.h | 32 +++++-- driver/device-mapper/dm-blkdev.c | 8 +- driver/device-mapper/dm-linear.c | 43 +++++---- driver/device-mapper/dm-table.c | 110 +---------------------- driver/device-mapper/dm.h | 31 +------ driver/device-mapper/patches/00_makefile | 4 +- 6 files changed, 62 insertions(+), 166 deletions(-) diff --git a/driver/device-mapper/device-mapper.h b/driver/device-mapper/device-mapper.h index 257dac566..bf28e49f8 100644 --- a/driver/device-mapper/device-mapper.h +++ b/driver/device-mapper/device-mapper.h @@ -64,14 +64,34 @@ struct target_type { int dm_register_target(struct target_type *t); int dm_unregister_target(struct target_type *t); +struct dm_bdev { + struct list_head list; + struct block_device *bdev; + int use; +}; -/* contructors should call this to make sure any - * destination devices are handled correctly - * (ie. opened/closed). +struct dm_bdev *dm_blkdev_get(const char *path); +void dm_blkdev_put(struct dm_bdev *); + +static inline kdev_t dm_bdev2rdev(struct dm_bdev *d) +{ + return to_kdev_t(d->bdev->bd_dev); +} + +struct text_region { + const char *b; + const char *e; +}; + +/* + * These may be useful for people writing target + * types. */ -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); +int dm_get_number(struct text_region *txt, unsigned int *n); +int dm_get_line(struct text_region *txt, struct text_region *line); +int dm_get_word(struct text_region *txt, struct text_region *word); +void dm_txt_copy(char *dest, size_t max, struct text_region *txt); +void dm_eat_space(struct text_region *txt); #endif /* DEVICE_MAPPER_H */ diff --git a/driver/device-mapper/dm-blkdev.c b/driver/device-mapper/dm-blkdev.c index ecf4e19db..6fdf1b742 100644 --- a/driver/device-mapper/dm-blkdev.c +++ b/driver/device-mapper/dm-blkdev.c @@ -80,7 +80,6 @@ static struct dm_bdev *dm_get_device(struct block_device *bdev) n->bdev = bdev; n->use = 1; - n->flags = 0; down(&bdev_sem); read_lock(&bdev_lock); @@ -109,12 +108,11 @@ static struct dm_bdev *dm_get_device(struct block_device *bdev) return d; } -struct dm_bdev *dm_blkdev_get(const char *name) +struct dm_bdev *dm_blkdev_get(const char *path) { struct dm_bdev *d; struct nameidata nd; struct inode *inode; - int rv; if (!path_init(path, LOOKUP_FOLLOW, &nd)) return ERR_PTR(-EINVAL); @@ -128,7 +126,7 @@ struct dm_bdev *dm_blkdev_get(const char *name) goto out; } - d = dm_get_device(inode->i_bdev->bd_dev); + d = dm_get_device(inode->i_bdev); out: path_release(&nd); @@ -165,4 +163,6 @@ void dm_blkdev_put(struct dm_bdev *d) dm_blkdev_drop(d); } +EXPORT_SYMBOL(dm_blkdev_get); +EXPORT_SYMBOL(dm_blkdev_put); diff --git a/driver/device-mapper/dm-linear.c b/driver/device-mapper/dm-linear.c index 04aab2b0b..aec7a00f7 100644 --- a/driver/device-mapper/dm-linear.c +++ b/driver/device-mapper/dm-linear.c @@ -24,16 +24,18 @@ #include #include #include +#include #include -#include "dm.h" /* going away soon */ +#include "dm.h" /* * linear: maps a linear range of a device. */ struct linear_c { - kdev_t dev; + kdev_t rdev; long delta; /* FIXME: we need a signed offset type */ + struct dm_bdev *bdev; }; /* @@ -46,10 +48,11 @@ static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, { struct linear_c *lc; unsigned int start; - kdev_t dev; - int r; char path[256]; struct text_region word; + struct dm_bdev *bdev; + int rv = 0; + int hardsect_size; if (!dm_get_word(args, &word)) { fn("couldn't get device path", private); @@ -58,38 +61,45 @@ static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, dm_txt_copy(path, sizeof(path) - 1, &word); - if ((r = dm_table_lookup_device(path, &dev))) { + + bdev = dm_blkdev_get(path); + if (IS_ERR(bdev)) { fn("no such device", private); - return r; + return PTR_ERR(bdev); } if (!dm_get_number(args, &start)) { fn("destination start not given", private); - return -EINVAL; + rv = -EINVAL; + goto out_bdev_put; } if (!(lc = kmalloc(sizeof(lc), GFP_KERNEL))) { fn("couldn't allocate memory for linear context\n", private); - return -ENOMEM; + rv = -ENOMEM; + goto out_bdev_put; } - lc->dev = dev; + lc->rdev = dm_bdev2rdev(bdev); + lc->bdev = bdev; 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; - } + hardsect_size = get_hardsect_size(lc->rdev); + if (t->hardsect_size > hardsect_size); + t->hardsect_size = hardsect_size; *result = lc; return 0; + +out_bdev_put: + dm_blkdev_put(bdev); + return rv; } 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); + dm_blkdev_put(lc->bdev); kfree(c); } @@ -97,7 +107,7 @@ 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_rdev = lc->rdev; bh->b_rsector = bh->b_rsector + lc->delta; return 1; } @@ -138,4 +148,5 @@ module_exit(linear_exit); MODULE_AUTHOR("Joe Thornber "); MODULE_DESCRIPTION("Device Mapper: Linear mapping"); +MODULE_LICENSE("GPL"); diff --git a/driver/device-mapper/dm-table.c b/driver/device-mapper/dm-table.c index ed05ca155..ba5116db0 100644 --- a/driver/device-mapper/dm-table.c +++ b/driver/device-mapper/dm-table.c @@ -131,7 +131,8 @@ struct dm_table *dm_table_create(void) /* allocate a single nodes worth of targets to begin with */ - if (t && alloc_targets(t, KEYS_PER_NODE)) { + t->hardsect_size = PAGE_CACHE_SIZE; + if (alloc_targets(t, KEYS_PER_NODE)) { kfree(t); t = 0; } @@ -161,19 +162,6 @@ void dm_table_destroy(struct dm_table *t) } vfree(t->targets); - /* free the device list */ - if (t->devices) { - struct dev_list *d, *n; - - WARN("there are still devices present, someone isn't " - "calling dm_table_remove_device"); - - for (d = t->devices; d; d = n) { - n = d->next; - kfree(d); - } - } - kfree(t); } @@ -207,98 +195,6 @@ int dm_table_add_target(struct dm_table *t, offset_t high, return 0; } -/* - * convert a device path to a kdev_t. - */ -int dm_table_lookup_device(const char *path, kdev_t *d) -{ - int r; - struct nameidata nd; - struct inode *inode; - - if (!path_init(path, LOOKUP_FOLLOW, &nd)) - return 0; - - if ((r = path_walk(path, &nd))) - goto bad; - - inode = nd.dentry->d_inode; - if (!inode) { - r = -ENOENT; - goto bad; - } - - if (!S_ISBLK(inode->i_mode)) { - r = -EINVAL; - goto bad; - } - - *d = inode->i_bdev->bd_dev; - - bad: - path_release(&nd); - return r; -} - -/* - * see if we've already got a device in the list. - */ -static struct dev_list **find_device(struct dev_list **d, kdev_t dev) -{ - while (*d) { - if ((*d)->dev == dev) - break; - - d = &(*d)->next; - } - - return d; -} - -/* - * add a device to the list, or just increment the - * usage count if it's already present. - */ -int dm_table_add_device(struct dm_table *t, kdev_t dev) -{ - struct dev_list *d; - - d = *find_device(&t->devices, dev); - if (!d) { - d = kmalloc(sizeof(*d), GFP_KERNEL); - if (!d) - return -ENOMEM; - - d->dev = dev; - atomic_set(&d->count, 0); - d->next = t->devices; - t->devices = d; - } - atomic_inc(&d->count); - - return 0; -} - -/* - * decrement a devices use count and remove it if - * neccessary. - */ -void dm_table_remove_device(struct dm_table *t, kdev_t dev) -{ - struct dev_list **d = find_device(&t->devices, dev); - - if (!*d) { - WARN("asked to remove a device that isn't present"); - return; - } - - if (atomic_dec_and_test(&(*d)->count)) { - struct dev_list *node = *d; - *d = (*d)->next; - kfree(node); - } -} - /* * builds the btree to index the map */ @@ -324,5 +220,3 @@ int dm_table_complete(struct dm_table *t) return 0; } - -EXPORT_SYMBOL(dm_table_add_device); diff --git a/driver/device-mapper/dm.h b/driver/device-mapper/dm.h index 9893094e7..cf77a543b 100644 --- a/driver/device-mapper/dm.h +++ b/driver/device-mapper/dm.h @@ -145,18 +145,6 @@ enum { DM_ACTIVE, /* device is running */ }; -/* - * devices that a metadevice uses and hence should - * open/close - */ -struct dev_list { - kdev_t dev; - atomic_t count; - - struct block_device *bd; - struct dev_list *next; -}; - /* * io that had to be deferred while we were * suspended @@ -184,13 +172,11 @@ struct dm_table { int counts[MAX_DEPTH]; /* in nodes */ offset_t *index[MAX_DEPTH]; + int hardsect_size; int num_targets; int num_allocated; offset_t *highs; struct target *targets; - - /* a list of devices used by this table */ - struct dev_list *devices; }; /* @@ -245,28 +231,13 @@ int dm_table_add_target(struct dm_table *t, offset_t high, struct target_type *type, void *private); int dm_table_complete(struct dm_table *t); - /* dm-parse.c */ -struct text_region { - const char *b; - const char *e; -}; - typedef int (*extract_line_fn)(struct text_region *line, void *private); struct dm_table *dm_parse(extract_line_fn line_fn, void *line_private, dm_error_fn err_fn, void *err_private); -/* - * These may be useful for people writing target - * types. - */ -int dm_get_number(struct text_region *txt, unsigned int *n); -int dm_get_line(struct text_region *txt, struct text_region *line); -int dm_get_word(struct text_region *txt, struct text_region *word); -void dm_txt_copy(char *dest, size_t max, struct text_region *txt); -void dm_eat_space(struct text_region *txt); static inline int dm_empty_tok(struct text_region *txt) { diff --git a/driver/device-mapper/patches/00_makefile b/driver/device-mapper/patches/00_makefile index b606c4b94..52fbd93fc 100644 --- a/driver/device-mapper/patches/00_makefile +++ b/driver/device-mapper/patches/00_makefile @@ -1,10 +1,10 @@ --- 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 ++++ linux/drivers/md/Makefile Fri Sep 14 09:12:39 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-fs.o -+dm-mod-objs := dm.o dm-table.o dm-target.o dm-fs.o dm-parse.o ++dm-mod-objs := dm.o dm-table.o dm-target.o dm-fs.o dm-parse.o dm-blkdev.o # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise