diff --git a/driver/device-mapper/device-mapper.h b/driver/device-mapper/device-mapper.h index 386572f9c..c110d9694 100644 --- a/driver/device-mapper/device-mapper.h +++ b/driver/device-mapper/device-mapper.h @@ -15,7 +15,8 @@ #ifndef DEVICE_MAPPER_H #define DEVICE_MAPPER_H -#include +#define DM_DIR "device-mapper" +#define DM_MAX_TYPE_NAME 16 struct dm_table; struct dm_dev; @@ -40,6 +41,7 @@ typedef char *(*dm_print_fn)(void *context); * (ie. opened/closed). */ int dm_table_get_device(struct dm_table *t, const char *path, + offset_t start, offset_t len, struct dm_dev **result); void dm_table_put_device(struct dm_table *table, struct dm_dev *d); @@ -59,19 +61,6 @@ struct target_type { int dm_register_target(struct target_type *t); int dm_unregister_target(struct target_type *t); -static inline char *next_token(char **p) -{ - static const char *delim = " \t"; - char *r; - - do { - r = strsep(p, delim); - } while(r && *r == 0); - - return r; -} - - #endif /* DEVICE_MAPPER_H */ /* diff --git a/driver/device-mapper/dm-ioctl.c b/driver/device-mapper/dm-ioctl.c new file mode 100644 index 000000000..66cae85fe --- /dev/null +++ b/driver/device-mapper/dm-ioctl.c @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include + +#include "dm.h" +#include + +static void free_params(struct dm_ioctl *p) +{ + vfree(p); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **result) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (!(dmi = vmalloc(tmp.data_size))) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) + return -EFAULT; + + *result = dmi; + return 0; +} + +/* + * check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int valid_str(char *str, void *end) +{ + while (((void *) str < end) && *str) + str++; + + return *str ? 0 : 1; +} + +static int first_target(struct dm_ioctl *a, void *end, + struct dm_target_spec **spec, char **params) +{ + *spec = (struct dm_target_spec *) (a + 1); + *params = (char *) (*spec + 1); + + return valid_str(*params, end); +} + +static int next_target(struct dm_target_spec *last, void *end, + struct dm_target_spec **spec, char **params) +{ + *spec = (struct dm_target_spec *) + (((unsigned char *) last) + last->next); + *params = (char *) (*spec + 1); + + return valid_str(*params, end); +} + +void err_fn(const char *message, void *private) +{ + printk(KERN_WARNING "%s\n", message); +} + +/* + * Checks to see if there's a gap in the table. + * Returns true iff there is a gap. + */ +static int gap(struct dm_table *table, struct dm_target_spec *spec) +{ + if (!table->num_targets) + return (spec->sector_start > 0) ? 1 : 0; + + if (spec->sector_start != table->highs[table->num_targets - 1] + 1) + return 1; + + return 0; +} + +static int populate_table(struct dm_table *table, struct dm_ioctl *args) +{ + int i = 0, r, first = 1; + struct dm_target_spec *spec; + char *params; + struct target_type *ttype; + void *context, *end; + offset_t high = 0; + + if (!args->target_count) { + WARN("No targets specified"); + return -EINVAL; + } + + end = ((void *) args) + args->data_size; + +#define PARSE_ERROR(msg) {err_fn(msg, NULL); return -EINVAL;} + + for (i = 0; i < args->target_count; i++) { + + r = first ? first_target(args, end, &spec, ¶ms) : + next_target(spec, end, &spec, ¶ms); + + if (!r) + PARSE_ERROR("unable to find target"); + + /* lookup the target type */ + if (!(ttype = dm_get_target_type(spec->target_type))) + PARSE_ERROR("unable to find target type"); + + if (gap(table, spec)) + PARSE_ERROR("gap in target ranges"); + + /* build the target */ + if (ttype->ctr(table, spec->sector_start, spec->length, params, + &context)) + PARSE_ERROR(context); + + /* add the target to the table */ + high = spec->sector_start + (spec->length - 1); + if (dm_table_add_target(table, high, ttype, context)) + PARSE_ERROR("internal error adding target to table"); + + first = 0; + } + +#undef PARSE_ERROR + + r = dm_table_complete(table); + return r; +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int info(const char *name, struct dm_ioctl *user) +{ + struct dm_ioctl param; + struct mapped_device *md = dm_get(name); + + if (!md) { + param.exists = 0; + goto out; + } + + param.data_size = 0; + strncpy(param.name, md->name, sizeof(param.name)); + param.exists = 1; + param.suspend = md->suspended; + param.open_count = md->use_count; + param.major = MAJOR(md->dev); + param.minor = MINOR(md->dev); + param.target_count = md->map->num_targets; + + out: + return copy_to_user(user, ¶m, sizeof(param)); +} + +static int create(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + struct dm_table *t; + + t = dm_table_create(); + r = PTR_ERR(t); + if (IS_ERR(t)) + goto bad; + + if ((r = populate_table(t, param))) + goto bad; + + md = dm_create(param->name, param->minor, t); + r = PTR_ERR(md); + if (IS_ERR(md)) + goto bad; + + if ((r = info(param->name, user))) { + dm_destroy(md); + goto bad; + } + + return 0; + + bad: + dm_table_destroy(t); + return r; +} + +static int remove(struct dm_ioctl *param) +{ + struct mapped_device *md = dm_get(param->name); + + if (!md) + return -ENXIO; + + return dm_destroy(md); +} + +static int suspend(struct dm_ioctl *param) +{ + struct mapped_device *md = dm_get(param->name); + + if (!md) + return -ENXIO; + + return param->suspend ? dm_suspend(md) : dm_resume(md); +} + +static int reload(struct dm_ioctl *param) +{ + int r; + struct mapped_device *md = dm_get(param->name); + struct dm_table *t; + + if (!md) + return -ENXIO; + + t = dm_table_create(); + if (IS_ERR(t)) + return PTR_ERR(t); + + if ((r = populate_table(t, param))) { + dm_table_destroy(t); + return r; + } + + if ((r = dm_swap_table(md, t))) { + dm_table_destroy(t); + return r; + } + + return 0; +} + +static int ctl_open(struct inode *inode, struct file *file) +{ + /* only root can open this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + return 0; +} + +static int ctl_close(struct inode *inode, struct file *file) +{ + return 0; +} + + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) +{ + int r; + struct dm_ioctl *p; + + if ((r = copy_params((struct dm_ioctl *) a, &p))) + return r; + + switch (command) { + case DM_CREATE: + r = create(p, (struct dm_ioctl *) a); + break; + + case DM_REMOVE: + r = remove(p); + break; + + case DM_SUSPEND: + r = suspend(p); + break; + + case DM_RELOAD: + r = reload(p); + break; + + case DM_INFO: + r = info(p->name, (struct dm_ioctl *) a); + break; + + default: + WARN("dm_ctl_ioctl: unknown command 0x%x\n", command); + r = -EINVAL; + } + + free_params(p); + return r; +} + + +static struct file_operations _ctl_fops = { + open: ctl_open, + release: ctl_close, + ioctl: ctl_ioctl, + owner: THIS_MODULE, +}; + + +static devfs_handle_t _ctl_handle; + +int dm_interface_init(void) +{ + int r; + + if ((r = devfs_register_chrdev(DM_CHAR_MAJOR, DM_DIR, + &_ctl_fops)) < 0) { + WARN("devfs_register_chrdev failed for dm control dev"); + return -EIO; + } + + _ctl_handle = devfs_register(0 , DM_DIR "/control", 0, + DM_CHAR_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &_ctl_fops, NULL); + + return r; +} + +void dm_interface_exit(void) +{ + // FIXME: remove control device + + if (devfs_unregister_chrdev(DM_CHAR_MAJOR, DM_DIR) < 0) + WARN("devfs_unregister_chrdev failed for dm control device"); +} + diff --git a/driver/device-mapper/dm-ioctl.h b/driver/device-mapper/dm-ioctl.h new file mode 100644 index 000000000..4f746a2fa --- /dev/null +++ b/driver/device-mapper/dm-ioctl.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#ifndef _DM_IOCTL_H +#define _DM_IOCTL_H + +#include "device-mapper.h" + +/* + * Implements a traditional ioctl interface to the + * device mapper. Yuck. + */ + +struct dm_target_spec { + int32_t status; /* used when reading from kernel only */ + unsigned long long sector_start; + unsigned long long length; + + char target_type[DM_MAX_TYPE_NAME]; + + unsigned long next; /* offset in bytes to next target_spec */ + + /* + * Parameter string starts immediately + * after this object. Be careful to add + * padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +struct dm_ioctl { + unsigned long data_size; /* the size of this structure */ + char name[DM_NAME_LEN]; + + int exists; /* out */ + int suspend; /* in/out */ + int open_count; /* out */ + int major; /* out */ + int minor; /* in/out */ + + int target_count; /* in/out */ +}; + +/* FIXME: find own numbers, 109 is pinched from LVM */ +#define DM_IOCTL 0xfd +#define DM_CHAR_MAJOR 124 + +#define DM_CREATE _IOWR(DM_IOCTL, 0x00, struct dm_ioctl) +#define DM_REMOVE _IOW(DM_IOCTL, 0x01, struct dm_ioctl) +#define DM_SUSPEND _IOW(DM_IOCTL, 0x02, struct dm_ioctl) +#define DM_RELOAD _IOWR(DM_IOCTL, 0x03, struct dm_ioctl) +#define DM_INFO _IOWR(DM_IOCTL, 0x04, struct dm_ioctl) + +#endif diff --git a/driver/device-mapper/dm-linear.c b/driver/device-mapper/dm-linear.c index 322bef1c7..bd11dd816 100644 --- a/driver/device-mapper/dm-linear.c +++ b/driver/device-mapper/dm-linear.c @@ -24,6 +24,18 @@ struct linear_c { struct dm_dev *dev; }; +static inline char *next_token(char **p) +{ + static const char *delim = " \t"; + char *r; + + do { + r = strsep(p, delim); + } while(r && *r == 0); + + return r; +} + /* * construct a linear mapping. * @@ -55,7 +67,7 @@ static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, goto bad; *context = "Cannot get target device"; - r = dm_table_get_device(t, path, &lc->dev); + r = dm_table_get_device(t, path, start, l, &lc->dev); if (r) goto bad_free; diff --git a/driver/device-mapper/dm-stripe.c b/driver/device-mapper/dm-stripe.c new file mode 100644 index 000000000..d1284116f --- /dev/null +++ b/driver/device-mapper/dm-stripe.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dm.h" + +struct stripe { + struct dm_dev *dev; + offset_t physical_start; +}; + +struct stripe_c { + offset_t logical_start; + uint32_t stripes; + + /* The size of this target / num. stripes */ + uint32_t stripe_width; + + /* eg, we stripe in 64k chunks */ + uint32_t chunk_shift; + offset_t chunk_mask; + + struct stripe stripe[0]; +}; + + +static inline struct stripe_c *alloc_context(int stripes) +{ + size_t len = sizeof(struct stripe_c) + + (sizeof(struct stripe) * stripes); + return kmalloc(len, GFP_KERNEL); +} + +/* + * parses a single pair. + */ +static int get_stripe(struct dm_table *t, struct stripe_c *sc, + int stripe, char *args) +{ + int n, r; + char path[256]; /* FIXME: buffer overrun risk */ + unsigned long start; + + if (sscanf(args, "%s %lu %n", path, &start, &n) != 2) + return -EINVAL; + + if ((r = dm_table_get_device(t, path, start, sc->stripe_width, + &sc->stripe[stripe].dev))) + return -ENXIO; + + sc->stripe[stripe].physical_start = start; + return n; +} + +/* + * construct a striped mapping. + * [ ]+ + */ +static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, + char *args, void **context) +{ + struct stripe_c *sc; + uint32_t stripes; + uint32_t chunk_size; + int n, i; + + *context = "couldn't parse "; + if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) { + return -EINVAL; + } + + *context = "target length is not divisable by the number of stripes"; + if (l % stripes) { + return -EINVAL; + } + + *context = "couldn't allocate memory for striped context"; + if (!(sc = alloc_context(stripes))) { + return -ENOMEM; + } + + sc->logical_start = b; + sc->stripes = stripes; + sc->stripe_width = l / stripes; + + /* + * chunk_size is a power of two. We only + * that power and the mask. + */ + *context = "invalid chunk size"; + if (!chunk_size) { + return -EINVAL; + } + + sc->chunk_mask = chunk_size - 1; + for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) + chunk_size >>= 1; + sc->chunk_shift--; + + /* + * Get the stripe destinations. + */ + for (i = 0; i < stripes; i++) { + args += n; + n = get_stripe(t, sc, i, args); + + *context = "couldn't parse stripe destination"; + if (n < 0) { + kfree(sc); + return n; + } + } + + + *context = sc; + return 0; +} + +static void stripe_dtr(struct dm_table *t, void *c) +{ + unsigned int i; + struct stripe_c *sc = (struct stripe_c *) c; + + for (i = 0; i < sc->stripes; i++) + dm_table_put_device(t, sc->stripe[i].dev); + + kfree(sc); +} + +static int stripe_map(struct buffer_head *bh, int rw, void *context) +{ + struct stripe_c *sc = (struct stripe_c *) context; + + offset_t offset = bh->b_rsector - sc->logical_start; + uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift); + uint32_t stripe = chunk % sc->stripes; /* 32bit modulus */ + chunk = chunk / sc->stripes; + + bh->b_rdev = sc->stripe[stripe].dev->dev; + bh->b_rsector = sc->stripe[stripe].physical_start + + (chunk << sc->chunk_shift) + + (offset & sc->chunk_mask); + return 1; +} + +static struct target_type stripe_target = { + name: "striped", + module: THIS_MODULE, + ctr: stripe_ctr, + dtr: stripe_dtr, + map: stripe_map, +}; + +static int __init stripe_init(void) +{ + int r; + + if ((r = dm_register_target(&stripe_target)) < 0) + WARN("linear target register failed"); + + return r; +} + +static void __exit stripe_exit(void) +{ + if (dm_unregister_target(&stripe_target)) + WARN("striped target unregister failed"); +} + +module_init(stripe_init); +module_exit(stripe_exit); + +MODULE_AUTHOR("Joe Thornber "); +MODULE_DESCRIPTION("Device Mapper: Striped mapping"); +MODULE_LICENSE("GPL"); diff --git a/driver/device-mapper/dm-table.c b/driver/device-mapper/dm-table.c index 24052fb6c..f0a350bc8 100644 --- a/driver/device-mapper/dm-table.c +++ b/driver/device-mapper/dm-table.c @@ -1,19 +1,14 @@ /* - * dm-table.c - * * Copyright (C) 2001 Sistina Software (UK) Limited. * * This file is released under the GPL. */ -/* - * Changelog - * - * 16/08/2001 - First version [Joe Thornber] - */ - #include "dm.h" +#include + + /* ceiling(n / size) * size */ static inline ulong round_up(ulong n, ulong size) { @@ -96,6 +91,7 @@ static int alloc_targets(struct dm_table *t, int num) memcpy(n_targets, t->targets, sizeof(*n_targets) * n); } + memset(n_highs + n , -1, sizeof(*n_highs) * (num - n)); vfree(t->highs); t->num_allocated = num; @@ -110,7 +106,7 @@ struct dm_table *dm_table_create(void) struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO); if (!t) - return 0; + return ERR_PTR(-ENOMEM); memset(t, 0, sizeof(*t)); INIT_LIST_HEAD(&t->devices); @@ -119,7 +115,7 @@ struct dm_table *dm_table_create(void) begin with */ if (alloc_targets(t, KEYS_PER_NODE)) { kfree(t); - t = 0; + t = ERR_PTR(-ENOMEM); } return t; @@ -144,12 +140,14 @@ void dm_table_destroy(struct dm_table *t) if (t->depth >= 2) vfree(t->index[t->depth - 2]); - /* free the targets */ for (i = 0; i < t->num_targets; i++) { struct target *tgt = &t->targets[i]; + if (tgt->type->dtr) tgt->type->dtr(t, tgt->private); + + dm_put_target_type(t->targets[i].type); } vfree(t->highs); @@ -218,21 +216,74 @@ static struct dm_dev *find_device(struct list_head *l, kdev_t dev) { struct list_head *tmp; - for (tmp = l->next; tmp != l; tmp = tmp->next) { - + list_for_each(tmp, l) { struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); if (dd->dev == dev) return dd; } + return NULL; +} + +/* + * open a device so we can use it as a map + * destination. + */ +static int open_dev(struct dm_dev *d) +{ + int err; + + if (d->bd) + BUG(); + + if (!(d->bd = bdget(kdev_t_to_nr(d->dev)))) + return -ENOMEM; + + if ((err = blkdev_get(d->bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE))) + return err; + return 0; } +/* + * close a device that we've been using. + */ +static void close_dev(struct dm_dev *d) +{ + if (!d->bd) + return; + + blkdev_put(d->bd, BDEV_FILE); + d->bd = NULL; +} + +/* + * If possible (ie. blk_size[major] is set), this + * checks an area of a destination device is + * valid. + */ +static int check_device_area(kdev_t dev, offset_t start, offset_t len) +{ + int *sizes; + offset_t dev_size; + + if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)])) + /* we don't know the device details, + * so give the benefit of the doubt */ + return 1; + + /* convert to 512-byte sectors */ + dev_size <<= 1; + + return ((start < dev_size) && (len <= (dev_size - start))); +} + /* * add a device to the list, or just increment the * usage count if it's already present. */ int dm_table_get_device(struct dm_table *t, const char *path, + offset_t start, offset_t len, struct dm_dev **result) { int r; @@ -251,14 +302,28 @@ int dm_table_get_device(struct dm_table *t, const char *path, dd->dev = dev; dd->bd = 0; + + if ((r = open_dev(dd))) { + kfree(dd); + return r; + } + atomic_set(&dd->count, 0); list_add(&dd->list, &t->devices); } atomic_inc(&dd->count); + + if (!check_device_area(dd->dev, start, len)) { + WARN("device '%s' not large enough for target", path); + dm_table_put_device(t, dd); + return -EINVAL; + } + *result = dd; return 0; } + /* * decrement a devices use count and remove it if * neccessary. @@ -266,6 +331,7 @@ int dm_table_get_device(struct dm_table *t, const char *path, void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) { if (atomic_dec_and_test(&dd->count)) { + close_dev(dd); list_del(&dd->list); kfree(dd); } @@ -307,7 +373,8 @@ static int setup_indexes(struct dm_table *t) /* set up internal nodes, bottom-up */ for (i = t->depth - 2, total = 0; i >= 0; i--) { - t->index[i] = indexes + (KEYS_PER_NODE * t->counts[i]); + t->index[i] = indexes; + indexes += (KEYS_PER_NODE * t->counts[i]); setup_btree_index(i, t); } diff --git a/driver/device-mapper/dm-target.c b/driver/device-mapper/dm-target.c index 662a7c8a8..1b885099a 100644 --- a/driver/device-mapper/dm-target.c +++ b/driver/device-mapper/dm-target.c @@ -1,15 +1,9 @@ /* - * dm-target.c - * * Copyright (C) 2001 Sistina Software (UK) Limited * * This file is released under the GPL. */ -/* - * 16/08/2001 - First Version [Joe Thornber] - */ - #include "dm.h" #include @@ -30,14 +24,14 @@ static inline struct tt_internal *__find_target_type(const char *name) struct list_head *tmp; struct tt_internal *ti; - for(tmp = _targets.next; tmp != &_targets; tmp = tmp->next) { - + list_for_each(tmp, &_targets) { ti = list_entry(tmp, struct tt_internal, list); + if (!strcmp(name, ti->tt.name)) return ti; } - return 0; + return NULL; } static struct tt_internal *get_target_type(const char *name) @@ -78,7 +72,7 @@ struct target_type *dm_get_target_type(const char *name) ti = get_target_type(name); } - return ti ? &ti->tt : 0; + return ti ? &ti->tt : NULL; } void dm_put_target_type(struct target_type *t) @@ -126,18 +120,24 @@ int dm_register_target(struct target_type *t) int dm_unregister_target(struct target_type *t) { - struct tt_internal *ti = (struct tt_internal *) t; - int rv = -ETXTBSY; + struct tt_internal *ti; write_lock(&_lock); - if (ti->use == 0) { - list_del(&ti->list); - kfree(ti); - rv = 0; + if (!(ti = __find_target_type(t->name))) { + write_unlock(&_lock); + return -EINVAL; } - write_unlock(&_lock); - return rv; + if (ti->use) { + write_unlock(&_lock); + return -ETXTBSY; + } + + list_del(&ti->list); + kfree(ti); + + write_unlock(&_lock); + return 0; } /* @@ -147,7 +147,7 @@ int dm_unregister_target(struct target_type *t) static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l, char *args, void **context) { - *context = 0; + *context = NULL; return 0; } diff --git a/driver/device-mapper/dm.c b/driver/device-mapper/dm.c index f0eca11fe..77657d388 100644 --- a/driver/device-mapper/dm.c +++ b/driver/device-mapper/dm.c @@ -1,35 +1,14 @@ /* - * device-mapper.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. - */ - -/* - * Changelog - * - * 14/08/2001 - First Version [Joe Thornber] + * This file is released under the GPL. */ #include "dm.h" -#include "dmfs.h" -#include +#include #include +#include #include /* we only need this for the lv_bmap struct definition, not happy */ @@ -37,10 +16,11 @@ #define MAX_DEVICES 64 #define DEFAULT_READ_AHEAD 64 +#define DEVICE_NAME "device-mapper" +static const char *_name = DEVICE_NAME; +static int _version[3] = {0, 1, 0}; static int major = 0; -const char *_name = "device-mapper"; -int _version[3] = {0, 1, 0}; struct io_hook { struct mapped_device *md; @@ -51,14 +31,14 @@ struct io_hook { void *context; }; -kmem_cache_t *_io_hook_cache; +static kmem_cache_t *_io_hook_cache; #define rl down_read(&_dev_lock) #define ru up_read(&_dev_lock) #define wl down_write(&_dev_lock) #define wu up_write(&_dev_lock) -struct rw_semaphore _dev_lock; +static struct rw_semaphore _dev_lock; static struct mapped_device *_devs[MAX_DEVICES]; /* block device arrays */ @@ -66,7 +46,6 @@ static int _block_size[MAX_DEVICES]; static int _blksize_size[MAX_DEVICES]; static int _hardsect_size[MAX_DEVICES]; -const char *_fs_dir = "device-mapper"; static devfs_handle_t _dev_dir; static int request(request_queue_t *q, int rw, struct buffer_head *bh); @@ -88,13 +67,13 @@ static int __init dm_init(void) if (!_io_hook_cache) goto err; - ret = dmfs_init(); - if (ret < 0) - goto err_kmem_cache_destroy; - ret = dm_target_init(); - if (ret) - goto err_kmem_cache_destroy; + if (ret < 0) + goto err_cache_free; + + ret = dm_interface_init(); + if (ret < 0) + goto err_cache_free; ret = devfs_register_blkdev(major, _name, &dm_blk_dops); if (ret < 0) @@ -109,11 +88,9 @@ static int __init dm_init(void) blksize_size[major] = _blksize_size; hardsect_size[major] = _hardsect_size; - ret = -EIO; - blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request); - _dev_dir = devfs_mk_dir(0, _fs_dir, NULL); + _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); printk(KERN_INFO "%s %d.%d.%d initialised\n", _name, _version[0], _version[1], _version[2]); @@ -121,7 +98,8 @@ static int __init dm_init(void) err_blkdev: printk(KERN_ERR "%s -- register_blkdev failed\n", _name); -err_kmem_cache_destroy: + dm_interface_exit(); +err_cache_free: kmem_cache_destroy(_io_hook_cache); err: return ret; @@ -129,11 +107,12 @@ err: static void __exit dm_exit(void) { - dmfs_exit(); + dm_interface_exit(); if (kmem_cache_destroy(_io_hook_cache)) WARN("it looks like there are still some io_hooks allocated"); + _io_hook_cache = NULL; if (devfs_unregister_blkdev(major, _name) < 0) printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name); @@ -147,45 +126,6 @@ static void __exit dm_exit(void) _version[0], _version[1], _version[2]); } -#ifdef CONFIG_HOTPLUG -static void dm_sbin_hotplug(struct mapped_device *md, char *action, int minor) -{ - int i; - char *argv[3]; - char *envp[7]; - char name[DM_NAME_LEN + 16]; - char dev_major[16], dev_minor[16]; - - if (!hotplug_path[0]) - return; - - if (!current->fs->root) - return; - - sprintf(name, "DMNAME=%s\n", md->name); - sprintf(dev_major, "MAJOR=%d", major); - sprintf(dev_minor, "MINOR=%d", minor); - - i = 0; - argv[i++] = hotplug_path; - argv[i++] = "devmap"; - argv[i] = 0; - - i = 0; - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - envp[i++] = name; - envp[i++] = action; - envp[i++] = dev_minor; - envp[i++] = dev_major; - envp[i] = 0; - - call_usermodehelper(argv[0], argv, envp); -} -#else -#define dm_sbin_hotplug(md, action, minor) do { } while(0) -#endif /* CONFIG_HOTPLUG */ - /* * block device functions */ @@ -200,7 +140,7 @@ static int dm_blk_open(struct inode *inode, struct file *file) wl; md = _devs[minor]; - if (!md || !is_active(md)) { + if (!md) { wu; return -ENXIO; } @@ -208,6 +148,7 @@ static int dm_blk_open(struct inode *inode, struct file *file) md->use_count++; wu; + MOD_INC_USE_COUNT; return 0; } @@ -230,11 +171,12 @@ static int dm_blk_close(struct inode *inode, struct file *file) md->use_count--; wu; + MOD_DEC_USE_COUNT; return 0; } /* In 512-byte units */ -#define VOLUME_SIZE(minor) (_block_size[(minor)] >> 1) +#define VOLUME_SIZE(minor) (_block_size[(minor)] << 1) static int dm_blk_ioctl(struct inode *inode, struct file *file, uint command, ulong a) @@ -358,7 +300,7 @@ static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) return -ENOMEM; wl; - if (test_bit(DM_ACTIVE, &md->state)) { + if (!md->suspended) { wu; return 0; } @@ -449,12 +391,19 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) rl; md = _devs[minor]; - if (!md || !md->map) + if (!md) goto bad; - /* if we're suspended we have to queue this io for later */ - if (!test_bit(DM_ACTIVE, &md->state)) { + /* + * If we're suspended we have to queue + * this io for later. + */ + while (md->suspended) { ru; + + if (rw == READA) + goto bad_no_lock; + r = queue_io(md, bh, rw); if (r < 0) @@ -463,7 +412,13 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) else if (r > 0) return 0; /* deferred successfully */ - rl; /* FIXME: there's still a race here */ + /* + * We're in a while loop, because + * someone could suspend before we + * get to the following read + * lock + */ + rl; } if (!__map_buffer(md, bh, rw, __find_node(md->map, bh))) @@ -501,8 +456,7 @@ static int do_bmap(kdev_t dev, unsigned long block, struct target *t; rl; - if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) || - !test_bit(DM_ACTIVE, &md->state)) { + if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) || md->suspended) { r = -ENXIO; goto out; } @@ -611,7 +565,7 @@ static struct mapped_device *alloc_dev(int minor) md->dev = MKDEV(major, minor); md->name[0] = '\0'; - md->state = 0; + md->suspended = 0; init_waitqueue_head(&md->wait); @@ -621,84 +575,9 @@ static struct mapped_device *alloc_dev(int minor) return md; } -/* - * open a device so we can use it as a map - * destination. - */ -static int open_dev(struct dm_dev *d) +static void free_dev(struct mapped_device *md) { - int err; - - if (d->bd) - BUG(); - - if (!(d->bd = bdget(kdev_t_to_nr(d->dev)))) - return -ENOMEM; - - if ((err = blkdev_get(d->bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE))) { - bdput(d->bd); - return err; - } - - return 0; -} - -/* - * close a device that we've been using. - */ -static void close_dev(struct dm_dev *d) -{ - if (!d->bd) - return; - - blkdev_put(d->bd, BDEV_FILE); - bdput(d->bd); - d->bd = 0; -} - -/* - * Close a list of devices. - */ -static void close_devices(struct list_head *devices) -{ - struct list_head *tmp; - - for (tmp = devices->next; tmp != devices; tmp = tmp->next) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - close_dev(dd); - } -} - -/* - * Open a list of devices. - */ -static int open_devices(struct list_head *devices) -{ - int r = 0; - struct list_head *tmp; - - for (tmp = devices->next; tmp != devices; tmp = tmp->next) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - if ((r = open_dev(dd))) - goto bad; - } - return 0; - - bad: - close_devices(devices); - return r; -} - - -struct mapped_device *dm_find_by_minor(int minor) -{ - struct mapped_device *md; - - rl; - md = _devs[minor]; - ru; - - return md; + kfree(md); } static int register_device(struct mapped_device *md) @@ -718,10 +597,95 @@ static int unregister_device(struct mapped_device *md) return 0; } +/* + * the hardsect size for a mapped device is the + * smallest hard sect size from the devices it + * maps onto. + */ +static int __find_hardsect_size(struct list_head *devices) +{ + int result = INT_MAX, size; + struct list_head *tmp; + + list_for_each(tmp, devices) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + size = get_hardsect_size(dd->dev); + if (size < result) + result = size; + } + return result; +} + +/* + * Bind a table to the device. + */ +static int __bind(struct mapped_device *md, struct dm_table *t) +{ + int minor = MINOR(md->dev); + + md->map = t; + + if (!t->num_targets) { + _block_size[minor] = 0; + _blksize_size[minor] = BLOCK_SIZE; + _hardsect_size[minor] = 0; + return 0; + } + + /* in k */ + _block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1; + + _blksize_size[minor] = BLOCK_SIZE; + _hardsect_size[minor] = __find_hardsect_size(&t->devices); + register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]); + + return 0; +} + +static void __unbind(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + + dm_table_destroy(md->map); + md->map = NULL; + + _block_size[minor] = 0; + _blksize_size[minor] = 0; + _hardsect_size[minor] = 0; +} + + +static struct mapped_device *__get_by_name(const char *name) +{ + int i; + + for (i = 0; i < MAX_DEVICES; i++) + if (_devs[i] && !strcmp(_devs[i]->name, name)) + return _devs[i]; + + return NULL; +} + +static int check_name(const char *name) +{ + if (strchr(name, '/')) { + WARN("invalid device name"); + return 0; + } + + if (__get_by_name(name)) { + WARN("device name already in use"); + return 0; + } + + return 1; +} + /* * constructor for a new device */ -struct mapped_device *dm_create(const char *name, int minor) +struct mapped_device *dm_create(const char *name, int minor, + struct dm_table *table) { int r; struct mapped_device *md; @@ -733,28 +697,47 @@ struct mapped_device *dm_create(const char *name, int minor) return ERR_PTR(-ENXIO); wl; + if (!check_name(name)) { + wu; + free_dev(md); + return ERR_PTR(-EINVAL); + } + strcpy(md->name, name); _devs[minor] = md; if ((r = register_device(md))) { wu; + free_dev(md); + return ERR_PTR(r); + } + + if ((r = __bind(md, table))) { + wu; + free_dev(md); return ERR_PTR(r); } wu; - dm_sbin_hotplug(md, "ACTION=create", minor); - return md; } /* - * destructor for the device. md->map is - * deliberately not destroyed, dm-fs should manage - * table objects. + * Destructor for the device. You cannot destroy + * a suspended device. */ -int dm_remove(struct mapped_device *md) +int dm_destroy(struct mapped_device *md) { int minor, r; + rl; + if (md->suspended || md->use_count) { + ru; + return -EPERM; + } + + fsync_dev(md->dev); + ru; + wl; if (md->use_count) { wu; @@ -768,131 +751,59 @@ int dm_remove(struct mapped_device *md) minor = MINOR(md->dev); _devs[minor] = 0; + __unbind(md); + wu; - dm_sbin_hotplug(md, "ACTION=remove", minor); - kfree(md); + free_dev(md); return 0; } -/* - * the hardsect size for a mapped device is the - * smallest hard sect size from the devices it - * maps onto. - */ -static int __find_hardsect_size(struct list_head *devices) -{ - int result = INT_MAX, size; - struct list_head *tmp; - - for (tmp = devices->next; tmp != devices; tmp = tmp->next) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); - size = get_hardsect_size(dd->dev); - if (size < result) - result = size; - } - return result; -} - -/* - * Bind a table to the device. - */ -void __bind(struct mapped_device *md, struct dm_table *t) -{ - int minor = MINOR(md->dev); - - md->map = t; - - /* in k */ - _block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1; - - _blksize_size[minor] = BLOCK_SIZE; - _hardsect_size[minor] = __find_hardsect_size(&t->devices); - register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]); -} /* * requeue the deferred buffer_heads by calling * generic_make_request. */ -static void __flush_deferred_io(struct mapped_device *md) +static void flush_deferred_io(struct deferred_io *c) { - struct deferred_io *c, *n; + struct deferred_io *n; - for (c = md->deferred, md->deferred = 0; c; c = n) { + while (c) { n = c->next; generic_make_request(c->rw, c->bh); free_deferred(c); + c = n; } } /* - * make the device available for use, if was - * previously suspended rather than newly created - * then all queued io is flushed + * Swap in a new table (destroying old one). */ -int dm_activate(struct mapped_device *md, struct dm_table *table) +int dm_swap_table(struct mapped_device *md, struct dm_table *table) { int r; - /* check that the mapping has at least been loaded. */ - if (!table->num_targets) - return -EINVAL; - wl; - /* you must be deactivated first */ - if (is_active(md)) { + /* device must be suspended */ + if (!md->suspended) { wu; return -EPERM; } - __bind(md, table); + __unbind(md); - if ((r = open_devices(&md->map->devices))) { + if ((r = __bind(md, table))) { wu; return r; } - set_bit(DM_ACTIVE, &md->state); - __flush_deferred_io(md); wu; return 0; } -/* - * Deactivate the device, the device must not be - * opened by anyone. - */ -int dm_deactivate(struct mapped_device *md) -{ - rl; - if (md->use_count) { - ru; - return -EPERM; - } - - fsync_dev(md->dev); - - ru; - - wl; - if (md->use_count) { - /* drat, somebody got in quick ... */ - wu; - return -EPERM; - } - - if (md->map) - close_devices(&md->map->devices); - md->map = NULL; - clear_bit(DM_ACTIVE, &md->state); - wu; - - return 0; -} /* * We need to be able to change a mapping table @@ -903,17 +814,17 @@ int dm_deactivate(struct mapped_device *md) * flush any in flight buffer_heads and ensure * that any further io gets deferred. */ -void dm_suspend(struct mapped_device *md) +int dm_suspend(struct mapped_device *md) { DECLARE_WAITQUEUE(wait, current); wl; - if (!is_active(md)) { + if (md->suspended) { wu; - return; + return -EINVAL; } - clear_bit(DM_ACTIVE, &md->state); + md->suspended = 1; wu; /* wait for all the pending io to flush */ @@ -931,10 +842,43 @@ void dm_suspend(struct mapped_device *md) current->state = TASK_RUNNING; remove_wait_queue(&md->wait, &wait); - close_devices(&md->map->devices); - - md->map = 0; wu; + + return 0; +} + +int dm_resume(struct mapped_device *md) +{ + struct deferred_io *def; + + wl; + if (!md->suspended) { + wu; + return -EINVAL; + } + + md->suspended = 0; + def = md->deferred; + md->deferred = NULL; + wu; + + flush_deferred_io(def); + + return 0; +} + +/* + * Search for a device with a particular name. + */ +struct mapped_device *dm_get(const char *name) +{ + struct mapped_device *md; + + rl; + md = __get_by_name(name); + ru; + + return md; } struct block_device_operations dm_blk_dops = { @@ -951,13 +895,8 @@ module_init(dm_init); module_exit(dm_exit); MODULE_PARM(major, "i"); -MODULE_PARM_DESC(major, "The major device number of the device-mapper"); +MODULE_PARM_DESC(major, "The major number of the device mapper"); MODULE_DESCRIPTION("device-mapper driver"); -MODULE_AUTHOR("Joe Thornber "); +MODULE_AUTHOR("Joe Thornber "); MODULE_LICENSE("GPL"); -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/driver/device-mapper/dm.h b/driver/device-mapper/dm.h index d16f3ece4..a15904908 100644 --- a/driver/device-mapper/dm.h +++ b/driver/device-mapper/dm.h @@ -124,13 +124,6 @@ #define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t)) #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) #define DM_NAME_LEN 128 -#define MAX_TARGET_LINE 256 - -enum { - DM_BOUND = 0, /* device has been bound to a table */ - DM_ACTIVE, /* device is running */ -}; - /* * list of devices that a metadevice uses @@ -188,7 +181,7 @@ struct mapped_device { char name[DM_NAME_LEN]; int use_count; - int state; + int suspended; /* a list of io's that arrived while we were suspended */ atomic_t pending; @@ -211,15 +204,11 @@ void dm_put_target_type(struct target_type *t); /* dm.c */ struct mapped_device *dm_find_by_minor(int minor); - -struct mapped_device *dm_create(const char *name, int minor); -int dm_remove(struct mapped_device *md); - -int dm_activate(struct mapped_device *md, struct dm_table *t); -int dm_deactivate(struct mapped_device *md); - -void dm_suspend(struct mapped_device *md); - +struct mapped_device *dm_get(const char *name); +struct mapped_device *dm_create(const char *name, int minor, struct dm_table *);int dm_destroy(struct mapped_device *md); +int dm_swap_table(struct mapped_device *md, struct dm_table *t); +int dm_suspend(struct mapped_device *md); +int dm_resume(struct mapped_device *md); /* dm-table.c */ struct dm_table *dm_table_create(void); @@ -248,9 +237,7 @@ static inline offset_t *get_node(struct dm_table *t, int l, int n) return t->index[l] + (n * KEYS_PER_NODE); } -static inline int is_active(struct mapped_device *md) -{ - return test_bit(DM_ACTIVE, &md->state); -} +int dm_interface_init(void) __init; +void dm_interface_exit(void) __exit; #endif diff --git a/driver/device-mapper/dmfs-lv.c b/driver/device-mapper/dmfs-lv.c index bc619ae58..44b20640d 100644 --- a/driver/device-mapper/dmfs-lv.c +++ b/driver/device-mapper/dmfs-lv.c @@ -40,8 +40,8 @@ struct dmfs_inode_info { extern struct inode *dmfs_create_table(struct inode *, int, struct seq_operations *, int); extern struct seq_operations dmfs_error_seq_ops; extern struct seq_operations dmfs_status_seq_ops; -extern struct seq_operations dmfs_active_seq_ops; -extern ssize_t dmfs_active_write(struct file *file, const char *buf, size_t size, loff_t *ppos); +extern struct seq_operations dmfs_suspend_seq_ops; +extern ssize_t dmfs_suspend_write(struct file *file, const char *buf, size_t size, loff_t *ppos); static int dmfs_seq_open(struct inode *inode, struct file *file) { @@ -58,12 +58,12 @@ static int dmfs_no_fsync(struct file *file, struct dentry *dentry, int datasync) return 0; }; -static struct file_operations dmfs_active_file_operations = { +static struct file_operations dmfs_suspend_file_operations = { open: dmfs_seq_open, read: seq_read, llseek: seq_lseek, release: seq_release, - write: dmfs_active_write, + write: dmfs_suspend_write, fsync: dmfs_no_fsync, }; @@ -98,11 +98,11 @@ static struct inode *dmfs_create_device(struct inode *dir, int mode, struct seq_ return inode; } -static struct inode *dmfs_create_active(struct inode *dir, int mode, struct seq_operations *seq_ops, int dev) +static struct inode *dmfs_create_suspend(struct inode *dir, int mode, struct seq_operations *seq_ops, int dev) { struct inode *inode = dmfs_create_seq_ro(dir, mode, seq_ops, dev); if (inode) { - inode->i_fop = &dmfs_active_file_operations; + inode->i_fop = &dmfs_suspend_file_operations; } return inode; } @@ -123,7 +123,7 @@ static struct dmfs_inode_info dmfs_ii[] = { { "error", dmfs_create_seq_ro, &dmfs_error_seq_ops, DT_REG }, { "status", dmfs_create_seq_ro, &dmfs_status_seq_ops, DT_REG }, { "device", dmfs_create_device, NULL, DT_BLK }, - { "active", dmfs_create_active, &dmfs_active_seq_ops, DT_REG }, + { "suspend", dmfs_create_suspend, &dmfs_suspend_seq_ops, DT_REG }, }; #define NR_DMFS_II (sizeof(dmfs_ii)/sizeof(struct dmfs_inode_info)) @@ -205,21 +205,32 @@ struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *de struct mapped_device *md; const char *name = dentry->d_name.name; char tmp_name[DM_NAME_LEN + 1]; + struct dm_table *table; + int ret = -ENOMEM; if (inode) { - inode->i_fop = &dmfs_lv_file_operations; - inode->i_op = &dmfs_lv_inode_operations; - memcpy(tmp_name, name, dentry->d_name.len); - tmp_name[dentry->d_name.len] = 0; - md = dm_create(tmp_name, -1); - if (IS_ERR(md)) { - iput(inode); - return ERR_PTR(PTR_ERR(md)); + table = dm_table_create(); + ret = PTR_ERR(table); + if (!IS_ERR(table)) { + ret = dm_table_complete(table); + if (ret == 0) { + inode->i_fop = &dmfs_lv_file_operations; + inode->i_op = &dmfs_lv_inode_operations; + memcpy(tmp_name, name, dentry->d_name.len); + tmp_name[dentry->d_name.len] = 0; + md = dm_create(tmp_name, -1, table); + if (!IS_ERR(md)) { + DMFS_I(inode)->md = md; + return inode; + } + ret = PTR_ERR(md); + } + dm_table_destroy(table); } - DMFS_I(inode)->md = md; + iput(inode); } - return inode; + return ERR_PTR(ret); } diff --git a/driver/device-mapper/dmfs-root.c b/driver/device-mapper/dmfs-root.c index 8345814ae..7ce093af0 100644 --- a/driver/device-mapper/dmfs-root.c +++ b/driver/device-mapper/dmfs-root.c @@ -55,12 +55,12 @@ static int dmfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) return -EINVAL; inode = dmfs_create_lv(dir->i_sb, mode, dentry); - if (inode) { + if (!IS_ERR(inode)) { d_instantiate(dentry, inode); dget(dentry); - rv = 0; + return 0; } - return rv; + return PTR_ERR(inode); } /* @@ -99,8 +99,9 @@ static int dmfs_root_rmdir(struct inode *dir, struct dentry *dentry) if (empty(dentry)) { struct inode *inode = dentry->d_inode; - ret = dm_deactivate(DMFS_I(inode)->md); + ret = dm_destroy(DMFS_I(inode)->md); if (ret == 0) { + DMFS_I(inode)->md = NULL; inode->i_nlink--; dput(dentry); } diff --git a/driver/device-mapper/dmfs-super.c b/driver/device-mapper/dmfs-super.c index 5013fbd09..0270c26b5 100644 --- a/driver/device-mapper/dmfs-super.c +++ b/driver/device-mapper/dmfs-super.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "dmfs.h" #include "dm.h" @@ -46,9 +47,7 @@ static void dmfs_delete_inode(struct inode *inode) if (dmi) { if (dmi->md) - dm_remove(dmi->md); - if (dmi->dentry) - dput(dmi->dentry); + BUG(); if (!list_empty(&dmi->errors)) dmfs_zap_errors(inode); kfree(dmi); @@ -130,7 +129,7 @@ struct inode *dmfs_new_private_inode(struct super_block *sb, int mode) static DECLARE_FSTYPE(dmfs_fstype, "dmfs", dmfs_read_super, FS_SINGLE); static struct vfsmount *dmfs_mnt; -int __init dmfs_init(void) +int __init dm_interface_init(void) { int ret; @@ -149,7 +148,7 @@ out: return ret; } -int __exit dmfs_exit(void) +void __exit dm_interface_exit(void) { MOD_INC_USE_COUNT; /* So that it lands up being zero */ @@ -157,6 +156,5 @@ int __exit dmfs_exit(void) unregister_filesystem(&dmfs_fstype); - return 0; } diff --git a/driver/device-mapper/dmfs-active.c b/driver/device-mapper/dmfs-suspend.c similarity index 79% rename from driver/device-mapper/dmfs-active.c rename to driver/device-mapper/dmfs-suspend.c index f70e4b1d5..8fc20cf9c 100644 --- a/driver/device-mapper/dmfs-active.c +++ b/driver/device-mapper/dmfs-suspend.c @@ -1,5 +1,5 @@ /* - * dmfs-active.c + * dmfs-suspend.c * * Copyright (C) 2001 Sistina Software * @@ -51,22 +51,22 @@ static void s_stop(struct seq_file *s, void *v) static int s_show(struct seq_file *s, void *v) { struct dmfs_i *dmi = s->context; - char msg[3] = "0\n"; - if (is_active(dmi->md)) { - msg[1] = '1'; + char msg[3] = "1\n"; + if (dmi->md->suspended == 0) { + msg[0] = '0'; } seq_puts(s, msg); return 0; } -struct seq_operations dmfs_active_seq_ops = { +struct seq_operations dmfs_suspend_seq_ops = { start: s_start, next: s_next, stop: s_stop, show: s_show, }; -ssize_t dmfs_active_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +ssize_t dmfs_suspend_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct inode *dir = file->f_dentry->d_parent->d_inode; struct dmfs_i *dmi = DMFS_I(dir); @@ -80,19 +80,12 @@ ssize_t dmfs_active_write(struct file *file, const char *buf, size_t count, loff return -EINVAL; down(&dmi->sem); - written = count; - if (is_active(dmi->md)) { - if (buf[0] == '0') - dm_deactivate(dmi->md); - } else { - if (buf[0] == '1') { - if (dmi->md->map) { - dm_activate(dmi->md, dmi->md->map); - } else { - written = -EPERM; - } - } - } + if (buf[0] == '0') + written = dm_resume(dmi->md); + if (buf[0] == '1') + written = dm_suspend(dmi->md); + if (written >= 0) + written = count; up(&dmi->sem); out: diff --git a/driver/device-mapper/dmfs-table.c b/driver/device-mapper/dmfs-table.c index 0c80c55e1..625ad2fd0 100644 --- a/driver/device-mapper/dmfs-table.c +++ b/driver/device-mapper/dmfs-table.c @@ -50,7 +50,7 @@ static char *err_table[] = { "Missing/Invalid size argument", "Missing target type" }; - printk("dmfs_parse_line: (%s)\n", str); + /* printk("dmfs_parse_line: (%s)\n", str); */ rv = sscanf(str, "%d %d %32s%n", &start, &size, target, &pos); if (rv < 3) { @@ -72,9 +72,11 @@ static char *err_table[] = { rv = ttype->ctr(t, start, size, str, &context); msg = context; if (rv == 0) { +#if 0 printk("dmfs_parse: %u %u %s %s\n", start, size, ttype->name, ttype->print ? ttype->print(context) : "-"); +#endif msg = "Error adding target to table"; high = start + (size - 1); if (dm_table_add_target(t, high, ttype, context) == 0) @@ -228,17 +230,15 @@ static int dmfs_table_release(struct inode *inode, struct file *f) if (table) { struct mapped_device *md = dmi->md; - int need_activate = 0; + int need_resume = 0; - if (is_active(md)) { - dm_deactivate(md); - need_activate = 1; + if (md->suspended == 0) { + dm_suspend(md); + need_resume = 1; } - if (md->map) { - dm_table_destroy(md->map); - } - if (need_activate) { - dm_activate(md, table); + dm_swap_table(md, table); + if (need_resume) { + dm_resume(md); } } up(&dmi->sem); diff --git a/driver/device-mapper/dmfs.h b/driver/device-mapper/dmfs.h index eb6338e27..5f1e1faac 100644 --- a/driver/device-mapper/dmfs.h +++ b/driver/device-mapper/dmfs.h @@ -4,7 +4,6 @@ struct dmfs_i { struct semaphore sem; struct mapped_device *md; - struct dentry *dentry; struct list_head errors; int status; }; @@ -12,14 +11,11 @@ struct dmfs_i { #define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip) -extern int dmfs_init(void) __init; -extern int dmfs_exit(void) __exit; +extern struct inode *dmfs_new_inode(struct super_block *sb, int mode); +extern struct inode *dmfs_new_private_inode(struct super_block *sb, int mode); -struct inode *dmfs_new_inode(struct super_block *sb, int mode); -struct inode *dmfs_new_private_inode(struct super_block *sb, int mode); - -void dmfs_add_error(struct inode *inode, unsigned num, char *str); -void dmfs_zap_errors(struct inode *inode); +extern void dmfs_add_error(struct inode *inode, unsigned num, char *str); +extern void dmfs_zap_errors(struct inode *inode);