]> sourceware.org Git - dm.git/commitdiff
Revised ioctl/dmfs merge with fixes for bugs found in tests.
authorAlasdair Kergon <agk@redhat.com>
Thu, 20 Dec 2001 20:32:14 +0000 (20:32 +0000)
committerAlasdair Kergon <agk@redhat.com>
Thu, 20 Dec 2001 20:32:14 +0000 (20:32 +0000)
20 files changed:
VERSION
dmsetup/dmsetup.c
kernel/common/device-mapper.h
kernel/common/dm-linear.c
kernel/common/dm-stripe.c
kernel/common/dm-table.c
kernel/common/dm-target.c
kernel/common/dm.c.in
kernel/common/dm.h
kernel/fs/dmfs-error.c
kernel/fs/dmfs-lv.c
kernel/fs/dmfs-suspend.c
kernel/fs/dmfs-table.c
kernel/fs/dmfs.h
kernel/ioctl/dm-ioctl.c
kernel/ioctl/dm-ioctl.h
kernel/projects.txt
lib/fs/libdevmapper.c
patches/linux-2.4.16-devmapper-fs.patch
patches/linux-2.4.16-devmapper-ioctl.patch

diff --git a/VERSION b/VERSION
index 8b0fa358b26d2de4792ce20787d6ce2e4d9d4d4a..ab63fc28b3b301186c8ad06b7c5145d55c71682c 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.90.02-cvs (2001-12-14)
+0.90.03-cvs (2001-12-20)
index a2adb00a568f0a3873d97dc5c220430ba674b83f..770e084aa611ed8a9b18ae1d92f643bb272b2218 100644 (file)
@@ -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:
index 80560a60a1c6a4f80b895659e57d0ee94531d5f0..78b42c8d59c067237226bc7e553515385dc0c9dd 100644 (file)
@@ -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 
index 124a73a8fd6efe087a58f475ca88b3872fb420bc..caa3b836565cf2364c279f1d7fcce8d14a5e4a24 100644 (file)
@@ -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: <dev_path> <offset>
  */
 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;
 }
 
index b4cfe023a4690ba8dbe680e81d28e0c0d68de2bd..6061b313f23f9a3c81264063524c8e2eaa478c00 100644 (file)
@@ -45,13 +45,13 @@ static inline struct stripe_c *alloc_context(int stripes)
  * Parse a single <dev> <sector> 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,
  * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
  */
 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 <stripes> <chunk size>";
-       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 <stripes> <chunk size>";
                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)
index dee0983a81a3ff27fca34fcd817d1a34b6f10a6c..396560b5c7b39eca668a04e880b6ab7273b24122 100644 (file)
@@ -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)
 {
index cb03e26179868a4218028b7ae9a7fe42f9aa13ee..0e8ceb7ad38e8e6c57f395e1afe2ad4e33719f08 100644 (file)
@@ -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);
index ee0364a4ead503ac85a11fea0a12a9fe189de100..4411b910bf0c93bea26dd7c5a63634d96470cc47 100644 (file)
@@ -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 <linux/blk.h>
-#include <linux/blkdev.h>
 #include <linux/blkpg.h>
-#include <linux/kmod.h>
 
 /* we only need this for the lv_bmap struct definition, not happy */
 #include <linux/lvm.h>
 
 #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 <thornber@sistina.com>");
 MODULE_LICENSE("GPL");
index 37bedcdbcef7c94dfcc2869cb89658483880d5a9..8ac869b1e208f776e6c37478be2dacdb20455563 100644 (file)
@@ -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
index 070b456ee406c4f5506e93e9138831b14e2539c7..dd603730966bb0b0e3579ae98fa95cf6466a9145 100644 (file)
@@ -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);
index 57f9c8afe4899a797428cdb5c442aee65cc239b3..fa9228ba1fa11e606499d61fe47889ffbfa0b69e 100644 (file)
@@ -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);
                }
index c9a89bd9d2bde9e663ec61c150c598152e8d8f51..7b9d6e4d5d1ba0b5f0c3abf76ed34344d98b1714 100644 (file)
@@ -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:
index 62ef93fee703b76baaa66eec4fe2ee654ee3ee2a..92a9ad64376ed3138b965d2ed0f4e9422fe46978 100644 (file)
@@ -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;
index 013e5325325814e54f082a5b6fdc871f5b74b331..a9ac3aaa8c6732224a60436aa8211084572e9ba3 100644 (file)
@@ -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);
 
index a41d57ee237899a42b25c6f3868e56e98bc57bb1..cfd6d653ae4f747b540cb381542e74c7f379fa5f 100644 (file)
@@ -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;
 }
 
index 25425ac4e6444e15d5c20fbf06d0e36111d85313..585d02a49af6e093f6073e96fd9954353b71649c 100644 (file)
@@ -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
 
index f8f932afed78df3aaff7a38bdaa26c8f83ba088b..734ee9ce7ecd5ba6b7100971abcf14f4a1a429fb 100644 (file)
@@ -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
index bb1bde1d84ec10363e2ae7a4b6d75523a10635e2..1e7103e765385c6cb963362b33e08eece6bb5d0b 100644 (file)
@@ -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;
 }
 
index bbabd684f518f50f3f6b91c225f4f000cfe6655c..133229f5d91260c7d582fc00ef92ef1533f7e472 100644 (file)
@@ -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: <dev_path> <offset>
 + */
 +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 <dev> <sector> 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
 + * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
 + */
 +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 <stripes> <chunk size>";
-+      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 <stripes> <chunk size>";
 +              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 <linux/blk.h>
-+#include <linux/blkdev.h>
 +#include <linux/blkpg.h>
-+#include <linux/kmod.h>
 +
 +/* we only need this for the lv_bmap struct definition, not happy */
 +#include <linux/lvm.h>
 +
 +#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 <thornber@sistina.com>");
 +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 <linux/tty.h>
  #include <linux/in6.h>
index af27bca6365181472b9b6d7208202bb6773ae706..aaaf5edb32a5465db4455276b37b3193e68ef952 100644 (file)
@@ -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: <dev_path> <offset>
 + */
 +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 <dev> <sector> 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
 + * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
 + */
 +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 <stripes> <chunk size>";
-+      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 <stripes> <chunk size>";
 +              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 <linux/blk.h>
-+#include <linux/blkdev.h>
 +#include <linux/blkpg.h>
-+#include <linux/kmod.h>
 +
 +/* we only need this for the lv_bmap struct definition, not happy */
 +#include <linux/lvm.h>
 +
 +#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 <thornber@sistina.com>");
 +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
 +
This page took 0.182869 seconds and 5 git commands to generate.