From 5aaee0c71a2cd028ce82141376c7459f9abeb2ba Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 20 Dec 2001 20:32:14 +0000 Subject: [PATCH] Revised ioctl/dmfs merge with fixes for bugs found in tests. --- VERSION | 2 +- dmsetup/dmsetup.c | 14 +- kernel/common/device-mapper.h | 17 +- kernel/common/dm-linear.c | 55 +- kernel/common/dm-stripe.c | 29 +- kernel/common/dm-table.c | 44 +- kernel/common/dm-target.c | 18 +- kernel/common/dm.c.in | 311 +++++----- kernel/common/dm.h | 26 +- kernel/fs/dmfs-error.c | 13 + kernel/fs/dmfs-lv.c | 30 +- kernel/fs/dmfs-suspend.c | 15 +- kernel/fs/dmfs-table.c | 18 +- kernel/fs/dmfs.h | 2 + kernel/ioctl/dm-ioctl.c | 31 +- kernel/ioctl/dm-ioctl.h | 5 +- kernel/projects.txt | 5 + lib/fs/libdevmapper.c | 12 +- patches/linux-2.4.16-devmapper-fs.patch | 661 ++++++++++++--------- patches/linux-2.4.16-devmapper-ioctl.patch | 599 ++++++++++--------- 20 files changed, 1068 insertions(+), 839 deletions(-) diff --git a/VERSION b/VERSION index 8b0fa35..ab63fc2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.90.02-cvs (2001-12-14) +0.90.03-cvs (2001-12-20) diff --git a/dmsetup/dmsetup.c b/dmsetup/dmsetup.c index a2adb00..770e084 100644 --- a/dmsetup/dmsetup.c +++ b/dmsetup/dmsetup.c @@ -169,11 +169,17 @@ static int _info(int argc, char **argv) goto out; } - printf("state: %s\n", + printf("State: %s\n", info.suspended ? "SUSPENDED" : "ACTIVE"); - printf("open count: %d\n", info.open_count); - printf("major, minor: %d, %d\n", info.major, info.minor); - printf("number of targets: %d\n", info.target_count); + + if (info.open_count != -1) + printf("Open count: %d\n", info.open_count); + + printf("Major, minor: %d, %d\n", info.major, info.minor); + + if (info.target_count != -1) + printf("Number of targets: %d\n", info.target_count); + r = 1; out: diff --git a/kernel/common/device-mapper.h b/kernel/common/device-mapper.h index 80560a6..78b42c8 100644 --- a/kernel/common/device-mapper.h +++ b/kernel/common/device-mapper.h @@ -1,6 +1,4 @@ /* - * device-mapper.h - * * Copyright (C) 2001 Sistina Software (UK) Limited. * * This file is released under the LGPL. @@ -19,15 +17,18 @@ struct dm_table; struct dm_dev; typedef unsigned int offset_t; + /* - * Prototypes for functions of a target + * Prototypes for functions for a target */ -typedef int (*dm_ctr_fn) (struct dm_table * t, offset_t b, offset_t l, - char *args, void **context); -typedef void (*dm_dtr_fn) (struct dm_table * t, void *c); -typedef int (*dm_map_fn) (struct buffer_head * bh, int rw, void *context); -typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); +typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l, + const char *args, void **context); +typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); +typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); +typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); + +void dm_error(const char *message); /* * Contructors should call these functions to ensure destination devices diff --git a/kernel/common/dm-linear.c b/kernel/common/dm-linear.c index 124a73a..caa3b83 100644 --- a/kernel/common/dm-linear.c +++ b/kernel/common/dm-linear.c @@ -24,59 +24,42 @@ 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: */ static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, - char *args, void **context) + const char *args, void **context) { struct linear_c *lc; - unsigned int start; - int r = -EINVAL; - char *tok; - char *path; - char *p = args; - - *context = "No device path given"; - path = next_token(&p); - if (!path) - goto bad; + unsigned long start; /* FIXME: unsigned long long with sscanf fix */ - *context = "No initial offset given"; - tok = next_token(&p); - if (!tok) - goto bad; - start = simple_strtoul(tok, NULL, 10); + int r = -EINVAL; + char path[4096]; - *context = "Cannot allocate linear context private structure"; lc = kmalloc(sizeof(*lc), GFP_KERNEL); - if (lc == NULL) - goto bad; + if (lc == NULL) { + *context = "dm-linear: Cannot allocate linear context"; + return -ENOMEM; + } + + if (sscanf(args, "%4096s %lu", path, &start) != 2) { + *context = "dm-linear: Missing target parms: dev_path sector"; + return -ENOMEM; + } - *context = "Cannot get target device"; r = dm_table_get_device(t, path, start, l, &lc->dev); - if (r) - goto bad_free; + if (r) { + *context = "dm-linear: Device lookup failed"; + r = -ENXIO; + goto bad; + } lc->delta = (int) start - (int) b; *context = lc; return 0; - bad_free: - kfree(lc); bad: + kfree(lc); return r; } diff --git a/kernel/common/dm-stripe.c b/kernel/common/dm-stripe.c index b4cfe02..6061b31 100644 --- a/kernel/common/dm-stripe.c +++ b/kernel/common/dm-stripe.c @@ -45,13 +45,13 @@ static inline struct stripe_c *alloc_context(int stripes) * Parse a single pair */ static int get_stripe(struct dm_table *t, struct stripe_c *sc, - int stripe, char *args) + int stripe, const char *args) { int n, r; char path[4096]; unsigned long start; - if (sscanf(args, "%4095s %lu %n", path, &start, &n) != 2) + if (sscanf(args, "%4096s %lu %n", path, &start, &n) != 2) return -EINVAL; r = dm_table_get_device(t, path, start, sc->stripe_width, @@ -68,25 +68,30 @@ static int get_stripe(struct dm_table *t, struct stripe_c *sc, * [ ]+ */ static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, - char *args, void **context) + const 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) + if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) { + *context = "dm-stripe: Couldn't parse "; return -EINVAL; + } - *context = "target length is not divisable by the number of stripes"; - if (l % stripes) + if (l % stripes) { + *context = "dm-stripe: Target length not divisable by " + "number of stripes"; return -EINVAL; + } - *context = "couldn't allocate memory for striped context"; sc = alloc_context(stripes); - if (!sc) + if (!sc) { + *context = "dm-stripe: Memory allocation for striped context" + "failed"; return -ENOMEM; + } sc->logical_start = b; sc->stripes = stripes; @@ -96,7 +101,7 @@ static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, * chunk_size is a power of two */ if (!chunk_size || chunk_size & (chunk_size - 1)) { - *context = "invalid chunk size"; + *context = "dm-stripe: Invalid chunk size"; kfree(sc); return -EINVAL; } @@ -114,7 +119,8 @@ static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, n = get_stripe(t, sc, i, args); if (n < 0) { - *context = "couldn't parse stripe destination"; + *context = "dm-stripe: Couldn't parse stripe " + "destination"; kfree(sc); return n; } @@ -133,7 +139,6 @@ static void stripe_dtr(struct dm_table *t, void *c) dm_table_put_device(t, sc->stripe[i].dev); kfree(sc); - return; } static int stripe_map(struct buffer_head *bh, int rw, void *context) diff --git a/kernel/common/dm-table.c b/kernel/common/dm-table.c index dee0983..396560b 100644 --- a/kernel/common/dm-table.c +++ b/kernel/common/dm-table.c @@ -100,24 +100,25 @@ static int alloc_targets(struct dm_table *t, int num) return 0; } -struct dm_table *dm_table_create(void) +int dm_table_create(struct dm_table **result) { struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO); if (!t) - return ERR_PTR(-ENOMEM); + return -ENOMEM; memset(t, 0, sizeof(*t)); INIT_LIST_HEAD(&t->devices); - /* allocate a single nodes worth of targets to - begin with */ + /* allocate a single node's worth of targets to begin with */ if (alloc_targets(t, KEYS_PER_NODE)) { kfree(t); - t = ERR_PTR(-ENOMEM); + t = NULL; + return -ENOMEM; } - return t; + *result = t; + return 0; } static void free_devices(struct list_head *devices) @@ -143,10 +144,10 @@ void dm_table_destroy(struct dm_table *t) for (i = 0; i < t->num_targets; i++) { struct target *tgt = &t->targets[i]; + dm_put_target_type(t->targets[i].type); + if (tgt->type->dtr) tgt->type->dtr(t, tgt->private); - - dm_put_target_type(t->targets[i].type); } vfree(t->highs); @@ -163,8 +164,7 @@ void dm_table_destroy(struct dm_table *t) } /* - * Checks to see if we need to extend - * highs or targets. + * Checks to see if we need to extend highs or targets. */ static inline int check_space(struct dm_table *t) { @@ -175,9 +175,9 @@ static inline int check_space(struct dm_table *t) } /* - * convert a device path to a kdev_t. + * Convert a device path to a kdev_t. */ -int lookup_device(const char *path, kdev_t * dev) +int lookup_device(const char *path, kdev_t *dev) { int r; struct nameidata nd; @@ -208,7 +208,7 @@ int lookup_device(const char *path, kdev_t * dev) } /* - * see if we've already got a device in the list. + * See if we've already got a device in the list. */ static struct dm_dev *find_device(struct list_head *l, kdev_t dev) { @@ -224,8 +224,7 @@ static struct dm_dev *find_device(struct list_head *l, kdev_t dev) } /* - * open a device so we can use it as a map - * destination. + * Open a device so we can use it as a map destination. */ static int open_dev(struct dm_dev *d) { @@ -244,7 +243,7 @@ static int open_dev(struct dm_dev *d) } /* - * close a device that we've been using. + * Close a device that we've been using. */ static void close_dev(struct dm_dev *d) { @@ -277,8 +276,8 @@ static int check_device_area(kdev_t dev, offset_t start, offset_t len) } /* - * add a device to the list, or just increment the - * usage count if it's already present. + * 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) @@ -298,7 +297,7 @@ int dm_table_get_device(struct dm_table *t, const char *path, return -ENOMEM; dd->dev = dev; - dd->bd = 0; + dd->bd = NULL; if ((r = open_dev(dd))) { kfree(dd); @@ -322,8 +321,7 @@ int dm_table_get_device(struct dm_table *t, const char *path, } /* - * decrement a devices use count and remove it if - * neccessary. + * Decrement a devices use count and remove it if neccessary. */ void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) { @@ -335,7 +333,7 @@ void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) } /* - * adds a target to the map + * Adds a target to the map */ int dm_table_add_target(struct dm_table *t, offset_t high, struct target_type *type, void *private) @@ -378,7 +376,7 @@ static int setup_indexes(struct dm_table *t) } /* - * builds the btree to index the map + * Builds the btree to index the map */ int dm_table_complete(struct dm_table *t) { diff --git a/kernel/common/dm-target.c b/kernel/common/dm-target.c index cb03e26..0e8ceb7 100644 --- a/kernel/common/dm-target.c +++ b/kernel/common/dm-target.c @@ -149,7 +149,7 @@ int dm_unregister_target(struct target_type *t) * up LV's that have holes in them. */ static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l, - char *args, void **context) + const char *args, void **context) { *context = NULL; return 0; @@ -168,11 +168,11 @@ static int io_err_map(struct buffer_head *bh, int rw, void *context) } static struct target_type error_target = { - name:"error", - ctr:io_err_ctr, - dtr:io_err_dtr, - map:io_err_map, - err:NULL + name: "error", + ctr: io_err_ctr, + dtr: io_err_dtr, + map: io_err_map, + err: NULL }; int dm_target_init(void) @@ -180,5 +180,11 @@ int dm_target_init(void) return dm_register_target(&error_target); } +void dm_target_exit(void) +{ + if (dm_unregister_target(&error_target)) + WARN("unregister of error target failed."); +} + EXPORT_SYMBOL(dm_register_target); EXPORT_SYMBOL(dm_unregister_target); diff --git a/kernel/common/dm.c.in b/kernel/common/dm.c.in index ee0364a..4411b91 100644 --- a/kernel/common/dm.c.in +++ b/kernel/common/dm.c.in @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software + * Copyright (C) 2001 Sistina Software (UK) Limited. * * This file is released under the GPL. */ @@ -7,22 +7,20 @@ #include "dm.h" #include -#include #include -#include /* we only need this for the lv_bmap struct definition, not happy */ #include #define MAX_DEVICES 64 #define DEFAULT_READ_AHEAD 64 -#define DEVICE_NAME "device-mapper" +#define DEVICE_NAME "device-mapper" /* Name for messaging */ static const char *_name = DEVICE_NAME; static const char *_version = @DM_VERSION@; static const char *_email = "lvm-devel@lists.sistina.com"; -static int major = 0; +static int _major = 0; struct io_hook { struct mapped_device *md; @@ -49,80 +47,115 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh); static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); /* - * setup and teardown the driver + * Shortcuts to lock/unlock the global _dev_lock */ -static int __init dm_init(void) -{ - int ret = -ENOMEM; +static inline void dm_lock_r(void) { + down_read(&_dev_lock); +} - init_rwsem(&_dev_lock); +static inline void dm_unlock_r(void) { + up_read(&_dev_lock); +} - _io_hook_cache = kmem_cache_create("dm io hooks", - sizeof(struct io_hook), - 0, 0, NULL, NULL); +static inline void dm_lock_w(void) { + down_write(&_dev_lock); +} + +static inline void dm_unlock_w(void) { + up_write(&_dev_lock); +} - if (!_io_hook_cache) - goto err; - ret = dm_target_init(); - if (ret < 0) - goto err_cache_free; +/* + * Setup and tear down the driver + */ +static int __init local_init(void) +{ + int r; - ret = dm_interface_init(); - if (ret < 0) - goto err_cache_free; + init_rwsem(&_dev_lock); - ret = devfs_register_blkdev(major, _name, &dm_blk_dops); - if (ret < 0) - goto err_blkdev; + /* allocate a slab for the io-hooks */ + if (!_io_hook_cache && + !(_io_hook_cache = kmem_cache_create("dm io hooks", + sizeof(struct io_hook), + 0, 0, NULL, NULL))) + return -ENOMEM; - if (major == 0) - major = ret; + r = devfs_register_blkdev(_major, _name, &dm_blk_dops); + if (r < 0) { + printk(KERN_ERR "%s -- register_blkdev failed\n", _name); + kmem_cache_destroy(_io_hook_cache); + return r; + } + + if (!_major) + _major = r; /* set up the arrays */ - read_ahead[major] = DEFAULT_READ_AHEAD; - blk_size[major] = _block_size; - blksize_size[major] = _blksize_size; - hardsect_size[major] = _hardsect_size; + read_ahead[_major] = DEFAULT_READ_AHEAD; + blk_size[_major] = _block_size; + blksize_size[_major] = _blksize_size; + hardsect_size[_major] = _hardsect_size; - blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request); + blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request); _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); printk(KERN_INFO "%s %s initialised, %s\n", _name, _version, _email); return 0; - - err_blkdev: - printk(KERN_ERR "%s -- register_blkdev failed\n", _name); - dm_interface_exit(); - err_cache_free: - kmem_cache_destroy(_io_hook_cache); - err: - return ret; } -static void __exit dm_exit(void) +static void __exit local_exit(void) { - 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) + if (devfs_unregister_blkdev(_major, _name) < 0) printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name); - read_ahead[major] = 0; - blk_size[major] = NULL; - blksize_size[major] = NULL; - hardsect_size[major] = NULL; + read_ahead[_major] = 0; + blk_size[_major] = NULL; + blksize_size[_major] = NULL; + hardsect_size[_major] = NULL; printk(KERN_INFO "%s %s cleaned up\n", _name, _version); } +static int __init dm_init(void) +{ + int r; + + r = local_init(); + if (r) + return r; + + r = dm_target_init(); + if (r) { + local_exit(); + return r; + } + + r = dm_interface_init(); + if (r) { + dm_target_exit(); + local_exit(); + return r; + } + + return 0; +} + +static void __exit dm_exit(void) +{ + dm_interface_exit(); + dm_target_exit(); + local_exit(); +} + /* - * block device functions + * Block device functions */ static int dm_blk_open(struct inode *inode, struct file *file) { @@ -132,16 +165,16 @@ static int dm_blk_open(struct inode *inode, struct file *file) if (minor >= MAX_DEVICES) return -ENXIO; - down_write(&_dev_lock); + dm_lock_w(); md = _devs[minor]; if (!md) { - up_write(&_dev_lock); + dm_unlock_w(); return -ENXIO; } md->use_count++; - up_write(&_dev_lock); + dm_unlock_w(); return 0; } @@ -154,16 +187,16 @@ static int dm_blk_close(struct inode *inode, struct file *file) if (minor >= MAX_DEVICES) return -ENXIO; - down_write(&_dev_lock); + dm_lock_w(); md = _devs[minor]; if (!md || md->use_count < 1) { WARN("reference count in mapped_device incorrect"); - up_write(&_dev_lock); + dm_unlock_w(); return -ENXIO; } md->use_count--; - up_write(&_dev_lock); + dm_unlock_w(); return 0; } @@ -232,7 +265,7 @@ static inline void free_io_hook(struct io_hook *ih) } /* - * FIXME: need to decide if deferred_io's need + * FIXME: We need to decide if deferred_io's need * their own slab, I say no for now since they are * only used when the device is suspended. */ @@ -247,12 +280,12 @@ static inline void free_deferred(struct deferred_io *di) } /* - * call a targets optional error function if - * an io failed. + * Call a target's optional error function if an I/O failed. */ static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) { dm_err_fn err = ih->target->type->err; + if (err) return err(bh, ih->rw, ih->target->private); @@ -260,9 +293,8 @@ static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) } /* - * bh->b_end_io routine that decrements the - * pending count and then calls the original - * bh->b_end_io fn. + * bh->b_end_io routine that decrements the pending count + * and then calls the original bh->b_end_io fn. */ static void dec_pending(struct buffer_head *bh, int uptodate) { @@ -283,7 +315,7 @@ static void dec_pending(struct buffer_head *bh, int uptodate) } /* - * add the bh to the list of deferred io. + * Add the bh to the list of deferred io. */ static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) { @@ -292,23 +324,23 @@ static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) if (!di) return -ENOMEM; - down_write(&_dev_lock); + dm_lock_w(); if (!md->suspended) { - up_write(&_dev_lock); - return 0; + dm_unlock_w(); + return 1; } di->bh = bh; di->rw = rw; di->next = md->deferred; md->deferred = di; - up_write(&_dev_lock); + dm_unlock_w(); - return 1; + return 0; /* deferred successfully */ } /* - * do the bh mapping for a given leaf + * Do the bh mapping for a given leaf */ static inline int __map_buffer(struct mapped_device *md, struct buffer_head *bh, int rw, int leaf) @@ -325,7 +357,7 @@ static inline int __map_buffer(struct mapped_device *md, ih = alloc_io_hook(); if (!ih) - return 0; + return -1; ih->md = md; ih->rw = rw; @@ -340,21 +372,19 @@ static inline int __map_buffer(struct mapped_device *md, atomic_inc(&md->pending); bh->b_end_io = dec_pending; bh->b_private = ih; - } else if (r == 0) /* we don't need to hook */ free_io_hook(ih); - else if (r < 0) { free_io_hook(ih); - return 0; + return -1; } - return 1; + return 0; } /* - * search the btree for the correct target. + * Search the btree for the correct target. */ static inline int __find_node(struct dm_table *t, struct buffer_head *bh) { @@ -381,7 +411,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) if (minor >= MAX_DEVICES) goto bad_no_lock; - down_read(&_dev_lock); + dm_lock_r(); md = _devs[minor]; if (!md) @@ -392,7 +422,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) * this io for later. */ while (md->suspended) { - up_read(&_dev_lock); + dm_unlock_r(); if (rw == READA) goto bad_no_lock; @@ -402,26 +432,24 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh) if (r < 0) goto bad_no_lock; - else if (r > 0) + else if (r == 0) return 0; /* deferred successfully */ /* - * We're in a while loop, because - * someone could suspend before we - * get to the following read - * lock + * We're in a while loop, because someone could suspend + * before we get to the following read lock */ - down_read(&_dev_lock); + dm_lock_r(); } - if (!__map_buffer(md, bh, rw, __find_node(md->map, bh))) + if (__map_buffer(md, bh, rw, __find_node(md->map, bh)) < 0) goto bad; - up_read(&_dev_lock); + dm_unlock_r(); return 1; bad: - up_read(&_dev_lock); + dm_unlock_r(); bad_no_lock: buffer_IO_error(bh); @@ -438,7 +466,7 @@ static int check_dev_size(int minor, unsigned long block) } /* - * creates a dummy buffer head and maps it (for lilo). + * Creates a dummy buffer head and maps it (for lilo). */ static int do_bmap(kdev_t dev, unsigned long block, kdev_t * r_dev, unsigned long *r_block) @@ -448,7 +476,7 @@ static int do_bmap(kdev_t dev, unsigned long block, int minor = MINOR(dev), r; struct target *t; - down_read(&_dev_lock); + dm_lock_r(); if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) || md->suspended) { r = -ENXIO; goto out; @@ -476,13 +504,12 @@ static int do_bmap(kdev_t dev, unsigned long block, *r_block = bh.b_rsector / (bh.b_size >> 9); out: - up_read(&_dev_lock); + dm_unlock_r(); return r; } /* - * marshals arguments and results between user and - * kernel space. + * Marshals arguments and results between user and kernel space. */ static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) { @@ -504,8 +531,7 @@ static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) } /* - * see if the device with a specific minor # is - * free. + * See if the device with a specific minor # is free. */ static inline int __specific_dev(int minor) { @@ -546,24 +572,24 @@ static struct mapped_device *alloc_dev(int minor) memset(md, 0, sizeof(*md)); - down_write(&_dev_lock); + dm_lock_w(); minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor); if (minor < 0) { WARN("no free devices available"); - up_write(&_dev_lock); + dm_unlock_w(); kfree(md); return 0; } - md->dev = MKDEV(major, minor); + md->dev = MKDEV(_major, minor); md->name[0] = '\0'; md->suspended = 0; init_waitqueue_head(&md->wait); _devs[minor] = md; - up_write(&_dev_lock); + dm_unlock_w(); return md; } @@ -591,9 +617,8 @@ static int unregister_device(struct mapped_device *md) } /* - * the hardsect size for a mapped device is the - * smallest hard sect size from the devices it - * maps onto. + * The hardsect size for a mapped device is the smallest hardsect size + * from the devices it maps onto. */ static int __find_hardsect_size(struct list_head *devices) { @@ -662,36 +687,38 @@ static int check_name(const char *name) { if (strchr(name, '/')) { WARN("invalid device name"); - return 0; + return -1; } if (__get_by_name(name)) { WARN("device name already in use"); - return 0; + return -1; } - return 1; + return 0; } /* - * constructor for a new device + * Constructor for a new device */ -struct mapped_device *dm_create(const char *name, int minor, - struct dm_table *table) +int dm_create(const char *name, int minor, struct dm_table *table, + struct mapped_device **result) { - int r = -EINVAL; + int r; struct mapped_device *md; if (minor >= MAX_DEVICES) - return ERR_PTR(-ENXIO); + return -ENXIO; if (!(md = alloc_dev(minor))) - return ERR_PTR(-ENXIO); + return -ENXIO; - down_write(&_dev_lock); + dm_lock_w(); - if (!check_name(name)) + if (check_name(name) < 0) { + r = -EINVAL; goto err; + } strcpy(md->name, name); _devs[minor] = md; @@ -704,14 +731,15 @@ struct mapped_device *dm_create(const char *name, int minor, if (r) goto err; - up_write(&_dev_lock); + dm_unlock_w(); - return md; + *result = md; + return 0; err: - up_write(&_dev_lock); + dm_unlock_w(); free_dev(md); - return ERR_PTR(r); + return r; } /* @@ -722,23 +750,23 @@ int dm_destroy(struct mapped_device *md) { int minor, r; - down_read(&_dev_lock); + dm_lock_r(); if (md->suspended || md->use_count) { - up_read(&_dev_lock); + dm_unlock_r(); return -EPERM; } fsync_dev(md->dev); - up_read(&_dev_lock); + dm_unlock_r(); - down_write(&_dev_lock); + dm_lock_w(); if (md->use_count) { - up_write(&_dev_lock); + dm_unlock_w(); return -EPERM; } if ((r = unregister_device(md))) { - up_write(&_dev_lock); + dm_unlock_w(); return r; } @@ -746,7 +774,7 @@ int dm_destroy(struct mapped_device *md) _devs[minor] = 0; __unbind(md); - up_write(&_dev_lock); + dm_unlock_w(); free_dev(md); @@ -754,8 +782,7 @@ int dm_destroy(struct mapped_device *md) } /* - * requeue the deferred buffer_heads by calling - * generic_make_request. + * Requeue the deferred buffer_heads by calling generic_make_request. */ static void flush_deferred_io(struct deferred_io *c) { @@ -776,22 +803,22 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) { int r; - down_write(&_dev_lock); + dm_lock_w(); /* device must be suspended */ if (!md->suspended) { - up_write(&_dev_lock); + dm_unlock_w(); return -EPERM; } __unbind(md); if ((r = __bind(md, table))) { - up_write(&_dev_lock); + dm_unlock_w(); return r; } - up_write(&_dev_lock); + dm_unlock_w(); return 0; } @@ -809,31 +836,31 @@ int dm_suspend(struct mapped_device *md) { DECLARE_WAITQUEUE(wait, current); - down_write(&_dev_lock); + dm_lock_w(); if (md->suspended) { - up_write(&_dev_lock); + dm_unlock_w(); return -EINVAL; } md->suspended = 1; - up_write(&_dev_lock); + dm_unlock_w(); /* wait for all the pending io to flush */ add_wait_queue(&md->wait, &wait); current->state = TASK_UNINTERRUPTIBLE; do { - down_write(&_dev_lock); + dm_lock_w(); if (!atomic_read(&md->pending)) break; - up_write(&_dev_lock); + dm_unlock_w(); schedule(); } while (1); current->state = TASK_RUNNING; remove_wait_queue(&md->wait, &wait); - up_write(&_dev_lock); + dm_unlock_w(); return 0; } @@ -842,19 +869,21 @@ int dm_resume(struct mapped_device *md) { struct deferred_io *def; - down_write(&_dev_lock); - if (!md->suspended) { - up_write(&_dev_lock); + dm_lock_w(); + if (!md->suspended || !md->map->num_targets) { + dm_unlock_w(); return -EINVAL; } md->suspended = 0; def = md->deferred; md->deferred = NULL; - up_write(&_dev_lock); + dm_unlock_w(); flush_deferred_io(def); + fsync_dev(md->dev); + return 0; } @@ -865,9 +894,9 @@ struct mapped_device *dm_get(const char *name) { struct mapped_device *md; - down_read(&_dev_lock); + dm_lock_r(); md = __get_by_name(name); - up_read(&_dev_lock); + dm_unlock_r(); return md; } @@ -885,8 +914,8 @@ struct block_device_operations dm_blk_dops = { module_init(dm_init); module_exit(dm_exit); -MODULE_PARM(major, "i"); -MODULE_PARM_DESC(major, "The major number of the device mapper"); +MODULE_PARM(_major, "i"); +MODULE_PARM_DESC(_major, "The major number of the device mapper"); MODULE_DESCRIPTION("device-mapper driver"); MODULE_AUTHOR("Joe Thornber "); MODULE_LICENSE("GPL"); diff --git a/kernel/common/dm.h b/kernel/common/dm.h index 37bedcd..8ac869b 100644 --- a/kernel/common/dm.h +++ b/kernel/common/dm.h @@ -1,6 +1,4 @@ /* - * dm.h - * * Internal header file for device mapper * * Copyright (C) 2001 Sistina Software @@ -103,18 +101,27 @@ extern struct block_device_operations dm_blk_dops; int dm_target_init(void); struct target_type *dm_get_target_type(const char *name); void dm_put_target_type(struct target_type *t); +void dm_target_exit(void); /* dm.c */ -struct mapped_device *dm_find_by_minor(int minor); struct mapped_device *dm_get(const char *name); -struct mapped_device *dm_create(const char *name, int minor, struct dm_table *); +int dm_create(const char *name, int minor, struct dm_table *table, + struct mapped_device **result); int dm_destroy(struct mapped_device *md); + +/* + * The device must be suspended before calling this method. + */ int dm_swap_table(struct mapped_device *md, struct dm_table *t); + +/* + * A device can still be used while suspended, but I/O is deferred. + */ int dm_suspend(struct mapped_device *md); int dm_resume(struct mapped_device *md); /* dm-table.c */ -struct dm_table *dm_table_create(void); +int dm_table_create(struct dm_table **result); void dm_table_destroy(struct dm_table *t); int dm_table_add_target(struct dm_table *t, offset_t high, @@ -139,7 +146,12 @@ static inline offset_t *get_node(struct dm_table *t, int l, int n) return t->index[l] + (n * KEYS_PER_NODE); } -int dm_interface_init(void) __init; -void dm_interface_exit(void) __exit; +/* + * The device-mapper can be driven through one of two interfaces; + * ioctl or filesystem, depending which patch you have applied. + */ + +int dm_interface_init(void); +void dm_interface_exit(void); #endif diff --git a/kernel/fs/dmfs-error.c b/kernel/fs/dmfs-error.c index 070b456..dd60373 100644 --- a/kernel/fs/dmfs-error.c +++ b/kernel/fs/dmfs-error.c @@ -46,6 +46,19 @@ static struct dmfs_error oom_error = { msg: "Out of memory during creation of table\n", }; +int dmfs_error_revalidate(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct inode *parent = dentry->d_parent->d_inode; + + if (!list_empty(&DMFS_I(parent)->errors)) + inode->i_size = 1; + else + inode->i_size = 0; + + return 0; +} + void dmfs_add_error(struct inode *inode, unsigned num, char *str) { struct dmfs_i *dmi = DMFS_I(inode); diff --git a/kernel/fs/dmfs-lv.c b/kernel/fs/dmfs-lv.c index 57f9c8a..fa9228b 100644 --- a/kernel/fs/dmfs-lv.c +++ b/kernel/fs/dmfs-lv.c @@ -45,6 +45,7 @@ extern struct seq_operations dmfs_status_seq_ops; 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); +extern int dmfs_error_revalidate(struct dentry *dentry); static int dmfs_seq_open(struct inode *inode, struct file *file) { @@ -74,6 +75,10 @@ static struct file_operations dmfs_suspend_file_operations = { static struct inode_operations dmfs_null_inode_operations = { }; +static struct inode_operations dmfs_error_inode_operations = { + revalidate: dmfs_error_revalidate +}; + static struct file_operations dmfs_seq_ro_file_operations = { open: dmfs_seq_open, read: seq_read, @@ -94,6 +99,18 @@ static struct inode *dmfs_create_seq_ro(struct inode *dir, int mode, return inode; } +static struct inode *dmfs_create_error(struct inode *dir, int mode, + struct seq_operations *seq_ops, int dev) +{ + struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG); + if (inode) { + inode->i_fop = &dmfs_seq_ro_file_operations; + inode->i_op = &dmfs_error_inode_operations; + DMFS_SEQ(inode) = seq_ops; + } + return inode; +} + static struct inode *dmfs_create_device(struct inode *dir, int mode, struct seq_operations *seq_ops, int dev) { @@ -128,7 +145,7 @@ static struct dmfs_inode_info dmfs_ii[] = { {".", NULL, NULL, DT_DIR}, {"..", NULL, NULL, DT_DIR}, {"table", dmfs_create_table, NULL, DT_REG}, - {"error", dmfs_create_seq_ro, &dmfs_error_seq_ops, DT_REG}, + {"error", dmfs_create_error, &dmfs_error_seq_ops, DT_REG}, {"status", dmfs_create_seq_ro, &dmfs_status_seq_ops, DT_REG}, {"device", dmfs_create_device, NULL, DT_BLK}, {"suspend", dmfs_create_suspend, &dmfs_suspend_seq_ops, DT_REG}, @@ -217,21 +234,20 @@ struct inode *dmfs_create_lv(struct super_block *sb, int mode, int ret = -ENOMEM; if (inode) { - table = dm_table_create(); - ret = PTR_ERR(table); - if (!IS_ERR(table)) { + ret = dm_table_create(&table); + if (!ret) { ret = dm_table_complete(table); if (!ret) { 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)) { + ret = dm_create(tmp_name, -1, table, &md); + if (!ret) { DMFS_I(inode)->md = md; + md->suspended = 1; return inode; } - ret = PTR_ERR(md); } dm_table_destroy(table); } diff --git a/kernel/fs/dmfs-suspend.c b/kernel/fs/dmfs-suspend.c index c9a89bd..7b9d6e4 100644 --- a/kernel/fs/dmfs-suspend.c +++ b/kernel/fs/dmfs-suspend.c @@ -87,12 +87,25 @@ ssize_t dmfs_suspend_write(struct file *file, const char *buf, size_t count, return -EINVAL; down(&dmi->sem); - if (buf[0] == '0') + if (buf[0] == '0') { + if (get_exclusive_write_access(dir)) { + written = -EPERM; + goto out_unlock; + } + if (!list_empty(&dmi->errors)) { + put_write_access(dir); + written = -EPERM; + goto out_unlock; + } written = dm_resume(dmi->md); + put_write_access(dir); + } if (buf[0] == '1') written = dm_suspend(dmi->md); if (written >= 0) written = count; + + out_unlock: up(&dmi->sem); out: diff --git a/kernel/fs/dmfs-table.c b/kernel/fs/dmfs-table.c index 62ef93f..92a9ad6 100644 --- a/kernel/fs/dmfs-table.c +++ b/kernel/fs/dmfs-table.c @@ -178,14 +178,15 @@ static struct dm_table *dmfs_parse(struct inode *inode, struct file *filp) unsigned long page; struct dmfs_desc d; loff_t pos = 0; + int r; if (inode->i_size == 0) return NULL; page = __get_free_page(GFP_NOFS); if (page) { - t = dm_table_create(); - if (t) { + r = dm_table_create(&t); + if (!r) { read_descriptor_t desc; desc.written = 0; @@ -202,7 +203,10 @@ static struct dm_table *dmfs_parse(struct inode *inode, struct file *filp) if (desc.written != inode->i_size) { dm_table_destroy(t); t = NULL; - } + } + if (!t || (t && !t->num_targets)) + dmfs_add_error(d.inode, 0, + "No valid targets found"); } free_page(page); } @@ -296,7 +300,7 @@ static int dmfs_commit_write(struct file *file, struct page *page, * at some stage if we continue to use this set of functions for ensuring * exclusive write access to the file */ -static int get_exclusive_write_access(struct inode *inode) +int get_exclusive_write_access(struct inode *inode) { if (get_write_access(inode)) return -1; @@ -311,10 +315,16 @@ static int dmfs_table_open(struct inode *inode, struct file *file) { struct dentry *dentry = file->f_dentry; struct inode *parent = dentry->d_parent->d_inode; + struct dmfs_i *dmi = DMFS_I(parent); if (file->f_mode & FMODE_WRITE) { if (get_exclusive_write_access(parent)) return -EPERM; + + if (!dmi->md->suspended) { + put_write_access(parent); + return -EPERM; + } } return 0; diff --git a/kernel/fs/dmfs.h b/kernel/fs/dmfs.h index 013e532..a9ac3aa 100644 --- a/kernel/fs/dmfs.h +++ b/kernel/fs/dmfs.h @@ -10,6 +10,8 @@ struct dmfs_i { #define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip) +int get_exclusive_write_access(struct inode *inode); + 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); diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index a41d57e..cfd6d65 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -62,9 +62,9 @@ static int next_target(struct dm_target_spec *last, void *end, return valid_str(*params, end); } -void err_fn(const char *message, void *private) +void dm_error(const char *message) { - printk(KERN_WARNING "%s\n", message); + WARN("%s", message); } /* @@ -98,7 +98,7 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) end = ((void *) args) + args->data_size; -#define PARSE_ERROR(msg) {err_fn(msg, NULL); return -EINVAL;} +#define PARSE_ERROR(msg) {dm_error(msg); return -EINVAL;} for (i = 0; i < args->target_count; i++) { @@ -117,8 +117,10 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) /* build the target */ if (ttype->ctr(table, spec->sector_start, spec->length, params, - &context)) - PARSE_ERROR(context); + &context)) { + dm_error(context); + PARSE_ERROR("target constructor failed"); + } /* add the target to the table */ high = spec->sector_start + (spec->length - 1); @@ -167,17 +169,13 @@ static int create(struct dm_ioctl *param, struct dm_ioctl *user) struct mapped_device *md; struct dm_table *t; - t = dm_table_create(); - r = PTR_ERR(t); - if (IS_ERR(t)) - goto bad; + if ((r = dm_table_create(&t))) + return r; if ((r = populate_table(t, param))) goto bad; - md = dm_create(param->name, param->minor, t); - r = PTR_ERR(md); - if (IS_ERR(md)) + if ((r = dm_create(param->name, param->minor, t, &md))) goto bad; if ((r = info(param->name, user))) { @@ -221,9 +219,9 @@ static int reload(struct dm_ioctl *param) if (!md) return -ENXIO; - t = dm_table_create(); - if (IS_ERR(t)) - return PTR_ERR(t); + r = dm_table_create(&t); + if ((r = dm_table_create(&t))) + return r; if ((r = populate_table(t, param))) { dm_table_destroy(t); @@ -244,11 +242,14 @@ static int ctl_open(struct inode *inode, struct file *file) if (!capable(CAP_SYS_ADMIN)) return -EACCES; + MOD_INC_USE_COUNT; + return 0; } static int ctl_close(struct inode *inode, struct file *file) { + MOD_DEC_USE_COUNT; return 0; } diff --git a/kernel/ioctl/dm-ioctl.h b/kernel/ioctl/dm-ioctl.h index 25425ac..585d02a 100644 --- a/kernel/ioctl/dm-ioctl.h +++ b/kernel/ioctl/dm-ioctl.h @@ -10,8 +10,7 @@ #include "device-mapper.h" /* - * Implements a traditional ioctl interface to the - * device mapper. Yuck. + * Implements a traditional ioctl interface to the device mapper. */ struct dm_target_spec { @@ -43,7 +42,7 @@ struct dm_ioctl { int target_count; /* in/out */ }; -/* FIXME: find own numbers, 109 is pinched from LVM */ +/* FIXME: find own numbers: LVM1 used 109 */ #define DM_IOCTL 0xfd #define DM_CHAR_MAJOR 124 diff --git a/kernel/projects.txt b/kernel/projects.txt index f8f932a..734ee9c 100644 --- a/kernel/projects.txt +++ b/kernel/projects.txt @@ -9,6 +9,11 @@ o Locking on mapped_devices in dm-ioctl.c + o Check dm_lock_r/w protection on all md use + + o Make table file not lose text for existing table when the device + is active and new text is passed in (and otherwise gets ignored) + o Port to 2.5 kernels (new block I/O layer) o Investigate char device number allocation for dm-ioctl.c (maybe use misc diff --git a/lib/fs/libdevmapper.c b/lib/fs/libdevmapper.c index bb1bde1..1e7103e 100644 --- a/lib/fs/libdevmapper.c +++ b/lib/fs/libdevmapper.c @@ -112,15 +112,17 @@ static int do_suspend(char *mnt, char *name, int on) char *path; FILE *fp; int ret = 0; + char c; if (!(path = mkpath(3, mnt, name, "suspend"))) return 0; - if ((fp = fopen(path, "rw"))) { - if (fprintf(fp, "%d\n", on) > 0) + if ((fp = fopen(path, "w"))) { + c = on ? '1' : '0'; + if (fputc(c, fp) == (int)c) ret = 1; else - log("%s: fprintf failed: %s", path, strerror(errno)); + log("%s: fputc failed: %s", path, strerror(errno)); fclose(fp); } else log("%s: fopen failed: %s", path, strerror(errno)); @@ -206,6 +208,10 @@ static int do_info(char *mnt, char *name, struct dm_info *info) if (info->exists && !do_suspend_state(mnt, name, info)) return 0; + /* Unsupported */ + info->target_count = -1; + info->open_count = -1; + return 1; } diff --git a/patches/linux-2.4.16-devmapper-fs.patch b/patches/linux-2.4.16-devmapper-fs.patch index bbabd68..133229f 100644 --- a/patches/linux-2.4.16-devmapper-fs.patch +++ b/patches/linux-2.4.16-devmapper-fs.patch @@ -1,6 +1,6 @@ diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in --- linux-2.4.16/drivers/md/Config.in Fri Sep 14 22:22:18 2001 -+++ linux/drivers/md/Config.in Fri Dec 14 13:39:00 2001 ++++ linux/drivers/md/Config.in Thu Dec 20 20:11:26 2001 @@ -14,5 +14,6 @@ dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD @@ -10,7 +10,7 @@ diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in endmenu diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile --- linux-2.4.16/drivers/md/Makefile Thu Dec 6 15:57:55 2001 -+++ linux/drivers/md/Makefile Fri Dec 14 13:39:00 2001 ++++ linux/drivers/md/Makefile Thu Dec 20 20:11:27 2001 @@ -4,9 +4,12 @@ O_TARGET := mddev.o @@ -41,11 +41,9 @@ diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile + diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper.h --- linux-2.4.16/drivers/md/device-mapper.h Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/device-mapper.h Mon Dec 10 15:43:56 2001 -@@ -0,0 +1,57 @@ ++++ linux/drivers/md/device-mapper.h Wed Dec 19 19:42:09 2001 +@@ -0,0 +1,58 @@ +/* -+ * device-mapper.h -+ * + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. @@ -64,16 +62,19 @@ diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper +struct dm_dev; +typedef unsigned int offset_t; + ++ +/* -+ * Prototypes for functions of a target ++ * Prototypes for functions for a target + */ -+typedef int (*dm_ctr_fn) (struct dm_table * t, offset_t b, offset_t l, -+ char *args, void **context); -+typedef void (*dm_dtr_fn) (struct dm_table * t, void *c); -+typedef int (*dm_map_fn) (struct buffer_head * bh, int rw, void *context); -+typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l, ++ const char *args, void **context); ++typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); ++typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); + + ++void dm_error(const char *message); ++ +/* + * Contructors should call these functions to ensure destination devices + * are opened/closed correctly @@ -102,8 +103,8 @@ diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper +#endif /* _LINUX_DEVICE_MAPPER_H */ diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c --- linux-2.4.16/drivers/md/dm-linear.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-linear.c Thu Dec 13 12:57:39 2001 -@@ -0,0 +1,135 @@ ++++ linux/drivers/md/dm-linear.c Thu Dec 20 12:23:38 2001 +@@ -0,0 +1,118 @@ +/* + * dm-linear.c + * @@ -130,59 +131,42 @@ diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-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: + */ +static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const char *args, void **context) +{ + struct linear_c *lc; -+ unsigned int start; -+ int r = -EINVAL; -+ char *tok; -+ char *path; -+ char *p = args; -+ -+ *context = "No device path given"; -+ path = next_token(&p); -+ if (!path) -+ goto bad; ++ unsigned long start; /* FIXME: unsigned long long with sscanf fix */ + -+ *context = "No initial offset given"; -+ tok = next_token(&p); -+ if (!tok) -+ goto bad; -+ start = simple_strtoul(tok, NULL, 10); ++ int r = -EINVAL; ++ char path[4096]; + -+ *context = "Cannot allocate linear context private structure"; + lc = kmalloc(sizeof(*lc), GFP_KERNEL); -+ if (lc == NULL) -+ goto bad; ++ if (lc == NULL) { ++ *context = "dm-linear: Cannot allocate linear context"; ++ return -ENOMEM; ++ } ++ ++ if (sscanf(args, "%4096s %lu", path, &start) != 2) { ++ *context = "dm-linear: Missing target parms: dev_path sector"; ++ return -ENOMEM; ++ } + -+ *context = "Cannot get target device"; + r = dm_table_get_device(t, path, start, l, &lc->dev); -+ if (r) -+ goto bad_free; ++ if (r) { ++ *context = "dm-linear: Device lookup failed"; ++ r = -ENXIO; ++ goto bad; ++ } + + lc->delta = (int) start - (int) b; + *context = lc; + return 0; + -+ bad_free: -+ kfree(lc); + bad: ++ kfree(lc); + return r; +} + @@ -241,8 +225,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c --- linux-2.4.16/drivers/md/dm-stripe.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-stripe.c Mon Dec 10 16:30:25 2001 -@@ -0,0 +1,187 @@ ++++ linux/drivers/md/dm-stripe.c Wed Dec 19 20:33:01 2001 +@@ -0,0 +1,192 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -290,13 +274,13 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * Parse a single pair + */ +static int get_stripe(struct dm_table *t, struct stripe_c *sc, -+ int stripe, char *args) ++ int stripe, const char *args) +{ + int n, r; + char path[4096]; + unsigned long start; + -+ if (sscanf(args, "%4095s %lu %n", path, &start, &n) != 2) ++ if (sscanf(args, "%4096s %lu %n", path, &start, &n) != 2) + return -EINVAL; + + r = dm_table_get_device(t, path, start, sc->stripe_width, @@ -313,25 +297,30 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * [ ]+ + */ +static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const 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) ++ if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) { ++ *context = "dm-stripe: Couldn't parse "; + return -EINVAL; ++ } + -+ *context = "target length is not divisable by the number of stripes"; -+ if (l % stripes) ++ if (l % stripes) { ++ *context = "dm-stripe: Target length not divisable by " ++ "number of stripes"; + return -EINVAL; ++ } + -+ *context = "couldn't allocate memory for striped context"; + sc = alloc_context(stripes); -+ if (!sc) ++ if (!sc) { ++ *context = "dm-stripe: Memory allocation for striped context" ++ "failed"; + return -ENOMEM; ++ } + + sc->logical_start = b; + sc->stripes = stripes; @@ -341,7 +330,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * chunk_size is a power of two + */ + if (!chunk_size || chunk_size & (chunk_size - 1)) { -+ *context = "invalid chunk size"; ++ *context = "dm-stripe: Invalid chunk size"; + kfree(sc); + return -EINVAL; + } @@ -359,7 +348,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + n = get_stripe(t, sc, i, args); + + if (n < 0) { -+ *context = "couldn't parse stripe destination"; ++ *context = "dm-stripe: Couldn't parse stripe " ++ "destination"; + kfree(sc); + return n; + } @@ -378,7 +368,6 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + dm_table_put_device(t, sc->stripe[i].dev); + + kfree(sc); -+ return; +} + +static int stripe_map(struct buffer_head *bh, int rw, void *context) @@ -432,8 +421,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c --- linux-2.4.16/drivers/md/dm-table.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-table.c Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,402 @@ ++++ linux/drivers/md/dm-table.c Wed Dec 19 19:40:07 2001 +@@ -0,0 +1,400 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -536,24 +525,25 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + return 0; +} + -+struct dm_table *dm_table_create(void) ++int dm_table_create(struct dm_table **result) +{ + struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO); + + if (!t) -+ return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + memset(t, 0, sizeof(*t)); + INIT_LIST_HEAD(&t->devices); + -+ /* allocate a single nodes worth of targets to -+ begin with */ ++ /* allocate a single node's worth of targets to begin with */ + if (alloc_targets(t, KEYS_PER_NODE)) { + kfree(t); -+ t = ERR_PTR(-ENOMEM); ++ t = NULL; ++ return -ENOMEM; + } + -+ return t; ++ *result = t; ++ return 0; +} + +static void free_devices(struct list_head *devices) @@ -579,10 +569,10 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + for (i = 0; i < t->num_targets; i++) { + struct target *tgt = &t->targets[i]; + ++ dm_put_target_type(t->targets[i].type); ++ + if (tgt->type->dtr) + tgt->type->dtr(t, tgt->private); -+ -+ dm_put_target_type(t->targets[i].type); + } + + vfree(t->highs); @@ -599,8 +589,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * Checks to see if we need to extend -+ * highs or targets. ++ * Checks to see if we need to extend highs or targets. + */ +static inline int check_space(struct dm_table *t) +{ @@ -611,9 +600,9 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * convert a device path to a kdev_t. ++ * Convert a device path to a kdev_t. + */ -+int lookup_device(const char *path, kdev_t * dev) ++int lookup_device(const char *path, kdev_t *dev) +{ + int r; + struct nameidata nd; @@ -644,7 +633,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * see if we've already got a device in the list. ++ * See if we've already got a device in the list. + */ +static struct dm_dev *find_device(struct list_head *l, kdev_t dev) +{ @@ -660,8 +649,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * open a device so we can use it as a map -+ * destination. ++ * Open a device so we can use it as a map destination. + */ +static int open_dev(struct dm_dev *d) +{ @@ -680,7 +668,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * close a device that we've been using. ++ * Close a device that we've been using. + */ +static void close_dev(struct dm_dev *d) +{ @@ -713,8 +701,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * add a device to the list, or just increment the -+ * usage count if it's already present. ++ * 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) @@ -734,7 +722,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + return -ENOMEM; + + dd->dev = dev; -+ dd->bd = 0; ++ dd->bd = NULL; + + if ((r = open_dev(dd))) { + kfree(dd); @@ -758,8 +746,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * decrement a devices use count and remove it if -+ * neccessary. ++ * Decrement a devices use count and remove it if neccessary. + */ +void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) +{ @@ -771,7 +758,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * adds a target to the map ++ * Adds a target to the map + */ +int dm_table_add_target(struct dm_table *t, offset_t high, + struct target_type *type, void *private) @@ -814,7 +801,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * builds the btree to index the map ++ * Builds the btree to index the map + */ +int dm_table_complete(struct dm_table *t) +{ @@ -838,8 +825,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +EXPORT_SYMBOL(dm_table_put_device); diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c --- linux-2.4.16/drivers/md/dm-target.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-target.c Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,184 @@ ++++ linux/drivers/md/dm-target.c Wed Dec 19 19:57:41 2001 +@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited + * @@ -991,7 +978,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c + * up LV's that have holes in them. + */ +static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const char *args, void **context) +{ + *context = NULL; + return 0; @@ -1010,11 +997,11 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c +} + +static struct target_type error_target = { -+ name:"error", -+ ctr:io_err_ctr, -+ dtr:io_err_dtr, -+ map:io_err_map, -+ err:NULL ++ name: "error", ++ ctr: io_err_ctr, ++ dtr: io_err_dtr, ++ map: io_err_map, ++ err: NULL +}; + +int dm_target_init(void) @@ -1022,14 +1009,20 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c + return dm_register_target(&error_target); +} + ++void dm_target_exit(void) ++{ ++ if (dm_unregister_target(&error_target)) ++ WARN("unregister of error target failed."); ++} ++ +EXPORT_SYMBOL(dm_register_target); +EXPORT_SYMBOL(dm_unregister_target); diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c --- linux-2.4.16/drivers/md/dm.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm.c Fri Dec 14 13:38:25 2001 -@@ -0,0 +1,892 @@ ++++ linux/drivers/md/dm.c Thu Dec 20 20:10:49 2001 +@@ -0,0 +1,921 @@ +/* -+ * Copyright (C) 2001 Sistina Software ++ * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ @@ -1037,22 +1030,20 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +#include "dm.h" + +#include -+#include +#include -+#include + +/* we only need this for the lv_bmap struct definition, not happy */ +#include + +#define MAX_DEVICES 64 +#define DEFAULT_READ_AHEAD 64 -+#define DEVICE_NAME "device-mapper" ++#define DEVICE_NAME "device-mapper" /* Name for messaging */ + +static const char *_name = DEVICE_NAME; -+static const char *_version = "0.90.02-fs (2001-12-14)"; ++static const char *_version = "0.90.03-fs (2001-12-20)"; +static const char *_email = "lvm-devel@lists.sistina.com"; + -+static int major = 0; ++static int _major = 0; + +struct io_hook { + struct mapped_device *md; @@ -1079,80 +1070,115 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); + +/* -+ * setup and teardown the driver ++ * Shortcuts to lock/unlock the global _dev_lock + */ -+static int __init dm_init(void) -+{ -+ int ret = -ENOMEM; ++static inline void dm_lock_r(void) { ++ down_read(&_dev_lock); ++} + -+ init_rwsem(&_dev_lock); ++static inline void dm_unlock_r(void) { ++ up_read(&_dev_lock); ++} + -+ _io_hook_cache = kmem_cache_create("dm io hooks", -+ sizeof(struct io_hook), -+ 0, 0, NULL, NULL); ++static inline void dm_lock_w(void) { ++ down_write(&_dev_lock); ++} + -+ if (!_io_hook_cache) -+ goto err; ++static inline void dm_unlock_w(void) { ++ up_write(&_dev_lock); ++} + -+ ret = dm_target_init(); -+ if (ret < 0) -+ goto err_cache_free; + -+ ret = dm_interface_init(); -+ if (ret < 0) -+ goto err_cache_free; ++/* ++ * Setup and tear down the driver ++ */ ++static int __init local_init(void) ++{ ++ int r; + -+ ret = devfs_register_blkdev(major, _name, &dm_blk_dops); -+ if (ret < 0) -+ goto err_blkdev; ++ init_rwsem(&_dev_lock); + -+ if (major == 0) -+ major = ret; ++ /* allocate a slab for the io-hooks */ ++ if (!_io_hook_cache && ++ !(_io_hook_cache = kmem_cache_create("dm io hooks", ++ sizeof(struct io_hook), ++ 0, 0, NULL, NULL))) ++ return -ENOMEM; ++ ++ r = devfs_register_blkdev(_major, _name, &dm_blk_dops); ++ if (r < 0) { ++ printk(KERN_ERR "%s -- register_blkdev failed\n", _name); ++ kmem_cache_destroy(_io_hook_cache); ++ return r; ++ } ++ ++ if (!_major) ++ _major = r; + + /* set up the arrays */ -+ read_ahead[major] = DEFAULT_READ_AHEAD; -+ blk_size[major] = _block_size; -+ blksize_size[major] = _blksize_size; -+ hardsect_size[major] = _hardsect_size; ++ read_ahead[_major] = DEFAULT_READ_AHEAD; ++ blk_size[_major] = _block_size; ++ blksize_size[_major] = _blksize_size; ++ hardsect_size[_major] = _hardsect_size; + -+ blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request); ++ blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request); + + _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); + + printk(KERN_INFO "%s %s initialised, %s\n", _name, _version, _email); + return 0; -+ -+ err_blkdev: -+ printk(KERN_ERR "%s -- register_blkdev failed\n", _name); -+ dm_interface_exit(); -+ err_cache_free: -+ kmem_cache_destroy(_io_hook_cache); -+ err: -+ return ret; +} + -+static void __exit dm_exit(void) ++static void __exit local_exit(void) +{ -+ 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) ++ if (devfs_unregister_blkdev(_major, _name) < 0) + printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name); + -+ read_ahead[major] = 0; -+ blk_size[major] = NULL; -+ blksize_size[major] = NULL; -+ hardsect_size[major] = NULL; ++ read_ahead[_major] = 0; ++ blk_size[_major] = NULL; ++ blksize_size[_major] = NULL; ++ hardsect_size[_major] = NULL; + + printk(KERN_INFO "%s %s cleaned up\n", _name, _version); +} + ++static int __init dm_init(void) ++{ ++ int r; ++ ++ r = local_init(); ++ if (r) ++ return r; ++ ++ r = dm_target_init(); ++ if (r) { ++ local_exit(); ++ return r; ++ } ++ ++ r = dm_interface_init(); ++ if (r) { ++ dm_target_exit(); ++ local_exit(); ++ return r; ++ } ++ ++ return 0; ++} ++ ++static void __exit dm_exit(void) ++{ ++ dm_interface_exit(); ++ dm_target_exit(); ++ local_exit(); ++} ++ +/* -+ * block device functions ++ * Block device functions + */ +static int dm_blk_open(struct inode *inode, struct file *file) +{ @@ -1162,16 +1188,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + md = _devs[minor]; + + if (!md) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -ENXIO; + } + + md->use_count++; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1184,16 +1210,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + md = _devs[minor]; + if (!md || md->use_count < 1) { + WARN("reference count in mapped_device incorrect"); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -ENXIO; + } + + md->use_count--; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1262,7 +1288,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * FIXME: need to decide if deferred_io's need ++ * FIXME: We need to decide if deferred_io's need + * their own slab, I say no for now since they are + * only used when the device is suspended. + */ @@ -1277,12 +1303,12 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * call a targets optional error function if -+ * an io failed. ++ * Call a target's optional error function if an I/O failed. + */ +static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) +{ + dm_err_fn err = ih->target->type->err; ++ + if (err) + return err(bh, ih->rw, ih->target->private); + @@ -1290,9 +1316,8 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * bh->b_end_io routine that decrements the -+ * pending count and then calls the original -+ * bh->b_end_io fn. ++ * bh->b_end_io routine that decrements the pending count ++ * and then calls the original bh->b_end_io fn. + */ +static void dec_pending(struct buffer_head *bh, int uptodate) +{ @@ -1313,7 +1338,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * add the bh to the list of deferred io. ++ * Add the bh to the list of deferred io. + */ +static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) +{ @@ -1322,23 +1347,23 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (!di) + return -ENOMEM; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (!md->suspended) { -+ up_write(&_dev_lock); -+ return 0; ++ dm_unlock_w(); ++ return 1; + } + + di->bh = bh; + di->rw = rw; + di->next = md->deferred; + md->deferred = di; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + -+ return 1; ++ return 0; /* deferred successfully */ +} + +/* -+ * do the bh mapping for a given leaf ++ * Do the bh mapping for a given leaf + */ +static inline int __map_buffer(struct mapped_device *md, + struct buffer_head *bh, int rw, int leaf) @@ -1355,7 +1380,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + ih = alloc_io_hook(); + + if (!ih) -+ return 0; ++ return -1; + + ih->md = md; + ih->rw = rw; @@ -1370,21 +1395,19 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + atomic_inc(&md->pending); + bh->b_end_io = dec_pending; + bh->b_private = ih; -+ + } else if (r == 0) + /* we don't need to hook */ + free_io_hook(ih); -+ + else if (r < 0) { + free_io_hook(ih); -+ return 0; ++ return -1; + } + -+ return 1; ++ return 0; +} + +/* -+ * search the btree for the correct target. ++ * Search the btree for the correct target. + */ +static inline int __find_node(struct dm_table *t, struct buffer_head *bh) +{ @@ -1411,7 +1434,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + goto bad_no_lock; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + md = _devs[minor]; + + if (!md) @@ -1422,7 +1445,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + * this io for later. + */ + while (md->suspended) { -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + if (rw == READA) + goto bad_no_lock; @@ -1432,26 +1455,24 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (r < 0) + goto bad_no_lock; + -+ else if (r > 0) ++ else if (r == 0) + return 0; /* deferred successfully */ + + /* -+ * We're in a while loop, because -+ * someone could suspend before we -+ * get to the following read -+ * lock ++ * We're in a while loop, because someone could suspend ++ * before we get to the following read lock + */ -+ down_read(&_dev_lock); ++ dm_lock_r(); + } + -+ if (!__map_buffer(md, bh, rw, __find_node(md->map, bh))) ++ if (__map_buffer(md, bh, rw, __find_node(md->map, bh)) < 0) + goto bad; + -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return 1; + + bad: -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + bad_no_lock: + buffer_IO_error(bh); @@ -1468,7 +1489,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * creates a dummy buffer head and maps it (for lilo). ++ * Creates a dummy buffer head and maps it (for lilo). + */ +static int do_bmap(kdev_t dev, unsigned long block, + kdev_t * r_dev, unsigned long *r_block) @@ -1478,7 +1499,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + int minor = MINOR(dev), r; + struct target *t; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) || md->suspended) { + r = -ENXIO; + goto out; @@ -1506,13 +1527,12 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + *r_block = bh.b_rsector / (bh.b_size >> 9); + + out: -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return r; +} + +/* -+ * marshals arguments and results between user and -+ * kernel space. ++ * Marshals arguments and results between user and kernel space. + */ +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) +{ @@ -1534,8 +1554,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * see if the device with a specific minor # is -+ * free. ++ * See if the device with a specific minor # is free. + */ +static inline int __specific_dev(int minor) +{ @@ -1576,24 +1595,24 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + + memset(md, 0, sizeof(*md)); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor); + + if (minor < 0) { + WARN("no free devices available"); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + kfree(md); + return 0; + } + -+ md->dev = MKDEV(major, minor); ++ md->dev = MKDEV(_major, minor); + md->name[0] = '\0'; + md->suspended = 0; + + init_waitqueue_head(&md->wait); + + _devs[minor] = md; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return md; +} @@ -1621,9 +1640,8 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * the hardsect size for a mapped device is the -+ * smallest hard sect size from the devices it -+ * maps onto. ++ * The hardsect size for a mapped device is the smallest hardsect size ++ * from the devices it maps onto. + */ +static int __find_hardsect_size(struct list_head *devices) +{ @@ -1692,36 +1710,38 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + if (strchr(name, '/')) { + WARN("invalid device name"); -+ return 0; ++ return -1; + } + + if (__get_by_name(name)) { + WARN("device name already in use"); -+ return 0; ++ return -1; + } + -+ return 1; ++ return 0; +} + +/* -+ * constructor for a new device ++ * Constructor for a new device + */ -+struct mapped_device *dm_create(const char *name, int minor, -+ struct dm_table *table) ++int dm_create(const char *name, int minor, struct dm_table *table, ++ struct mapped_device **result) +{ -+ int r = -EINVAL; ++ int r; + struct mapped_device *md; + + if (minor >= MAX_DEVICES) -+ return ERR_PTR(-ENXIO); ++ return -ENXIO; + + if (!(md = alloc_dev(minor))) -+ return ERR_PTR(-ENXIO); ++ return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + -+ if (!check_name(name)) ++ if (check_name(name) < 0) { ++ r = -EINVAL; + goto err; ++ } + + strcpy(md->name, name); + _devs[minor] = md; @@ -1734,14 +1754,15 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (r) + goto err; + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + -+ return md; ++ *result = md; ++ return 0; + + err: -+ up_write(&_dev_lock); ++ dm_unlock_w(); + free_dev(md); -+ return ERR_PTR(r); ++ return r; +} + +/* @@ -1752,23 +1773,23 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + int minor, r; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + if (md->suspended || md->use_count) { -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return -EPERM; + } + + fsync_dev(md->dev); -+ up_read(&_dev_lock); ++ dm_unlock_r(); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (md->use_count) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EPERM; + } + + if ((r = unregister_device(md))) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return r; + } + @@ -1776,7 +1797,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + _devs[minor] = 0; + __unbind(md); + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + free_dev(md); + @@ -1784,8 +1805,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * requeue the deferred buffer_heads by calling -+ * generic_make_request. ++ * Requeue the deferred buffer_heads by calling generic_make_request. + */ +static void flush_deferred_io(struct deferred_io *c) +{ @@ -1806,22 +1826,22 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + int r; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + + /* device must be suspended */ + if (!md->suspended) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EPERM; + } + + __unbind(md); + + if ((r = __bind(md, table))) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return r; + } + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1839,31 +1859,31 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + DECLARE_WAITQUEUE(wait, current); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (md->suspended) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EINVAL; + } + + md->suspended = 1; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + /* wait for all the pending io to flush */ + add_wait_queue(&md->wait, &wait); + current->state = TASK_UNINTERRUPTIBLE; + do { -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (!atomic_read(&md->pending)) + break; + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + schedule(); + + } while (1); + + current->state = TASK_RUNNING; + remove_wait_queue(&md->wait, &wait); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1872,19 +1892,21 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + struct deferred_io *def; + -+ down_write(&_dev_lock); -+ if (!md->suspended) { -+ up_write(&_dev_lock); ++ dm_lock_w(); ++ if (!md->suspended || !md->map->num_targets) { ++ dm_unlock_w(); + return -EINVAL; + } + + md->suspended = 0; + def = md->deferred; + md->deferred = NULL; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + flush_deferred_io(def); + ++ fsync_dev(md->dev); ++ + return 0; +} + @@ -1895,9 +1917,9 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + struct mapped_device *md; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + md = __get_by_name(name); -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + return md; +} @@ -1915,18 +1937,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +module_init(dm_init); +module_exit(dm_exit); + -+MODULE_PARM(major, "i"); -+MODULE_PARM_DESC(major, "The major number of the device mapper"); ++MODULE_PARM(_major, "i"); ++MODULE_PARM_DESC(_major, "The major number of the device mapper"); +MODULE_DESCRIPTION("device-mapper driver"); +MODULE_AUTHOR("Joe Thornber "); +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h --- linux-2.4.16/drivers/md/dm.h Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm.h Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,145 @@ ++++ linux/drivers/md/dm.h Wed Dec 19 19:42:58 2001 +@@ -0,0 +1,157 @@ +/* -+ * dm.h -+ * + * Internal header file for device mapper + * + * Copyright (C) 2001 Sistina Software @@ -2029,18 +2049,27 @@ diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h +int dm_target_init(void); +struct target_type *dm_get_target_type(const char *name); +void dm_put_target_type(struct target_type *t); ++void dm_target_exit(void); + +/* dm.c */ -+struct mapped_device *dm_find_by_minor(int minor); +struct mapped_device *dm_get(const char *name); -+struct mapped_device *dm_create(const char *name, int minor, struct dm_table *); ++int dm_create(const char *name, int minor, struct dm_table *table, ++ struct mapped_device **result); +int dm_destroy(struct mapped_device *md); ++ ++/* ++ * The device must be suspended before calling this method. ++ */ +int dm_swap_table(struct mapped_device *md, struct dm_table *t); ++ ++/* ++ * A device can still be used while suspended, but I/O is deferred. ++ */ +int dm_suspend(struct mapped_device *md); +int dm_resume(struct mapped_device *md); + +/* dm-table.c */ -+struct dm_table *dm_table_create(void); ++int dm_table_create(struct dm_table **result); +void dm_table_destroy(struct dm_table *t); + +int dm_table_add_target(struct dm_table *t, offset_t high, @@ -2065,14 +2094,19 @@ diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h + return t->index[l] + (n * KEYS_PER_NODE); +} + -+int dm_interface_init(void) __init; -+void dm_interface_exit(void) __exit; ++/* ++ * The device-mapper can be driven through one of two interfaces; ++ * ioctl or filesystem, depending which patch you have applied. ++ */ ++ ++int dm_interface_init(void); ++void dm_interface_exit(void); + +#endif diff -ruN linux-2.4.16/drivers/md/dmfs-error.c linux/drivers/md/dmfs-error.c --- linux-2.4.16/drivers/md/dmfs-error.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dmfs-error.c Mon Dec 10 17:26:07 2001 -@@ -0,0 +1,125 @@ ++++ linux/drivers/md/dmfs-error.c Thu Dec 20 18:33:50 2001 +@@ -0,0 +1,138 @@ +/* + * dmfs-error.c + * @@ -2121,6 +2155,19 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-error.c linux/drivers/md/dmfs-error.c + msg: "Out of memory during creation of table\n", +}; + ++int dmfs_error_revalidate(struct dentry *dentry) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct inode *parent = dentry->d_parent->d_inode; ++ ++ if (!list_empty(&DMFS_I(parent)->errors)) ++ inode->i_size = 1; ++ else ++ inode->i_size = 0; ++ ++ return 0; ++} ++ +void dmfs_add_error(struct inode *inode, unsigned num, char *str) +{ + struct dmfs_i *dmi = DMFS_I(inode); @@ -2200,8 +2247,8 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-error.c linux/drivers/md/dmfs-error.c +}; diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c --- linux-2.4.16/drivers/md/dmfs-lv.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dmfs-lv.c Mon Dec 10 16:42:24 2001 -@@ -0,0 +1,242 @@ ++++ linux/drivers/md/dmfs-lv.c Thu Dec 20 18:07:13 2001 +@@ -0,0 +1,258 @@ +/* + * dmfs-lv.c + * @@ -2249,6 +2296,7 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c +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); ++extern int dmfs_error_revalidate(struct dentry *dentry); + +static int dmfs_seq_open(struct inode *inode, struct file *file) +{ @@ -2278,6 +2326,10 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c +static struct inode_operations dmfs_null_inode_operations = { +}; + ++static struct inode_operations dmfs_error_inode_operations = { ++ revalidate: dmfs_error_revalidate ++}; ++ +static struct file_operations dmfs_seq_ro_file_operations = { + open: dmfs_seq_open, + read: seq_read, @@ -2298,6 +2350,18 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c + return inode; +} + ++static struct inode *dmfs_create_error(struct inode *dir, int mode, ++ struct seq_operations *seq_ops, int dev) ++{ ++ struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG); ++ if (inode) { ++ inode->i_fop = &dmfs_seq_ro_file_operations; ++ inode->i_op = &dmfs_error_inode_operations; ++ DMFS_SEQ(inode) = seq_ops; ++ } ++ return inode; ++} ++ +static struct inode *dmfs_create_device(struct inode *dir, int mode, + struct seq_operations *seq_ops, int dev) +{ @@ -2332,7 +2396,7 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c + {".", NULL, NULL, DT_DIR}, + {"..", NULL, NULL, DT_DIR}, + {"table", dmfs_create_table, NULL, DT_REG}, -+ {"error", dmfs_create_seq_ro, &dmfs_error_seq_ops, DT_REG}, ++ {"error", dmfs_create_error, &dmfs_error_seq_ops, DT_REG}, + {"status", dmfs_create_seq_ro, &dmfs_status_seq_ops, DT_REG}, + {"device", dmfs_create_device, NULL, DT_BLK}, + {"suspend", dmfs_create_suspend, &dmfs_suspend_seq_ops, DT_REG}, @@ -2421,21 +2485,20 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-lv.c linux/drivers/md/dmfs-lv.c + int ret = -ENOMEM; + + if (inode) { -+ table = dm_table_create(); -+ ret = PTR_ERR(table); -+ if (!IS_ERR(table)) { ++ ret = dm_table_create(&table); ++ if (!ret) { + ret = dm_table_complete(table); + if (!ret) { + 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)) { ++ ret = dm_create(tmp_name, -1, table, &md); ++ if (!ret) { + DMFS_I(inode)->md = md; ++ md->suspended = 1; + return inode; + } -+ ret = PTR_ERR(md); + } + dm_table_destroy(table); + } @@ -2833,8 +2896,8 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-super.c linux/drivers/md/dmfs-super.c +} diff -ruN linux-2.4.16/drivers/md/dmfs-suspend.c linux/drivers/md/dmfs-suspend.c --- linux-2.4.16/drivers/md/dmfs-suspend.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dmfs-suspend.c Mon Dec 10 17:16:32 2001 -@@ -0,0 +1,100 @@ ++++ linux/drivers/md/dmfs-suspend.c Thu Dec 20 17:35:51 2001 +@@ -0,0 +1,113 @@ +/* + * dmfs-suspend.c + * @@ -2924,12 +2987,25 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-suspend.c linux/drivers/md/dmfs-suspend.c + return -EINVAL; + + down(&dmi->sem); -+ if (buf[0] == '0') ++ if (buf[0] == '0') { ++ if (get_exclusive_write_access(dir)) { ++ written = -EPERM; ++ goto out_unlock; ++ } ++ if (!list_empty(&dmi->errors)) { ++ put_write_access(dir); ++ written = -EPERM; ++ goto out_unlock; ++ } + written = dm_resume(dmi->md); ++ put_write_access(dir); ++ } + if (buf[0] == '1') + written = dm_suspend(dmi->md); + if (written >= 0) + written = count; ++ ++ out_unlock: + up(&dmi->sem); + + out: @@ -2937,8 +3013,8 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-suspend.c linux/drivers/md/dmfs-suspend.c +} diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c --- linux-2.4.16/drivers/md/dmfs-table.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dmfs-table.c Mon Dec 10 17:25:17 2001 -@@ -0,0 +1,371 @@ ++++ linux/drivers/md/dmfs-table.c Thu Dec 20 18:59:15 2001 +@@ -0,0 +1,381 @@ +/* + * dmfs-table.c + * @@ -3119,14 +3195,15 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c + unsigned long page; + struct dmfs_desc d; + loff_t pos = 0; ++ int r; + + if (inode->i_size == 0) + return NULL; + + page = __get_free_page(GFP_NOFS); + if (page) { -+ t = dm_table_create(); -+ if (t) { ++ r = dm_table_create(&t); ++ if (!r) { + read_descriptor_t desc; + + desc.written = 0; @@ -3143,7 +3220,10 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c + if (desc.written != inode->i_size) { + dm_table_destroy(t); + t = NULL; -+ } ++ } ++ if (!t || (t && !t->num_targets)) ++ dmfs_add_error(d.inode, 0, ++ "No valid targets found"); + } + free_page(page); + } @@ -3237,7 +3317,7 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c + * at some stage if we continue to use this set of functions for ensuring + * exclusive write access to the file + */ -+static int get_exclusive_write_access(struct inode *inode) ++int get_exclusive_write_access(struct inode *inode) +{ + if (get_write_access(inode)) + return -1; @@ -3252,10 +3332,16 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c +{ + struct dentry *dentry = file->f_dentry; + struct inode *parent = dentry->d_parent->d_inode; ++ struct dmfs_i *dmi = DMFS_I(parent); + + if (file->f_mode & FMODE_WRITE) { + if (get_exclusive_write_access(parent)) + return -EPERM; ++ ++ if (!dmi->md->suspended) { ++ put_write_access(parent); ++ return -EPERM; ++ } + } + + return 0; @@ -3312,8 +3398,8 @@ diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c +} diff -ruN linux-2.4.16/drivers/md/dmfs.h linux/drivers/md/dmfs.h --- linux-2.4.16/drivers/md/dmfs.h Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dmfs.h Mon Dec 10 17:17:17 2001 -@@ -0,0 +1,19 @@ ++++ linux/drivers/md/dmfs.h Thu Dec 20 14:59:39 2001 +@@ -0,0 +1,21 @@ +#ifndef LINUX_DMFS_H +#define LINUX_DMFS_H + @@ -3326,6 +3412,8 @@ diff -ruN linux-2.4.16/drivers/md/dmfs.h linux/drivers/md/dmfs.h + +#define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip) + ++int get_exclusive_write_access(struct inode *inode); ++ +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); + @@ -3335,7 +3423,7 @@ diff -ruN linux-2.4.16/drivers/md/dmfs.h linux/drivers/md/dmfs.h +#endif /* LINUX_DMFS_H */ diff -ruN linux-2.4.16/fs/namespace.c linux/fs/namespace.c --- linux-2.4.16/fs/namespace.c Thu Dec 6 15:57:56 2001 -+++ linux/fs/namespace.c Fri Dec 14 13:39:00 2001 ++++ linux/fs/namespace.c Thu Dec 20 20:11:27 2001 @@ -332,7 +332,7 @@ } } @@ -3347,11 +3435,9 @@ diff -ruN linux-2.4.16/fs/namespace.c linux/fs/namespace.c int retval = 0; diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device-mapper.h --- linux-2.4.16/include/linux/device-mapper.h Thu Jan 1 01:00:00 1970 -+++ linux/include/linux/device-mapper.h Mon Dec 10 15:43:56 2001 -@@ -0,0 +1,57 @@ ++++ linux/include/linux/device-mapper.h Wed Dec 19 19:42:09 2001 +@@ -0,0 +1,58 @@ +/* -+ * device-mapper.h -+ * + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. @@ -3370,15 +3456,18 @@ diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device- +struct dm_dev; +typedef unsigned int offset_t; + ++ +/* -+ * Prototypes for functions of a target ++ * Prototypes for functions for a target + */ -+typedef int (*dm_ctr_fn) (struct dm_table * t, offset_t b, offset_t l, -+ char *args, void **context); -+typedef void (*dm_dtr_fn) (struct dm_table * t, void *c); -+typedef int (*dm_map_fn) (struct buffer_head * bh, int rw, void *context); -+typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l, ++ const char *args, void **context); ++typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); ++typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); ++ + ++void dm_error(const char *message); + +/* + * Contructors should call these functions to ensure destination devices @@ -3408,7 +3497,7 @@ diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device- +#endif /* _LINUX_DEVICE_MAPPER_H */ diff -ruN linux-2.4.16/include/linux/fs.h linux/include/linux/fs.h --- linux-2.4.16/include/linux/fs.h Thu Dec 6 15:57:58 2001 -+++ linux/include/linux/fs.h Fri Dec 14 13:39:00 2001 ++++ linux/include/linux/fs.h Thu Dec 20 20:11:27 2001 @@ -980,6 +980,7 @@ extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); @@ -3419,7 +3508,7 @@ diff -ruN linux-2.4.16/include/linux/fs.h linux/include/linux/fs.h diff -ruN linux-2.4.16/include/linux/seq_file.h linux/include/linux/seq_file.h --- linux-2.4.16/include/linux/seq_file.h Thu Dec 6 15:57:56 2001 -+++ linux/include/linux/seq_file.h Fri Dec 14 13:39:00 2001 ++++ linux/include/linux/seq_file.h Thu Dec 20 20:11:27 2001 @@ -12,6 +12,7 @@ loff_t index; struct semaphore sem; @@ -3430,7 +3519,7 @@ diff -ruN linux-2.4.16/include/linux/seq_file.h linux/include/linux/seq_file.h struct seq_operations { diff -ruN linux-2.4.16/kernel/ksyms.c linux/kernel/ksyms.c --- linux-2.4.16/kernel/ksyms.c Thu Dec 6 15:57:56 2001 -+++ linux/kernel/ksyms.c Fri Dec 14 13:39:00 2001 ++++ linux/kernel/ksyms.c Thu Dec 20 20:11:27 2001 @@ -46,6 +46,7 @@ #include #include diff --git a/patches/linux-2.4.16-devmapper-ioctl.patch b/patches/linux-2.4.16-devmapper-ioctl.patch index af27bca..aaaf5ed 100644 --- a/patches/linux-2.4.16-devmapper-ioctl.patch +++ b/patches/linux-2.4.16-devmapper-ioctl.patch @@ -1,6 +1,6 @@ diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in --- linux-2.4.16/drivers/md/Config.in Fri Sep 14 22:22:18 2001 -+++ linux/drivers/md/Config.in Fri Dec 14 13:38:13 2001 ++++ linux/drivers/md/Config.in Thu Dec 20 20:12:07 2001 @@ -14,5 +14,6 @@ dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD @@ -10,7 +10,7 @@ diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in endmenu diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile --- linux-2.4.16/drivers/md/Makefile Thu Dec 6 15:57:55 2001 -+++ linux/drivers/md/Makefile Fri Dec 14 13:38:13 2001 ++++ linux/drivers/md/Makefile Thu Dec 20 20:12:07 2001 @@ -4,9 +4,11 @@ O_TARGET := mddev.o @@ -39,11 +39,9 @@ diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile + $(LD) -r -o $@ $(dm-mod-objs) diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper.h --- linux-2.4.16/drivers/md/device-mapper.h Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/device-mapper.h Mon Dec 10 15:43:56 2001 -@@ -0,0 +1,57 @@ ++++ linux/drivers/md/device-mapper.h Wed Dec 19 19:42:09 2001 +@@ -0,0 +1,58 @@ +/* -+ * device-mapper.h -+ * + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. @@ -62,15 +60,18 @@ diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper +struct dm_dev; +typedef unsigned int offset_t; + ++ +/* -+ * Prototypes for functions of a target ++ * Prototypes for functions for a target + */ -+typedef int (*dm_ctr_fn) (struct dm_table * t, offset_t b, offset_t l, -+ char *args, void **context); -+typedef void (*dm_dtr_fn) (struct dm_table * t, void *c); -+typedef int (*dm_map_fn) (struct buffer_head * bh, int rw, void *context); -+typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l, ++ const char *args, void **context); ++typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); ++typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); ++ + ++void dm_error(const char *message); + +/* + * Contructors should call these functions to ensure destination devices @@ -100,8 +101,8 @@ diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper +#endif /* _LINUX_DEVICE_MAPPER_H */ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c --- linux-2.4.16/drivers/md/dm-ioctl.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-ioctl.c Mon Dec 10 17:38:20 2001 -@@ -0,0 +1,327 @@ ++++ linux/drivers/md/dm-ioctl.c Thu Dec 20 12:23:14 2001 +@@ -0,0 +1,328 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -166,9 +167,9 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + return valid_str(*params, end); +} + -+void err_fn(const char *message, void *private) ++void dm_error(const char *message) +{ -+ printk(KERN_WARNING "%s\n", message); ++ WARN("%s", message); +} + +/* @@ -202,7 +203,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + + end = ((void *) args) + args->data_size; + -+#define PARSE_ERROR(msg) {err_fn(msg, NULL); return -EINVAL;} ++#define PARSE_ERROR(msg) {dm_error(msg); return -EINVAL;} + + for (i = 0; i < args->target_count; i++) { + @@ -221,8 +222,10 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + + /* build the target */ + if (ttype->ctr(table, spec->sector_start, spec->length, params, -+ &context)) -+ PARSE_ERROR(context); ++ &context)) { ++ dm_error(context); ++ PARSE_ERROR("target constructor failed"); ++ } + + /* add the target to the table */ + high = spec->sector_start + (spec->length - 1); @@ -271,17 +274,13 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + struct mapped_device *md; + struct dm_table *t; + -+ t = dm_table_create(); -+ r = PTR_ERR(t); -+ if (IS_ERR(t)) -+ goto bad; ++ if ((r = dm_table_create(&t))) ++ return r; + + if ((r = populate_table(t, param))) + goto bad; + -+ md = dm_create(param->name, param->minor, t); -+ r = PTR_ERR(md); -+ if (IS_ERR(md)) ++ if ((r = dm_create(param->name, param->minor, t, &md))) + goto bad; + + if ((r = info(param->name, user))) { @@ -325,9 +324,9 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + if (!md) + return -ENXIO; + -+ t = dm_table_create(); -+ if (IS_ERR(t)) -+ return PTR_ERR(t); ++ r = dm_table_create(&t); ++ if ((r = dm_table_create(&t))) ++ return r; + + if ((r = populate_table(t, param))) { + dm_table_destroy(t); @@ -348,11 +347,14 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + ++ MOD_INC_USE_COUNT; ++ + return 0; +} + +static int ctl_close(struct inode *inode, struct file *file) +{ ++ MOD_DEC_USE_COUNT; + return 0; +} + @@ -431,8 +433,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c +} diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c --- linux-2.4.16/drivers/md/dm-linear.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-linear.c Thu Dec 13 12:57:39 2001 -@@ -0,0 +1,135 @@ ++++ linux/drivers/md/dm-linear.c Thu Dec 20 12:23:38 2001 +@@ -0,0 +1,118 @@ +/* + * dm-linear.c + * @@ -459,59 +461,42 @@ diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-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: + */ +static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const char *args, void **context) +{ + struct linear_c *lc; -+ unsigned int start; -+ int r = -EINVAL; -+ char *tok; -+ char *path; -+ char *p = args; ++ unsigned long start; /* FIXME: unsigned long long with sscanf fix */ + -+ *context = "No device path given"; -+ path = next_token(&p); -+ if (!path) -+ goto bad; -+ -+ *context = "No initial offset given"; -+ tok = next_token(&p); -+ if (!tok) -+ goto bad; -+ start = simple_strtoul(tok, NULL, 10); ++ int r = -EINVAL; ++ char path[4096]; + -+ *context = "Cannot allocate linear context private structure"; + lc = kmalloc(sizeof(*lc), GFP_KERNEL); -+ if (lc == NULL) -+ goto bad; ++ if (lc == NULL) { ++ *context = "dm-linear: Cannot allocate linear context"; ++ return -ENOMEM; ++ } ++ ++ if (sscanf(args, "%4096s %lu", path, &start) != 2) { ++ *context = "dm-linear: Missing target parms: dev_path sector"; ++ return -ENOMEM; ++ } + -+ *context = "Cannot get target device"; + r = dm_table_get_device(t, path, start, l, &lc->dev); -+ if (r) -+ goto bad_free; ++ if (r) { ++ *context = "dm-linear: Device lookup failed"; ++ r = -ENXIO; ++ goto bad; ++ } + + lc->delta = (int) start - (int) b; + *context = lc; + return 0; + -+ bad_free: -+ kfree(lc); + bad: ++ kfree(lc); + return r; +} + @@ -570,8 +555,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c --- linux-2.4.16/drivers/md/dm-stripe.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-stripe.c Mon Dec 10 16:30:25 2001 -@@ -0,0 +1,187 @@ ++++ linux/drivers/md/dm-stripe.c Wed Dec 19 20:33:01 2001 +@@ -0,0 +1,192 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -619,13 +604,13 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * Parse a single pair + */ +static int get_stripe(struct dm_table *t, struct stripe_c *sc, -+ int stripe, char *args) ++ int stripe, const char *args) +{ + int n, r; + char path[4096]; + unsigned long start; + -+ if (sscanf(args, "%4095s %lu %n", path, &start, &n) != 2) ++ if (sscanf(args, "%4096s %lu %n", path, &start, &n) != 2) + return -EINVAL; + + r = dm_table_get_device(t, path, start, sc->stripe_width, @@ -642,25 +627,30 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * [ ]+ + */ +static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const 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) ++ if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) { ++ *context = "dm-stripe: Couldn't parse "; + return -EINVAL; ++ } + -+ *context = "target length is not divisable by the number of stripes"; -+ if (l % stripes) ++ if (l % stripes) { ++ *context = "dm-stripe: Target length not divisable by " ++ "number of stripes"; + return -EINVAL; ++ } + -+ *context = "couldn't allocate memory for striped context"; + sc = alloc_context(stripes); -+ if (!sc) ++ if (!sc) { ++ *context = "dm-stripe: Memory allocation for striped context" ++ "failed"; + return -ENOMEM; ++ } + + sc->logical_start = b; + sc->stripes = stripes; @@ -670,7 +660,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + * chunk_size is a power of two + */ + if (!chunk_size || chunk_size & (chunk_size - 1)) { -+ *context = "invalid chunk size"; ++ *context = "dm-stripe: Invalid chunk size"; + kfree(sc); + return -EINVAL; + } @@ -688,7 +678,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + n = get_stripe(t, sc, i, args); + + if (n < 0) { -+ *context = "couldn't parse stripe destination"; ++ *context = "dm-stripe: Couldn't parse stripe " ++ "destination"; + kfree(sc); + return n; + } @@ -707,7 +698,6 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c + dm_table_put_device(t, sc->stripe[i].dev); + + kfree(sc); -+ return; +} + +static int stripe_map(struct buffer_head *bh, int rw, void *context) @@ -761,8 +751,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c --- linux-2.4.16/drivers/md/dm-table.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-table.c Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,402 @@ ++++ linux/drivers/md/dm-table.c Wed Dec 19 19:40:07 2001 +@@ -0,0 +1,400 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -865,24 +855,25 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + return 0; +} + -+struct dm_table *dm_table_create(void) ++int dm_table_create(struct dm_table **result) +{ + struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO); + + if (!t) -+ return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + memset(t, 0, sizeof(*t)); + INIT_LIST_HEAD(&t->devices); + -+ /* allocate a single nodes worth of targets to -+ begin with */ ++ /* allocate a single node's worth of targets to begin with */ + if (alloc_targets(t, KEYS_PER_NODE)) { + kfree(t); -+ t = ERR_PTR(-ENOMEM); ++ t = NULL; ++ return -ENOMEM; + } + -+ return t; ++ *result = t; ++ return 0; +} + +static void free_devices(struct list_head *devices) @@ -908,10 +899,10 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + for (i = 0; i < t->num_targets; i++) { + struct target *tgt = &t->targets[i]; + ++ dm_put_target_type(t->targets[i].type); ++ + if (tgt->type->dtr) + tgt->type->dtr(t, tgt->private); -+ -+ dm_put_target_type(t->targets[i].type); + } + + vfree(t->highs); @@ -928,8 +919,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * Checks to see if we need to extend -+ * highs or targets. ++ * Checks to see if we need to extend highs or targets. + */ +static inline int check_space(struct dm_table *t) +{ @@ -940,9 +930,9 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * convert a device path to a kdev_t. ++ * Convert a device path to a kdev_t. + */ -+int lookup_device(const char *path, kdev_t * dev) ++int lookup_device(const char *path, kdev_t *dev) +{ + int r; + struct nameidata nd; @@ -973,7 +963,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * see if we've already got a device in the list. ++ * See if we've already got a device in the list. + */ +static struct dm_dev *find_device(struct list_head *l, kdev_t dev) +{ @@ -989,8 +979,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * open a device so we can use it as a map -+ * destination. ++ * Open a device so we can use it as a map destination. + */ +static int open_dev(struct dm_dev *d) +{ @@ -1009,7 +998,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * close a device that we've been using. ++ * Close a device that we've been using. + */ +static void close_dev(struct dm_dev *d) +{ @@ -1042,8 +1031,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * add a device to the list, or just increment the -+ * usage count if it's already present. ++ * 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) @@ -1063,7 +1052,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c + return -ENOMEM; + + dd->dev = dev; -+ dd->bd = 0; ++ dd->bd = NULL; + + if ((r = open_dev(dd))) { + kfree(dd); @@ -1087,8 +1076,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * decrement a devices use count and remove it if -+ * neccessary. ++ * Decrement a devices use count and remove it if neccessary. + */ +void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) +{ @@ -1100,7 +1088,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * adds a target to the map ++ * Adds a target to the map + */ +int dm_table_add_target(struct dm_table *t, offset_t high, + struct target_type *type, void *private) @@ -1143,7 +1131,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +} + +/* -+ * builds the btree to index the map ++ * Builds the btree to index the map + */ +int dm_table_complete(struct dm_table *t) +{ @@ -1167,8 +1155,8 @@ diff -ruN linux-2.4.16/drivers/md/dm-table.c linux/drivers/md/dm-table.c +EXPORT_SYMBOL(dm_table_put_device); diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c --- linux-2.4.16/drivers/md/dm-target.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm-target.c Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,184 @@ ++++ linux/drivers/md/dm-target.c Wed Dec 19 19:57:41 2001 +@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited + * @@ -1320,7 +1308,7 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c + * up LV's that have holes in them. + */ +static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l, -+ char *args, void **context) ++ const char *args, void **context) +{ + *context = NULL; + return 0; @@ -1339,11 +1327,11 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c +} + +static struct target_type error_target = { -+ name:"error", -+ ctr:io_err_ctr, -+ dtr:io_err_dtr, -+ map:io_err_map, -+ err:NULL ++ name: "error", ++ ctr: io_err_ctr, ++ dtr: io_err_dtr, ++ map: io_err_map, ++ err: NULL +}; + +int dm_target_init(void) @@ -1351,14 +1339,20 @@ diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c + return dm_register_target(&error_target); +} + ++void dm_target_exit(void) ++{ ++ if (dm_unregister_target(&error_target)) ++ WARN("unregister of error target failed."); ++} ++ +EXPORT_SYMBOL(dm_register_target); +EXPORT_SYMBOL(dm_unregister_target); diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c --- linux-2.4.16/drivers/md/dm.c Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm.c Fri Dec 14 13:37:30 2001 -@@ -0,0 +1,892 @@ ++++ linux/drivers/md/dm.c Thu Dec 20 20:11:36 2001 +@@ -0,0 +1,921 @@ +/* -+ * Copyright (C) 2001 Sistina Software ++ * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ @@ -1366,22 +1360,20 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +#include "dm.h" + +#include -+#include +#include -+#include + +/* we only need this for the lv_bmap struct definition, not happy */ +#include + +#define MAX_DEVICES 64 +#define DEFAULT_READ_AHEAD 64 -+#define DEVICE_NAME "device-mapper" ++#define DEVICE_NAME "device-mapper" /* Name for messaging */ + +static const char *_name = DEVICE_NAME; -+static const char *_version = "0.90.02-ioctl (2001-12-14)"; ++static const char *_version = "0.90.03-ioctl (2001-12-20)"; +static const char *_email = "lvm-devel@lists.sistina.com"; + -+static int major = 0; ++static int _major = 0; + +struct io_hook { + struct mapped_device *md; @@ -1408,80 +1400,115 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); + +/* -+ * setup and teardown the driver ++ * Shortcuts to lock/unlock the global _dev_lock + */ -+static int __init dm_init(void) -+{ -+ int ret = -ENOMEM; ++static inline void dm_lock_r(void) { ++ down_read(&_dev_lock); ++} + -+ init_rwsem(&_dev_lock); ++static inline void dm_unlock_r(void) { ++ up_read(&_dev_lock); ++} ++ ++static inline void dm_lock_w(void) { ++ down_write(&_dev_lock); ++} + -+ _io_hook_cache = kmem_cache_create("dm io hooks", -+ sizeof(struct io_hook), -+ 0, 0, NULL, NULL); ++static inline void dm_unlock_w(void) { ++ up_write(&_dev_lock); ++} + -+ if (!_io_hook_cache) -+ goto err; + -+ ret = dm_target_init(); -+ if (ret < 0) -+ goto err_cache_free; ++/* ++ * Setup and tear down the driver ++ */ ++static int __init local_init(void) ++{ ++ int r; + -+ ret = dm_interface_init(); -+ if (ret < 0) -+ goto err_cache_free; ++ init_rwsem(&_dev_lock); + -+ ret = devfs_register_blkdev(major, _name, &dm_blk_dops); -+ if (ret < 0) -+ goto err_blkdev; ++ /* allocate a slab for the io-hooks */ ++ if (!_io_hook_cache && ++ !(_io_hook_cache = kmem_cache_create("dm io hooks", ++ sizeof(struct io_hook), ++ 0, 0, NULL, NULL))) ++ return -ENOMEM; + -+ if (major == 0) -+ major = ret; ++ r = devfs_register_blkdev(_major, _name, &dm_blk_dops); ++ if (r < 0) { ++ printk(KERN_ERR "%s -- register_blkdev failed\n", _name); ++ kmem_cache_destroy(_io_hook_cache); ++ return r; ++ } ++ ++ if (!_major) ++ _major = r; + + /* set up the arrays */ -+ read_ahead[major] = DEFAULT_READ_AHEAD; -+ blk_size[major] = _block_size; -+ blksize_size[major] = _blksize_size; -+ hardsect_size[major] = _hardsect_size; ++ read_ahead[_major] = DEFAULT_READ_AHEAD; ++ blk_size[_major] = _block_size; ++ blksize_size[_major] = _blksize_size; ++ hardsect_size[_major] = _hardsect_size; + -+ blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request); ++ blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request); + + _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); + + printk(KERN_INFO "%s %s initialised, %s\n", _name, _version, _email); + return 0; -+ -+ err_blkdev: -+ printk(KERN_ERR "%s -- register_blkdev failed\n", _name); -+ dm_interface_exit(); -+ err_cache_free: -+ kmem_cache_destroy(_io_hook_cache); -+ err: -+ return ret; +} + -+static void __exit dm_exit(void) ++static void __exit local_exit(void) +{ -+ 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) ++ if (devfs_unregister_blkdev(_major, _name) < 0) + printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name); + -+ read_ahead[major] = 0; -+ blk_size[major] = NULL; -+ blksize_size[major] = NULL; -+ hardsect_size[major] = NULL; ++ read_ahead[_major] = 0; ++ blk_size[_major] = NULL; ++ blksize_size[_major] = NULL; ++ hardsect_size[_major] = NULL; + + printk(KERN_INFO "%s %s cleaned up\n", _name, _version); +} + ++static int __init dm_init(void) ++{ ++ int r; ++ ++ r = local_init(); ++ if (r) ++ return r; ++ ++ r = dm_target_init(); ++ if (r) { ++ local_exit(); ++ return r; ++ } ++ ++ r = dm_interface_init(); ++ if (r) { ++ dm_target_exit(); ++ local_exit(); ++ return r; ++ } ++ ++ return 0; ++} ++ ++static void __exit dm_exit(void) ++{ ++ dm_interface_exit(); ++ dm_target_exit(); ++ local_exit(); ++} ++ +/* -+ * block device functions ++ * Block device functions + */ +static int dm_blk_open(struct inode *inode, struct file *file) +{ @@ -1491,16 +1518,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + md = _devs[minor]; + + if (!md) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -ENXIO; + } + + md->use_count++; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1513,16 +1540,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + md = _devs[minor]; + if (!md || md->use_count < 1) { + WARN("reference count in mapped_device incorrect"); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -ENXIO; + } + + md->use_count--; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -1591,7 +1618,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * FIXME: need to decide if deferred_io's need ++ * FIXME: We need to decide if deferred_io's need + * their own slab, I say no for now since they are + * only used when the device is suspended. + */ @@ -1606,12 +1633,12 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * call a targets optional error function if -+ * an io failed. ++ * Call a target's optional error function if an I/O failed. + */ +static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) +{ + dm_err_fn err = ih->target->type->err; ++ + if (err) + return err(bh, ih->rw, ih->target->private); + @@ -1619,9 +1646,8 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * bh->b_end_io routine that decrements the -+ * pending count and then calls the original -+ * bh->b_end_io fn. ++ * bh->b_end_io routine that decrements the pending count ++ * and then calls the original bh->b_end_io fn. + */ +static void dec_pending(struct buffer_head *bh, int uptodate) +{ @@ -1642,7 +1668,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * add the bh to the list of deferred io. ++ * Add the bh to the list of deferred io. + */ +static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw) +{ @@ -1651,23 +1677,23 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (!di) + return -ENOMEM; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (!md->suspended) { -+ up_write(&_dev_lock); -+ return 0; ++ dm_unlock_w(); ++ return 1; + } + + di->bh = bh; + di->rw = rw; + di->next = md->deferred; + md->deferred = di; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + -+ return 1; ++ return 0; /* deferred successfully */ +} + +/* -+ * do the bh mapping for a given leaf ++ * Do the bh mapping for a given leaf + */ +static inline int __map_buffer(struct mapped_device *md, + struct buffer_head *bh, int rw, int leaf) @@ -1684,7 +1710,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + ih = alloc_io_hook(); + + if (!ih) -+ return 0; ++ return -1; + + ih->md = md; + ih->rw = rw; @@ -1699,21 +1725,19 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + atomic_inc(&md->pending); + bh->b_end_io = dec_pending; + bh->b_private = ih; -+ + } else if (r == 0) + /* we don't need to hook */ + free_io_hook(ih); -+ + else if (r < 0) { + free_io_hook(ih); -+ return 0; ++ return -1; + } + -+ return 1; ++ return 0; +} + +/* -+ * search the btree for the correct target. ++ * Search the btree for the correct target. + */ +static inline int __find_node(struct dm_table *t, struct buffer_head *bh) +{ @@ -1740,7 +1764,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (minor >= MAX_DEVICES) + goto bad_no_lock; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + md = _devs[minor]; + + if (!md) @@ -1751,7 +1775,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + * this io for later. + */ + while (md->suspended) { -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + if (rw == READA) + goto bad_no_lock; @@ -1761,26 +1785,24 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (r < 0) + goto bad_no_lock; + -+ else if (r > 0) ++ else if (r == 0) + return 0; /* deferred successfully */ + + /* -+ * We're in a while loop, because -+ * someone could suspend before we -+ * get to the following read -+ * lock ++ * We're in a while loop, because someone could suspend ++ * before we get to the following read lock + */ -+ down_read(&_dev_lock); ++ dm_lock_r(); + } + -+ if (!__map_buffer(md, bh, rw, __find_node(md->map, bh))) ++ if (__map_buffer(md, bh, rw, __find_node(md->map, bh)) < 0) + goto bad; + -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return 1; + + bad: -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + bad_no_lock: + buffer_IO_error(bh); @@ -1797,7 +1819,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * creates a dummy buffer head and maps it (for lilo). ++ * Creates a dummy buffer head and maps it (for lilo). + */ +static int do_bmap(kdev_t dev, unsigned long block, + kdev_t * r_dev, unsigned long *r_block) @@ -1807,7 +1829,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + int minor = MINOR(dev), r; + struct target *t; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) || md->suspended) { + r = -ENXIO; + goto out; @@ -1835,13 +1857,12 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + *r_block = bh.b_rsector / (bh.b_size >> 9); + + out: -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return r; +} + +/* -+ * marshals arguments and results between user and -+ * kernel space. ++ * Marshals arguments and results between user and kernel space. + */ +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) +{ @@ -1863,8 +1884,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * see if the device with a specific minor # is -+ * free. ++ * See if the device with a specific minor # is free. + */ +static inline int __specific_dev(int minor) +{ @@ -1905,24 +1925,24 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + + memset(md, 0, sizeof(*md)); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor); + + if (minor < 0) { + WARN("no free devices available"); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + kfree(md); + return 0; + } + -+ md->dev = MKDEV(major, minor); ++ md->dev = MKDEV(_major, minor); + md->name[0] = '\0'; + md->suspended = 0; + + init_waitqueue_head(&md->wait); + + _devs[minor] = md; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return md; +} @@ -1950,9 +1970,8 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * the hardsect size for a mapped device is the -+ * smallest hard sect size from the devices it -+ * maps onto. ++ * The hardsect size for a mapped device is the smallest hardsect size ++ * from the devices it maps onto. + */ +static int __find_hardsect_size(struct list_head *devices) +{ @@ -2021,36 +2040,38 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + if (strchr(name, '/')) { + WARN("invalid device name"); -+ return 0; ++ return -1; + } + + if (__get_by_name(name)) { + WARN("device name already in use"); -+ return 0; ++ return -1; + } + -+ return 1; ++ return 0; +} + +/* -+ * constructor for a new device ++ * Constructor for a new device + */ -+struct mapped_device *dm_create(const char *name, int minor, -+ struct dm_table *table) ++int dm_create(const char *name, int minor, struct dm_table *table, ++ struct mapped_device **result) +{ -+ int r = -EINVAL; ++ int r; + struct mapped_device *md; + + if (minor >= MAX_DEVICES) -+ return ERR_PTR(-ENXIO); ++ return -ENXIO; + + if (!(md = alloc_dev(minor))) -+ return ERR_PTR(-ENXIO); ++ return -ENXIO; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + -+ if (!check_name(name)) ++ if (check_name(name) < 0) { ++ r = -EINVAL; + goto err; ++ } + + strcpy(md->name, name); + _devs[minor] = md; @@ -2063,14 +2084,15 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + if (r) + goto err; + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + -+ return md; ++ *result = md; ++ return 0; + + err: -+ up_write(&_dev_lock); ++ dm_unlock_w(); + free_dev(md); -+ return ERR_PTR(r); ++ return r; +} + +/* @@ -2081,23 +2103,23 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + int minor, r; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + if (md->suspended || md->use_count) { -+ up_read(&_dev_lock); ++ dm_unlock_r(); + return -EPERM; + } + + fsync_dev(md->dev); -+ up_read(&_dev_lock); ++ dm_unlock_r(); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (md->use_count) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EPERM; + } + + if ((r = unregister_device(md))) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return r; + } + @@ -2105,7 +2127,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c + _devs[minor] = 0; + __unbind(md); + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + free_dev(md); + @@ -2113,8 +2135,7 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +} + +/* -+ * requeue the deferred buffer_heads by calling -+ * generic_make_request. ++ * Requeue the deferred buffer_heads by calling generic_make_request. + */ +static void flush_deferred_io(struct deferred_io *c) +{ @@ -2135,22 +2156,22 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + int r; + -+ down_write(&_dev_lock); ++ dm_lock_w(); + + /* device must be suspended */ + if (!md->suspended) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EPERM; + } + + __unbind(md); + + if ((r = __bind(md, table))) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return r; + } + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -2168,31 +2189,31 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + DECLARE_WAITQUEUE(wait, current); + -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (md->suspended) { -+ up_write(&_dev_lock); ++ dm_unlock_w(); + return -EINVAL; + } + + md->suspended = 1; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + /* wait for all the pending io to flush */ + add_wait_queue(&md->wait, &wait); + current->state = TASK_UNINTERRUPTIBLE; + do { -+ down_write(&_dev_lock); ++ dm_lock_w(); + if (!atomic_read(&md->pending)) + break; + -+ up_write(&_dev_lock); ++ dm_unlock_w(); + schedule(); + + } while (1); + + current->state = TASK_RUNNING; + remove_wait_queue(&md->wait, &wait); -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + return 0; +} @@ -2201,19 +2222,21 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + struct deferred_io *def; + -+ down_write(&_dev_lock); -+ if (!md->suspended) { -+ up_write(&_dev_lock); ++ dm_lock_w(); ++ if (!md->suspended || !md->map->num_targets) { ++ dm_unlock_w(); + return -EINVAL; + } + + md->suspended = 0; + def = md->deferred; + md->deferred = NULL; -+ up_write(&_dev_lock); ++ dm_unlock_w(); + + flush_deferred_io(def); + ++ fsync_dev(md->dev); ++ + return 0; +} + @@ -2224,9 +2247,9 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +{ + struct mapped_device *md; + -+ down_read(&_dev_lock); ++ dm_lock_r(); + md = __get_by_name(name); -+ up_read(&_dev_lock); ++ dm_unlock_r(); + + return md; +} @@ -2244,18 +2267,16 @@ diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c +module_init(dm_init); +module_exit(dm_exit); + -+MODULE_PARM(major, "i"); -+MODULE_PARM_DESC(major, "The major number of the device mapper"); ++MODULE_PARM(_major, "i"); ++MODULE_PARM_DESC(_major, "The major number of the device mapper"); +MODULE_DESCRIPTION("device-mapper driver"); +MODULE_AUTHOR("Joe Thornber "); +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h --- linux-2.4.16/drivers/md/dm.h Thu Jan 1 01:00:00 1970 -+++ linux/drivers/md/dm.h Mon Dec 10 16:23:04 2001 -@@ -0,0 +1,145 @@ ++++ linux/drivers/md/dm.h Wed Dec 19 19:42:58 2001 +@@ -0,0 +1,157 @@ +/* -+ * dm.h -+ * + * Internal header file for device mapper + * + * Copyright (C) 2001 Sistina Software @@ -2358,18 +2379,27 @@ diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h +int dm_target_init(void); +struct target_type *dm_get_target_type(const char *name); +void dm_put_target_type(struct target_type *t); ++void dm_target_exit(void); + +/* dm.c */ -+struct mapped_device *dm_find_by_minor(int minor); +struct mapped_device *dm_get(const char *name); -+struct mapped_device *dm_create(const char *name, int minor, struct dm_table *); ++int dm_create(const char *name, int minor, struct dm_table *table, ++ struct mapped_device **result); +int dm_destroy(struct mapped_device *md); ++ ++/* ++ * The device must be suspended before calling this method. ++ */ +int dm_swap_table(struct mapped_device *md, struct dm_table *t); ++ ++/* ++ * A device can still be used while suspended, but I/O is deferred. ++ */ +int dm_suspend(struct mapped_device *md); +int dm_resume(struct mapped_device *md); + +/* dm-table.c */ -+struct dm_table *dm_table_create(void); ++int dm_table_create(struct dm_table **result); +void dm_table_destroy(struct dm_table *t); + +int dm_table_add_target(struct dm_table *t, offset_t high, @@ -2394,17 +2424,20 @@ diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h + return t->index[l] + (n * KEYS_PER_NODE); +} + -+int dm_interface_init(void) __init; -+void dm_interface_exit(void) __exit; ++/* ++ * The device-mapper can be driven through one of two interfaces; ++ * ioctl or filesystem, depending which patch you have applied. ++ */ ++ ++int dm_interface_init(void); ++void dm_interface_exit(void); + +#endif diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device-mapper.h --- linux-2.4.16/include/linux/device-mapper.h Thu Jan 1 01:00:00 1970 -+++ linux/include/linux/device-mapper.h Mon Dec 10 15:43:56 2001 -@@ -0,0 +1,57 @@ ++++ linux/include/linux/device-mapper.h Wed Dec 19 19:42:09 2001 +@@ -0,0 +1,58 @@ +/* -+ * device-mapper.h -+ * + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. @@ -2423,15 +2456,18 @@ diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device- +struct dm_dev; +typedef unsigned int offset_t; + ++ +/* -+ * Prototypes for functions of a target ++ * Prototypes for functions for a target + */ -+typedef int (*dm_ctr_fn) (struct dm_table * t, offset_t b, offset_t l, -+ char *args, void **context); -+typedef void (*dm_dtr_fn) (struct dm_table * t, void *c); -+typedef int (*dm_map_fn) (struct buffer_head * bh, int rw, void *context); -+typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l, ++ const char *args, void **context); ++typedef void (*dm_dtr_fn)(struct dm_table *t, void *c); ++typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context); ++typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context); ++ + ++void dm_error(const char *message); + +/* + * Contructors should call these functions to ensure destination devices @@ -2461,8 +2497,8 @@ diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device- +#endif /* _LINUX_DEVICE_MAPPER_H */ diff -ruN linux-2.4.16/include/linux/dm-ioctl.h linux/include/linux/dm-ioctl.h --- linux-2.4.16/include/linux/dm-ioctl.h Thu Jan 1 01:00:00 1970 -+++ linux/include/linux/dm-ioctl.h Tue Dec 11 14:17:26 2001 -@@ -0,0 +1,56 @@ ++++ linux/include/linux/dm-ioctl.h Wed Dec 19 15:42:14 2001 +@@ -0,0 +1,55 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * @@ -2475,8 +2511,7 @@ diff -ruN linux-2.4.16/include/linux/dm-ioctl.h linux/include/linux/dm-ioctl.h +#include "device-mapper.h" + +/* -+ * Implements a traditional ioctl interface to the -+ * device mapper. Yuck. ++ * Implements a traditional ioctl interface to the device mapper. + */ + +struct dm_target_spec { @@ -2508,7 +2543,7 @@ diff -ruN linux-2.4.16/include/linux/dm-ioctl.h linux/include/linux/dm-ioctl.h + int target_count; /* in/out */ +}; + -+/* FIXME: find own numbers, 109 is pinched from LVM */ ++/* FIXME: find own numbers: LVM1 used 109 */ +#define DM_IOCTL 0xfd +#define DM_CHAR_MAJOR 124 + -- 2.43.5