]> sourceware.org Git - dm.git/commitdiff
Backport changes from kernel 2.5 to 2.4.
authorAlasdair Kergon <agk@redhat.com>
Wed, 13 Nov 2002 19:38:07 +0000 (19:38 +0000)
committerAlasdair Kergon <agk@redhat.com>
Wed, 13 Nov 2002 19:38:07 +0000 (19:38 +0000)
patches/common/README
patches/common/linux-2.4.19-devmapper_only.patch
patches/linux-2.4.19-devmapper-ioctl.patch

index b8ee904a47006d1c3edd449be96ea28d72c96b58..3558affc85bd8317dfeb4df422a21be588534761 100644 (file)
@@ -10,3 +10,5 @@ These patches provide the core driver and implement basic mapping functions:
   -config.patch             - add device-mapper option (tagged experimental)
   -devmapper_only.patch     - the driver, including snapshot support
 
+And for 64-bit architectures:
+  -arch64.patch
index a189ff55a013f7f8abb4ec107931c413b1b13e17..85d41090feb81c627865cc9eab4fd2cc63eca190 100644 (file)
@@ -1,6 +1,6 @@
-diff -ruN linux-2.4.19/drivers/md/Makefile linux/drivers/md/Makefile
---- linux-2.4.19/drivers/md/Makefile   Tue Jun 25 14:14:54 2002
-+++ linux-2.4.19-dm/drivers/md/Makefile        Tue Jun 25 21:33:16 2002
+diff -ruN linux-2.4.19-dm/drivers/md/Makefile linux-2.4.19-dmbackport/drivers/md/Makefile
+--- linux-2.4.19-dm/drivers/md/Makefile        Wed Aug 14 11:51:06 2002
++++ linux-2.4.19-dmbackport/drivers/md/Makefile        Tue Nov 12 12:47:39 2002
 @@ -4,9 +4,12 @@
  
  O_TARGET      := mddev.o
@@ -28,10 +28,10 @@ diff -ruN linux-2.4.19/drivers/md/Makefile linux/drivers/md/Makefile
 +
 +dm-mod.o: $(dm-mod-objs)
 +      $(LD) -r -o $@ $(dm-mod-objs)
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-exception-store.c linux-2.4.19-dm/drivers/md/dm-exception-store.c
---- linux-2.4.19/drivers/md/dm-exception-store.c       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-exception-store.c    Wed Jun 26 20:18:59 2002
-@@ -0,0 +1,698 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm-exception-store.c linux-2.4.19-dmbackport/drivers/md/dm-exception-store.c
+--- linux-2.4.19-dm/drivers/md/dm-exception-store.c    Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-exception-store.c    Wed Nov 13 17:29:01 2002
+@@ -0,0 +1,701 @@
 +/*
 + * dm-snapshot.c
 + *
@@ -42,8 +42,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#include "dm-snapshot.h"
 +#include "kcopyd.h"
++
 +#include <linux/mm.h>
 +#include <linux/pagemap.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
 +
 +#define SECTOR_SIZE 512
 +#define SECTOR_SHIFT 9
@@ -112,7 +115,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +};
 +
 +struct commit_callback {
-+      void (*callback)(void *, int success);
++      void (*callback) (void *, int success);
 +      void *context;
 +};
 +
@@ -480,7 +483,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct pstore *ps = get_info(store);
 +      uint32_t stride;
-+      offset_t size = get_dev_size(store->snap->cow->dev);
++      sector_t size = get_dev_size(store->snap->cow->dev);
 +
 +      /* Is there enough room ? */
 +      if (size <= (ps->next_free * store->snap->chunk_size))
@@ -672,7 +675,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Implementation of the store for non-persistent snapshots.
 + *---------------------------------------------------------------*/
 +struct transient_c {
-+      offset_t next_free;
++      sector_t next_free;
 +};
 +
 +void transient_destroy(struct exception_store *store)
@@ -683,7 +686,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int transient_prepare(struct exception_store *store, struct exception *e)
 +{
 +      struct transient_c *tc = (struct transient_c *) store->context;
-+      offset_t size = get_dev_size(store->snap->cow->dev);
++      sector_t size = get_dev_size(store->snap->cow->dev);
 +
 +      if (size < (tc->next_free + store->snap->chunk_size))
 +              return -1;
@@ -710,7 +713,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +int dm_create_transient(struct exception_store *store,
-+                      struct dm_snapshot *s, int blocksize, void **error)
++                      struct dm_snapshot *s, int blocksize)
 +{
 +      struct transient_c *tc;
 +
@@ -730,42 +733,337 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      return 0;
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-ioctl.c linux-2.4.19-dm/drivers/md/dm-ioctl.c
---- linux-2.4.19/drivers/md/dm-ioctl.c Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-ioctl.c      Wed Aug 14 14:12:35 2002
-@@ -0,0 +1,830 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm-ioctl.c linux-2.4.19-dmbackport/drivers/md/dm-ioctl.c
+--- linux-2.4.19-dm/drivers/md/dm-ioctl.c      Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-ioctl.c      Wed Nov 13 17:38:50 2002
+@@ -0,0 +1,1139 @@
 +/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited.
++ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
 +#include "dm.h"
 +
++#include <linux/module.h>
++#include <linux/vmalloc.h>
 +#include <linux/miscdevice.h>
 +#include <linux/dm-ioctl.h>
 +#include <linux/init.h>
 +#include <linux/wait.h>
++#include <linux/blk.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++
++#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
 +
 +/*-----------------------------------------------------------------
-+ * Implementation of the ioctl commands
++ * The ioctl interface needs to be able to look up devices by
++ * name or uuid.
 + *---------------------------------------------------------------*/
++struct hash_cell {
++      struct list_head name_list;
++      struct list_head uuid_list;
++
++      char *name;
++      char *uuid;
++      struct mapped_device *md;
++
++      /* I hate devfs */
++      devfs_handle_t devfs_entry;
++};
++
++#define NUM_BUCKETS 64
++#define MASK_BUCKETS (NUM_BUCKETS - 1)
++static struct list_head _name_buckets[NUM_BUCKETS];
++static struct list_head _uuid_buckets[NUM_BUCKETS];
++
++static devfs_handle_t _dev_dir;
++void dm_hash_remove_all(void);
 +
 +/*
-+ * All the ioctl commands get dispatched to functions with this
-+ * prototype.
++ * Guards access to all three tables.
 + */
-+typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
++static DECLARE_RWSEM(_hash_lock);
++
++static void init_buckets(struct list_head *buckets)
++{
++      unsigned int i;
++
++      for (i = 0; i < NUM_BUCKETS; i++)
++              INIT_LIST_HEAD(buckets + i);
++}
++
++int dm_hash_init(void)
++{
++      init_buckets(_name_buckets);
++      init_buckets(_uuid_buckets);
++      _dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
++      return 0;
++}
++
++void dm_hash_exit(void)
++{
++      dm_hash_remove_all();
++      devfs_unregister(_dev_dir);
++}
++
++/*-----------------------------------------------------------------
++ * Hash function:
++ * We're not really concerned with the str hash function being
++ * fast since it's only used by the ioctl interface.
++ *---------------------------------------------------------------*/
++static unsigned int hash_str(const char *str)
++{
++      const unsigned int hash_mult = 2654435387U;
++      unsigned int h = 0;
++
++      while (*str)
++              h = (h + (unsigned int) *str++) * hash_mult;
++
++      return h & MASK_BUCKETS;
++}
++
++/*-----------------------------------------------------------------
++ * Code for looking up a device by name
++ *---------------------------------------------------------------*/
++static struct hash_cell *__get_name_cell(const char *str)
++{
++      struct list_head *tmp;
++      struct hash_cell *hc;
++      unsigned int h = hash_str(str);
++
++      list_for_each(tmp, _name_buckets + h) {
++              hc = list_entry(tmp, struct hash_cell, name_list);
++              if (!strcmp(hc->name, str))
++                      return hc;
++      }
++
++      return NULL;
++}
++
++static struct hash_cell *__get_uuid_cell(const char *str)
++{
++      struct list_head *tmp;
++      struct hash_cell *hc;
++      unsigned int h = hash_str(str);
++
++      list_for_each(tmp, _uuid_buckets + h) {
++              hc = list_entry(tmp, struct hash_cell, uuid_list);
++              if (!strcmp(hc->uuid, str))
++                      return hc;
++      }
++
++      return NULL;
++}
++
++/*-----------------------------------------------------------------
++ * Inserting, removing and renaming a device.
++ *---------------------------------------------------------------*/
++static inline char *kstrdup(const char *str)
++{
++      char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
++      if (r)
++              strcpy(r, str);
++      return r;
++}
++
++static struct hash_cell *alloc_cell(const char *name, const char *uuid,
++                                  struct mapped_device *md)
++{
++      struct hash_cell *hc;
++
++      hc = kmalloc(sizeof(*hc), GFP_KERNEL);
++      if (!hc)
++              return NULL;
++
++      hc->name = kstrdup(name);
++      if (!hc->name) {
++              kfree(hc);
++              return NULL;
++      }
++
++      if (!uuid)
++              hc->uuid = NULL;
++
++      else {
++              hc->uuid = kstrdup(uuid);
++              if (!hc->uuid) {
++                      kfree(hc->name);
++                      kfree(hc);
++                      return NULL;
++              }
++      }
++
++      INIT_LIST_HEAD(&hc->name_list);
++      INIT_LIST_HEAD(&hc->uuid_list);
++      hc->md = md;
++      return hc;
++}
++
++static void free_cell(struct hash_cell *hc)
++{
++      if (hc) {
++              kfree(hc->name);
++              kfree(hc->uuid);
++              kfree(hc);
++      }
++}
 +
 +/*
-+ * This is really a debug only call.
++ * devfs stuff.
 + */
-+static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
++static int register_with_devfs(struct hash_cell *hc)
++{
++      kdev_t dev = dm_kdev(hc->md);
++
++      hc->devfs_entry =
++          devfs_register(_dev_dir, hc->name, DEVFS_FL_CURRENT_OWNER,
++                         major(dev), minor(dev),
++                         S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
++                         &dm_blk_dops, NULL);
++
++      return 0;
++}
++
++static int unregister_with_devfs(struct hash_cell *hc)
++{
++      devfs_unregister(hc->devfs_entry);
++      return 0;
++}
++
++/*
++ * The kdev_t and uuid of a device can never change once it is
++ * initially inserted.
++ */
++int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
++{
++      struct hash_cell *cell;
++
++      /*
++       * Allocate the new cells.
++       */
++      cell = alloc_cell(name, uuid, md);
++      if (!cell)
++              return -ENOMEM;
++
++      /*
++       * Insert the cell into all three hash tables.
++       */
++      down_write(&_hash_lock);
++      if (__get_name_cell(name))
++              goto bad;
++
++      list_add(&cell->name_list, _name_buckets + hash_str(name));
++
++      if (uuid) {
++              if (__get_uuid_cell(uuid)) {
++                      list_del(&cell->name_list);
++                      goto bad;
++              }
++              list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
++      }
++      register_with_devfs(cell);
++      dm_get(md);
++      up_write(&_hash_lock);
++
++      return 0;
++
++      bad:
++      up_write(&_hash_lock);
++      free_cell(cell);
++      return -EBUSY;
++}
++
++void __hash_remove(struct hash_cell *hc)
++{
++      /* remove from the dev hash */
++      list_del(&hc->uuid_list);
++      list_del(&hc->name_list);
++      unregister_with_devfs(hc);
++      dm_put(hc->md);
++}
++
++void dm_hash_remove_all(void)
++{
++      int i;
++      struct hash_cell *hc;
++      struct list_head *tmp, *n;
++
++      down_write(&_hash_lock);
++      for (i = 0; i < NUM_BUCKETS; i++) {
++              list_for_each_safe(tmp, n, _name_buckets + i) {
++                      hc = list_entry(tmp, struct hash_cell, name_list);
++                      __hash_remove(hc);
++              }
++      }
++      up_write(&_hash_lock);
++}
++
++int dm_hash_rename(const char *old, const char *new)
 +{
-+      dm_destroy_all();
++      char *new_name, *old_name;
++      struct hash_cell *hc;
++
++      /*
++       * duplicate new.
++       */
++      new_name = kstrdup(new);
++      if (!new_name)
++              return -ENOMEM;
++
++      down_write(&_hash_lock);
++
++      /*
++       * Is new free ?
++       */
++      hc = __get_name_cell(new);
++      if (hc) {
++              DMWARN("asked to rename to an already existing name %s -> %s",
++                     old, new);
++              up_write(&_hash_lock);
++              return -EBUSY;
++      }
++
++      /*
++       * Is there such a device as 'old' ?
++       */
++      hc = __get_name_cell(old);
++      if (!hc) {
++              DMWARN("asked to rename a non existent device %s -> %s",
++                     old, new);
++              up_write(&_hash_lock);
++              return -ENXIO;
++      }
++
++      /*
++       * rename and move the name cell.
++       */
++      list_del(&hc->name_list);
++      old_name = hc->name;
++      hc->name = new_name;
++      list_add(&hc->name_list, _name_buckets + hash_str(new_name));
++
++      /* rename the device node in devfs */
++      unregister_with_devfs(hc);
++      register_with_devfs(hc);
++
++      up_write(&_hash_lock);
++      kfree(old_name);
 +      return 0;
 +}
 +
++
++/*-----------------------------------------------------------------
++ * Implementation of the ioctl commands
++ *---------------------------------------------------------------*/
++
++/*
++ * All the ioctl commands get dispatched to functions with this
++ * prototype.
++ */
++typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
++
 +/*
 + * Check a string doesn't overrun the chunk of
 + * memory we copied from userland.
@@ -793,29 +1091,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return valid_str(*params, begin, end);
 +}
 +
-+/*
-+ * Checks to see if there's a gap in the table.
-+ * Returns true iff there is a gap.
-+ */
-+static int gap(struct dm_table *table, struct dm_target_spec *spec)
-+{
-+      if (!table->num_targets)
-+              return (spec->sector_start > 0) ? 1 : 0;
-+
-+      if (spec->sector_start != table->highs[table->num_targets - 1] + 1)
-+              return 1;
-+
-+      return 0;
-+}
-+
 +static int populate_table(struct dm_table *table, struct dm_ioctl *args)
 +{
-+      int i = 0, r, first = 1, argc;
++      int i = 0, r, first = 1;
 +      struct dm_target_spec *spec;
-+      char *params, *argv[MAX_ARGS];
-+      struct target_type *ttype;
-+      void *context, *begin, *end;
-+      offset_t highs = 0;
++      char *params;
++      void *begin, *end;
 +
 +      if (!args->target_count) {
 +              DMWARN("populate_table: no targets specified");
@@ -825,8 +1106,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      begin = (void *) args;
 +      end = begin + args->data_size;
 +
-+#define PARSE_ERROR(msg) {DMWARN(msg); return -EINVAL;}
-+
 +      for (i = 0; i < args->target_count; i++) {
 +
 +              if (first)
@@ -837,41 +1116,23 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +                      r = next_target(spec, spec->next, begin, end,
 +                                      &spec, &params);
 +
-+              if (r)
-+                      PARSE_ERROR("unable to find target");
-+
-+              /* Look up the target type */
-+              ttype = dm_get_target_type(spec->target_type);
-+              if (!ttype)
-+                      PARSE_ERROR("unable to find target type");
-+
-+              if (gap(table, spec))
-+                      PARSE_ERROR("gap in target ranges");
-+
-+              /* Split up the parameter list */
-+              if (split_args(MAX_ARGS, &argc, argv, params) < 0)
-+                      PARSE_ERROR("Too many arguments");
-+
-+              /* Build the target */
-+              if (ttype->ctr(table, spec->sector_start, spec->length,
-+                             argc, argv, &context)) {
-+                      DMWARN("%s: target constructor failed",
-+                             (char *) context);
++              if (r) {
++                      DMWARN("unable to find target");
 +                      return -EINVAL;
 +              }
 +
-+              /* Add the target to the table */
-+              highs = spec->sector_start + (spec->length - 1);
-+              if (dm_table_add_target(table, highs, ttype, context))
-+                      PARSE_ERROR("internal error adding target to table");
++              r = dm_table_add_target(table, spec->target_type,
++                                      spec->sector_start, spec->length,
++                                      params);
++              if (r) {
++                      DMWARN("internal error adding target to table");
++                      return -EINVAL;
++              }
 +
 +              first = 0;
 +      }
 +
-+#undef PARSE_ERROR
-+
-+      r = dm_table_complete(table);
-+      return r;
++      return dm_table_complete(table);
 +}
 +
 +/*
@@ -923,37 +1184,63 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Fills in a dm_ioctl structure, ready for sending back to
 + * userland.
 + */
-+static void __info(struct mapped_device *md, struct dm_ioctl *param)
++static int __info(struct mapped_device *md, struct dm_ioctl *param)
 +{
++      kdev_t dev = dm_kdev(md);
++      struct dm_table *table;
++      struct block_device *bdev;
++
 +      param->flags = DM_EXISTS_FLAG;
-+      if (md->suspended)
++      if (dm_suspended(md))
 +              param->flags |= DM_SUSPEND_FLAG;
-+      if (md->read_only)
-+              param->flags |= DM_READONLY_FLAG;
 +
-+      strncpy(param->name, md->name, sizeof(param->name));
++      param->dev = kdev_t_to_nr(dev);
++      bdev = bdget(param->dev);
++      if (!bdev)
++              return -ENXIO;
 +
-+      if (md->uuid)
-+              strncpy(param->uuid, md->uuid, sizeof(param->uuid) - 1);
-+      else
-+              param->uuid[0] = '\0';
++      param->open_count = bdev->bd_openers;
++      bdput(bdev);
 +
-+      param->open_count = md->use_count;
-+      param->dev = kdev_t_to_nr(md->dev);
-+      param->target_count = md->map->num_targets;
++      if (is_read_only(dev))
++              param->flags |= DM_READONLY_FLAG;
++
++      table = dm_get_table(md);
++      param->target_count = dm_table_get_num_targets(table);
++      dm_table_put(table);
++
++      return 0;
 +}
 +
 +/*
 + * Always use UUID for lookups if it's present, otherwise use name.
 + */
-+static inline char *lookup_name(struct dm_ioctl *param)
++static inline struct mapped_device *find_device(struct dm_ioctl *param)
 +{
-+      return (*param->uuid) ? param->uuid : param->name;
-+}
++      struct hash_cell *hc;
++      struct mapped_device *md = NULL;
 +
-+static inline int lookup_type(struct dm_ioctl *param)
-+{
-+      return (*param->uuid) ? DM_LOOKUP_BY_UUID : DM_LOOKUP_BY_NAME;
++      down_read(&_hash_lock);
++      hc = *param->uuid ? __get_uuid_cell(param->uuid) :
++          __get_name_cell(param->name);
++      if (hc) {
++              md = hc->md;
++
++              /*
++               * Sneakily write in both the name and the uuid
++               * while we have the cell.
++               */
++              strncpy(param->name, hc->name, sizeof(param->name));
++              if (hc->uuid)
++                      strncpy(param->uuid, hc->uuid, sizeof(param->uuid) - 1);
++              else
++                      param->uuid[0] = '\0';
++
++              dm_get(md);
++      }
++      up_read(&_hash_lock);
++
++      return md;
 +}
 +
 +#define ALIGNMENT sizeof(int)
@@ -974,7 +1261,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      param->flags = 0;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
@@ -982,7 +1269,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              goto out;
 +
 +      __info(md, param);
-+      dm_put_r(md);
++      dm_put(md);
 +
 +      out:
 +      return results_to_user(user, param, NULL, 0);
@@ -998,38 +1285,55 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return mode;
 +}
 +
++static int check_name(const char *name)
++{
++      if (strchr(name, '/')) {
++              DMWARN("invalid device name");
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
 +static int create(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      int r, ro;
++      int r;
++      kdev_t dev;
 +      struct dm_table *t;
++      struct mapped_device *md;
 +      int minor;
 +
++      r = check_name(param->name);
++      if (r)
++              return r;
++
 +      r = dm_table_create(&t, get_mode(param));
 +      if (r)
 +              return r;
 +
 +      r = populate_table(t, param);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
 +
 +      minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
-+          MINOR(to_kdev_t(param->dev)) : -1;
-+
-+      ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0;
++          minor(to_kdev_t(param->dev)) : -1;
 +
-+      r = dm_create(param->name, param->uuid, minor, ro, t);
++      r = dm_create(minor, t, &md);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
++      dm_table_put(t);        /* md will have grabbed its own reference */
 +
-+      r = info(param, user);
-+      return r;
-+}
-+
++      dev = dm_kdev(md);
++      set_device_ro(dev, (param->flags & DM_READONLY_FLAG));
++      r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
++      dm_put(md);
 +
++      return r ? r : info(param, user);
++}
 +
 +/*
 + * Build up the status struct for each target
@@ -1037,11 +1341,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int __status(struct mapped_device *md, struct dm_ioctl *param,
 +                  char *outbuf, int *len)
 +{
-+      int i;
++      int i, num_targets;
 +      struct dm_target_spec *spec;
-+      uint64_t sector = 0LL;
 +      char *outptr;
 +      status_type_t type;
++      struct dm_table *table = dm_get_table(md);
 +
 +      if (param->flags & DM_STATUS_TABLE_FLAG)
 +              type = STATUSTYPE_TABLE;
@@ -1051,41 +1355,41 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      outptr = outbuf;
 +
 +      /* Get all the target info */
-+      for (i = 0; i < md->map->num_targets; i++) {
-+              struct target_type *tt = md->map->targets[i].type;
-+              offset_t high = md->map->highs[i];
++      num_targets = dm_table_get_num_targets(table);
++      for (i = 0; i < num_targets; i++) {
++              struct dm_target *ti = dm_table_get_target(table, i);
 +
 +              if (outptr - outbuf +
-+                  sizeof(struct dm_target_spec) > param->data_size)
-+                          return -ENOMEM;
++                  sizeof(struct dm_target_spec) > param->data_size) {
++                      dm_table_put(table);
++                      return -ENOMEM;
++              }
 +
 +              spec = (struct dm_target_spec *) outptr;
 +
 +              spec->status = 0;
-+              spec->sector_start = sector;
-+              spec->length = high - sector + 1;
-+              strncpy(spec->target_type, tt->name, sizeof(spec->target_type));
++              spec->sector_start = ti->begin;
++              spec->length = ti->len;
++              strncpy(spec->target_type, ti->type->name,
++                      sizeof(spec->target_type));
 +
 +              outptr += sizeof(struct dm_target_spec);
 +
 +              /* Get the status/table string from the target driver */
-+              if (tt->status)
-+                      tt->status(type, outptr,
-+                                 outbuf + param->data_size - outptr,
-+                                 md->map->targets[i].private);
++              if (ti->type->status)
++                      ti->type->status(ti, type, outptr,
++                                       outbuf + param->data_size - outptr);
 +              else
 +                      outptr[0] = '\0';
 +
 +              outptr += strlen(outptr) + 1;
 +              _align(outptr, ALIGNMENT);
-+
-+              sector = high + 1;
-+
 +              spec->next = outptr - outbuf;
 +      }
 +
-+      param->target_count = md->map->num_targets;
++      param->target_count = num_targets;
 +      *len = outptr - outbuf;
++      dm_table_put(table);
 +
 +      return 0;
 +}
@@ -1101,7 +1405,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int ret;
 +      char *outbuf = NULL;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
@@ -1126,7 +1430,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      out:
 +      if (md)
-+              dm_put_r(md);
++              dm_put(md);
 +
 +      ret = results_to_user(user, param, outbuf, len);
 +
@@ -1142,14 +1446,16 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
 +      struct mapped_device *md;
++      struct dm_table *table;
 +      DECLARE_WAITQUEUE(wq, current);
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
 +               */
 +              goto out;
++
 +      /*
 +       * Setup the basic dm_ioctl structure.
 +       */
@@ -1159,11 +1465,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Wait for a notification event
 +       */
 +      set_current_state(TASK_INTERRUPTIBLE);
-+      add_wait_queue(&md->map->eventq, &wq);
++      table = dm_get_table(md);
++      dm_table_add_wait_queue(table, &wq);
++      dm_table_put(table);
++      dm_put(md);
 +
-+      dm_put_r(md);
-+
-+      schedule();
++      yield();
 +      set_current_state(TASK_RUNNING);
 +
 +      out:
@@ -1180,10 +1487,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      struct list_head *tmp;
 +      size_t len = 0;
 +      struct dm_target_deps *deps = NULL;
++      struct dm_table *table;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              goto out;
++      table = dm_get_table(md);
 +
 +      /*
 +       * Setup the basic dm_ioctl structure.
@@ -1194,7 +1503,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Count the devices.
 +       */
 +      count = 0;
-+      list_for_each(tmp, &md->map->devices)
++      list_for_each(tmp, dm_table_get_devices(table))
 +          count++;
 +
 +      /*
@@ -1202,14 +1511,16 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * struct.
 +       */
 +      if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
-+              dm_put_r(md);
++              dm_table_put(table);
++              dm_put(md);
 +              return -ENOMEM;
 +      }
 +
 +      len = sizeof(*deps) + (sizeof(*deps->dev) * count);
 +      deps = kmalloc(len, GFP_KERNEL);
 +      if (!deps) {
-+              dm_put_r(md);
++              dm_table_put(table);
++              dm_put(md);
 +              return -ENOMEM;
 +      }
 +
@@ -1218,11 +1529,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       */
 +      deps->count = count;
 +      count = 0;
-+      list_for_each(tmp, &md->map->devices) {
++      list_for_each(tmp, dm_table_get_devices(table)) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-+              deps->dev[count++] = kdev_t_to_nr(dd->dev);
++              deps->dev[count++] = dd->bdev->bd_dev;
 +      }
-+      dm_put_r(md);
++      dm_table_put(table);
++      dm_put(md);
 +
 +      out:
 +      r = results_to_user(user, param, deps, len);
@@ -1233,19 +1545,26 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      int r;
-+      struct mapped_device *md;
++      struct hash_cell *hc;
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
-+      if (!md)
-+              return -ENXIO;
++      down_write(&_hash_lock);
++      hc = *param->uuid ? __get_uuid_cell(param->uuid) :
++          __get_name_cell(param->name);
++      if (!hc) {
++              DMWARN("device doesn't appear to be in the dev hash table.");
++              up_write(&_hash_lock);
++              return -EINVAL;
++      }
 +
-+      r = dm_destroy(md);
-+      dm_put_w(md);
-+      if (!r)
-+              kfree(md);
++      __hash_remove(hc);
++      up_write(&_hash_lock);
++      return 0;
++}
 +
-+      return r;
++static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
++{
++      dm_hash_remove_all();
++      return 0;
 +}
 +
 +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
@@ -1253,19 +1572,23 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int r;
 +      struct mapped_device *md;
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              return -ENXIO;
 +
-+      r = (param->flags & DM_SUSPEND_FLAG) ? dm_suspend(md) : dm_resume(md);
-+      dm_put_w(md);
++      if (param->flags & DM_SUSPEND_FLAG)
++              r = dm_suspend(md);
++      else
++              r = dm_resume(md);
 +
++      dm_put(md);
 +      return r;
 +}
 +
 +static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
 +      int r;
++      kdev_t dev;
 +      struct mapped_device *md;
 +      struct dm_table *t;
 +
@@ -1275,25 +1598,26 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      r = populate_table(t, param);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return -ENXIO;
 +      }
 +
 +      r = dm_swap_table(md, t);
 +      if (r) {
-+              dm_put_w(md);
-+              dm_table_destroy(t);
++              dm_put(md);
++              dm_table_put(t);
 +              return r;
 +      }
 +
-+      dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
-+      dm_put_w(md);
++      dev = dm_kdev(md);
++      set_device_ro(dev, (param->flags & DM_READONLY_FLAG));
++      dm_put(md);
 +
 +      r = info(param, user);
 +      return r;
@@ -1301,16 +1625,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      char *newname = (char *) param + param->data_start;
++      int r;
++      char *new_name = (char *) param + param->data_start;
 +
-+      if (valid_str(newname, (void *) param,
-+                    (void *) param + param->data_size) ||
-+          dm_set_name(lookup_name(param), lookup_type(param), newname)) {
++      if (valid_str(new_name, (void *) param,
++                    (void *) param + param->data_size)) {
 +              DMWARN("Invalid new logical volume name supplied.");
 +              return -EINVAL;
 +      }
 +
-+      return 0;
++      r = check_name(new_name);
++      if (r)
++              return r;
++
++      return dm_hash_rename(param->name, new_name);
 +}
 +
 +
@@ -1318,24 +1646,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Implementation of open/close/ioctl on the special char
 + * device.
 + *---------------------------------------------------------------*/
-+static int ctl_open(struct inode *inode, struct file *file)
-+{
-+      /* only root can open this */
-+      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;
-+}
-+
-+static ioctl_fn lookup_ioctl(unsigned int cmd)
++static ioctl_fn lookup_ioctl(unsigned int cmd)
 +{
 +      static struct {
 +              int cmd;
@@ -1353,9 +1664,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              {DM_TARGET_STATUS_CMD, get_status},
 +              {DM_TARGET_WAIT_CMD, wait_device_event},
 +      };
-+      static int nelts = sizeof(_ioctls) / sizeof(*_ioctls);
 +
-+      return (cmd >= nelts) ? NULL : _ioctls[cmd].fn;
++      return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
 +}
 +
 +/*
@@ -1445,12 +1755,15 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int ctl_ioctl(struct inode *inode, struct file *file,
 +                   uint command, ulong u)
 +{
-+
 +      int r = 0, cmd;
 +      struct dm_ioctl *param;
 +      struct dm_ioctl *user = (struct dm_ioctl *) u;
 +      ioctl_fn fn = NULL;
 +
++      /* only root can play with this */
++      if (!capable(CAP_SYS_ADMIN))
++              return -EACCES;
++
 +      if (_IOC_TYPE(command) != DM_IOCTL)
 +              return -ENOTTY;
 +
@@ -1495,24 +1808,37 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +static struct file_operations _ctl_fops = {
-+      open:    ctl_open,
-+      release: ctl_close,
-+      ioctl:   ctl_ioctl,
-+      owner:   THIS_MODULE,
++      .ioctl = ctl_ioctl,
++      .owner = THIS_MODULE,
 +};
 +
 +static devfs_handle_t _ctl_handle;
 +
 +static struct miscdevice _dm_misc = {
-+      minor: MISC_DYNAMIC_MINOR,
-+      name:  DM_NAME,
-+      fops:  &_ctl_fops
++      .minor = MISC_DYNAMIC_MINOR,
++      .name  = DM_NAME,
++      .fops  = &_ctl_fops
 +};
 +
-+static int __init dm_devfs_init(void) {
++/*
++ * Create misc character device and link to DM_DIR/control.
++ */
++int __init dm_interface_init(void)
++{
 +      int r;
 +      char rname[64];
 +
++      r = dm_hash_init();
++      if (r)
++              return r;
++
++      r = misc_register(&_dm_misc);
++      if (r) {
++              DMERR("misc_register failed for control device");
++              dm_hash_exit();
++              return r;
++      }
++
 +      r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3,
 +                              sizeof rname - 3);
 +      if (r == -ENOSYS)
@@ -1520,7 +1846,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      if (r < 0) {
 +              DMERR("devfs_generate_path failed for control device");
-+              return r;
++              goto failed;
 +      }
 +
 +      strncpy(rname + r, "../", 3);
@@ -1528,46 +1854,32 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +                           DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL);
 +      if (r) {
 +              DMERR("devfs_mk_symlink failed for control device");
-+              return r;
++              goto failed;
 +      }
 +      devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle);
 +
-+      return 0;
-+}
-+
-+/* Create misc character device and link to DM_DIR/control */
-+int __init dm_interface_init(void)
-+{
-+      int r;
-+
-+      r = misc_register(&_dm_misc);
-+      if (r) {
-+              DMERR("misc_register failed for control device");
-+              return r;
-+      }
-+
-+      r = dm_devfs_init();
-+      if (r) {
-+              misc_deregister(&_dm_misc);
-+              return r;
-+      }
-+
 +      DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
 +             DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
 +             DM_DRIVER_EMAIL);
-+
 +      return 0;
++
++      failed:
++      dm_hash_exit();
++      misc_deregister(&_dm_misc);
++      return r;
 +}
 +
 +void dm_interface_exit(void)
 +{
++      dm_hash_exit();
++
 +      if (misc_deregister(&_dm_misc) < 0)
 +              DMERR("misc_deregister failed for control device");
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-linear.c linux-2.4.19-dm/drivers/md/dm-linear.c
---- linux-2.4.19/drivers/md/dm-linear.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-linear.c     Wed Aug 14 13:58:34 2002
-@@ -0,0 +1,125 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm-linear.c linux-2.4.19-dmbackport/drivers/md/dm-linear.c
+--- linux-2.4.19-dm/drivers/md/dm-linear.c     Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-linear.c     Wed Nov 13 17:39:17 2002
+@@ -0,0 +1,120 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -1579,51 +1891,46 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/blkdev.h>
++#include <linux/slab.h>
 +
 +/*
 + * Linear: maps a linear range of a device.
 + */
 +struct linear_c {
-+      long delta;             /* FIXME: we need a signed offset type */
-+      long start;             /* For display only */
 +      struct dm_dev *dev;
++      sector_t start;
 +};
 +
 +/*
 + * Construct a linear mapping: <dev_path> <offset>
 + */
-+static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int linear_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct linear_c *lc;
-+      unsigned long start;    /* FIXME: unsigned long long */
-+      char *end;
 +
 +      if (argc != 2) {
-+              *context = "dm-linear: Not enough arguments";
++              ti->error = "dm-linear: Not enough arguments";
 +              return -EINVAL;
 +      }
 +
 +      lc = kmalloc(sizeof(*lc), GFP_KERNEL);
 +      if (lc == NULL) {
-+              *context = "dm-linear: Cannot allocate linear context";
++              ti->error = "dm-linear: Cannot allocate linear context";
 +              return -ENOMEM;
 +      }
 +
-+      start = simple_strtoul(argv[1], &end, 10);
-+      if (*end) {
-+              *context = "dm-linear: Invalid device sector";
++      if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) {
++              ti->error = "dm-linear: Invalid device sector";
 +              goto bad;
 +      }
 +
-+      if (dm_table_get_device(t, argv[0], start, l, t->mode, &lc->dev)) {
-+              *context = "dm-linear: Device lookup failed";
++      if (dm_get_device(ti, argv[0], lc->start, ti->len,
++                        dm_table_get_mode(ti->table), &lc->dev)) {
++              ti->error = "dm-linear: Device lookup failed";
 +              goto bad;
 +      }
 +
-+      lc->delta = (int) start - (int) b;
-+      lc->start = start;
-+      *context = lc;
++      ti->private = lc;
 +      return 0;
 +
 +      bad:
@@ -1631,28 +1938,28 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return -EINVAL;
 +}
 +
-+static void linear_dtr(struct dm_table *t, void *c)
++static void linear_dtr(struct dm_target *ti)
 +{
-+      struct linear_c *lc = (struct linear_c *) c;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
-+      dm_table_put_device(t, lc->dev);
-+      kfree(c);
++      dm_put_device(ti, lc->dev);
++      kfree(lc);
 +}
 +
-+static int linear_map(struct buffer_head *bh, int rw, void *context)
++static int linear_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct linear_c *lc = (struct linear_c *) context;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
 +      bh->b_rdev = lc->dev->dev;
-+      bh->b_rsector = bh->b_rsector + lc->delta;
++      bh->b_rsector = lc->start + (bh->b_rsector - ti->begin);
 +
 +      return 1;
 +}
 +
-+static int linear_status(status_type_t type, char *result, int maxlen,
-+                       void *context)
++static int linear_status(struct dm_target *ti, status_type_t type,
++                       char *result, int maxlen)
 +{
-+      struct linear_c *lc = (struct linear_c *) context;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
 +      switch (type) {
 +      case STATUSTYPE_INFO:
@@ -1660,20 +1967,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              break;
 +
 +      case STATUSTYPE_TABLE:
-+              snprintf(result, maxlen, "%s %ld", kdevname(lc->dev->dev),
-+                       lc->start);
++              snprintf(result, maxlen, "%s " SECTOR_FORMAT,
++                       kdevname(to_kdev_t(lc->dev->bdev->bd_dev)), lc->start);
 +              break;
 +      }
 +      return 0;
 +}
 +
 +static struct target_type linear_target = {
-+      name:   "linear",
-+      module: THIS_MODULE,
-+      ctr:    linear_ctr,
-+      dtr:    linear_dtr,
-+      map:    linear_map,
-+      status: linear_status,
++      .name   = "linear",
++      .module = THIS_MODULE,
++      .ctr    = linear_ctr,
++      .dtr    = linear_dtr,
++      .map    = linear_map,
++      .status = linear_status,
 +};
 +
 +int __init dm_linear_init(void)
@@ -1693,9 +2000,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if (r < 0)
 +              DMERR("linear: unregister failed %d", r);
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-snapshot.c linux-2.4.19-dm/drivers/md/dm-snapshot.c
---- linux-2.4.19/drivers/md/dm-snapshot.c      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-snapshot.c   Wed Aug 14 14:00:43 2002
+diff -ruN linux-2.4.19-dm/drivers/md/dm-snapshot.c linux-2.4.19-dmbackport/drivers/md/dm-snapshot.c
+--- linux-2.4.19-dm/drivers/md/dm-snapshot.c   Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-snapshot.c   Wed Nov 13 17:44:55 2002
 @@ -0,0 +1,1169 @@
 +/*
 + * dm-snapshot.c
@@ -1714,6 +2021,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/blkdev.h>
 +#include <linux/mempool.h>
 +#include <linux/device-mapper.h>
++#include <linux/vmalloc.h>
 +
 +#include "dm-snapshot.h"
 +#include "kcopyd.h"
@@ -2044,7 +2352,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int init_hash_tables(struct dm_snapshot *s)
 +{
-+      offset_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
++      sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
 +
 +      /*
 +       * Calculate based on the size of the original volume or
@@ -2091,8 +2399,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
 + */
-+static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                      int argc, char **argv, void **context)
++static int snapshot_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct dm_snapshot *s;
 +      unsigned long chunk_size;
@@ -2104,7 +2411,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int blocksize;
 +
 +      if (argc < 4) {
-+              *context = "dm-snapshot: requires exactly 4 arguments";
++              ti->error = "dm-snapshot: requires exactly 4 arguments";
 +              r = -EINVAL;
 +              goto bad;
 +      }
@@ -2114,36 +2421,38 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      persistent = argv[2];
 +
 +      if ((*persistent & 0x5f) != 'P' && (*persistent & 0x5f) != 'N') {
-+              *context = "Persistent flag is not P or N";
++              ti->error = "Persistent flag is not P or N";
 +              r = -EINVAL;
 +              goto bad;
 +      }
 +
 +      chunk_size = simple_strtoul(argv[3], &value, 10);
 +      if (chunk_size == 0 || value == NULL) {
-+              *context = "Invalid chunk size";
++              ti->error = "Invalid chunk size";
 +              r = -EINVAL;
 +              goto bad;
 +      }
 +
 +      s = kmalloc(sizeof(*s), GFP_KERNEL);
 +      if (s == NULL) {
-+              *context = "Cannot allocate snapshot context private structure";
++              ti->error = "Cannot allocate snapshot context private "
++                          "structure";
 +              r = -ENOMEM;
 +              goto bad;
 +      }
 +
-+      r = dm_table_get_device(t, origin_path, 0, 0, FMODE_READ, &s->origin);
++      r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
 +      if (r) {
-+              *context = "Cannot get origin device";
++              ti->error = "Cannot get origin device";
 +              goto bad_free;
 +      }
 +
-+      r = dm_table_get_device(t, cow_path, 0, 0,
-+                              FMODE_READ | FMODE_WRITE, &s->cow);
++      /* FIXME: get cow length */
++      r = dm_get_device(ti, cow_path, 0, 0,
++                        FMODE_READ | FMODE_WRITE, &s->cow);
 +      if (r) {
-+              dm_table_put_device(t, s->origin);
-+              *context = "Cannot get COW device";
++              dm_put_device(ti, s->origin);
++              ti->error = "Cannot get COW device";
 +              goto bad_free;
 +      }
 +
@@ -2156,21 +2465,21 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Validate the chunk size against the device block size */
 +      blocksize = get_hardsect_size(s->cow->dev);
 +      if (chunk_size % (blocksize / SECTOR_SIZE)) {
-+              *context = "Chunk size is not a multiple of device blocksize";
++              ti->error = "Chunk size is not a multiple of device blocksize";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
 +
 +      /* Check the sizes are small enough to fit in one kiovec */
 +      if (chunk_size > KIO_MAX_SECTORS) {
-+              *context = "Chunk size is too big";
++              ti->error = "Chunk size is too big";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
 +
 +      /* Check chunk_size is a power of 2 */
 +      if (chunk_size & (chunk_size - 1)) {
-+              *context = "Chunk size is not a power of 2";
++              ti->error = "Chunk size is not a power of 2";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
@@ -2185,12 +2494,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      s->valid = 1;
 +      s->last_percent = 0;
-+      s->table = t;
 +      init_rwsem(&s->lock);
++      s->table = ti->table;
 +
 +      /* Allocate hash table for COW data */
 +      if (init_hash_tables(s)) {
-+              *context = "Unable to allocate hash table space";
++              ti->error = "Unable to allocate hash table space";
 +              r = -ENOMEM;
 +              goto bad_putdev;
 +      }
@@ -2204,10 +2513,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if ((*persistent & 0x5f) == 'P')
 +              r = dm_create_persistent(&s->store, s->chunk_size);
 +      else
-+              r = dm_create_transient(&s->store, s, blocksize, context);
++              r = dm_create_transient(&s->store, s, blocksize);
 +
 +      if (r) {
-+              *context = "Couldn't create exception store";
++              ti->error = "Couldn't create exception store";
 +              r = -EINVAL;
 +              goto bad_free1;
 +      }
@@ -2222,7 +2531,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Add snapshot to the list of snapshots for this origin */
 +      if (register_snapshot(s)) {
 +              r = -EINVAL;
-+              *context = "Cannot register snapshot origin";
++              ti->error = "Cannot register snapshot origin";
 +              goto bad_free2;
 +      }
 +#if LVM_VFS_ENHANCEMENT
@@ -2230,7 +2539,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#endif
 +      kcopyd_inc_client_count();
 +
-+      *context = s;
++      ti->private = s;
 +      return 0;
 +
 +      bad_free2:
@@ -2241,8 +2550,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      exit_exception_table(&s->complete, exception_cache);
 +
 +      bad_putdev:
-+      dm_table_put_device(t, s->cow);
-+      dm_table_put_device(t, s->origin);
++      dm_put_device(ti, s->cow);
++      dm_put_device(ti, s->origin);
 +
 +      bad_free:
 +      kfree(s);
@@ -2251,11 +2560,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return r;
 +}
 +
-+static void snapshot_dtr(struct dm_table *t, void *context)
++static void snapshot_dtr(struct dm_target *ti)
 +{
-+      struct dm_snapshot *s = (struct dm_snapshot *) context;
++      struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 +
-+      dm_table_event(s->table);
++      dm_table_event(ti->table);
 +
 +      unregister_snapshot(s);
 +
@@ -2265,8 +2574,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Deallocate memory used */
 +      s->store.destroy(&s->store);
 +
-+      dm_table_put_device(t, s->origin);
-+      dm_table_put_device(t, s->cow);
++      dm_put_device(ti, s->origin);
++      dm_put_device(ti, s->cow);
 +      kfree(s);
 +
 +      kcopyd_dec_client_count();
@@ -2482,10 +2791,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +          (bh->b_rsector & s->chunk_mask);
 +}
 +
-+static int snapshot_map(struct buffer_head *bh, int rw, void *context)
++static int snapshot_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
 +      struct exception *e;
-+      struct dm_snapshot *s = (struct dm_snapshot *) context;
++      struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 +      int r = 1;
 +      chunk_t chunk;
 +      struct pending_exception *pe;
@@ -2632,10 +2941,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return r;
 +}
 +
-+static int snapshot_status(status_type_t type, char *result,
-+                         int maxlen, void *context)
++static int snapshot_status(struct dm_target *ti, status_type_t type,
++                         char *result, int maxlen)
 +{
-+      struct dm_snapshot *snap = (struct dm_snapshot *) context;
++      struct dm_snapshot *snap = (struct dm_snapshot *) ti->private;
 +      char cow[16];
 +      char org[16];
 +
@@ -2697,47 +3006,47 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * The context for an origin is merely a 'struct dm_dev *'
 + * pointing to the real device.
 + */
-+static int origin_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int origin_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      int r;
 +      struct dm_dev *dev;
 +
 +      if (argc != 1) {
-+              *context = "dm-origin: incorrect number of arguments";
++              ti->error = "dm-origin: incorrect number of arguments";
 +              return -EINVAL;
 +      }
 +
-+      r = dm_table_get_device(t, argv[0], 0, l, t->mode, &dev);
++      r = dm_get_device(ti, argv[0], 0, ti->len,
++                        dm_table_get_mode(ti->table), &dev);
 +      if (r) {
-+              *context = "Cannot get target device";
++              ti->error = "Cannot get target device";
 +              return r;
 +      }
 +
-+      *context = dev;
++      ti->private = dev;
 +
 +      return 0;
 +}
 +
-+static void origin_dtr(struct dm_table *t, void *c)
++static void origin_dtr(struct dm_target *ti)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) c;
-+      dm_table_put_device(t, dev);
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
++      dm_put_device(ti, dev);
 +}
 +
-+static int origin_map(struct buffer_head *bh, int rw, void *context)
++static int origin_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) context;
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
 +      bh->b_rdev = dev->dev;
 +
 +      /* Only tell snapshots if this is a write */
 +      return (rw == WRITE) ? do_origin(dev, bh) : 1;
 +}
 +
-+static int origin_status(status_type_t type, char *result,
-+                       int maxlen, void *context)
++static int origin_status(struct dm_target *ti, status_type_t type, char *result,
++                       int maxlen)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) context;
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
 +
 +      switch (type) {
 +      case STATUSTYPE_INFO:
@@ -2759,7 +3068,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dtr:    origin_dtr,
 +      map:    origin_map,
 +      status: origin_status,
-+      err:    NULL
 +};
 +
 +static struct target_type snapshot_target = {
@@ -2769,7 +3077,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dtr:    snapshot_dtr,
 +      map:    snapshot_map,
 +      status: snapshot_status,
-+      err:    NULL
 +};
 +
 +int __init dm_snapshot_init(void)
@@ -2866,9 +3173,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * c-file-style: "linux"
 + * End:
 + */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-snapshot.h linux-2.4.19-dm/drivers/md/dm-snapshot.h
---- linux-2.4.19/drivers/md/dm-snapshot.h      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-snapshot.h   Wed Jul 17 15:04:57 2002
+diff -ruN linux-2.4.19-dm/drivers/md/dm-snapshot.h linux-2.4.19-dmbackport/drivers/md/dm-snapshot.h
+--- linux-2.4.19-dm/drivers/md/dm-snapshot.h   Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-snapshot.h   Wed Nov 13 18:08:24 2002
 @@ -0,0 +1,147 @@
 +/*
 + * dm-snapshot.c
@@ -2894,7 +3201,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * time. Typically 64k - 256k.
 + */
 +/* FIXME: can we get away with limiting these to a uint32_t ? */
-+typedef offset_t chunk_t;
++typedef sector_t chunk_t;
 +
 +/*
 + * An exception is used where an old chunk of data has been
@@ -2916,31 +3223,31 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /*
 +       * Destroys this object when you've finished with it.
 +       */
-+      void (*destroy) (struct exception_store *store);
++      void (*destroy) (struct exception_store * store);
 +
 +      /*
 +       * Find somewhere to store the next exception.
 +       */
-+      int (*prepare_exception) (struct exception_store *store,
-+                                struct exception *e);
++      int (*prepare_exception) (struct exception_store * store,
++                                struct exception * e);
 +
 +      /*
 +       * Update the metadata with this exception.
 +       */
-+      void (*commit_exception) (struct exception_store *store,
-+                                struct exception *e,
++      void (*commit_exception) (struct exception_store * store,
++                                struct exception * e,
 +                                void (*callback) (void *, int success),
 +                                void *callback_context);
 +
 +      /*
 +       * The snapshot is invalid, note this in the metadata.
 +       */
-+      void (*drop_snapshot) (struct exception_store *store);
++      void (*drop_snapshot) (struct exception_store * store);
 +
 +      /*
 +       * Return the %age full of the snapshot
 +       */
-+      int (*percent_full) (struct exception_store *store);
++      int (*percent_full) (struct exception_store * store);
 +
 +      struct dm_snapshot *snap;
 +      void *context;
@@ -2990,12 +3297,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
 +
 +int dm_create_transient(struct exception_store *store,
-+                      struct dm_snapshot *s, int blocksize, void **error);
++                      struct dm_snapshot *s, int blocksize);
 +
 +/*
 + * Return the number of sectors in the device.
 + */
-+static inline offset_t get_dev_size(kdev_t dev)
++static inline sector_t get_dev_size(kdev_t dev)
 +{
 +      int *sizes;
 +
@@ -3006,21 +3313,21 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 0;
 +}
 +
-+static inline chunk_t sector_to_chunk(struct dm_snapshot *s, offset_t sector)
++static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector)
 +{
 +      return (sector & ~s->chunk_mask) >> s->chunk_shift;
 +}
 +
-+static inline offset_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
++static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
 +{
 +      return chunk << s->chunk_shift;
 +}
 +
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-stripe.c linux-2.4.19-dm/drivers/md/dm-stripe.c
---- linux-2.4.19/drivers/md/dm-stripe.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-stripe.c     Wed Aug 14 14:00:56 2002
-@@ -0,0 +1,234 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm-stripe.c linux-2.4.19-dmbackport/drivers/md/dm-stripe.c
+--- linux-2.4.19-dm/drivers/md/dm-stripe.c     Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-stripe.c     Wed Nov 13 17:45:21 2002
+@@ -0,0 +1,256 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -3032,14 +3339,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/blkdev.h>
++#include <linux/slab.h>
 +
 +struct stripe {
 +      struct dm_dev *dev;
-+      offset_t physical_start;
++      sector_t physical_start;
 +};
 +
 +struct stripe_c {
-+      offset_t logical_start;
 +      uint32_t stripes;
 +
 +      /* The size of this target / num. stripes */
@@ -3047,7 +3354,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      /* stripe chunk size */
 +      uint32_t chunk_shift;
-+      offset_t chunk_mask;
++      sector_t chunk_mask;
 +
 +      struct stripe stripe[0];
 +};
@@ -3068,18 +3375,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Parse a single <dev> <sector> pair
 + */
-+static int get_stripe(struct dm_table *t, struct stripe_c *sc,
++static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
 +                    int stripe, char **argv)
 +{
-+      char *end;
-+      unsigned long start;
++      sector_t start;
 +
-+      start = simple_strtoul(argv[1], &end, 10);
-+      if (*end)
++      if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1)
 +              return -EINVAL;
 +
-+      if (dm_table_get_device(t, argv[0], start, sc->stripe_width,
-+                              t->mode, &sc->stripe[stripe].dev))
++      if (dm_get_device(ti, argv[0], start, sc->stripe_width,
++                        dm_table_get_mode(ti->table),
++                        &sc->stripe[stripe].dev))
 +              return -ENXIO;
 +
 +      sc->stripe[stripe].physical_start = start;
@@ -3087,62 +3393,85 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
++ * FIXME: Nasty function, only present because we can't link
++ * against __moddi3 and __divdi3.
++ *
++ * returns a == b * n
++ */
++static int multiple(sector_t a, sector_t b, sector_t *n)
++{
++      sector_t acc, prev, i;
++
++      *n = 0;
++      while (a >= b) {
++              for (acc = b, prev = 0, i = 1;
++                   acc <= a;
++                   prev = acc, acc <<= 1, i <<= 1)
++                      ;
++
++              a -= prev;
++              *n += i >> 1;
++      }
++
++      return a == 0;
++}
++
++/*
 + * Construct a striped mapping.
 + * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
 + */
-+static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int stripe_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct stripe_c *sc;
++      sector_t width;
 +      uint32_t stripes;
 +      uint32_t chunk_size;
 +      char *end;
 +      int r, i;
 +
 +      if (argc < 2) {
-+              *context = "dm-stripe: Not enough arguments";
++              ti->error = "dm-stripe: Not enough arguments";
 +              return -EINVAL;
 +      }
 +
 +      stripes = simple_strtoul(argv[0], &end, 10);
 +      if (*end) {
-+              *context = "dm-stripe: Invalid stripe count";
++              ti->error = "dm-stripe: Invalid stripe count";
 +              return -EINVAL;
 +      }
 +
 +      chunk_size = simple_strtoul(argv[1], &end, 10);
 +      if (*end) {
-+              *context = "dm-stripe: Invalid chunk_size";
++              ti->error = "dm-stripe: Invalid chunk_size";
 +              return -EINVAL;
 +      }
 +
-+      if (l % stripes) {
-+              *context = "dm-stripe: Target length not divisable by "
++      if (!multiple(ti->len, stripes, &width)) {
++              ti->error = "dm-stripe: Target length not divisable by "
 +                  "number of stripes";
 +              return -EINVAL;
 +      }
 +
 +      sc = alloc_context(stripes);
 +      if (!sc) {
-+              *context = "dm-stripe: Memory allocation for striped context "
-+                  "failed";
++              ti->error = "dm-stripe: Memory allocation for striped context "
++                          "failed";
 +              return -ENOMEM;
 +      }
 +
-+      sc->logical_start = b;
 +      sc->stripes = stripes;
-+      sc->stripe_width = l / stripes;
++      sc->stripe_width = width;
 +
 +      /*
 +       * chunk_size is a power of two
 +       */
 +      if (!chunk_size || (chunk_size & (chunk_size - 1))) {
-+              *context = "dm-stripe: Invalid chunk size";
++              ti->error = "dm-stripe: Invalid chunk size";
 +              kfree(sc);
 +              return -EINVAL;
 +      }
 +
-+      sc->chunk_mask = chunk_size - 1;
++      sc->chunk_mask = ((sector_t) chunk_size) - 1;
 +      for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
 +              chunk_size >>= 1;
 +      sc->chunk_shift--;
@@ -3152,45 +3481,45 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       */
 +      for (i = 0; i < stripes; i++) {
 +              if (argc < 2) {
-+                      *context = "dm-stripe: Not enough destinations "
-+                          "specified";
++                      ti->error = "dm-stripe: Not enough destinations "
++                                  "specified";
 +                      kfree(sc);
 +                      return -EINVAL;
 +              }
 +
 +              argv += 2;
 +
-+              r = get_stripe(t, sc, i, argv);
++              r = get_stripe(ti, sc, i, argv);
 +              if (r < 0) {
-+                      *context = "dm-stripe: Couldn't parse stripe "
-+                          "destination";
++                      ti->error = "dm-stripe: Couldn't parse stripe "
++                                  "destination";
 +                      while (i--)
-+                              dm_table_put_device(t, sc->stripe[i].dev);
++                              dm_put_device(ti, sc->stripe[i].dev);
 +                      kfree(sc);
 +                      return r;
 +              }
 +      }
 +
-+      *context = sc;
++      ti->private = sc;
 +      return 0;
 +}
 +
-+static void stripe_dtr(struct dm_table *t, void *c)
++static void stripe_dtr(struct dm_target *ti)
 +{
 +      unsigned int i;
-+      struct stripe_c *sc = (struct stripe_c *) c;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +
 +      for (i = 0; i < sc->stripes; i++)
-+              dm_table_put_device(t, sc->stripe[i].dev);
++              dm_put_device(ti, sc->stripe[i].dev);
 +
 +      kfree(sc);
 +}
 +
-+static int stripe_map(struct buffer_head *bh, int rw, void *context)
++static int stripe_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct stripe_c *sc = (struct stripe_c *) context;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +
-+      offset_t offset = bh->b_rsector - sc->logical_start;
++      sector_t offset = bh->b_rsector - ti->begin;
 +      uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift);
 +      uint32_t stripe = chunk % sc->stripes;  /* 32bit modulus */
 +      chunk = chunk / sc->stripes;
@@ -3201,10 +3530,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 1;
 +}
 +
-+static int stripe_status(status_type_t type, char *result, int maxlen,
-+                       void *context)
++static int stripe_status(struct dm_target *ti,
++                       status_type_t type, char *result, int maxlen)
 +{
-+      struct stripe_c *sc = (struct stripe_c *) context;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +      int offset;
 +      int i;
 +
@@ -3214,14 +3543,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              break;
 +
 +      case STATUSTYPE_TABLE:
-+              offset = snprintf(result, maxlen, "%d %ld",
++              offset = snprintf(result, maxlen, "%d " SECTOR_FORMAT,
 +                                sc->stripes, sc->chunk_mask + 1);
 +              for (i = 0; i < sc->stripes; i++) {
-+                      offset +=
-+                          snprintf(result + offset, maxlen - offset,
-+                                   " %s %ld",
-+                                   kdevname(sc->stripe[i].dev->dev),
-+                                   sc->stripe[i].physical_start);
++                      offset += snprintf(result + offset, maxlen - offset,
++                                         " %s " SECTOR_FORMAT,
++                                         kdevname(to_kdev_t
++                                           (sc->stripe[i].dev->bdev->bd_dev)),
++                                         sc->stripe[i].physical_start);
 +              }
 +              break;
 +      }
@@ -3229,12 +3558,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +static struct target_type stripe_target = {
-+      name:   "striped",
-+      module: THIS_MODULE,
-+      ctr:    stripe_ctr,
-+      dtr:    stripe_dtr,
-+      map:    stripe_map,
-+      status: stripe_status,
++      .name   = "striped",
++      .module = THIS_MODULE,
++      .ctr    = stripe_ctr,
++      .dtr    = stripe_dtr,
++      .map    = stripe_map,
++      .status = stripe_status,
 +};
 +
 +int __init dm_stripe_init(void)
@@ -3255,10 +3584,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      return;
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-table.c linux-2.4.19-dm/drivers/md/dm-table.c
---- linux-2.4.19/drivers/md/dm-table.c Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-table.c      Wed Aug 14 14:17:32 2002
-@@ -0,0 +1,452 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm-table.c linux-2.4.19-dmbackport/drivers/md/dm-table.c
+--- linux-2.4.19-dm/drivers/md/dm-table.c      Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-table.c      Wed Nov 13 17:47:11 2002
+@@ -0,0 +1,665 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -3267,23 +3596,60 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#include "dm.h"
 +
++#include <linux/module.h>
++#include <linux/vmalloc.h>
 +#include <linux/blkdev.h>
++#include <linux/ctype.h>
++#include <linux/slab.h>
++#include <asm/atomic.h>
 +
-+/* ceiling(n / size) * size */
-+static inline unsigned long round_up(unsigned long n, unsigned long size)
-+{
-+      unsigned long r = n % size;
-+      return n + (r ? (size - r) : 0);
-+}
++#define MAX_DEPTH 16
++#define NODE_SIZE L1_CACHE_BYTES
++#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
++#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
++
++struct dm_table {
++      atomic_t holders;
++
++      /* btree table */
++      int depth;
++      int counts[MAX_DEPTH];  /* in nodes */
++      sector_t *index[MAX_DEPTH];
++
++      int num_targets;
++      int num_allocated;
++      sector_t *highs;
++      struct dm_target *targets;
++
++      /*
++       * Indicates the rw permissions for the new logical
++       * device.  This should be a combination of FMODE_READ
++       * and FMODE_WRITE.
++       */
++      int mode;
++
++      /* a list of devices used by this table */
++      struct list_head devices;
++
++      /*
++       * A waitqueue for processes waiting for something
++       * interesting to happen to this table.
++       */
++      wait_queue_head_t eventq;
++};
 +
-+/* ceiling(n / size) */
++/*
++ * Ceiling(n / size)
++ */
 +static inline unsigned long div_up(unsigned long n, unsigned long size)
 +{
-+      return round_up(n, size) / size;
++      return dm_round_up(n, size) / size;
 +}
 +
-+/* similar to ceiling(log_size(n)) */
-+static uint int_log(unsigned long n, unsigned long base)
++/*
++ * Similar to ceiling(log_size(n))
++ */
++static unsigned int int_log(unsigned long n, unsigned long base)
 +{
 +      int result = 0;
 +
@@ -3296,28 +3662,44 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * return the highest key that you could lookup
-+ * from the n'th node on level l of the btree.
++ * Calculate the index of the child node of the n'th node k'th key.
++ */
++static inline int get_child(int n, int k)
++{
++      return (n * CHILDREN_PER_NODE) + k;
++}
++
++/*
++ * Return the n'th node of level l from table t.
++ */
++static inline sector_t *get_node(struct dm_table *t, int l, int n)
++{
++      return t->index[l] + (n * KEYS_PER_NODE);
++}
++
++/*
++ * Return the highest key that you could lookup from the n'th
++ * node on level l of the btree.
 + */
-+static offset_t high(struct dm_table *t, int l, int n)
++static sector_t high(struct dm_table *t, int l, int n)
 +{
 +      for (; l < t->depth - 1; l++)
 +              n = get_child(n, CHILDREN_PER_NODE - 1);
 +
 +      if (n >= t->counts[l])
-+              return (offset_t) - 1;
++              return (sector_t) - 1;
 +
 +      return get_node(t, l, n)[KEYS_PER_NODE - 1];
 +}
 +
 +/*
-+ * fills in a level of the btree based on the
-+ * highs of the level below it.
++ * Fills in a level of the btree based on the highs of the level
++ * below it.
 + */
 +static int setup_btree_index(int l, struct dm_table *t)
 +{
 +      int n, k;
-+      offset_t *node;
++      sector_t *node;
 +
 +      for (n = 0; n < t->counts[l]; n++) {
 +              node = get_node(t, l, n);
@@ -3330,24 +3712,24 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * highs, and targets are managed as dynamic
-+ * arrays during a table load.
++ * highs, and targets are managed as dynamic arrays during a
++ * table load.
 + */
 +static int alloc_targets(struct dm_table *t, int num)
 +{
-+      offset_t *n_highs;
-+      struct target *n_targets;
++      sector_t *n_highs;
++      struct dm_target *n_targets;
 +      int n = t->num_targets;
 +
 +      /*
 +       * Allocate both the target array and offset array at once.
 +       */
-+      n_highs = (offset_t *) vcalloc(sizeof(struct target) + sizeof(offset_t),
-+                                     num);
++      n_highs = (sector_t *) vcalloc(sizeof(struct dm_target) +
++                                     sizeof(sector_t), num);
 +      if (!n_highs)
 +              return -ENOMEM;
 +
-+      n_targets = (struct target *) (n_highs + num);
++      n_targets = (struct dm_target *) (n_highs + num);
 +
 +      if (n) {
 +              memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
@@ -3355,8 +3737,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      }
 +
 +      memset(n_highs + n, -1, sizeof(*n_highs) * (num - n));
-+      if (t->highs)
-+              vfree(t->highs);
++      vfree(t->highs);
 +
 +      t->num_allocated = num;
 +      t->highs = n_highs;
@@ -3374,8 +3755,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      memset(t, 0, sizeof(*t));
 +      INIT_LIST_HEAD(&t->devices);
++      atomic_set(&t->holders, 1);
 +
-+      /* allocate a single node's worth of targets to begin with */
++      /* allocate a single nodes worth of targets to begin with */
 +      if (alloc_targets(t, KEYS_PER_NODE)) {
 +              kfree(t);
 +              t = NULL;
@@ -3399,7 +3781,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      }
 +}
 +
-+void dm_table_destroy(struct dm_table *t)
++void table_destroy(struct dm_table *t)
 +{
 +      int i;
 +
@@ -3412,12 +3794,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      /* free the targets */
 +      for (i = 0; i < t->num_targets; i++) {
-+              struct target *tgt = &t->targets[i];
++              struct dm_target *tgt = &t->targets[i];
 +
 +              dm_put_target_type(t->targets[i].type);
 +
 +              if (tgt->type->dtr)
-+                      tgt->type->dtr(t, tgt->private);
++                      tgt->type->dtr(tgt);
 +      }
 +
 +      vfree(t->highs);
@@ -3433,6 +3815,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      kfree(t);
 +}
 +
++void dm_table_get(struct dm_table *t)
++{
++      atomic_inc(&t->holders);
++}
++
++void dm_table_put(struct dm_table *t)
++{
++      if (atomic_dec_and_test(&t->holders))
++              table_destroy(t);
++}
++
 +/*
 + * Checks to see if we need to extend highs or targets.
 + */
@@ -3445,9 +3838,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Convert a device path to a kdev_t.
++ * Convert a device path to a dev_t.
 + */
-+int lookup_device(const char *path, kdev_t *dev)
++static int lookup_device(const char *path, kdev_t *dev)
 +{
 +      int r;
 +      struct nameidata nd;
@@ -3457,22 +3850,22 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              return 0;
 +
 +      if ((r = path_walk(path, &nd)))
-+              goto bad;
++              goto out;
 +
 +      inode = nd.dentry->d_inode;
 +      if (!inode) {
 +              r = -ENOENT;
-+              goto bad;
++              goto out;
 +      }
 +
 +      if (!S_ISBLK(inode->i_mode)) {
 +              r = -EINVAL;
-+              goto bad;
++              goto out;
 +      }
 +
 +      *dev = inode->i_rdev;
 +
-+      bad:
++      out:
 +      path_release(&nd);
 +      return r;
 +}
@@ -3486,7 +3879,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      list_for_each(tmp, l) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-+              if (dd->dev == dev)
++              if (kdev_same(dd->dev, dev))
 +                      return dd;
 +      }
 +
@@ -3496,45 +3889,40 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Open a device so we can use it as a map destination.
 + */
-+static int open_dev(struct dm_dev *d)
++static int open_dev(struct dm_dev *dd)
 +{
-+      int err;
-+
-+      if (d->bd)
++      if (dd->bdev)
 +              BUG();
 +
-+      if (!(d->bd = bdget(kdev_t_to_nr(d->dev))))
++      dd->bdev = bdget(kdev_t_to_nr(dd->dev));
++      if (!dd->bdev)
 +              return -ENOMEM;
 +
-+      if ((err = blkdev_get(d->bd, d->mode, 0, BDEV_FILE)))
-+              return err;
-+
-+      return 0;
++      return blkdev_get(dd->bdev, dd->mode, 0, BDEV_RAW);
 +}
 +
 +/*
 + * Close a device that we've been using.
 + */
-+static void close_dev(struct dm_dev *d)
++static void close_dev(struct dm_dev *dd)
 +{
-+      if (!d->bd)
++      if (!dd->bdev)
 +              return;
 +
-+      blkdev_put(d->bd, BDEV_FILE);
-+      d->bd = NULL;
++      blkdev_put(dd->bdev, BDEV_RAW);
++      dd->bdev = NULL;
 +}
 +
 +/*
-+ * If possible (ie. blk_size[major] is set), this
-+ * checks an area of a destination device is
-+ * valid.
++ * If possible (ie. blk_size[major] is set), this checks an area
++ * of a destination device is valid.
 + */
-+static int check_device_area(kdev_t dev, offset_t start, offset_t len)
++static int check_device_area(kdev_t dev, sector_t start, sector_t len)
 +{
 +      int *sizes;
-+      offset_t dev_size;
++      sector_t dev_size;
 +
-+      if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)]))
++      if (!(sizes = blk_size[major(dev)]) || !(dev_size = sizes[minor(dev)]))
 +              /* we don't know the device details,
 +               * so give the benefit of the doubt */
 +              return 1;
@@ -3558,7 +3946,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      memcpy(&dd_copy, dd, sizeof(dd_copy));
 +
 +      dd->mode |= new_mode;
-+      dd->bd = NULL;
++      dd->bdev = NULL;
 +      r = open_dev(dd);
 +      if (!r)
 +              close_dev(&dd_copy);
@@ -3569,21 +3957,24 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * 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, int mode,
-+                      struct dm_dev **result)
++int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
++                sector_t len, int mode, struct dm_dev **result)
 +{
 +      int r;
 +      kdev_t dev;
 +      struct dm_dev *dd;
 +      int major, minor;
++      struct dm_table *t = ti->table;
++
++      if (!t)
++              BUG();
 +
 +      if (sscanf(path, "%x:%x", &major, &minor) == 2) {
 +              /* Extract the major/minor numbers */
-+              dev = MKDEV(major, minor);
++              dev = mk_kdev(major, minor);
 +      } else {
 +              /* convert the path to a device */
 +              if ((r = lookup_device(path, &dev)))
@@ -3596,9 +3987,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              if (!dd)
 +                      return -ENOMEM;
 +
-+              dd->mode = mode;
 +              dd->dev = dev;
-+              dd->bd = NULL;
++              dd->mode = mode;
++              dd->bdev = NULL;
 +
 +              if ((r = open_dev(dd))) {
 +                      kfree(dd);
@@ -3617,7 +4008,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      if (!check_device_area(dd->dev, start, len)) {
 +              DMWARN("device %s too small for target", path);
-+              dm_table_put_device(t, dd);
++              dm_put_device(ti, dd);
 +              return -EINVAL;
 +      }
 +
@@ -3629,7 +4020,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Decrement a devices use count and remove it if neccessary.
 + */
-+void dm_table_put_device(struct dm_table *t, struct dm_dev *dd)
++void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
 +{
 +      if (atomic_dec_and_test(&dd->count)) {
 +              close_dev(dd);
@@ -3639,28 +4030,126 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Adds a target to the map
++ * Checks to see if the target joins onto the end of the table.
++ */
++static int adjoin(struct dm_table *table, struct dm_target *ti)
++{
++      struct dm_target *prev;
++
++      if (!table->num_targets)
++              return !ti->begin;
++
++      prev = &table->targets[table->num_targets - 1];
++      return (ti->begin == (prev->begin + prev->len));
++}
++
++/*
++ * Destructively splits up the argument list to pass to ctr.
 + */
-+int dm_table_add_target(struct dm_table *t, offset_t highs,
-+                      struct target_type *type, void *private)
++static int split_args(int max, int *argc, char **argv, char *input)
++{
++      char *start, *end = input, *out;
++      *argc = 0;
++
++      while (1) {
++              start = end;
++
++              /* Skip whitespace */
++              while (*start && isspace(*start))
++                      start++;
++
++              if (!*start)
++                      break;  /* success, we hit the end */
++
++              /* 'out' is used to remove any back-quotes */
++              end = out = start;
++              while (*end) {
++                      /* Everything apart from '\0' can be quoted */
++                      if (*end == '\\' && *(end + 1)) {
++                              *out++ = *(end + 1);
++                              end += 2;
++                              continue;
++                      }
++
++                      if (isspace(*end))
++                              break;  /* end of token */
++
++                      *out++ = *end++;
++              }
++
++              /* have we already filled the array ? */
++              if ((*argc + 1) > max)
++                      return -EINVAL;
++
++              /* we know this is whitespace */
++              if (*end)
++                      end++;
++
++              /* terminate the string and put it in the array */
++              *out = '\0';
++              argv[*argc] = start;
++              (*argc)++;
++      }
++
++      return 0;
++}
++
++int dm_table_add_target(struct dm_table *t, const char *type,
++                      sector_t start, sector_t len, char *params)
 +{
-+      int r, n;
++      int r, argc;
++      char *argv[32];
++      struct target_type *tt;
++      struct dm_target *tgt;
 +
 +      if ((r = check_space(t)))
 +              return r;
 +
-+      n = t->num_targets++;
-+      t->highs[n] = highs;
-+      t->targets[n].type = type;
-+      t->targets[n].private = private;
++      tgt = t->targets + t->num_targets;
++      memset(tgt, 0, sizeof(*tgt));
++
++      tt = dm_get_target_type(type);
++      if (!tt) {
++              tgt->error = "unknown target type";
++              return -EINVAL;
++      }
++
++      tgt->table = t;
++      tgt->type = tt;
++      tgt->begin = start;
++      tgt->len = len;
++      tgt->error = "Unknown error";
++
++      /*
++       * Does this target adjoin the previous one ?
++       */
++      if (!adjoin(t, tgt)) {
++              DMERR("Gap in table");
++              dm_put_target_type(tt);
++              return -EINVAL;
++      }
++
++      r = split_args(ARRAY_SIZE(argv), &argc, argv, params);
++      if (r) {
++              tgt->error = "couldn't split parameters";
++              dm_put_target_type(tt);
++              return r;
++      }
++
++      r = tt->ctr(tgt, argc, argv);
++      if (r) {
++              dm_put_target_type(tt);
++              return r;
++      }
 +
++      t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
 +      return 0;
 +}
 +
 +static int setup_indexes(struct dm_table *t)
 +{
 +      int i, total = 0;
-+      offset_t *indexes;
++      sector_t *indexes;
 +
 +      /* allocate the space for *all* the indexes */
 +      for (i = t->depth - 2; i >= 0; i--) {
@@ -3668,7 +4157,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              total += t->counts[i];
 +      }
 +
-+      indexes = (offset_t *) vcalloc(total, (unsigned long) NODE_SIZE);
++      indexes = (sector_t *) vcalloc(total, (unsigned long) NODE_SIZE);
 +      if (!indexes)
 +              return -ENOMEM;
 +
@@ -3683,7 +4172,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Builds the btree to index the map
++ * Builds the btree to index the map.
 + */
 +int dm_table_complete(struct dm_table *t)
 +{
@@ -3708,85 +4197,89 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      wake_up_interruptible(&t->eventq);
 +}
 +
-+EXPORT_SYMBOL(dm_table_get_device);
-+EXPORT_SYMBOL(dm_table_put_device);
-+EXPORT_SYMBOL(dm_table_event);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-target.c linux-2.4.19-dm/drivers/md/dm-target.c
---- linux-2.4.19/drivers/md/dm-target.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-target.c     Thu Jun 13 15:07:55 2002
-@@ -0,0 +1,242 @@
-+/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited
-+ *
-+ * This file is released under the GPL.
-+ */
-+
-+#include "dm.h"
-+
-+#include <linux/kmod.h>
-+
-+struct tt_internal {
-+      struct target_type tt;
-+
-+      struct list_head list;
-+      long use;
-+};
++sector_t dm_table_get_size(struct dm_table *t)
++{
++      return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
++}
 +
-+static LIST_HEAD(_targets);
-+static rwlock_t _lock = RW_LOCK_UNLOCKED;
++struct dm_target *dm_table_get_target(struct dm_table *t, int index)
++{
++      if (index > t->num_targets)
++              return NULL;
 +
-+#define DM_MOD_NAME_SIZE 32
++      return t->targets + index;
++}
 +
 +/*
-+ * Destructively splits up the argument list to pass to ctr.
++ * Search the btree for the correct target.
 + */
-+int split_args(int max, int *argc, char **argv, char *input)
++struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
 +{
-+      char *start, *end = input, *out;
-+      *argc = 0;
++      int l, n = 0, k = 0;
++      sector_t *node;
 +
-+      while (1) {
-+              start = end;
++      for (l = 0; l < t->depth; l++) {
++              n = get_child(n, k);
++              node = get_node(t, l, n);
 +
-+              /* Skip whitespace */
-+              while (*start && isspace(*start))
-+                      start++;
++              for (k = 0; k < KEYS_PER_NODE; k++)
++                      if (node[k] >= sector)
++                              break;
++      }
 +
-+              if (!*start)
-+                      break;  /* success, we hit the end */
++      return &t->targets[(KEYS_PER_NODE * n) + k];
++}
 +
-+              /* 'out' is used to remove any back-quotes */
-+              end = out = start;
-+              while (*end) {
-+                      /* Everything apart from '\0' can be quoted */
-+                      if (*end == '\\' && *(end + 1)) {
-+                              *out++ = *(end + 1);
-+                              end += 2;
-+                              continue;
-+                      }
++unsigned int dm_table_get_num_targets(struct dm_table *t)
++{
++      return t->num_targets;
++}
 +
-+                      if (isspace(*end))
-+                              break;  /* end of token */
++struct list_head *dm_table_get_devices(struct dm_table *t)
++{
++      return &t->devices;
++}
 +
-+                      *out++ = *end++;
-+              }
++int dm_table_get_mode(struct dm_table *t)
++{
++      return t->mode;
++}
 +
-+              /* have we already filled the array ? */
-+              if ((*argc + 1) > max)
-+                      return -EINVAL;
++void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq)
++{
++      add_wait_queue(&t->eventq, wq);
++}
 +
-+              /* we know this is whitespace */
-+              if (*end)
-+                      end++;
++EXPORT_SYMBOL(dm_get_device);
++EXPORT_SYMBOL(dm_put_device);
++EXPORT_SYMBOL(dm_table_event);
+diff -ruN linux-2.4.19-dm/drivers/md/dm-target.c linux-2.4.19-dmbackport/drivers/md/dm-target.c
+--- linux-2.4.19-dm/drivers/md/dm-target.c     Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm-target.c     Wed Nov 13 17:47:29 2002
+@@ -0,0 +1,190 @@
++/*
++ * Copyright (C) 2001 Sistina Software (UK) Limited
++ *
++ * This file is released under the GPL.
++ */
 +
-+              /* terminate the string and put it in the array */
-+              *out = '\0';
-+              argv[*argc] = start;
-+              (*argc)++;
-+      }
++#include "dm.h"
 +
-+      return 0;
-+}
++#include <linux/module.h>
++#include <linux/kmod.h>
++#include <linux/slab.h>
++
++struct tt_internal {
++      struct target_type tt;
++
++      struct list_head list;
++      long use;
++};
++
++static LIST_HEAD(_targets);
++static rwlock_t _lock = RW_LOCK_UNLOCKED;
++
++#define DM_MOD_NAME_SIZE 32
 +
 +static inline struct tt_internal *__find_target_type(const char *name)
 +{
@@ -3915,33 +4408,30 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +/*
 + * io-err: always fails an io, useful for bringing
-+ * up LV's that have holes in them.
++ * up LVs that have holes in them.
 + */
-+static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **args, void **context)
++static int io_err_ctr(struct dm_target *ti, int argc, char **args)
 +{
-+      *context = NULL;
 +      return 0;
 +}
 +
-+static void io_err_dtr(struct dm_table *t, void *c)
++static void io_err_dtr(struct dm_target *ti)
 +{
 +      /* empty */
 +      return;
 +}
 +
-+static int io_err_map(struct buffer_head *bh, int rw, void *context)
++static int io_err_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
 +      buffer_IO_error(bh);
 +      return 0;
 +}
 +
 +static struct target_type error_target = {
-+      name:   "error",
-+      ctr:    io_err_ctr,
-+      dtr:    io_err_dtr,
-+      map:    io_err_map,
-+      status: NULL,
++      .name = "error",
++      .ctr  = io_err_ctr,
++      .dtr  = io_err_dtr,
++      .map  = io_err_map,
 +};
 +
 +int dm_target_init(void)
@@ -3957,228 +4447,114 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +EXPORT_SYMBOL(dm_register_target);
 +EXPORT_SYMBOL(dm_unregister_target);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm.c linux-2.4.19-dm/drivers/md/dm.c
---- linux-2.4.19/drivers/md/dm.c       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm.c    Wed Aug 14 14:50:17 2002
-@@ -0,0 +1,1173 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm.c linux-2.4.19-dmbackport/drivers/md/dm.c
+--- linux-2.4.19-dm/drivers/md/dm.c    Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm.c    Wed Nov 13 19:15:43 2002
+@@ -0,0 +1,868 @@
 +/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited.
++ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
 +#include "dm.h"
 +
++#include <linux/init.h>
++#include <linux/module.h>
 +#include <linux/blk.h>
 +#include <linux/blkpg.h>
-+
-+/* we only need this for the lv_bmap struct definition, not happy */
++#include <linux/mempool.h>
++#include <linux/slab.h>
++#include <linux/kdev_t.h>
 +#include <linux/lvm.h>
 +
-+#define DEFAULT_READ_AHEAD 64
++#include <asm/uaccess.h>
 +
 +static const char *_name = DM_NAME;
++#define MAX_DEVICES (1 << MINORBITS)
++#define SECTOR_SHIFT 9
++#define DEFAULT_READ_AHEAD 64
 +
 +static int major = 0;
 +static int _major = 0;
 +
-+struct io_hook {
++struct dm_io {
 +      struct mapped_device *md;
-+      struct target *target;
-+      int rw;
 +
 +      void (*end_io) (struct buffer_head * bh, int uptodate);
 +      void *context;
 +};
 +
-+static kmem_cache_t *_io_hook_cache;
-+
-+static struct mapped_device *_devs[MAX_DEVICES];
-+static struct rw_semaphore _dev_locks[MAX_DEVICES];
-+
-+/*
-+ * This lock is only held by dm_create and dm_set_name to avoid
-+ * race conditions where someone else may create a device with
-+ * the same name.
-+ */
-+static spinlock_t _create_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* block device arrays */
-+static int _block_size[MAX_DEVICES];
-+static int _blksize_size[MAX_DEVICES];
-+static int _hardsect_size[MAX_DEVICES];
-+
-+static devfs_handle_t _dev_dir;
-+
-+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);
-+
-+/*
-+ * Protect the mapped_devices referenced from _dev[]
-+ */
-+struct mapped_device *dm_get_r(int minor)
-+{
-+      struct mapped_device *md;
-+
-+      if (minor >= MAX_DEVICES)
-+              return NULL;
-+
-+      down_read(_dev_locks + minor);
-+      md = _devs[minor];
-+      if (!md)
-+              up_read(_dev_locks + minor);
-+      return md;
-+}
-+
-+struct mapped_device *dm_get_w(int minor)
-+{
-+      struct mapped_device *md;
-+
-+      if (minor >= MAX_DEVICES)
-+              return NULL;
-+
-+      down_write(_dev_locks + minor);
-+      md = _devs[minor];
-+      if (!md)
-+              up_write(_dev_locks + minor);
-+      return md;
-+}
-+
-+static int namecmp(struct mapped_device *md, const char *name, int nametype)
-+{
-+      switch (nametype) {
-+      case DM_LOOKUP_BY_NAME:
-+              return strcmp(md->name, name);
-+              break;
-+
-+      case DM_LOOKUP_BY_UUID:
-+              if (!md->uuid)
-+                      return -1;      /* never equal */
-+
-+              return strcmp(md->uuid, name);
-+              break;
-+
-+      default:
-+              DMWARN("Unknown comparison type in namecmp: %d", nametype);
-+              BUG();
-+      }
-+
-+      return -1;
-+}
++struct deferred_io {
++      int rw;
++      struct buffer_head *bh;
++      struct deferred_io *next;
++};
 +
 +/*
-+ * The interface (eg, ioctl) will probably access the devices
-+ * through these slow 'by name' locks, this needs improving at
-+ * some point if people start playing with *large* numbers of dm
-+ * devices.
++ * Bits for the md->flags field.
 + */
-+struct mapped_device *dm_get_name_r(const char *name, int nametype)
-+{
-+      int i;
-+      struct mapped_device *md;
-+
-+      for (i = 0; i < MAX_DEVICES; i++) {
-+              md = dm_get_r(i);
-+              if (md) {
-+                      if (!namecmp(md, name, nametype))
-+                              return md;
++#define DMF_BLOCK_IO 0
++#define DMF_SUSPENDED 1
 +
-+                      dm_put_r(md);
-+              }
-+      }
-+
-+      return NULL;
-+}
++struct mapped_device {
++      struct rw_semaphore lock;
++      atomic_t holders;
 +
-+struct mapped_device *dm_get_name_w(const char *name, int nametype)
-+{
-+      int i;
-+      struct mapped_device *md;
++      kdev_t dev;
++      unsigned long flags;
 +
 +      /*
-+       * To avoid getting write locks on all the devices we try
-+       * and promote a read lock to a write lock, this can
-+       * fail, in which case we just start again.
++       * A list of ios that arrived while we were suspended.
 +       */
++      atomic_t pending;
++      wait_queue_head_t wait;
++      struct deferred_io *deferred;
 +
-+      restart:
-+      for (i = 0; i < MAX_DEVICES; i++) {
-+              md = dm_get_r(i);
-+              if (!md)
-+                      continue;
-+
-+              if (namecmp(md, name, nametype)) {
-+                      dm_put_r(md);
-+                      continue;
-+              }
-+
-+              /* found it */
-+              dm_put_r(md);
-+
-+              md = dm_get_w(i);
-+              if (!md)
-+                      goto restart;
-+
-+              if (namecmp(md, name, nametype)) {
-+                      dm_put_w(md);
-+                      goto restart;
-+              }
-+
-+              return md;
-+      }
-+
-+      return NULL;
-+}
-+
-+void dm_put_r(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
-+
-+      if (minor >= MAX_DEVICES)
-+              return;
-+
-+      up_read(_dev_locks + minor);
-+}
-+
-+void dm_put_w(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
++      /*
++       * The current mapping.
++       */
++      struct dm_table *map;
++};
 +
-+      if (minor >= MAX_DEVICES)
-+              return;
++#define MIN_IOS 256
++static kmem_cache_t *_io_cache;
++static mempool_t *_io_pool;
 +
-+      up_write(_dev_locks + minor);
-+}
++/* block device arrays */
++static int _block_size[MAX_DEVICES];
++static int _blksize_size[MAX_DEVICES];
++static int _hardsect_size[MAX_DEVICES];
 +
-+/*
-+ * Setup and tear down the driver
-+ */
-+static __init void init_locks(void)
-+{
-+      int i;
++static struct mapped_device *get_kdev(kdev_t dev);
++static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh);
++static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb);
 +
-+      for (i = 0; i < MAX_DEVICES; i++)
-+              init_rwsem(_dev_locks + i);
-+}
 +
 +static __init int local_init(void)
 +{
 +      int r;
 +
-+      init_locks();
++      /* allocate a slab for the dm_ios */
++      _io_cache = kmem_cache_create("dm io",
++                                    sizeof(struct dm_io), 0, 0, NULL, NULL);
++
++      if (!_io_cache)
++              return -ENOMEM;
 +
-+      /* 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)))
++      _io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
++                                mempool_free_slab, _io_cache);
++      if (!_io_pool) {
++              kmem_cache_destroy(_io_cache);
 +              return -ENOMEM;
++      }
 +
 +      _major = major;
-+      r = devfs_register_blkdev(_major, _name, &dm_blk_dops);
++      r = register_blkdev(_major, _name, &dm_blk_dops);
 +      if (r < 0) {
 +              DMERR("register_blkdev failed");
-+              kmem_cache_destroy(_io_hook_cache);
++              mempool_destroy(_io_pool);
++              kmem_cache_destroy(_io_cache);
 +              return r;
 +      }
 +
@@ -4191,20 +4567,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      blksize_size[_major] = _blksize_size;
 +      hardsect_size[_major] = _hardsect_size;
 +
-+      blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request);
-+
-+      _dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
++      blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), dm_request);
 +
 +      return 0;
 +}
 +
 +static void local_exit(void)
 +{
-+      if (kmem_cache_destroy(_io_hook_cache))
-+              DMWARN("io_hooks still allocated during unregistration");
-+      _io_hook_cache = NULL;
++      mempool_destroy(_io_pool);
++      kmem_cache_destroy(_io_cache);
 +
-+      if (devfs_unregister_blkdev(_major, _name) < 0)
++      if (unregister_blkdev(_major, _name) < 0)
 +              DMERR("devfs_unregister_blkdev failed");
 +
 +      read_ahead[_major] = 0;
@@ -4222,8 +4595,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * expands a prefix into a pair of function names.
 + */
 +static struct {
-+      int (*init)(void);
-+      void (*exit)(void);
++      int (*init) (void);
++      void (*exit) (void);
 +
 +} _inits[] = {
 +#define xx(n) {n ## _init, n ## _exit},
@@ -4232,14 +4605,13 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      xx(dm_linear)
 +      xx(dm_stripe)
 +      xx(dm_snapshot)
-+/*    xx(dm_mirror) */
 +      xx(dm_interface)
 +#undef xx
 +};
 +
 +static int __init dm_init(void)
 +{
-+      const int count = sizeof(_inits) / sizeof(*_inits);
++      const int count = ARRAY_SIZE(_inits);
 +
 +      int r, i;
 +
@@ -4260,9 +4632,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static void __exit dm_exit(void)
 +{
-+      int i = sizeof(_inits) / sizeof(*_inits);
++      int i = ARRAY_SIZE(_inits);
 +
-+      dm_destroy_all();
 +      while (i--)
 +              _inits[i].exit();
 +}
@@ -4274,13 +4645,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct mapped_device *md;
 +
-+      md = dm_get_w(MINOR(inode->i_rdev));
++      md = get_kdev(inode->i_rdev);
 +      if (!md)
 +              return -ENXIO;
 +
-+      md->use_count++;
-+      dm_put_w(md);
-+
 +      return 0;
 +}
 +
@@ -4288,22 +4656,36 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct mapped_device *md;
 +
-+      md = dm_get_w(MINOR(inode->i_rdev));
-+      if (!md)
-+              return -ENXIO;
++      md = get_kdev(inode->i_rdev);
++      dm_put(md);             /* put the reference gained by dm_blk_open */
++      dm_put(md);
++      return 0;
++}
 +
-+      if (md->use_count < 1)
-+              DMWARN("incorrect reference count found in mapped_device");
++static inline struct dm_io *alloc_io(void)
++{
++      return mempool_alloc(_io_pool, GFP_NOIO);
++}
 +
-+      md->use_count--;
-+      dm_put_w(md);
++static inline void free_io(struct dm_io *io)
++{
++      mempool_free(io, _io_pool);
++}
 +
-+      return 0;
++static inline struct deferred_io *alloc_deferred(void)
++{
++      return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
++}
++
++static inline void free_deferred(struct deferred_io *di)
++{
++      kfree(di);
 +}
 +
 +/* In 512-byte units */
 +#define VOLUME_SIZE(minor) (_block_size[(minor)] << 1)
 +
++/* FIXME: check this */
 +static int dm_blk_ioctl(struct inode *inode, struct file *file,
 +                      uint command, unsigned long a)
 +{
@@ -4355,42 +4737,32 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 0;
 +}
 +
-+static inline struct io_hook *alloc_io_hook(void)
-+{
-+      return kmem_cache_alloc(_io_hook_cache, GFP_NOIO);
-+}
-+
-+static inline void free_io_hook(struct io_hook *ih)
-+{
-+      kmem_cache_free(_io_hook_cache, ih);
-+}
-+
 +/*
-+ * 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.
++ * Add the buffer to the list of deferred io.
 + */
-+static inline struct deferred_io *alloc_deferred(void)
++static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
 +{
-+      return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
-+}
++      struct deferred_io *di;
 +
-+static inline void free_deferred(struct deferred_io *di)
-+{
-+      kfree(di);
-+}
++      di = alloc_deferred();
++      if (!di)
++              return -ENOMEM;
 +
-+/*
-+ * 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;
++      down_write(&md->lock);
 +
-+      if (err)
-+              return err(bh, ih->rw, ih->target->private);
++      if (!test_bit(DMF_SUSPENDED, &md->flags)) {
++              up_write(&md->lock);
++              free_deferred(di);
++              return 1;
++      }
 +
-+      return 0;
++      di->bh = bh;
++      di->rw = rw;
++      di->next = md->deferred;
++      md->deferred = di;
++
++      up_write(&md->lock);
++      return 0;               /* deferred successfully */
 +}
 +
 +/*
@@ -4399,192 +4771,134 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static void dec_pending(struct buffer_head *bh, int uptodate)
 +{
-+      struct io_hook *ih = bh->b_private;
++      struct dm_io *io = bh->b_private;
 +
-+      if (!uptodate && call_err_fn(ih, bh))
-+              return;
-+
-+      if (atomic_dec_and_test(&ih->md->pending))
++      if (atomic_dec_and_test(&io->md->pending))
 +              /* nudge anyone waiting on suspend queue */
-+              wake_up(&ih->md->wait);
++              wake_up(&io->md->wait);
 +
-+      bh->b_end_io = ih->end_io;
-+      bh->b_private = ih->context;
-+      free_io_hook(ih);
++      bh->b_end_io = io->end_io;
++      bh->b_private = io->context;
++      free_io(io);
 +
 +      bh->b_end_io(bh, uptodate);
 +}
 +
 +/*
-+ * Add the bh to the list of deferred io.
-+ */
-+static int queue_io(struct buffer_head *bh, int rw)
-+{
-+      struct deferred_io *di = alloc_deferred();
-+      struct mapped_device *md;
-+
-+      if (!di)
-+              return -ENOMEM;
-+
-+      md = dm_get_w(MINOR(bh->b_rdev));
-+      if (!md) {
-+              free_deferred(di);
-+              return -ENXIO;
-+      }
-+
-+      if (!md->suspended) {
-+              dm_put_w(md);
-+              free_deferred(di);
-+              return 1;
-+      }
-+
-+      di->bh = bh;
-+      di->rw = rw;
-+      di->next = md->deferred;
-+      md->deferred = di;
-+
-+      dm_put_w(md);
-+
-+      return 0;               /* deferred successfully */
-+}
-+
-+/*
 + * 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)
++                             int rw, struct buffer_head *bh)
 +{
 +      int r;
-+      dm_map_fn fn;
-+      void *context;
-+      struct io_hook *ih = NULL;
-+      struct target *ti = md->map->targets + leaf;
-+
-+      fn = ti->type->map;
-+      context = ti->private;
++      struct dm_io *io;
++      struct dm_target *ti;
 +
-+      ih = alloc_io_hook();
++      ti = dm_table_find_target(md->map, bh->b_rsector);
++      if (!ti)
++              return -EINVAL;
 +
-+      if (!ih)
-+              return -1;
++      io = alloc_io();
++      if (!io)
++              return -ENOMEM;
 +
-+      ih->md = md;
-+      ih->rw = rw;
-+      ih->target = ti;
-+      ih->end_io = bh->b_end_io;
-+      ih->context = bh->b_private;
++      io->md = md;
++      io->end_io = bh->b_end_io;
++      io->context = bh->b_private;
 +
-+      r = fn(bh, rw, context);
++      r = ti->type->map(ti, bh, rw);
 +
 +      if (r > 0) {
 +              /* hook the end io request fn */
 +              atomic_inc(&md->pending);
 +              bh->b_end_io = dec_pending;
-+              bh->b_private = ih;
++              bh->b_private = io;
 +
-+      } else if (r == 0)
++      } else
 +              /* we don't need to hook */
-+              free_io_hook(ih);
-+
-+      else if (r < 0) {
-+              free_io_hook(ih);
-+              return -1;
-+      }
++              free_io(io);
 +
 +      return r;
 +}
 +
 +/*
-+ * Search the btree for the correct target.
++ * Checks to see if we should be deferring io, if so it queues it
++ * and returns 1.
 + */
-+static inline int __find_node(struct dm_table *t, struct buffer_head *bh)
++static inline int __deferring(struct mapped_device *md, int rw,
++                            struct buffer_head *bh)
 +{
-+      int l, n = 0, k = 0;
-+      offset_t *node;
++      int r;
 +
-+      for (l = 0; l < t->depth; l++) {
-+              n = get_child(n, k);
-+              node = get_node(t, l, n);
++      /*
++       * If we're suspended we have to queue this io for later.
++       */
++      while (test_bit(DMF_BLOCK_IO, &md->flags)) {
++              up_read(&md->lock);
++
++              /*
++               * There's no point deferring a read ahead
++               * request, just drop it.
++               */
++              if (rw == READA) {
++                      down_read(&md->lock);
++                      return -EIO;
++              }
++
++              r = queue_io(md, bh, rw);
++              down_read(&md->lock);
++
++              if (r < 0)
++                      return r;
++
++              if (r == 0)
++                      return 1;       /* deferred successfully */
 +
-+              for (k = 0; k < KEYS_PER_NODE; k++)
-+                      if (node[k] >= bh->b_rsector)
-+                              break;
 +      }
 +
-+      return (KEYS_PER_NODE * n) + k;
++      return 0;
 +}
 +
-+static int request(request_queue_t * q, int rw, struct buffer_head *bh)
++static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
 +{
++      int r;
 +      struct mapped_device *md;
-+      int r, minor = MINOR(bh->b_rdev);
-+      unsigned int block_size = _blksize_size[minor];
 +
-+      md = dm_get_r(minor);
++      md = get_kdev(bh->b_rdev);
 +      if (!md) {
 +              buffer_IO_error(bh);
 +              return 0;
 +      }
 +
-+      /*
-+       * Sanity checks.
-+       */
-+      if (bh->b_size > block_size)
-+              DMERR("request is larger than block size "
-+                    "b_size (%d), block size (%d)",
-+                    bh->b_size, block_size);
-+
-+      if (bh->b_rsector & ((bh->b_size >> 9) - 1))
-+              DMERR("misaligned block requested logical "
-+                    "sector (%lu), b_size (%d)",
-+                    bh->b_rsector, bh->b_size);
++      down_read(&md->lock);
 +
-+      /*
-+       * If we're suspended we have to queue
-+       * this io for later.
-+       */
-+      while (md->suspended) {
-+              dm_put_r(md);
-+
-+              if (rw == READA)
-+                      goto bad_no_lock;
-+
-+              r = queue_io(bh, rw);
++      r = __deferring(md, rw, bh);
++      if (r < 0)
++              goto bad;
 +
++      else if (!r) {
++              /* not deferring */
++              r = __map_buffer(md, rw, bh);
 +              if (r < 0)
-+                      goto bad_no_lock;
-+
-+              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.
-+               */
-+              md = dm_get_r(minor);
-+              if (!md) {
-+                      buffer_IO_error(bh);
-+                      return 0;
-+              }
-+      }
-+
-+      if ((r = __map_buffer(md, bh, rw, __find_node(md->map, bh))) < 0)
-+              goto bad;
++                      goto bad;
++      } else
++              r = 0;
 +
-+      dm_put_r(md);
++      up_read(&md->lock);
++      dm_put(md);
 +      return r;
 +
 +      bad:
-+      dm_put_r(md);
-+
-+      bad_no_lock:
 +      buffer_IO_error(bh);
++      up_read(&md->lock);
++      dm_put(md);
 +      return 0;
 +}
 +
-+static int check_dev_size(int minor, unsigned long block)
++static int check_dev_size(kdev_t dev, unsigned long block)
 +{
 +      /* FIXME: check this */
++      int minor = MINOR(dev);
 +      unsigned long max_sector = (_block_size[minor] << 1) + 1;
 +      unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9);
 +
@@ -4594,25 +4908,18 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * 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)
++static int __bmap(struct mapped_device *md, kdev_t dev, unsigned long block,
++                kdev_t *r_dev, unsigned long *r_block)
 +{
-+      struct mapped_device *md;
 +      struct buffer_head bh;
-+      int minor = MINOR(dev), r;
-+      struct target *t;
-+
-+      md = dm_get_r(minor);
-+      if (!md)
-+              return -ENXIO;
++      struct dm_target *ti;
++      int r;
 +
-+      if (md->suspended) {
-+              dm_put_r(md);
++      if (test_bit(DMF_BLOCK_IO, &md->flags)) {
 +              return -EPERM;
 +      }
 +
-+      if (!check_dev_size(minor, block)) {
-+              dm_put_r(md);
++      if (!check_dev_size(dev, block)) {
 +              return -EINVAL;
 +      }
 +
@@ -4620,19 +4927,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      memset(&bh, 0, sizeof(bh));
 +      bh.b_blocknr = block;
 +      bh.b_dev = bh.b_rdev = dev;
-+      bh.b_size = _blksize_size[minor];
++      bh.b_size = _blksize_size[MINOR(dev)];
 +      bh.b_rsector = block * (bh.b_size >> 9);
 +
 +      /* find target */
-+      t = md->map->targets + __find_node(md->map, &bh);
++      ti = dm_table_find_target(md->map, bh.b_rsector);
 +
 +      /* do the mapping */
-+      r = t->type->map(&bh, READ, t->private);
++      r = ti->type->map(ti, &bh, READ);
 +
-+      *r_dev = bh.b_rdev;
-+      *r_block = bh.b_rsector / (bh.b_size >> 9);
++      if (!r) {
++              *r_dev = bh.b_rdev;
++              *r_block = bh.b_rsector / (bh.b_size >> 9);
++      }
 +
-+      dm_put_r(md);
 +      return r;
 +}
 +
@@ -4641,6 +4949,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb)
 +{
++      struct mapped_device *md;
 +      unsigned long block, r_block;
 +      kdev_t r_dev;
 +      int r;
@@ -4648,143 +4957,141 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if (get_user(block, &lvb->lv_block))
 +              return -EFAULT;
 +
-+      if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block)))
-+              return r;
++      md = get_kdev(inode->i_rdev);
++      if (!md)
++              return -ENXIO;
 +
-+      if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
-+          put_user(r_block, &lvb->lv_block))
-+              return -EFAULT;
++      down_read(&md->lock);
++      r = __bmap(md, inode->i_rdev, block, &r_dev, &r_block);
++      up_read(&md->lock);
++      dm_put(md);
 +
-+      return 0;
++      if (!r && (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
++                 put_user(r_block, &lvb->lv_block)))
++              r = -EFAULT;
++
++      return r;
++}
++
++/*-----------------------------------------------------------------
++ * A bitset is used to keep track of allocated minor numbers.
++ *---------------------------------------------------------------*/
++static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED;
++static struct mapped_device *_mds[MAX_DEVICES];
++
++static void free_minor(int minor)
++{
++      spin_lock(&_minor_lock);
++      _mds[minor] = NULL;
++      spin_unlock(&_minor_lock);
 +}
 +
 +/*
-+ * See if the device with a specific minor # is free.  The write
-+ * lock is held when it returns successfully.
++ * See if the device with a specific minor # is free.
 + */
-+static inline int specific_dev(int minor, struct mapped_device *md)
++static int specific_minor(int minor, struct mapped_device *md)
 +{
++      int r = -EBUSY;
++
 +      if (minor >= MAX_DEVICES) {
 +              DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
 +                     MAX_DEVICES);
-+              return -1;
++              return -EINVAL;
 +      }
 +
-+      down_write(_dev_locks + minor);
-+      if (_devs[minor]) {
-+              /* in use */
-+              up_write(_dev_locks + minor);
-+              return -1;
++      spin_lock(&_minor_lock);
++      if (!_mds[minor]) {
++              _mds[minor] = md;
++              r = minor;
 +      }
++      spin_unlock(&_minor_lock);
 +
-+      return minor;
++      return r;
 +}
 +
-+/*
-+ * Find the first free device.  Again the write lock is held on
-+ * success.
-+ */
-+static int any_old_dev(struct mapped_device *md)
++static int next_free_minor(struct mapped_device *md)
 +{
 +      int i;
 +
-+      for (i = 0; i < MAX_DEVICES; i++)
-+              if (specific_dev(i, md) != -1)
-+                      return i;
++      spin_lock(&_minor_lock);
++      for (i = 0; i < MAX_DEVICES; i++) {
++              if (!_mds[i]) {
++                      _mds[i] = md;
++                      break;
++              }
++      }
++      spin_unlock(&_minor_lock);
++
++      return (i < MAX_DEVICES) ? i : -EBUSY;
++}
++
++static struct mapped_device *get_kdev(kdev_t dev)
++{
++      struct mapped_device *md;
 +
-+      return -1;
++      if (major(dev) != _major)
++              return NULL;
++
++      spin_lock(_minor_lock);
++      md = _mds[minor(dev)];
++      if (md)
++              dm_get(md);
++      spin_unlock(_minor_lock);
++
++      return md;
 +}
 +
 +/*
-+ * Allocate and initialise a blank device.
-+ * Caller must ensure uuid is null-terminated.
-+ * Device is returned with a write lock held.
++ * Allocate and initialise a blank device with a given minor.
 + */
-+static struct mapped_device *alloc_dev(const char *name, const char *uuid,
-+                                     int minor)
++static struct mapped_device *alloc_dev(int minor)
 +{
 +      struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
-+      int len;
 +
 +      if (!md) {
 +              DMWARN("unable to allocate device, out of memory.");
 +              return NULL;
 +      }
 +
-+      memset(md, 0, sizeof(*md));
-+
-+      /*
-+       * This grabs the write lock if it succeeds.
-+       */
-+      minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md);
++      /* get a minor number for the dev */
++      minor = (minor < 0) ? next_free_minor(md) : specific_minor(minor, md);
 +      if (minor < 0) {
 +              kfree(md);
 +              return NULL;
 +      }
 +
-+      md->dev = MKDEV(_major, minor);
-+      md->suspended = 0;
-+
-+      strncpy(md->name, name, sizeof(md->name) - 1);
-+      md->name[sizeof(md->name) - 1] = '\0';
-+
-+      /*
-+       * Copy in the uuid.
-+       */
-+      if (uuid && *uuid) {
-+              len = strlen(uuid) + 1;
-+              if (!(md->uuid = kmalloc(len, GFP_KERNEL))) {
-+                      DMWARN("unable to allocate uuid - out of memory.");
-+                      kfree(md);
-+                      return NULL;
-+              }
-+              strcpy(md->uuid, uuid);
-+      }
-+
++      memset(md, 0, sizeof(*md));
++      md->dev = mk_kdev(_major, minor);
++      init_rwsem(&md->lock);
++      atomic_set(&md->holders, 1);
++      atomic_set(&md->pending, 0);
 +      init_waitqueue_head(&md->wait);
-+      return md;
-+}
 +
-+static int __register_device(struct mapped_device *md)
-+{
-+      md->devfs_entry =
-+          devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER,
-+                         MAJOR(md->dev), MINOR(md->dev),
-+                         S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-+                         &dm_blk_dops, NULL);
-+
-+      return 0;
++      return md;
 +}
 +
-+static int __unregister_device(struct mapped_device *md)
++static void free_dev(struct mapped_device *md)
 +{
-+      devfs_unregister(md->devfs_entry);
-+      return 0;
++      free_minor(minor(md->dev));
++      kfree(md);
 +}
 +
 +/*
-+ * The hardsect size for a mapped device is the smallest hardsect size
++ * The hardsect size for a mapped device is the largest hardsect size
 + * from the devices it maps onto.
 + */
 +static int __find_hardsect_size(struct list_head *devices)
 +{
-+      int result = INT_MAX, size;
++      int result = 512, size;
 +      struct list_head *tmp;
 +
 +      list_for_each(tmp, devices) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
 +              size = get_hardsect_size(dd->dev);
-+              if (size < result)
++              if (size > result)
 +                      result = size;
 +      }
 +
-+      /*
-+       * I think it's safe to assume that no block devices have
-+       * a hard sector size this large.
-+       */
-+      if (result == INT_MAX)
-+              result = 512;
-+
 +      return result;
 +}
 +
@@ -4793,226 +5100,68 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int __bind(struct mapped_device *md, struct dm_table *t)
 +{
-+      int minor = MINOR(md->dev);
-+
++      int minor = minor(md->dev);
 +      md->map = t;
 +
-+      if (!t->num_targets) {
-+              _block_size[minor] = 0;
-+              _blksize_size[minor] = BLOCK_SIZE;
-+              _hardsect_size[minor] = 0;
-+              return 0;
-+      }
-+
 +      /* in k */
-+      _block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
-+
-+      _blksize_size[minor] = BLOCK_SIZE;
-+      _hardsect_size[minor] = __find_hardsect_size(&t->devices);
-+      register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
-+
-+      return 0;
-+}
-+
-+static void __unbind(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
-+
-+      dm_table_destroy(md->map);
-+      md->map = NULL;
-+
-+      _block_size[minor] = 0;
-+      _blksize_size[minor] = 0;
-+      _hardsect_size[minor] = 0;
-+}
-+
-+static int check_name(const char *name)
-+{
-+      struct mapped_device *md;
-+
-+      if (strchr(name, '/') || strlen(name) > DM_NAME_LEN) {
-+              DMWARN("invalid device name");
-+              return -1;
-+      }
-+
-+      md = dm_get_name_r(name, DM_LOOKUP_BY_NAME);
-+      if (md) {
-+              dm_put_r(md);
-+              DMWARN("device name already in use");
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+static int check_uuid(const char *uuid)
-+{
-+      struct mapped_device *md;
-+
-+      if (uuid) {
-+              md = dm_get_name_r(uuid, DM_LOOKUP_BY_UUID);
-+              if (md) {
-+                      dm_put_r(md);
-+                      DMWARN("device uuid already in use");
-+                      return -1;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * Constructor for a new device.
-+ */
-+int dm_create(const char *name, const char *uuid, int minor, int ro,
-+            struct dm_table *table)
-+{
-+      int r;
-+      struct mapped_device *md;
-+
-+      spin_lock(&_create_lock);
-+      if (check_name(name) || check_uuid(uuid)) {
-+              spin_unlock(&_create_lock);
-+              return -EINVAL;
-+      }
-+
-+      md = alloc_dev(name, uuid, minor);
-+      if (!md) {
-+              spin_unlock(&_create_lock);
-+              return -ENXIO;
-+      }
-+      minor = MINOR(md->dev);
-+      _devs[minor] = md;
-+
-+      r = __register_device(md);
-+      if (r)
-+              goto err;
-+
-+      r = __bind(md, table);
-+      if (r)
-+              goto err;
-+
-+      dm_set_ro(md, ro);
-+
-+      spin_unlock(&_create_lock);
-+      dm_put_w(md);
-+      return 0;
-+
-+      err:
-+      _devs[minor] = NULL;
-+      if (md->uuid)
-+              kfree(md->uuid);
-+
-+      dm_put_w(md);
-+      kfree(md);
-+      spin_unlock(&_create_lock);
-+      return r;
-+}
-+
-+/*
-+ * Renames the device.  No lock held.
-+ */
-+int dm_set_name(const char *name, int nametype, const char *newname)
-+{
-+      int r;
-+      struct mapped_device *md;
-+
-+      spin_lock(&_create_lock);
-+      if (check_name(newname) < 0) {
-+              spin_unlock(&_create_lock);
-+              return -EINVAL;
-+      }
-+
-+      md = dm_get_name_w(name, nametype);
-+      if (!md) {
-+              spin_unlock(&_create_lock);
-+              return -ENXIO;
-+      }
-+
-+      r = __unregister_device(md);
-+      if (r)
-+              goto out;
-+
-+      strcpy(md->name, newname);
-+      r = __register_device(md);
-+
-+      out:
-+      dm_put_w(md);
-+      spin_unlock(&_create_lock);
-+      return r;
-+}
-+
-+/*
-+ * Destructor for the device.  You cannot destroy an open
-+ * device.  Write lock must be held before calling.
-+ * Caller must dm_put_w(md) then kfree(md) if call was successful.
-+ */
-+int dm_destroy(struct mapped_device *md)
-+{
-+      int minor, r;
-+
-+      if (md->use_count)
-+              return -EPERM;
++      _block_size[minor] = dm_table_get_size(t) >> 1;
++      _blksize_size[minor] = BLOCK_SIZE;
++      _hardsect_size[minor] = __find_hardsect_size(dm_table_get_devices(t));
++      register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
 +
-+      r = __unregister_device(md);
-+      if (r)
-+              return r;
++      dm_table_get(t);
++      return 0;
++}
 +
-+      minor = MINOR(md->dev);
-+      _devs[minor] = NULL;
-+      __unbind(md);
++static void __unbind(struct mapped_device *md)
++{
++      int minor = minor(md->dev);
 +
-+      if (md->uuid)
-+              kfree(md->uuid);
++      dm_table_put(md->map);
++      md->map = NULL;
 +
-+      return 0;
++      _block_size[minor] = 0;
++      _blksize_size[minor] = 0;
++      _hardsect_size[minor] = 0;
 +}
 +
 +/*
-+ * Destroy all devices - except open ones
++ * Constructor for a new device.
 + */
-+void dm_destroy_all(void)
++int dm_create(int minor, struct dm_table *table, struct mapped_device **result)
 +{
-+      int i, some_destroyed, r;
++      int r;
 +      struct mapped_device *md;
 +
-+      do {
-+              some_destroyed = 0;
-+              for (i = 0; i < MAX_DEVICES; i++) {
-+                      md = dm_get_w(i);
-+                      if (!md)
-+                              continue;
++      md = alloc_dev(minor);
++      if (!md)
++              return -ENXIO;
 +
-+                      r = dm_destroy(md);
-+                      dm_put_w(md);
++      r = __bind(md, table);
++      if (r) {
++              free_dev(md);
++              return r;
++      }
 +
-+                      if (!r) {
-+                              kfree(md);
-+                              some_destroyed = 1;
-+                      }
-+              }
-+      } while (some_destroyed);
++      *result = md;
++      return 0;
 +}
 +
-+/*
-+ * Sets or clears the read-only flag for the device.  Write lock
-+ * must be held.
-+ */
-+void dm_set_ro(struct mapped_device *md, int ro)
++void dm_get(struct mapped_device *md)
 +{
-+      md->read_only = ro;
-+      set_device_ro(md->dev, ro);
++      atomic_inc(&md->holders);
 +}
 +
-+/*
-+ * A target is notifying us of some event
-+ */
-+void dm_notify(void *target)
++void dm_put(struct mapped_device *md)
 +{
++      if (atomic_dec_and_test(&md->holders)) {
++              __unbind(md);
++              free_dev(md);
++      }
 +}
 +
 +/*
-+ * Requeue the deferred buffer_heads by calling generic_make_request.
++ * Requeue the deferred io by calling generic_make_request.
 + */
 +static void flush_deferred_io(struct deferred_io *c)
 +{
@@ -5027,100 +5176,136 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Swap in a new table (destroying old one).  Write lock must be
-+ * held.
++ * Swap in a new table (destroying old one).
 + */
 +int dm_swap_table(struct mapped_device *md, struct dm_table *table)
 +{
 +      int r;
 +
++      down_write(&md->lock);
++
 +      /* device must be suspended */
-+      if (!md->suspended)
++      if (!test_bit(DMF_SUSPENDED, &md->flags)) {
++              up_write(&md->lock);
 +              return -EPERM;
++      }
 +
 +      __unbind(md);
-+
 +      r = __bind(md, table);
 +      if (r)
 +              return r;
 +
++      up_write(&md->lock);
 +      return 0;
 +}
 +
 +/*
 + * We need to be able to change a mapping table under a mounted
-+ * filesystem.  for example we might want to move some data in
++ * filesystem.  For example we might want to move some data in
 + * the background.  Before the table can be swapped with
 + * dm_bind_table, dm_suspend must be called to flush any in
-+ * flight buffer_heads and ensure that any further io gets
-+ * deferred.  Write lock must be held.
++ * flight io and ensure that any further io gets deferred.
 + */
 +int dm_suspend(struct mapped_device *md)
 +{
-+      int minor = MINOR(md->dev);
 +      DECLARE_WAITQUEUE(wait, current);
 +
-+      if (md->suspended)
++      down_write(&md->lock);
++
++      /*
++       * First we set the BLOCK_IO flag so no more ios will be
++       * mapped.
++       */
++      if (test_bit(DMF_BLOCK_IO, &md->flags)) {
++              up_write(&md->lock);
 +              return -EINVAL;
++      }
++
++      set_bit(DMF_BLOCK_IO, &md->flags);
++      up_write(&md->lock);
 +
-+      md->suspended = 1;
-+      dm_put_w(md);
++      /*
++       * Then we wait for the already mapped ios to
++       * complete.
++       */
++      down_read(&md->lock);
 +
-+      /* wait for all the pending io to flush */
 +      add_wait_queue(&md->wait, &wait);
-+      current->state = TASK_UNINTERRUPTIBLE;
-+      do {
-+              md = dm_get_w(minor);
-+              if (!md) {
-+                      /* Caller expects to free this lock. Yuck. */
-+                      down_write(_dev_locks + minor);
-+                      return -ENXIO;
-+              }
++      while (1) {
++              set_current_state(TASK_INTERRUPTIBLE);
 +
 +              if (!atomic_read(&md->pending))
 +                      break;
 +
-+              dm_put_w(md);
 +              schedule();
-+
-+      } while (1);
++      }
 +
 +      current->state = TASK_RUNNING;
 +      remove_wait_queue(&md->wait, &wait);
++      up_read(&md->lock);
++
++      /* set_bit is atomic */
++      set_bit(DMF_SUSPENDED, &md->flags);
 +
 +      return 0;
 +}
 +
 +int dm_resume(struct mapped_device *md)
 +{
-+      int minor = MINOR(md->dev);
 +      struct deferred_io *def;
 +
-+      if (!md->suspended || !md->map->num_targets)
++      down_write(&md->lock);
++      if (!test_bit(DMF_SUSPENDED, &md->flags) ||
++          !dm_table_get_size(md->map)) {
++              up_write(&md->lock);
 +              return -EINVAL;
++      }
 +
-+      md->suspended = 0;
++      clear_bit(DMF_SUSPENDED, &md->flags);
++      clear_bit(DMF_BLOCK_IO, &md->flags);
 +      def = md->deferred;
 +      md->deferred = NULL;
++      up_write(&md->lock);
 +
-+      dm_put_w(md);
 +      flush_deferred_io(def);
 +      run_task_queue(&tq_disk);
 +
-+      if (!dm_get_w(minor)) {
-+              /* FIXME: yuck */
-+              down_write(_dev_locks + minor);
-+              return -ENXIO;
-+      }
-+
 +      return 0;
 +}
 +
++struct dm_table *dm_get_table(struct mapped_device *md)
++{
++      struct dm_table *t;
++
++      down_read(&md->lock);
++      t = md->map;
++      dm_table_get(t);
++      up_read(&md->lock);
++
++      return t;
++}
++
++kdev_t dm_kdev(struct mapped_device *md)
++{
++      kdev_t dev;
++
++      down_read(&md->lock);
++      dev = md->dev;
++      up_read(&md->lock);
++
++      return dev;
++}
++
++int dm_suspended(struct mapped_device *md)
++{
++      return test_bit(DMF_SUSPENDED, &md->flags);
++}
++
 +struct block_device_operations dm_blk_dops = {
-+      open:           dm_blk_open,
-+      release:        dm_blk_close,
-+      ioctl:          dm_blk_ioctl,
-+      owner:          THIS_MODULE
++      .open = dm_blk_open,
++      .release = dm_blk_close,
++      .ioctl = dm_blk_ioctl,
++      .owner = THIS_MODULE
 +};
 +
 +/*
@@ -5134,14 +5319,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +MODULE_DESCRIPTION(DM_NAME " driver");
 +MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>");
 +MODULE_LICENSE("GPL");
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm.h linux-2.4.19-dm/drivers/md/dm.h
---- linux-2.4.19/drivers/md/dm.h       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm.h    Wed Aug 14 14:51:11 2002
-@@ -0,0 +1,242 @@
+diff -ruN linux-2.4.19-dm/drivers/md/dm.h linux-2.4.19-dmbackport/drivers/md/dm.h
+--- linux-2.4.19-dm/drivers/md/dm.h    Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/dm.h    Wed Nov 13 18:08:20 2002
+@@ -0,0 +1,150 @@
 +/*
 + * Internal header file for device mapper
 + *
-+ * Copyright (C) 2001 Sistina Software
++ * Copyright (C) 2001, 2002 Sistina Software
 + *
 + * This file is released under the LGPL.
 + */
@@ -5149,213 +5334,134 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef DM_INTERNAL_H
 +#define DM_INTERNAL_H
 +
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/major.h>
-+#include <linux/iobuf.h>
-+#include <linux/module.h>
 +#include <linux/fs.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/compatmac.h>
-+#include <linux/cache.h>
-+#include <linux/devfs_fs_kernel.h>
-+#include <linux/ctype.h>
 +#include <linux/device-mapper.h>
 +#include <linux/list.h>
-+#include <linux/init.h>
-+
-+#define DM_NAME "device-mapper"       /* Name for messaging */
-+#define DM_DRIVER_EMAIL "lvm-devel@lists.sistina.com"
-+#define MAX_DEPTH 16
-+#define NODE_SIZE L1_CACHE_BYTES
-+#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
-+#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
-+#define MAX_ARGS 32
-+#define MAX_DEVICES 256
-+
-+/*
-+ * List of devices that a metadevice uses and should open/close.
-+ */
-+struct dm_dev {
-+      atomic_t count;
-+      struct list_head list;
-+
-+      int mode;
++#include <linux/blkdev.h>
 +
-+      kdev_t dev;
-+      struct block_device *bd;
-+};
++#define DM_NAME "device-mapper"
++#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
++#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
++#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
 +
 +/*
-+ * I/O that had to be deferred while we were suspended
++ * FIXME: I think this should be with the definition of sector_t
++ * in types.h.
 + */
-+struct deferred_io {
-+      int rw;
-+      struct buffer_head *bh;
-+      struct deferred_io *next;
-+};
++#ifdef CONFIG_LBD
++#define SECTOR_FORMAT "%Lu"
++#else
++#define SECTOR_FORMAT "%lu"
++#endif
 +
-+/*
-+ * Btree leaf - this does the actual mapping
-+ */
-+struct target {
-+      struct target_type *type;
-+      void *private;
-+};
++extern struct block_device_operations dm_blk_dops;
 +
 +/*
-+ * The btree
++ * List of devices that a metadevice uses and should open/close.
 + */
-+struct dm_table {
-+      /* btree table */
-+      int depth;
-+      int counts[MAX_DEPTH];  /* in nodes */
-+      offset_t *index[MAX_DEPTH];
-+
-+      int num_targets;
-+      int num_allocated;
-+      offset_t *highs;
-+      struct target *targets;
++struct dm_dev {
++      struct list_head list;
 +
-+      /*
-+       * Indicates the rw permissions for the new logical
-+       * device.  This should be a combination of FMODE_READ
-+       * and FMODE_WRITE.
-+       */
++      atomic_t count;
 +      int mode;
-+
-+      /* a list of devices used by this table */
-+      struct list_head devices;
-+
-+      /*
-+       * A waitqueue for processes waiting for something
-+       * interesting to happen to this table.
-+       */
-+      wait_queue_head_t eventq;
-+};
-+
-+/*
-+ * The actual device struct
-+ */
-+struct mapped_device {
 +      kdev_t dev;
-+      char name[DM_NAME_LEN];
-+      char *uuid;
-+
-+      int use_count;
-+      int suspended;
-+      int read_only;
-+
-+      /* a list of io's that arrived while we were suspended */
-+      atomic_t pending;
-+      wait_queue_head_t wait;
-+      struct deferred_io *deferred;
-+
-+      struct dm_table *map;
-+
-+      /* used by dm-fs.c */
-+      devfs_handle_t devfs_entry;
++      struct block_device *bdev;
 +};
 +
-+extern struct block_device_operations dm_blk_dops;
-+
-+/* dm-target.c */
-+int dm_target_init(void);
-+struct target_type *dm_get_target_type(const char *name);
-+void dm_put_target_type(struct target_type *t);
-+void dm_target_exit(void);
-+
-+/*
-+ * Destructively splits argument list to pass to ctr.
-+ */
-+int split_args(int max, int *argc, char **argv, char *input);
++struct dm_table;
++struct mapped_device;
 +
-+/* dm.c */
-+struct mapped_device *dm_get_r(int minor);
-+struct mapped_device *dm_get_w(int minor);
++/*-----------------------------------------------------------------
++ * Functions for manipulating a struct mapped_device.
++ * Drop the reference with dm_put when you finish with the object.
++ *---------------------------------------------------------------*/
++int dm_create(int minor, struct dm_table *table, struct mapped_device **md);
 +
 +/*
-+ * There are two ways to lookup a device.
++ * Reference counting for md.
 + */
-+enum {
-+      DM_LOOKUP_BY_NAME,
-+      DM_LOOKUP_BY_UUID
-+};
-+
-+struct mapped_device *dm_get_name_r(const char *name, int nametype);
-+struct mapped_device *dm_get_name_w(const char *name, int nametype);
-+
-+void dm_put_r(struct mapped_device *md);
-+void dm_put_w(struct mapped_device *md);
++void dm_get(struct mapped_device *md);
++void dm_put(struct mapped_device *md);
 +
 +/*
-+ * Call with no lock.
++ * A device can still be used while suspended, but I/O is deferred.
 + */
-+int dm_create(const char *name, const char *uuid, int minor, int ro,
-+            struct dm_table *table);
-+int dm_set_name(const char *name, int nametype, const char *newname);
-+void dm_destroy_all(void);
++int dm_suspend(struct mapped_device *md);
++int dm_resume(struct mapped_device *md);
 +
 +/*
-+ * You must have the write lock before calling the remaining md
-+ * methods.
++ * The device must be suspended before calling this method.
 + */
-+int dm_destroy(struct mapped_device *md);
-+void dm_set_ro(struct mapped_device *md, int ro);
++int dm_swap_table(struct mapped_device *md, struct dm_table *t);
 +
 +/*
-+ * The device must be suspended before calling this method.
++ * Drop a reference on the table when you've finished with the
++ * result.
 + */
-+int dm_swap_table(struct mapped_device *md, struct dm_table *t);
++struct dm_table *dm_get_table(struct mapped_device *md);
 +
 +/*
-+ * A device can still be used while suspended, but I/O is deferred.
++ * Info functions.
 + */
-+int dm_suspend(struct mapped_device *md);
-+int dm_resume(struct mapped_device *md);
++kdev_t dm_kdev(struct mapped_device *md);
++int dm_suspended(struct mapped_device *md);
 +
-+/* dm-table.c */
++/*-----------------------------------------------------------------
++ * Functions for manipulating a table.  Tables are also reference
++ * counted.
++ *---------------------------------------------------------------*/
 +int dm_table_create(struct dm_table **result, int mode);
-+void dm_table_destroy(struct dm_table *t);
 +
-+int dm_table_add_target(struct dm_table *t, offset_t highs,
-+                      struct target_type *type, void *private);
-+int dm_table_complete(struct dm_table *t);
++void dm_table_get(struct dm_table *t);
++void dm_table_put(struct dm_table *t);
 +
-+/*
-+ * Event handling
-+ */
++int dm_table_add_target(struct dm_table *t, const char *type,
++                      sector_t start, sector_t len, char *params);
++int dm_table_complete(struct dm_table *t);
 +void dm_table_event(struct dm_table *t);
++sector_t dm_table_get_size(struct dm_table *t);
++struct dm_target *dm_table_get_target(struct dm_table *t, int index);
++struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
++unsigned int dm_table_get_num_targets(struct dm_table *t);
++struct list_head *dm_table_get_devices(struct dm_table *t);
++int dm_table_get_mode(struct dm_table *t);
++void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq);
 +
-+#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
-+#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
-+#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
++/*-----------------------------------------------------------------
++ * A registry of target types.
++ *---------------------------------------------------------------*/
++int dm_target_init(void);
++void dm_target_exit(void);
++struct target_type *dm_get_target_type(const char *name);
++void dm_put_target_type(struct target_type *t);
 +
-+/*
-+ * Calculate the index of the child node of the n'th node k'th key.
-+ */
-+static inline int get_child(int n, int k)
++/*-----------------------------------------------------------------
++ * Useful inlines.
++ *---------------------------------------------------------------*/
++static inline int array_too_big(unsigned long fixed, unsigned long obj,
++                              unsigned long num)
 +{
-+      return (n * CHILDREN_PER_NODE) + k;
++      return (num > (ULONG_MAX - fixed) / obj);
 +}
 +
 +/*
-+ * Return the n'th node of level l from table t.
++ * ceiling(n / size) * size
 + */
-+static inline offset_t *get_node(struct dm_table *t, int l, int n)
++static inline unsigned long dm_round_up(unsigned long n, unsigned long size)
 +{
-+      return t->index[l] + (n * KEYS_PER_NODE);
++      unsigned long r = n % size;
++      return n + (r ? (size - r) : 0);
 +}
 +
-+static inline int array_too_big(unsigned long fixed, unsigned long obj,
-+                              unsigned long num)
-+{
-+      return (num > (ULONG_MAX - fixed) / obj);
-+}
++/*
++ * 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);
 +
 +/*
-+ * Targets
++ * Targets for linear and striped mappings
 + */
 +int dm_linear_init(void);
 +void dm_linear_exit(void);
@@ -5366,42 +5472,31 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int dm_snapshot_init(void);
 +void dm_snapshot_exit(void);
 +
-+/* Future */
-+/* int dm_mirror_init(void); */
-+/* void dm_mirror_exit(void); */
-+
-+/*
-+ * Init functions for the user interface to device-mapper.  At
-+ * the moment an ioctl interface on a special char device is
-+ * used.  A filesystem based interface would be a nicer way to
-+ * go.
-+ */
-+int __init dm_interface_init(void);
-+void dm_interface_exit(void);
-+
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/kcopyd.c linux-2.4.19-dm/drivers/md/kcopyd.c
---- linux-2.4.19/drivers/md/kcopyd.c   Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/kcopyd.c        Wed Aug 14 14:13:40 2002
-@@ -0,0 +1,841 @@
+diff -ruN linux-2.4.19-dm/drivers/md/kcopyd.c linux-2.4.19-dmbackport/drivers/md/kcopyd.c
+--- linux-2.4.19-dm/drivers/md/kcopyd.c        Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/kcopyd.c        Wed Nov 13 17:52:16 2002
+@@ -0,0 +1,843 @@
 +/*
 + * Copyright (C) 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
++#include <asm/atomic.h>
++
++#include <linux/blkdev.h>
 +#include <linux/config.h>
-+#include <linux/module.h>
++#include <linux/device-mapper.h>
++#include <linux/fs.h>
 +#include <linux/init.h>
-+#include <linux/slab.h>
 +#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/device-mapper.h>
++#include <linux/locks.h>
 +#include <linux/mempool.h>
-+#include <asm/atomic.h>
++#include <linux/module.h>
 +#include <linux/pagemap.h>
-+#include <linux/locks.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
 +
 +#include "kcopyd.h"
 +
@@ -5641,7 +5736,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct kcopyd_job *job;
 +
-+      job = mempool_alloc(_job_pool, GFP_KERNEL);
++      job = mempool_alloc(_job_pool, GFP_NOIO);
 +      if (!job)
 +              return NULL;
 +
@@ -5997,7 +6092,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static inline struct copy_info *alloc_copy_info(void)
 +{
-+      return mempool_alloc(_copy_pool, GFP_KERNEL);
++      return mempool_alloc(_copy_pool, GFP_NOIO);
 +}
 +
 +static inline void free_copy_info(struct copy_info *info)
@@ -6225,9 +6320,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      up(&_client_count_sem);
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/kcopyd.h linux-2.4.19-dm/drivers/md/kcopyd.h
---- linux-2.4.19/drivers/md/kcopyd.h   Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/kcopyd.h        Wed Jul 17 14:59:03 2002
+diff -ruN linux-2.4.19-dm/drivers/md/kcopyd.h linux-2.4.19-dmbackport/drivers/md/kcopyd.h
+--- linux-2.4.19-dm/drivers/md/kcopyd.h        Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/drivers/md/kcopyd.h        Wed Nov 13 18:08:24 2002
 @@ -0,0 +1,101 @@
 +/*
 + * Copyright (C) 2001 Sistina Software
@@ -6246,8 +6341,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +struct kcopyd_region {
 +      kdev_t dev;
-+      offset_t sector;
-+      offset_t count;
++      sector_t sector;
++      sector_t count;
 +};
 +
 +#define MAX_KCOPYD_PAGES 128
@@ -6277,11 +6372,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Shifts and masks that will be useful when dispatching
 +       * each buffer_head.
 +       */
-+      offset_t offset;
-+      offset_t block_size;
-+      offset_t block_shift;
-+      offset_t bpp_shift;     /* blocks per page */
-+      offset_t bpp_mask;
++      sector_t offset;
++      sector_t block_size;
++      sector_t block_shift;
++      sector_t bpp_shift;     /* blocks per page */
++      sector_t bpp_mask;
 +
 +      /*
 +       * nr_blocks is how many buffer heads will have to be
@@ -6297,7 +6392,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Set this to ensure you are notified when the job has
 +       * completed.  'context' is for callback to use.
 +       */
-+      void (*callback)(struct kcopyd_job *job);
++      void (*callback) (struct kcopyd_job *job);
 +      void *context;
 +};
 +
@@ -6313,7 +6408,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Submit a copy job to kcopyd.  This is built on top of the
 + * previous three fns.
 + */
-+typedef void (*kcopyd_notify_fn)(int err, void *context);
++typedef void (*kcopyd_notify_fn) (int err, void *context);
 +
 +int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to,
 +              kcopyd_notify_fn fn, void *context);
@@ -6330,10 +6425,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +void kcopyd_dec_client_count(void);
 +
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/device-mapper.h linux-2.4.19-dm/include/linux/device-mapper.h
---- linux-2.4.19/include/linux/device-mapper.h Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/include/linux/device-mapper.h      Wed Aug 14 13:56:56 2002
-@@ -0,0 +1,63 @@
+diff -ruN linux-2.4.19-dm/include/linux/device-mapper.h linux-2.4.19-dmbackport/include/linux/device-mapper.h
+--- linux-2.4.19-dm/include/linux/device-mapper.h      Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/include/linux/device-mapper.h      Wed Nov 13 17:54:29 2002
+@@ -0,0 +1,85 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -6343,40 +6438,48 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef _LINUX_DEVICE_MAPPER_H
 +#define _LINUX_DEVICE_MAPPER_H
 +
-+#define DM_DIR "mapper"       /* Slashes not supported */
-+#define DM_MAX_TYPE_NAME 16
-+#define DM_NAME_LEN 128
-+#define DM_UUID_LEN 129
-+
 +#ifdef __KERNEL__
 +
++typedef unsigned long sector_t;
++
++struct dm_target;
 +struct dm_table;
 +struct dm_dev;
-+typedef unsigned long offset_t;
 +
 +typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 +
 +/*
-+ * Prototypes for functions for a target
++ * In the constructor the target parameter will already have the
++ * table, type, begin and len fields filled in.
++ */
++typedef int (*dm_ctr_fn) (struct dm_target *target, int argc, char **argv);
++
++/*
++ * The destructor doesn't need to free the dm_target, just
++ * anything hidden ti->private.
 + */
-+typedef int (*dm_ctr_fn) (struct dm_table *t, offset_t b, offset_t l,
-+                        int argc, char **argv, 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_status_fn) (status_type_t status_type, char *result,
-+                           int maxlen, void *context);
++typedef void (*dm_dtr_fn) (struct dm_target *ti);
++
++/*
++ * The map function must return:
++ * < 0: error
++ * = 0: The target will handle the io by resubmitting it later
++ * > 0: simple remap complete
++ */
++typedef int (*dm_map_fn) (struct dm_target *ti, struct buffer_head *bh, int rw);
++typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
++                           char *result, int maxlen);
 +
 +void dm_error(const char *message);
 +
 +/*
 + * Constructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * are opened/closed correctly.
++ * FIXME: too many arguments.
 + */
-+int dm_table_get_device(struct dm_table *t, const char *path,
-+                      offset_t start, offset_t len,
-+                      int mode, struct dm_dev **result);
-+void dm_table_put_device(struct dm_table *table, struct dm_dev *d);
++int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
++                sector_t len, int mode, struct dm_dev **result);
++void dm_put_device(struct dm_target *ti, struct dm_dev *d);
 +
 +/*
 + * Information about a target type
@@ -6387,20 +6490,34 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dm_ctr_fn ctr;
 +      dm_dtr_fn dtr;
 +      dm_map_fn map;
-+      dm_err_fn err;
 +      dm_status_fn status;
 +};
 +
++struct dm_target {
++      struct dm_table *table;
++      struct target_type *type;
++
++      /* target limits */
++      sector_t begin;
++      sector_t len;
++
++      /* target specific data */
++      void *private;
++
++      /* Used to provide an error string from the ctr */
++      char *error;
++};
++
 +int dm_register_target(struct target_type *t);
 +int dm_unregister_target(struct target_type *t);
 +
 +#endif                                /* __KERNEL__ */
 +
 +#endif                                /* _LINUX_DEVICE_MAPPER_H */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/dm-ioctl.h linux-2.4.19-dm/include/linux/dm-ioctl.h
---- linux-2.4.19/include/linux/dm-ioctl.h      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/include/linux/dm-ioctl.h   Wed Aug 14 16:30:49 2002
-@@ -0,0 +1,145 @@
+diff -ruN linux-2.4.19-dm/include/linux/dm-ioctl.h linux-2.4.19-dmbackport/include/linux/dm-ioctl.h
+--- linux-2.4.19-dm/include/linux/dm-ioctl.h   Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dmbackport/include/linux/dm-ioctl.h   Wed Nov 13 17:53:50 2002
+@@ -0,0 +1,149 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -6410,9 +6527,13 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef _LINUX_DM_IOCTL_H
 +#define _LINUX_DM_IOCTL_H
 +
-+#include "device-mapper.h"
 +#include <linux/types.h>
 +
++#define DM_DIR "mapper"               /* Slashes not supported */
++#define DM_MAX_TYPE_NAME 16
++#define DM_NAME_LEN 128
++#define DM_UUID_LEN 129
++
 +/*
 + * Implements a traditional ioctl interface to the device mapper.
 + */
@@ -6530,8 +6651,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#define DM_VERSION_MAJOR      1
 +#define DM_VERSION_MINOR      0
-+#define DM_VERSION_PATCHLEVEL 3
-+#define DM_VERSION_EXTRA      "-ioctl (2002-08-14)"
++#define DM_VERSION_PATCHLEVEL 7
++#define DM_VERSION_EXTRA      "-ioctl (2002-11-13)"
 +
 +/* Status bits */
 +#define DM_READONLY_FLAG      0x00000001
index 66670b0601ed607875da06c7bc0f80220ca1ca3d..e98ebc856a11d76c39a0848deabfb01d9c4b993a 100644 (file)
@@ -1,6 +1,6 @@
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/Documentation/Configure.help linux-2.4.19-dm/Documentation/Configure.help
+diff -ruN linux-2.4.19/Documentation/Configure.help linux-2.4.19-dm-test1/Documentation/Configure.help
 --- linux-2.4.19/Documentation/Configure.help  Wed Aug 14 11:49:48 2002
-+++ linux-2.4.19-dm/Documentation/Configure.help       Wed Aug 14 17:42:52 2002
++++ linux-2.4.19-dm-test1/Documentation/Configure.help Wed Nov 13 19:04:25 2002
 @@ -1775,6 +1775,20 @@
    want), say M here and read <file:Documentation/modules.txt>.  The
    module will be called lvm-mod.o.
@@ -22,9 +22,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  Multiple devices driver support (RAID and LVM)
  CONFIG_MD
    Support multiple physical spindles through a single logical device.
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/MAINTAINERS linux-2.4.19-dm/MAINTAINERS
+diff -ruN linux-2.4.19/MAINTAINERS linux-2.4.19-dm-test1/MAINTAINERS
 --- linux-2.4.19/MAINTAINERS   Wed Aug 14 11:49:45 2002
-+++ linux-2.4.19-dm/MAINTAINERS        Wed Aug 14 17:42:52 2002
++++ linux-2.4.19-dm-test1/MAINTAINERS  Wed Nov 13 19:04:25 2002
 @@ -426,6 +426,13 @@
  W:    http://www.debian.org/~dz/i8k/
  S:    Maintained
@@ -39,9 +39,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  DEVICE NUMBER REGISTRY
  P:    H. Peter Anvin
  M:    hpa@zytor.com
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/Config.in linux-2.4.19-dm/drivers/md/Config.in
+diff -ruN linux-2.4.19/drivers/md/Config.in linux-2.4.19-dm-test1/drivers/md/Config.in
 --- linux-2.4.19/drivers/md/Config.in  Wed Aug 14 11:51:06 2002
-+++ linux-2.4.19-dm/drivers/md/Config.in       Wed Aug 14 17:42:52 2002
++++ linux-2.4.19-dm-test1/drivers/md/Config.in Wed Nov 13 19:04:25 2002
 @@ -14,5 +14,8 @@
  dep_tristate '  Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
  
@@ -51,9 +51,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +fi
  
  endmenu
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/Makefile linux-2.4.19-dm/drivers/md/Makefile
+diff -ruN linux-2.4.19/drivers/md/Makefile linux-2.4.19-dm-test1/drivers/md/Makefile
 --- linux-2.4.19/drivers/md/Makefile   Wed Aug 14 11:51:06 2002
-+++ linux-2.4.19-dm/drivers/md/Makefile        Wed Aug 14 17:45:33 2002
++++ linux-2.4.19-dm-test1/drivers/md/Makefile  Wed Nov 13 19:21:59 2002
 @@ -4,9 +4,12 @@
  
  O_TARGET      := mddev.o
@@ -81,10 +81,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +dm-mod.o: $(dm-mod-objs)
 +      $(LD) -r -o $@ $(dm-mod-objs)
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-exception-store.c linux-2.4.19-dm/drivers/md/dm-exception-store.c
+diff -ruN linux-2.4.19/drivers/md/dm-exception-store.c linux-2.4.19-dm-test1/drivers/md/dm-exception-store.c
 --- linux-2.4.19/drivers/md/dm-exception-store.c       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-exception-store.c    Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,698 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm-exception-store.c      Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,701 @@
 +/*
 + * dm-snapshot.c
 + *
@@ -95,8 +95,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#include "dm-snapshot.h"
 +#include "kcopyd.h"
++
 +#include <linux/mm.h>
 +#include <linux/pagemap.h>
++#include <linux/vmalloc.h>
++#include <linux/slab.h>
 +
 +#define SECTOR_SIZE 512
 +#define SECTOR_SHIFT 9
@@ -165,7 +168,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +};
 +
 +struct commit_callback {
-+      void (*callback)(void *, int success);
++      void (*callback) (void *, int success);
 +      void *context;
 +};
 +
@@ -533,7 +536,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct pstore *ps = get_info(store);
 +      uint32_t stride;
-+      offset_t size = get_dev_size(store->snap->cow->dev);
++      sector_t size = get_dev_size(store->snap->cow->dev);
 +
 +      /* Is there enough room ? */
 +      if (size <= (ps->next_free * store->snap->chunk_size))
@@ -725,7 +728,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Implementation of the store for non-persistent snapshots.
 + *---------------------------------------------------------------*/
 +struct transient_c {
-+      offset_t next_free;
++      sector_t next_free;
 +};
 +
 +void transient_destroy(struct exception_store *store)
@@ -736,7 +739,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int transient_prepare(struct exception_store *store, struct exception *e)
 +{
 +      struct transient_c *tc = (struct transient_c *) store->context;
-+      offset_t size = get_dev_size(store->snap->cow->dev);
++      sector_t size = get_dev_size(store->snap->cow->dev);
 +
 +      if (size < (tc->next_free + store->snap->chunk_size))
 +              return -1;
@@ -763,7 +766,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +int dm_create_transient(struct exception_store *store,
-+                      struct dm_snapshot *s, int blocksize, void **error)
++                      struct dm_snapshot *s, int blocksize)
 +{
 +      struct transient_c *tc;
 +
@@ -783,42 +786,337 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      return 0;
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-ioctl.c linux-2.4.19-dm/drivers/md/dm-ioctl.c
+diff -ruN linux-2.4.19/drivers/md/dm-ioctl.c linux-2.4.19-dm-test1/drivers/md/dm-ioctl.c
 --- linux-2.4.19/drivers/md/dm-ioctl.c Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-ioctl.c      Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,830 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm-ioctl.c        Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,1139 @@
 +/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited.
++ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
 +#include "dm.h"
 +
++#include <linux/module.h>
++#include <linux/vmalloc.h>
 +#include <linux/miscdevice.h>
 +#include <linux/dm-ioctl.h>
 +#include <linux/init.h>
 +#include <linux/wait.h>
++#include <linux/blk.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++
++#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
 +
 +/*-----------------------------------------------------------------
-+ * Implementation of the ioctl commands
++ * The ioctl interface needs to be able to look up devices by
++ * name or uuid.
 + *---------------------------------------------------------------*/
++struct hash_cell {
++      struct list_head name_list;
++      struct list_head uuid_list;
++
++      char *name;
++      char *uuid;
++      struct mapped_device *md;
++
++      /* I hate devfs */
++      devfs_handle_t devfs_entry;
++};
++
++#define NUM_BUCKETS 64
++#define MASK_BUCKETS (NUM_BUCKETS - 1)
++static struct list_head _name_buckets[NUM_BUCKETS];
++static struct list_head _uuid_buckets[NUM_BUCKETS];
++
++static devfs_handle_t _dev_dir;
++void dm_hash_remove_all(void);
 +
 +/*
-+ * All the ioctl commands get dispatched to functions with this
-+ * prototype.
++ * Guards access to all three tables.
 + */
-+typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
++static DECLARE_RWSEM(_hash_lock);
++
++static void init_buckets(struct list_head *buckets)
++{
++      unsigned int i;
++
++      for (i = 0; i < NUM_BUCKETS; i++)
++              INIT_LIST_HEAD(buckets + i);
++}
++
++int dm_hash_init(void)
++{
++      init_buckets(_name_buckets);
++      init_buckets(_uuid_buckets);
++      _dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
++      return 0;
++}
++
++void dm_hash_exit(void)
++{
++      dm_hash_remove_all();
++      devfs_unregister(_dev_dir);
++}
++
++/*-----------------------------------------------------------------
++ * Hash function:
++ * We're not really concerned with the str hash function being
++ * fast since it's only used by the ioctl interface.
++ *---------------------------------------------------------------*/
++static unsigned int hash_str(const char *str)
++{
++      const unsigned int hash_mult = 2654435387U;
++      unsigned int h = 0;
++
++      while (*str)
++              h = (h + (unsigned int) *str++) * hash_mult;
++
++      return h & MASK_BUCKETS;
++}
++
++/*-----------------------------------------------------------------
++ * Code for looking up a device by name
++ *---------------------------------------------------------------*/
++static struct hash_cell *__get_name_cell(const char *str)
++{
++      struct list_head *tmp;
++      struct hash_cell *hc;
++      unsigned int h = hash_str(str);
++
++      list_for_each(tmp, _name_buckets + h) {
++              hc = list_entry(tmp, struct hash_cell, name_list);
++              if (!strcmp(hc->name, str))
++                      return hc;
++      }
++
++      return NULL;
++}
++
++static struct hash_cell *__get_uuid_cell(const char *str)
++{
++      struct list_head *tmp;
++      struct hash_cell *hc;
++      unsigned int h = hash_str(str);
++
++      list_for_each(tmp, _uuid_buckets + h) {
++              hc = list_entry(tmp, struct hash_cell, uuid_list);
++              if (!strcmp(hc->uuid, str))
++                      return hc;
++      }
++
++      return NULL;
++}
++
++/*-----------------------------------------------------------------
++ * Inserting, removing and renaming a device.
++ *---------------------------------------------------------------*/
++static inline char *kstrdup(const char *str)
++{
++      char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
++      if (r)
++              strcpy(r, str);
++      return r;
++}
++
++static struct hash_cell *alloc_cell(const char *name, const char *uuid,
++                                  struct mapped_device *md)
++{
++      struct hash_cell *hc;
++
++      hc = kmalloc(sizeof(*hc), GFP_KERNEL);
++      if (!hc)
++              return NULL;
++
++      hc->name = kstrdup(name);
++      if (!hc->name) {
++              kfree(hc);
++              return NULL;
++      }
++
++      if (!uuid)
++              hc->uuid = NULL;
++
++      else {
++              hc->uuid = kstrdup(uuid);
++              if (!hc->uuid) {
++                      kfree(hc->name);
++                      kfree(hc);
++                      return NULL;
++              }
++      }
++
++      INIT_LIST_HEAD(&hc->name_list);
++      INIT_LIST_HEAD(&hc->uuid_list);
++      hc->md = md;
++      return hc;
++}
++
++static void free_cell(struct hash_cell *hc)
++{
++      if (hc) {
++              kfree(hc->name);
++              kfree(hc->uuid);
++              kfree(hc);
++      }
++}
 +
 +/*
-+ * This is really a debug only call.
++ * devfs stuff.
 + */
-+static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
++static int register_with_devfs(struct hash_cell *hc)
++{
++      kdev_t dev = dm_kdev(hc->md);
++
++      hc->devfs_entry =
++          devfs_register(_dev_dir, hc->name, DEVFS_FL_CURRENT_OWNER,
++                         major(dev), minor(dev),
++                         S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
++                         &dm_blk_dops, NULL);
++
++      return 0;
++}
++
++static int unregister_with_devfs(struct hash_cell *hc)
++{
++      devfs_unregister(hc->devfs_entry);
++      return 0;
++}
++
++/*
++ * The kdev_t and uuid of a device can never change once it is
++ * initially inserted.
++ */
++int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
++{
++      struct hash_cell *cell;
++
++      /*
++       * Allocate the new cells.
++       */
++      cell = alloc_cell(name, uuid, md);
++      if (!cell)
++              return -ENOMEM;
++
++      /*
++       * Insert the cell into all three hash tables.
++       */
++      down_write(&_hash_lock);
++      if (__get_name_cell(name))
++              goto bad;
++
++      list_add(&cell->name_list, _name_buckets + hash_str(name));
++
++      if (uuid) {
++              if (__get_uuid_cell(uuid)) {
++                      list_del(&cell->name_list);
++                      goto bad;
++              }
++              list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
++      }
++      register_with_devfs(cell);
++      dm_get(md);
++      up_write(&_hash_lock);
++
++      return 0;
++
++      bad:
++      up_write(&_hash_lock);
++      free_cell(cell);
++      return -EBUSY;
++}
++
++void __hash_remove(struct hash_cell *hc)
++{
++      /* remove from the dev hash */
++      list_del(&hc->uuid_list);
++      list_del(&hc->name_list);
++      unregister_with_devfs(hc);
++      dm_put(hc->md);
++}
++
++void dm_hash_remove_all(void)
++{
++      int i;
++      struct hash_cell *hc;
++      struct list_head *tmp, *n;
++
++      down_write(&_hash_lock);
++      for (i = 0; i < NUM_BUCKETS; i++) {
++              list_for_each_safe(tmp, n, _name_buckets + i) {
++                      hc = list_entry(tmp, struct hash_cell, name_list);
++                      __hash_remove(hc);
++              }
++      }
++      up_write(&_hash_lock);
++}
++
++int dm_hash_rename(const char *old, const char *new)
 +{
-+      dm_destroy_all();
++      char *new_name, *old_name;
++      struct hash_cell *hc;
++
++      /*
++       * duplicate new.
++       */
++      new_name = kstrdup(new);
++      if (!new_name)
++              return -ENOMEM;
++
++      down_write(&_hash_lock);
++
++      /*
++       * Is new free ?
++       */
++      hc = __get_name_cell(new);
++      if (hc) {
++              DMWARN("asked to rename to an already existing name %s -> %s",
++                     old, new);
++              up_write(&_hash_lock);
++              return -EBUSY;
++      }
++
++      /*
++       * Is there such a device as 'old' ?
++       */
++      hc = __get_name_cell(old);
++      if (!hc) {
++              DMWARN("asked to rename a non existent device %s -> %s",
++                     old, new);
++              up_write(&_hash_lock);
++              return -ENXIO;
++      }
++
++      /*
++       * rename and move the name cell.
++       */
++      list_del(&hc->name_list);
++      old_name = hc->name;
++      hc->name = new_name;
++      list_add(&hc->name_list, _name_buckets + hash_str(new_name));
++
++      /* rename the device node in devfs */
++      unregister_with_devfs(hc);
++      register_with_devfs(hc);
++
++      up_write(&_hash_lock);
++      kfree(old_name);
 +      return 0;
 +}
 +
++
++/*-----------------------------------------------------------------
++ * Implementation of the ioctl commands
++ *---------------------------------------------------------------*/
++
++/*
++ * All the ioctl commands get dispatched to functions with this
++ * prototype.
++ */
++typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
++
 +/*
 + * Check a string doesn't overrun the chunk of
 + * memory we copied from userland.
@@ -846,29 +1144,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return valid_str(*params, begin, end);
 +}
 +
-+/*
-+ * Checks to see if there's a gap in the table.
-+ * Returns true iff there is a gap.
-+ */
-+static int gap(struct dm_table *table, struct dm_target_spec *spec)
-+{
-+      if (!table->num_targets)
-+              return (spec->sector_start > 0) ? 1 : 0;
-+
-+      if (spec->sector_start != table->highs[table->num_targets - 1] + 1)
-+              return 1;
-+
-+      return 0;
-+}
-+
 +static int populate_table(struct dm_table *table, struct dm_ioctl *args)
 +{
-+      int i = 0, r, first = 1, argc;
++      int i = 0, r, first = 1;
 +      struct dm_target_spec *spec;
-+      char *params, *argv[MAX_ARGS];
-+      struct target_type *ttype;
-+      void *context, *begin, *end;
-+      offset_t highs = 0;
++      char *params;
++      void *begin, *end;
 +
 +      if (!args->target_count) {
 +              DMWARN("populate_table: no targets specified");
@@ -878,8 +1159,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      begin = (void *) args;
 +      end = begin + args->data_size;
 +
-+#define PARSE_ERROR(msg) {DMWARN(msg); return -EINVAL;}
-+
 +      for (i = 0; i < args->target_count; i++) {
 +
 +              if (first)
@@ -890,41 +1169,23 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +                      r = next_target(spec, spec->next, begin, end,
 +                                      &spec, &params);
 +
-+              if (r)
-+                      PARSE_ERROR("unable to find target");
-+
-+              /* Look up the target type */
-+              ttype = dm_get_target_type(spec->target_type);
-+              if (!ttype)
-+                      PARSE_ERROR("unable to find target type");
-+
-+              if (gap(table, spec))
-+                      PARSE_ERROR("gap in target ranges");
-+
-+              /* Split up the parameter list */
-+              if (split_args(MAX_ARGS, &argc, argv, params) < 0)
-+                      PARSE_ERROR("Too many arguments");
-+
-+              /* Build the target */
-+              if (ttype->ctr(table, spec->sector_start, spec->length,
-+                             argc, argv, &context)) {
-+                      DMWARN("%s: target constructor failed",
-+                             (char *) context);
++              if (r) {
++                      DMWARN("unable to find target");
 +                      return -EINVAL;
 +              }
 +
-+              /* Add the target to the table */
-+              highs = spec->sector_start + (spec->length - 1);
-+              if (dm_table_add_target(table, highs, ttype, context))
-+                      PARSE_ERROR("internal error adding target to table");
++              r = dm_table_add_target(table, spec->target_type,
++                                      spec->sector_start, spec->length,
++                                      params);
++              if (r) {
++                      DMWARN("internal error adding target to table");
++                      return -EINVAL;
++              }
 +
 +              first = 0;
 +      }
 +
-+#undef PARSE_ERROR
-+
-+      r = dm_table_complete(table);
-+      return r;
++      return dm_table_complete(table);
 +}
 +
 +/*
@@ -976,37 +1237,63 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Fills in a dm_ioctl structure, ready for sending back to
 + * userland.
 + */
-+static void __info(struct mapped_device *md, struct dm_ioctl *param)
++static int __info(struct mapped_device *md, struct dm_ioctl *param)
 +{
++      kdev_t dev = dm_kdev(md);
++      struct dm_table *table;
++      struct block_device *bdev;
++
 +      param->flags = DM_EXISTS_FLAG;
-+      if (md->suspended)
++      if (dm_suspended(md))
 +              param->flags |= DM_SUSPEND_FLAG;
-+      if (md->read_only)
-+              param->flags |= DM_READONLY_FLAG;
 +
-+      strncpy(param->name, md->name, sizeof(param->name));
++      param->dev = kdev_t_to_nr(dev);
++      bdev = bdget(param->dev);
++      if (!bdev)
++              return -ENXIO;
 +
-+      if (md->uuid)
-+              strncpy(param->uuid, md->uuid, sizeof(param->uuid) - 1);
-+      else
-+              param->uuid[0] = '\0';
++      param->open_count = bdev->bd_openers;
++      bdput(bdev);
 +
-+      param->open_count = md->use_count;
-+      param->dev = kdev_t_to_nr(md->dev);
-+      param->target_count = md->map->num_targets;
++      if (is_read_only(dev))
++              param->flags |= DM_READONLY_FLAG;
++
++      table = dm_get_table(md);
++      param->target_count = dm_table_get_num_targets(table);
++      dm_table_put(table);
++
++      return 0;
 +}
 +
 +/*
 + * Always use UUID for lookups if it's present, otherwise use name.
 + */
-+static inline char *lookup_name(struct dm_ioctl *param)
++static inline struct mapped_device *find_device(struct dm_ioctl *param)
 +{
-+      return (*param->uuid) ? param->uuid : param->name;
-+}
++      struct hash_cell *hc;
++      struct mapped_device *md = NULL;
 +
-+static inline int lookup_type(struct dm_ioctl *param)
-+{
-+      return (*param->uuid) ? DM_LOOKUP_BY_UUID : DM_LOOKUP_BY_NAME;
++      down_read(&_hash_lock);
++      hc = *param->uuid ? __get_uuid_cell(param->uuid) :
++          __get_name_cell(param->name);
++      if (hc) {
++              md = hc->md;
++
++              /*
++               * Sneakily write in both the name and the uuid
++               * while we have the cell.
++               */
++              strncpy(param->name, hc->name, sizeof(param->name));
++              if (hc->uuid)
++                      strncpy(param->uuid, hc->uuid, sizeof(param->uuid) - 1);
++              else
++                      param->uuid[0] = '\0';
++
++              dm_get(md);
++      }
++      up_read(&_hash_lock);
++
++      return md;
 +}
 +
 +#define ALIGNMENT sizeof(int)
@@ -1027,7 +1314,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      param->flags = 0;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
@@ -1035,7 +1322,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              goto out;
 +
 +      __info(md, param);
-+      dm_put_r(md);
++      dm_put(md);
 +
 +      out:
 +      return results_to_user(user, param, NULL, 0);
@@ -1051,38 +1338,55 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return mode;
 +}
 +
++static int check_name(const char *name)
++{
++      if (strchr(name, '/')) {
++              DMWARN("invalid device name");
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
 +static int create(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      int r, ro;
++      int r;
++      kdev_t dev;
 +      struct dm_table *t;
++      struct mapped_device *md;
 +      int minor;
 +
++      r = check_name(param->name);
++      if (r)
++              return r;
++
 +      r = dm_table_create(&t, get_mode(param));
 +      if (r)
 +              return r;
 +
 +      r = populate_table(t, param);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
 +
 +      minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
-+          MINOR(to_kdev_t(param->dev)) : -1;
-+
-+      ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0;
++          minor(to_kdev_t(param->dev)) : -1;
 +
-+      r = dm_create(param->name, param->uuid, minor, ro, t);
++      r = dm_create(minor, t, &md);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
++      dm_table_put(t);        /* md will have grabbed its own reference */
 +
-+      r = info(param, user);
-+      return r;
-+}
-+
++      dev = dm_kdev(md);
++      set_device_ro(dev, (param->flags & DM_READONLY_FLAG));
++      r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
++      dm_put(md);
 +
++      return r ? r : info(param, user);
++}
 +
 +/*
 + * Build up the status struct for each target
@@ -1090,11 +1394,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int __status(struct mapped_device *md, struct dm_ioctl *param,
 +                  char *outbuf, int *len)
 +{
-+      int i;
++      int i, num_targets;
 +      struct dm_target_spec *spec;
-+      uint64_t sector = 0LL;
 +      char *outptr;
 +      status_type_t type;
++      struct dm_table *table = dm_get_table(md);
 +
 +      if (param->flags & DM_STATUS_TABLE_FLAG)
 +              type = STATUSTYPE_TABLE;
@@ -1104,41 +1408,41 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      outptr = outbuf;
 +
 +      /* Get all the target info */
-+      for (i = 0; i < md->map->num_targets; i++) {
-+              struct target_type *tt = md->map->targets[i].type;
-+              offset_t high = md->map->highs[i];
++      num_targets = dm_table_get_num_targets(table);
++      for (i = 0; i < num_targets; i++) {
++              struct dm_target *ti = dm_table_get_target(table, i);
 +
 +              if (outptr - outbuf +
-+                  sizeof(struct dm_target_spec) > param->data_size)
-+                          return -ENOMEM;
++                  sizeof(struct dm_target_spec) > param->data_size) {
++                      dm_table_put(table);
++                      return -ENOMEM;
++              }
 +
 +              spec = (struct dm_target_spec *) outptr;
 +
 +              spec->status = 0;
-+              spec->sector_start = sector;
-+              spec->length = high - sector + 1;
-+              strncpy(spec->target_type, tt->name, sizeof(spec->target_type));
++              spec->sector_start = ti->begin;
++              spec->length = ti->len;
++              strncpy(spec->target_type, ti->type->name,
++                      sizeof(spec->target_type));
 +
 +              outptr += sizeof(struct dm_target_spec);
 +
 +              /* Get the status/table string from the target driver */
-+              if (tt->status)
-+                      tt->status(type, outptr,
-+                                 outbuf + param->data_size - outptr,
-+                                 md->map->targets[i].private);
++              if (ti->type->status)
++                      ti->type->status(ti, type, outptr,
++                                       outbuf + param->data_size - outptr);
 +              else
 +                      outptr[0] = '\0';
 +
 +              outptr += strlen(outptr) + 1;
 +              _align(outptr, ALIGNMENT);
-+
-+              sector = high + 1;
-+
 +              spec->next = outptr - outbuf;
 +      }
 +
-+      param->target_count = md->map->num_targets;
++      param->target_count = num_targets;
 +      *len = outptr - outbuf;
++      dm_table_put(table);
 +
 +      return 0;
 +}
@@ -1154,7 +1458,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int ret;
 +      char *outbuf = NULL;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
@@ -1179,7 +1483,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      out:
 +      if (md)
-+              dm_put_r(md);
++              dm_put(md);
 +
 +      ret = results_to_user(user, param, outbuf, len);
 +
@@ -1195,14 +1499,16 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
 +      struct mapped_device *md;
++      struct dm_table *table;
 +      DECLARE_WAITQUEUE(wq, current);
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              /*
 +               * Device not found - returns cleared exists flag.
 +               */
 +              goto out;
++
 +      /*
 +       * Setup the basic dm_ioctl structure.
 +       */
@@ -1212,11 +1518,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Wait for a notification event
 +       */
 +      set_current_state(TASK_INTERRUPTIBLE);
-+      add_wait_queue(&md->map->eventq, &wq);
++      table = dm_get_table(md);
++      dm_table_add_wait_queue(table, &wq);
++      dm_table_put(table);
++      dm_put(md);
 +
-+      dm_put_r(md);
-+
-+      schedule();
++      yield();
 +      set_current_state(TASK_RUNNING);
 +
 +      out:
@@ -1233,10 +1540,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      struct list_head *tmp;
 +      size_t len = 0;
 +      struct dm_target_deps *deps = NULL;
++      struct dm_table *table;
 +
-+      md = dm_get_name_r(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              goto out;
++      table = dm_get_table(md);
 +
 +      /*
 +       * Setup the basic dm_ioctl structure.
@@ -1247,7 +1556,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Count the devices.
 +       */
 +      count = 0;
-+      list_for_each(tmp, &md->map->devices)
++      list_for_each(tmp, dm_table_get_devices(table))
 +          count++;
 +
 +      /*
@@ -1255,14 +1564,16 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * struct.
 +       */
 +      if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
-+              dm_put_r(md);
++              dm_table_put(table);
++              dm_put(md);
 +              return -ENOMEM;
 +      }
 +
 +      len = sizeof(*deps) + (sizeof(*deps->dev) * count);
 +      deps = kmalloc(len, GFP_KERNEL);
 +      if (!deps) {
-+              dm_put_r(md);
++              dm_table_put(table);
++              dm_put(md);
 +              return -ENOMEM;
 +      }
 +
@@ -1271,11 +1582,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       */
 +      deps->count = count;
 +      count = 0;
-+      list_for_each(tmp, &md->map->devices) {
++      list_for_each(tmp, dm_table_get_devices(table)) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-+              deps->dev[count++] = kdev_t_to_nr(dd->dev);
++              deps->dev[count++] = dd->bdev->bd_dev;
 +      }
-+      dm_put_r(md);
++      dm_table_put(table);
++      dm_put(md);
 +
 +      out:
 +      r = results_to_user(user, param, deps, len);
@@ -1286,19 +1598,26 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      int r;
-+      struct mapped_device *md;
++      struct hash_cell *hc;
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
-+      if (!md)
-+              return -ENXIO;
++      down_write(&_hash_lock);
++      hc = *param->uuid ? __get_uuid_cell(param->uuid) :
++          __get_name_cell(param->name);
++      if (!hc) {
++              DMWARN("device doesn't appear to be in the dev hash table.");
++              up_write(&_hash_lock);
++              return -EINVAL;
++      }
 +
-+      r = dm_destroy(md);
-+      dm_put_w(md);
-+      if (!r)
-+              kfree(md);
++      __hash_remove(hc);
++      up_write(&_hash_lock);
++      return 0;
++}
 +
-+      return r;
++static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
++{
++      dm_hash_remove_all();
++      return 0;
 +}
 +
 +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
@@ -1306,19 +1625,23 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int r;
 +      struct mapped_device *md;
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md)
 +              return -ENXIO;
 +
-+      r = (param->flags & DM_SUSPEND_FLAG) ? dm_suspend(md) : dm_resume(md);
-+      dm_put_w(md);
++      if (param->flags & DM_SUSPEND_FLAG)
++              r = dm_suspend(md);
++      else
++              r = dm_resume(md);
 +
++      dm_put(md);
 +      return r;
 +}
 +
 +static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
 +      int r;
++      kdev_t dev;
 +      struct mapped_device *md;
 +      struct dm_table *t;
 +
@@ -1328,25 +1651,26 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      r = populate_table(t, param);
 +      if (r) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return r;
 +      }
 +
-+      md = dm_get_name_w(lookup_name(param), lookup_type(param));
++      md = find_device(param);
 +      if (!md) {
-+              dm_table_destroy(t);
++              dm_table_put(t);
 +              return -ENXIO;
 +      }
 +
 +      r = dm_swap_table(md, t);
 +      if (r) {
-+              dm_put_w(md);
-+              dm_table_destroy(t);
++              dm_put(md);
++              dm_table_put(t);
 +              return r;
 +      }
 +
-+      dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
-+      dm_put_w(md);
++      dev = dm_kdev(md);
++      set_device_ro(dev, (param->flags & DM_READONLY_FLAG));
++      dm_put(md);
 +
 +      r = info(param, user);
 +      return r;
@@ -1354,16 +1678,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
 +{
-+      char *newname = (char *) param + param->data_start;
++      int r;
++      char *new_name = (char *) param + param->data_start;
 +
-+      if (valid_str(newname, (void *) param,
-+                    (void *) param + param->data_size) ||
-+          dm_set_name(lookup_name(param), lookup_type(param), newname)) {
++      if (valid_str(new_name, (void *) param,
++                    (void *) param + param->data_size)) {
 +              DMWARN("Invalid new logical volume name supplied.");
 +              return -EINVAL;
 +      }
 +
-+      return 0;
++      r = check_name(new_name);
++      if (r)
++              return r;
++
++      return dm_hash_rename(param->name, new_name);
 +}
 +
 +
@@ -1371,24 +1699,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Implementation of open/close/ioctl on the special char
 + * device.
 + *---------------------------------------------------------------*/
-+static int ctl_open(struct inode *inode, struct file *file)
-+{
-+      /* only root can open this */
-+      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;
-+}
-+
-+static ioctl_fn lookup_ioctl(unsigned int cmd)
++static ioctl_fn lookup_ioctl(unsigned int cmd)
 +{
 +      static struct {
 +              int cmd;
@@ -1406,9 +1717,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              {DM_TARGET_STATUS_CMD, get_status},
 +              {DM_TARGET_WAIT_CMD, wait_device_event},
 +      };
-+      static int nelts = sizeof(_ioctls) / sizeof(*_ioctls);
 +
-+      return (cmd >= nelts) ? NULL : _ioctls[cmd].fn;
++      return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
 +}
 +
 +/*
@@ -1498,12 +1808,15 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +static int ctl_ioctl(struct inode *inode, struct file *file,
 +                   uint command, ulong u)
 +{
-+
 +      int r = 0, cmd;
 +      struct dm_ioctl *param;
 +      struct dm_ioctl *user = (struct dm_ioctl *) u;
 +      ioctl_fn fn = NULL;
 +
++      /* only root can play with this */
++      if (!capable(CAP_SYS_ADMIN))
++              return -EACCES;
++
 +      if (_IOC_TYPE(command) != DM_IOCTL)
 +              return -ENOTTY;
 +
@@ -1548,24 +1861,37 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +static struct file_operations _ctl_fops = {
-+      open:    ctl_open,
-+      release: ctl_close,
-+      ioctl:   ctl_ioctl,
-+      owner:   THIS_MODULE,
++      .ioctl = ctl_ioctl,
++      .owner = THIS_MODULE,
 +};
 +
 +static devfs_handle_t _ctl_handle;
 +
 +static struct miscdevice _dm_misc = {
-+      minor: MISC_DYNAMIC_MINOR,
-+      name:  DM_NAME,
-+      fops:  &_ctl_fops
++      .minor = MISC_DYNAMIC_MINOR,
++      .name  = DM_NAME,
++      .fops  = &_ctl_fops
 +};
 +
-+static int __init dm_devfs_init(void) {
++/*
++ * Create misc character device and link to DM_DIR/control.
++ */
++int __init dm_interface_init(void)
++{
 +      int r;
 +      char rname[64];
 +
++      r = dm_hash_init();
++      if (r)
++              return r;
++
++      r = misc_register(&_dm_misc);
++      if (r) {
++              DMERR("misc_register failed for control device");
++              dm_hash_exit();
++              return r;
++      }
++
 +      r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3,
 +                              sizeof rname - 3);
 +      if (r == -ENOSYS)
@@ -1573,7 +1899,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      if (r < 0) {
 +              DMERR("devfs_generate_path failed for control device");
-+              return r;
++              goto failed;
 +      }
 +
 +      strncpy(rname + r, "../", 3);
@@ -1581,46 +1907,32 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +                           DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL);
 +      if (r) {
 +              DMERR("devfs_mk_symlink failed for control device");
-+              return r;
++              goto failed;
 +      }
 +      devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle);
 +
-+      return 0;
-+}
-+
-+/* Create misc character device and link to DM_DIR/control */
-+int __init dm_interface_init(void)
-+{
-+      int r;
-+
-+      r = misc_register(&_dm_misc);
-+      if (r) {
-+              DMERR("misc_register failed for control device");
-+              return r;
-+      }
-+
-+      r = dm_devfs_init();
-+      if (r) {
-+              misc_deregister(&_dm_misc);
-+              return r;
-+      }
-+
 +      DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
 +             DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
 +             DM_DRIVER_EMAIL);
-+
 +      return 0;
++
++      failed:
++      dm_hash_exit();
++      misc_deregister(&_dm_misc);
++      return r;
 +}
 +
 +void dm_interface_exit(void)
 +{
++      dm_hash_exit();
++
 +      if (misc_deregister(&_dm_misc) < 0)
 +              DMERR("misc_deregister failed for control device");
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-linear.c linux-2.4.19-dm/drivers/md/dm-linear.c
+diff -ruN linux-2.4.19/drivers/md/dm-linear.c linux-2.4.19-dm-test1/drivers/md/dm-linear.c
 --- linux-2.4.19/drivers/md/dm-linear.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-linear.c     Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,125 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm-linear.c       Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,120 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -1632,51 +1944,46 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/blkdev.h>
++#include <linux/slab.h>
 +
 +/*
 + * Linear: maps a linear range of a device.
 + */
 +struct linear_c {
-+      long delta;             /* FIXME: we need a signed offset type */
-+      long start;             /* For display only */
 +      struct dm_dev *dev;
++      sector_t start;
 +};
 +
 +/*
 + * Construct a linear mapping: <dev_path> <offset>
 + */
-+static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int linear_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct linear_c *lc;
-+      unsigned long start;    /* FIXME: unsigned long long */
-+      char *end;
 +
 +      if (argc != 2) {
-+              *context = "dm-linear: Not enough arguments";
++              ti->error = "dm-linear: Not enough arguments";
 +              return -EINVAL;
 +      }
 +
 +      lc = kmalloc(sizeof(*lc), GFP_KERNEL);
 +      if (lc == NULL) {
-+              *context = "dm-linear: Cannot allocate linear context";
++              ti->error = "dm-linear: Cannot allocate linear context";
 +              return -ENOMEM;
 +      }
 +
-+      start = simple_strtoul(argv[1], &end, 10);
-+      if (*end) {
-+              *context = "dm-linear: Invalid device sector";
++      if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) {
++              ti->error = "dm-linear: Invalid device sector";
 +              goto bad;
 +      }
 +
-+      if (dm_table_get_device(t, argv[0], start, l, t->mode, &lc->dev)) {
-+              *context = "dm-linear: Device lookup failed";
++      if (dm_get_device(ti, argv[0], lc->start, ti->len,
++                        dm_table_get_mode(ti->table), &lc->dev)) {
++              ti->error = "dm-linear: Device lookup failed";
 +              goto bad;
 +      }
 +
-+      lc->delta = (int) start - (int) b;
-+      lc->start = start;
-+      *context = lc;
++      ti->private = lc;
 +      return 0;
 +
 +      bad:
@@ -1684,28 +1991,28 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return -EINVAL;
 +}
 +
-+static void linear_dtr(struct dm_table *t, void *c)
++static void linear_dtr(struct dm_target *ti)
 +{
-+      struct linear_c *lc = (struct linear_c *) c;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
-+      dm_table_put_device(t, lc->dev);
-+      kfree(c);
++      dm_put_device(ti, lc->dev);
++      kfree(lc);
 +}
 +
-+static int linear_map(struct buffer_head *bh, int rw, void *context)
++static int linear_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct linear_c *lc = (struct linear_c *) context;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
 +      bh->b_rdev = lc->dev->dev;
-+      bh->b_rsector = bh->b_rsector + lc->delta;
++      bh->b_rsector = lc->start + (bh->b_rsector - ti->begin);
 +
 +      return 1;
 +}
 +
-+static int linear_status(status_type_t type, char *result, int maxlen,
-+                       void *context)
++static int linear_status(struct dm_target *ti, status_type_t type,
++                       char *result, int maxlen)
 +{
-+      struct linear_c *lc = (struct linear_c *) context;
++      struct linear_c *lc = (struct linear_c *) ti->private;
 +
 +      switch (type) {
 +      case STATUSTYPE_INFO:
@@ -1713,20 +2020,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              break;
 +
 +      case STATUSTYPE_TABLE:
-+              snprintf(result, maxlen, "%s %ld", kdevname(lc->dev->dev),
-+                       lc->start);
++              snprintf(result, maxlen, "%s " SECTOR_FORMAT,
++                       kdevname(to_kdev_t(lc->dev->bdev->bd_dev)), lc->start);
 +              break;
 +      }
 +      return 0;
 +}
 +
 +static struct target_type linear_target = {
-+      name:   "linear",
-+      module: THIS_MODULE,
-+      ctr:    linear_ctr,
-+      dtr:    linear_dtr,
-+      map:    linear_map,
-+      status: linear_status,
++      .name   = "linear",
++      .module = THIS_MODULE,
++      .ctr    = linear_ctr,
++      .dtr    = linear_dtr,
++      .map    = linear_map,
++      .status = linear_status,
 +};
 +
 +int __init dm_linear_init(void)
@@ -1746,9 +2053,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if (r < 0)
 +              DMERR("linear: unregister failed %d", r);
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-snapshot.c linux-2.4.19-dm/drivers/md/dm-snapshot.c
+diff -ruN linux-2.4.19/drivers/md/dm-snapshot.c linux-2.4.19-dm-test1/drivers/md/dm-snapshot.c
 --- linux-2.4.19/drivers/md/dm-snapshot.c      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-snapshot.c   Wed Aug 14 17:42:59 2002
++++ linux-2.4.19-dm-test1/drivers/md/dm-snapshot.c     Wed Nov 13 19:21:59 2002
 @@ -0,0 +1,1169 @@
 +/*
 + * dm-snapshot.c
@@ -1767,6 +2074,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/blkdev.h>
 +#include <linux/mempool.h>
 +#include <linux/device-mapper.h>
++#include <linux/vmalloc.h>
 +
 +#include "dm-snapshot.h"
 +#include "kcopyd.h"
@@ -2097,7 +2405,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int init_hash_tables(struct dm_snapshot *s)
 +{
-+      offset_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
++      sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
 +
 +      /*
 +       * Calculate based on the size of the original volume or
@@ -2144,8 +2452,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
 + */
-+static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                      int argc, char **argv, void **context)
++static int snapshot_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct dm_snapshot *s;
 +      unsigned long chunk_size;
@@ -2157,7 +2464,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      int blocksize;
 +
 +      if (argc < 4) {
-+              *context = "dm-snapshot: requires exactly 4 arguments";
++              ti->error = "dm-snapshot: requires exactly 4 arguments";
 +              r = -EINVAL;
 +              goto bad;
 +      }
@@ -2167,36 +2474,38 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      persistent = argv[2];
 +
 +      if ((*persistent & 0x5f) != 'P' && (*persistent & 0x5f) != 'N') {
-+              *context = "Persistent flag is not P or N";
++              ti->error = "Persistent flag is not P or N";
 +              r = -EINVAL;
 +              goto bad;
 +      }
 +
 +      chunk_size = simple_strtoul(argv[3], &value, 10);
 +      if (chunk_size == 0 || value == NULL) {
-+              *context = "Invalid chunk size";
++              ti->error = "Invalid chunk size";
 +              r = -EINVAL;
 +              goto bad;
 +      }
 +
 +      s = kmalloc(sizeof(*s), GFP_KERNEL);
 +      if (s == NULL) {
-+              *context = "Cannot allocate snapshot context private structure";
++              ti->error = "Cannot allocate snapshot context private "
++                          "structure";
 +              r = -ENOMEM;
 +              goto bad;
 +      }
 +
-+      r = dm_table_get_device(t, origin_path, 0, 0, FMODE_READ, &s->origin);
++      r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
 +      if (r) {
-+              *context = "Cannot get origin device";
++              ti->error = "Cannot get origin device";
 +              goto bad_free;
 +      }
 +
-+      r = dm_table_get_device(t, cow_path, 0, 0,
-+                              FMODE_READ | FMODE_WRITE, &s->cow);
++      /* FIXME: get cow length */
++      r = dm_get_device(ti, cow_path, 0, 0,
++                        FMODE_READ | FMODE_WRITE, &s->cow);
 +      if (r) {
-+              dm_table_put_device(t, s->origin);
-+              *context = "Cannot get COW device";
++              dm_put_device(ti, s->origin);
++              ti->error = "Cannot get COW device";
 +              goto bad_free;
 +      }
 +
@@ -2209,21 +2518,21 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Validate the chunk size against the device block size */
 +      blocksize = get_hardsect_size(s->cow->dev);
 +      if (chunk_size % (blocksize / SECTOR_SIZE)) {
-+              *context = "Chunk size is not a multiple of device blocksize";
++              ti->error = "Chunk size is not a multiple of device blocksize";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
 +
 +      /* Check the sizes are small enough to fit in one kiovec */
 +      if (chunk_size > KIO_MAX_SECTORS) {
-+              *context = "Chunk size is too big";
++              ti->error = "Chunk size is too big";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
 +
 +      /* Check chunk_size is a power of 2 */
 +      if (chunk_size & (chunk_size - 1)) {
-+              *context = "Chunk size is not a power of 2";
++              ti->error = "Chunk size is not a power of 2";
 +              r = -EINVAL;
 +              goto bad_putdev;
 +      }
@@ -2238,12 +2547,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      s->valid = 1;
 +      s->last_percent = 0;
-+      s->table = t;
 +      init_rwsem(&s->lock);
++      s->table = ti->table;
 +
 +      /* Allocate hash table for COW data */
 +      if (init_hash_tables(s)) {
-+              *context = "Unable to allocate hash table space";
++              ti->error = "Unable to allocate hash table space";
 +              r = -ENOMEM;
 +              goto bad_putdev;
 +      }
@@ -2257,10 +2566,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if ((*persistent & 0x5f) == 'P')
 +              r = dm_create_persistent(&s->store, s->chunk_size);
 +      else
-+              r = dm_create_transient(&s->store, s, blocksize, context);
++              r = dm_create_transient(&s->store, s, blocksize);
 +
 +      if (r) {
-+              *context = "Couldn't create exception store";
++              ti->error = "Couldn't create exception store";
 +              r = -EINVAL;
 +              goto bad_free1;
 +      }
@@ -2275,7 +2584,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Add snapshot to the list of snapshots for this origin */
 +      if (register_snapshot(s)) {
 +              r = -EINVAL;
-+              *context = "Cannot register snapshot origin";
++              ti->error = "Cannot register snapshot origin";
 +              goto bad_free2;
 +      }
 +#if LVM_VFS_ENHANCEMENT
@@ -2283,7 +2592,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#endif
 +      kcopyd_inc_client_count();
 +
-+      *context = s;
++      ti->private = s;
 +      return 0;
 +
 +      bad_free2:
@@ -2294,8 +2603,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      exit_exception_table(&s->complete, exception_cache);
 +
 +      bad_putdev:
-+      dm_table_put_device(t, s->cow);
-+      dm_table_put_device(t, s->origin);
++      dm_put_device(ti, s->cow);
++      dm_put_device(ti, s->origin);
 +
 +      bad_free:
 +      kfree(s);
@@ -2304,11 +2613,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return r;
 +}
 +
-+static void snapshot_dtr(struct dm_table *t, void *context)
++static void snapshot_dtr(struct dm_target *ti)
 +{
-+      struct dm_snapshot *s = (struct dm_snapshot *) context;
++      struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 +
-+      dm_table_event(s->table);
++      dm_table_event(ti->table);
 +
 +      unregister_snapshot(s);
 +
@@ -2318,8 +2627,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /* Deallocate memory used */
 +      s->store.destroy(&s->store);
 +
-+      dm_table_put_device(t, s->origin);
-+      dm_table_put_device(t, s->cow);
++      dm_put_device(ti, s->origin);
++      dm_put_device(ti, s->cow);
 +      kfree(s);
 +
 +      kcopyd_dec_client_count();
@@ -2535,10 +2844,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +          (bh->b_rsector & s->chunk_mask);
 +}
 +
-+static int snapshot_map(struct buffer_head *bh, int rw, void *context)
++static int snapshot_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
 +      struct exception *e;
-+      struct dm_snapshot *s = (struct dm_snapshot *) context;
++      struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 +      int r = 1;
 +      chunk_t chunk;
 +      struct pending_exception *pe;
@@ -2685,10 +2994,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return r;
 +}
 +
-+static int snapshot_status(status_type_t type, char *result,
-+                         int maxlen, void *context)
++static int snapshot_status(struct dm_target *ti, status_type_t type,
++                         char *result, int maxlen)
 +{
-+      struct dm_snapshot *snap = (struct dm_snapshot *) context;
++      struct dm_snapshot *snap = (struct dm_snapshot *) ti->private;
 +      char cow[16];
 +      char org[16];
 +
@@ -2750,47 +3059,47 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * The context for an origin is merely a 'struct dm_dev *'
 + * pointing to the real device.
 + */
-+static int origin_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int origin_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      int r;
 +      struct dm_dev *dev;
 +
 +      if (argc != 1) {
-+              *context = "dm-origin: incorrect number of arguments";
++              ti->error = "dm-origin: incorrect number of arguments";
 +              return -EINVAL;
 +      }
 +
-+      r = dm_table_get_device(t, argv[0], 0, l, t->mode, &dev);
++      r = dm_get_device(ti, argv[0], 0, ti->len,
++                        dm_table_get_mode(ti->table), &dev);
 +      if (r) {
-+              *context = "Cannot get target device";
++              ti->error = "Cannot get target device";
 +              return r;
 +      }
 +
-+      *context = dev;
++      ti->private = dev;
 +
 +      return 0;
 +}
 +
-+static void origin_dtr(struct dm_table *t, void *c)
++static void origin_dtr(struct dm_target *ti)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) c;
-+      dm_table_put_device(t, dev);
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
++      dm_put_device(ti, dev);
 +}
 +
-+static int origin_map(struct buffer_head *bh, int rw, void *context)
++static int origin_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) context;
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
 +      bh->b_rdev = dev->dev;
 +
 +      /* Only tell snapshots if this is a write */
 +      return (rw == WRITE) ? do_origin(dev, bh) : 1;
 +}
 +
-+static int origin_status(status_type_t type, char *result,
-+                       int maxlen, void *context)
++static int origin_status(struct dm_target *ti, status_type_t type, char *result,
++                       int maxlen)
 +{
-+      struct dm_dev *dev = (struct dm_dev *) context;
++      struct dm_dev *dev = (struct dm_dev *) ti->private;
 +
 +      switch (type) {
 +      case STATUSTYPE_INFO:
@@ -2812,7 +3121,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dtr:    origin_dtr,
 +      map:    origin_map,
 +      status: origin_status,
-+      err:    NULL
 +};
 +
 +static struct target_type snapshot_target = {
@@ -2822,7 +3130,6 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dtr:    snapshot_dtr,
 +      map:    snapshot_map,
 +      status: snapshot_status,
-+      err:    NULL
 +};
 +
 +int __init dm_snapshot_init(void)
@@ -2919,9 +3226,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * c-file-style: "linux"
 + * End:
 + */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-snapshot.h linux-2.4.19-dm/drivers/md/dm-snapshot.h
+diff -ruN linux-2.4.19/drivers/md/dm-snapshot.h linux-2.4.19-dm-test1/drivers/md/dm-snapshot.h
 --- linux-2.4.19/drivers/md/dm-snapshot.h      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-snapshot.h   Wed Aug 14 17:42:59 2002
++++ linux-2.4.19-dm-test1/drivers/md/dm-snapshot.h     Wed Nov 13 19:21:59 2002
 @@ -0,0 +1,147 @@
 +/*
 + * dm-snapshot.c
@@ -2947,7 +3254,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * time. Typically 64k - 256k.
 + */
 +/* FIXME: can we get away with limiting these to a uint32_t ? */
-+typedef offset_t chunk_t;
++typedef sector_t chunk_t;
 +
 +/*
 + * An exception is used where an old chunk of data has been
@@ -2969,31 +3276,31 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      /*
 +       * Destroys this object when you've finished with it.
 +       */
-+      void (*destroy) (struct exception_store *store);
++      void (*destroy) (struct exception_store * store);
 +
 +      /*
 +       * Find somewhere to store the next exception.
 +       */
-+      int (*prepare_exception) (struct exception_store *store,
-+                                struct exception *e);
++      int (*prepare_exception) (struct exception_store * store,
++                                struct exception * e);
 +
 +      /*
 +       * Update the metadata with this exception.
 +       */
-+      void (*commit_exception) (struct exception_store *store,
-+                                struct exception *e,
++      void (*commit_exception) (struct exception_store * store,
++                                struct exception * e,
 +                                void (*callback) (void *, int success),
 +                                void *callback_context);
 +
 +      /*
 +       * The snapshot is invalid, note this in the metadata.
 +       */
-+      void (*drop_snapshot) (struct exception_store *store);
++      void (*drop_snapshot) (struct exception_store * store);
 +
 +      /*
 +       * Return the %age full of the snapshot
 +       */
-+      int (*percent_full) (struct exception_store *store);
++      int (*percent_full) (struct exception_store * store);
 +
 +      struct dm_snapshot *snap;
 +      void *context;
@@ -3043,12 +3350,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
 +
 +int dm_create_transient(struct exception_store *store,
-+                      struct dm_snapshot *s, int blocksize, void **error);
++                      struct dm_snapshot *s, int blocksize);
 +
 +/*
 + * Return the number of sectors in the device.
 + */
-+static inline offset_t get_dev_size(kdev_t dev)
++static inline sector_t get_dev_size(kdev_t dev)
 +{
 +      int *sizes;
 +
@@ -3059,21 +3366,21 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 0;
 +}
 +
-+static inline chunk_t sector_to_chunk(struct dm_snapshot *s, offset_t sector)
++static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector)
 +{
 +      return (sector & ~s->chunk_mask) >> s->chunk_shift;
 +}
 +
-+static inline offset_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
++static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
 +{
 +      return chunk << s->chunk_shift;
 +}
 +
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-stripe.c linux-2.4.19-dm/drivers/md/dm-stripe.c
+diff -ruN linux-2.4.19/drivers/md/dm-stripe.c linux-2.4.19-dm-test1/drivers/md/dm-stripe.c
 --- linux-2.4.19/drivers/md/dm-stripe.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-stripe.c     Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,234 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm-stripe.c       Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,256 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -3085,14 +3392,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/blkdev.h>
++#include <linux/slab.h>
 +
 +struct stripe {
 +      struct dm_dev *dev;
-+      offset_t physical_start;
++      sector_t physical_start;
 +};
 +
 +struct stripe_c {
-+      offset_t logical_start;
 +      uint32_t stripes;
 +
 +      /* The size of this target / num. stripes */
@@ -3100,7 +3407,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      /* stripe chunk size */
 +      uint32_t chunk_shift;
-+      offset_t chunk_mask;
++      sector_t chunk_mask;
 +
 +      struct stripe stripe[0];
 +};
@@ -3121,18 +3428,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Parse a single <dev> <sector> pair
 + */
-+static int get_stripe(struct dm_table *t, struct stripe_c *sc,
++static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
 +                    int stripe, char **argv)
 +{
-+      char *end;
-+      unsigned long start;
++      sector_t start;
 +
-+      start = simple_strtoul(argv[1], &end, 10);
-+      if (*end)
++      if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1)
 +              return -EINVAL;
 +
-+      if (dm_table_get_device(t, argv[0], start, sc->stripe_width,
-+                              t->mode, &sc->stripe[stripe].dev))
++      if (dm_get_device(ti, argv[0], start, sc->stripe_width,
++                        dm_table_get_mode(ti->table),
++                        &sc->stripe[stripe].dev))
 +              return -ENXIO;
 +
 +      sc->stripe[stripe].physical_start = start;
@@ -3140,62 +3446,85 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
++ * FIXME: Nasty function, only present because we can't link
++ * against __moddi3 and __divdi3.
++ *
++ * returns a == b * n
++ */
++static int multiple(sector_t a, sector_t b, sector_t *n)
++{
++      sector_t acc, prev, i;
++
++      *n = 0;
++      while (a >= b) {
++              for (acc = b, prev = 0, i = 1;
++                   acc <= a;
++                   prev = acc, acc <<= 1, i <<= 1)
++                      ;
++
++              a -= prev;
++              *n += i >> 1;
++      }
++
++      return a == 0;
++}
++
++/*
 + * Construct a striped mapping.
 + * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
 + */
-+static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **argv, void **context)
++static int stripe_ctr(struct dm_target *ti, int argc, char **argv)
 +{
 +      struct stripe_c *sc;
++      sector_t width;
 +      uint32_t stripes;
 +      uint32_t chunk_size;
 +      char *end;
 +      int r, i;
 +
 +      if (argc < 2) {
-+              *context = "dm-stripe: Not enough arguments";
++              ti->error = "dm-stripe: Not enough arguments";
 +              return -EINVAL;
 +      }
 +
 +      stripes = simple_strtoul(argv[0], &end, 10);
 +      if (*end) {
-+              *context = "dm-stripe: Invalid stripe count";
++              ti->error = "dm-stripe: Invalid stripe count";
 +              return -EINVAL;
 +      }
 +
 +      chunk_size = simple_strtoul(argv[1], &end, 10);
 +      if (*end) {
-+              *context = "dm-stripe: Invalid chunk_size";
++              ti->error = "dm-stripe: Invalid chunk_size";
 +              return -EINVAL;
 +      }
 +
-+      if (l % stripes) {
-+              *context = "dm-stripe: Target length not divisable by "
++      if (!multiple(ti->len, stripes, &width)) {
++              ti->error = "dm-stripe: Target length not divisable by "
 +                  "number of stripes";
 +              return -EINVAL;
 +      }
 +
 +      sc = alloc_context(stripes);
 +      if (!sc) {
-+              *context = "dm-stripe: Memory allocation for striped context "
-+                  "failed";
++              ti->error = "dm-stripe: Memory allocation for striped context "
++                          "failed";
 +              return -ENOMEM;
 +      }
 +
-+      sc->logical_start = b;
 +      sc->stripes = stripes;
-+      sc->stripe_width = l / stripes;
++      sc->stripe_width = width;
 +
 +      /*
 +       * chunk_size is a power of two
 +       */
 +      if (!chunk_size || (chunk_size & (chunk_size - 1))) {
-+              *context = "dm-stripe: Invalid chunk size";
++              ti->error = "dm-stripe: Invalid chunk size";
 +              kfree(sc);
 +              return -EINVAL;
 +      }
 +
-+      sc->chunk_mask = chunk_size - 1;
++      sc->chunk_mask = ((sector_t) chunk_size) - 1;
 +      for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
 +              chunk_size >>= 1;
 +      sc->chunk_shift--;
@@ -3205,45 +3534,45 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       */
 +      for (i = 0; i < stripes; i++) {
 +              if (argc < 2) {
-+                      *context = "dm-stripe: Not enough destinations "
-+                          "specified";
++                      ti->error = "dm-stripe: Not enough destinations "
++                                  "specified";
 +                      kfree(sc);
 +                      return -EINVAL;
 +              }
 +
 +              argv += 2;
 +
-+              r = get_stripe(t, sc, i, argv);
++              r = get_stripe(ti, sc, i, argv);
 +              if (r < 0) {
-+                      *context = "dm-stripe: Couldn't parse stripe "
-+                          "destination";
++                      ti->error = "dm-stripe: Couldn't parse stripe "
++                                  "destination";
 +                      while (i--)
-+                              dm_table_put_device(t, sc->stripe[i].dev);
++                              dm_put_device(ti, sc->stripe[i].dev);
 +                      kfree(sc);
 +                      return r;
 +              }
 +      }
 +
-+      *context = sc;
++      ti->private = sc;
 +      return 0;
 +}
 +
-+static void stripe_dtr(struct dm_table *t, void *c)
++static void stripe_dtr(struct dm_target *ti)
 +{
 +      unsigned int i;
-+      struct stripe_c *sc = (struct stripe_c *) c;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +
 +      for (i = 0; i < sc->stripes; i++)
-+              dm_table_put_device(t, sc->stripe[i].dev);
++              dm_put_device(ti, sc->stripe[i].dev);
 +
 +      kfree(sc);
 +}
 +
-+static int stripe_map(struct buffer_head *bh, int rw, void *context)
++static int stripe_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
-+      struct stripe_c *sc = (struct stripe_c *) context;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +
-+      offset_t offset = bh->b_rsector - sc->logical_start;
++      sector_t offset = bh->b_rsector - ti->begin;
 +      uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift);
 +      uint32_t stripe = chunk % sc->stripes;  /* 32bit modulus */
 +      chunk = chunk / sc->stripes;
@@ -3254,10 +3583,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 1;
 +}
 +
-+static int stripe_status(status_type_t type, char *result, int maxlen,
-+                       void *context)
++static int stripe_status(struct dm_target *ti,
++                       status_type_t type, char *result, int maxlen)
 +{
-+      struct stripe_c *sc = (struct stripe_c *) context;
++      struct stripe_c *sc = (struct stripe_c *) ti->private;
 +      int offset;
 +      int i;
 +
@@ -3267,14 +3596,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              break;
 +
 +      case STATUSTYPE_TABLE:
-+              offset = snprintf(result, maxlen, "%d %ld",
++              offset = snprintf(result, maxlen, "%d " SECTOR_FORMAT,
 +                                sc->stripes, sc->chunk_mask + 1);
 +              for (i = 0; i < sc->stripes; i++) {
-+                      offset +=
-+                          snprintf(result + offset, maxlen - offset,
-+                                   " %s %ld",
-+                                   kdevname(sc->stripe[i].dev->dev),
-+                                   sc->stripe[i].physical_start);
++                      offset += snprintf(result + offset, maxlen - offset,
++                                         " %s " SECTOR_FORMAT,
++                                         kdevname(to_kdev_t
++                                           (sc->stripe[i].dev->bdev->bd_dev)),
++                                         sc->stripe[i].physical_start);
 +              }
 +              break;
 +      }
@@ -3282,12 +3611,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +static struct target_type stripe_target = {
-+      name:   "striped",
-+      module: THIS_MODULE,
-+      ctr:    stripe_ctr,
-+      dtr:    stripe_dtr,
-+      map:    stripe_map,
-+      status: stripe_status,
++      .name   = "striped",
++      .module = THIS_MODULE,
++      .ctr    = stripe_ctr,
++      .dtr    = stripe_dtr,
++      .map    = stripe_map,
++      .status = stripe_status,
 +};
 +
 +int __init dm_stripe_init(void)
@@ -3308,10 +3637,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      return;
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-table.c linux-2.4.19-dm/drivers/md/dm-table.c
+diff -ruN linux-2.4.19/drivers/md/dm-table.c linux-2.4.19-dm-test1/drivers/md/dm-table.c
 --- linux-2.4.19/drivers/md/dm-table.c Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-table.c      Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,452 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm-table.c        Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,665 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -3320,23 +3649,60 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#include "dm.h"
 +
++#include <linux/module.h>
++#include <linux/vmalloc.h>
 +#include <linux/blkdev.h>
++#include <linux/ctype.h>
++#include <linux/slab.h>
++#include <asm/atomic.h>
 +
-+/* ceiling(n / size) * size */
-+static inline unsigned long round_up(unsigned long n, unsigned long size)
-+{
-+      unsigned long r = n % size;
-+      return n + (r ? (size - r) : 0);
-+}
++#define MAX_DEPTH 16
++#define NODE_SIZE L1_CACHE_BYTES
++#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
++#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
++
++struct dm_table {
++      atomic_t holders;
++
++      /* btree table */
++      int depth;
++      int counts[MAX_DEPTH];  /* in nodes */
++      sector_t *index[MAX_DEPTH];
++
++      int num_targets;
++      int num_allocated;
++      sector_t *highs;
++      struct dm_target *targets;
++
++      /*
++       * Indicates the rw permissions for the new logical
++       * device.  This should be a combination of FMODE_READ
++       * and FMODE_WRITE.
++       */
++      int mode;
++
++      /* a list of devices used by this table */
++      struct list_head devices;
++
++      /*
++       * A waitqueue for processes waiting for something
++       * interesting to happen to this table.
++       */
++      wait_queue_head_t eventq;
++};
 +
-+/* ceiling(n / size) */
++/*
++ * Ceiling(n / size)
++ */
 +static inline unsigned long div_up(unsigned long n, unsigned long size)
 +{
-+      return round_up(n, size) / size;
++      return dm_round_up(n, size) / size;
 +}
 +
-+/* similar to ceiling(log_size(n)) */
-+static uint int_log(unsigned long n, unsigned long base)
++/*
++ * Similar to ceiling(log_size(n))
++ */
++static unsigned int int_log(unsigned long n, unsigned long base)
 +{
 +      int result = 0;
 +
@@ -3349,28 +3715,44 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * return the highest key that you could lookup
-+ * from the n'th node on level l of the btree.
++ * Calculate the index of the child node of the n'th node k'th key.
++ */
++static inline int get_child(int n, int k)
++{
++      return (n * CHILDREN_PER_NODE) + k;
++}
++
++/*
++ * Return the n'th node of level l from table t.
++ */
++static inline sector_t *get_node(struct dm_table *t, int l, int n)
++{
++      return t->index[l] + (n * KEYS_PER_NODE);
++}
++
++/*
++ * Return the highest key that you could lookup from the n'th
++ * node on level l of the btree.
 + */
-+static offset_t high(struct dm_table *t, int l, int n)
++static sector_t high(struct dm_table *t, int l, int n)
 +{
 +      for (; l < t->depth - 1; l++)
 +              n = get_child(n, CHILDREN_PER_NODE - 1);
 +
 +      if (n >= t->counts[l])
-+              return (offset_t) - 1;
++              return (sector_t) - 1;
 +
 +      return get_node(t, l, n)[KEYS_PER_NODE - 1];
 +}
 +
 +/*
-+ * fills in a level of the btree based on the
-+ * highs of the level below it.
++ * Fills in a level of the btree based on the highs of the level
++ * below it.
 + */
 +static int setup_btree_index(int l, struct dm_table *t)
 +{
 +      int n, k;
-+      offset_t *node;
++      sector_t *node;
 +
 +      for (n = 0; n < t->counts[l]; n++) {
 +              node = get_node(t, l, n);
@@ -3383,24 +3765,24 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * highs, and targets are managed as dynamic
-+ * arrays during a table load.
++ * highs, and targets are managed as dynamic arrays during a
++ * table load.
 + */
 +static int alloc_targets(struct dm_table *t, int num)
 +{
-+      offset_t *n_highs;
-+      struct target *n_targets;
++      sector_t *n_highs;
++      struct dm_target *n_targets;
 +      int n = t->num_targets;
 +
 +      /*
 +       * Allocate both the target array and offset array at once.
 +       */
-+      n_highs = (offset_t *) vcalloc(sizeof(struct target) + sizeof(offset_t),
-+                                     num);
++      n_highs = (sector_t *) vcalloc(sizeof(struct dm_target) +
++                                     sizeof(sector_t), num);
 +      if (!n_highs)
 +              return -ENOMEM;
 +
-+      n_targets = (struct target *) (n_highs + num);
++      n_targets = (struct dm_target *) (n_highs + num);
 +
 +      if (n) {
 +              memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
@@ -3408,8 +3790,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      }
 +
 +      memset(n_highs + n, -1, sizeof(*n_highs) * (num - n));
-+      if (t->highs)
-+              vfree(t->highs);
++      vfree(t->highs);
 +
 +      t->num_allocated = num;
 +      t->highs = n_highs;
@@ -3427,8 +3808,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      memset(t, 0, sizeof(*t));
 +      INIT_LIST_HEAD(&t->devices);
++      atomic_set(&t->holders, 1);
 +
-+      /* allocate a single node's worth of targets to begin with */
++      /* allocate a single nodes worth of targets to begin with */
 +      if (alloc_targets(t, KEYS_PER_NODE)) {
 +              kfree(t);
 +              t = NULL;
@@ -3452,7 +3834,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      }
 +}
 +
-+void dm_table_destroy(struct dm_table *t)
++void table_destroy(struct dm_table *t)
 +{
 +      int i;
 +
@@ -3465,12 +3847,12 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      /* free the targets */
 +      for (i = 0; i < t->num_targets; i++) {
-+              struct target *tgt = &t->targets[i];
++              struct dm_target *tgt = &t->targets[i];
 +
 +              dm_put_target_type(t->targets[i].type);
 +
 +              if (tgt->type->dtr)
-+                      tgt->type->dtr(t, tgt->private);
++                      tgt->type->dtr(tgt);
 +      }
 +
 +      vfree(t->highs);
@@ -3486,6 +3868,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      kfree(t);
 +}
 +
++void dm_table_get(struct dm_table *t)
++{
++      atomic_inc(&t->holders);
++}
++
++void dm_table_put(struct dm_table *t)
++{
++      if (atomic_dec_and_test(&t->holders))
++              table_destroy(t);
++}
++
 +/*
 + * Checks to see if we need to extend highs or targets.
 + */
@@ -3498,9 +3891,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Convert a device path to a kdev_t.
++ * Convert a device path to a dev_t.
 + */
-+int lookup_device(const char *path, kdev_t *dev)
++static int lookup_device(const char *path, kdev_t *dev)
 +{
 +      int r;
 +      struct nameidata nd;
@@ -3510,22 +3903,22 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              return 0;
 +
 +      if ((r = path_walk(path, &nd)))
-+              goto bad;
++              goto out;
 +
 +      inode = nd.dentry->d_inode;
 +      if (!inode) {
 +              r = -ENOENT;
-+              goto bad;
++              goto out;
 +      }
 +
 +      if (!S_ISBLK(inode->i_mode)) {
 +              r = -EINVAL;
-+              goto bad;
++              goto out;
 +      }
 +
 +      *dev = inode->i_rdev;
 +
-+      bad:
++      out:
 +      path_release(&nd);
 +      return r;
 +}
@@ -3539,7 +3932,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      list_for_each(tmp, l) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-+              if (dd->dev == dev)
++              if (kdev_same(dd->dev, dev))
 +                      return dd;
 +      }
 +
@@ -3549,45 +3942,40 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Open a device so we can use it as a map destination.
 + */
-+static int open_dev(struct dm_dev *d)
++static int open_dev(struct dm_dev *dd)
 +{
-+      int err;
-+
-+      if (d->bd)
++      if (dd->bdev)
 +              BUG();
 +
-+      if (!(d->bd = bdget(kdev_t_to_nr(d->dev))))
++      dd->bdev = bdget(kdev_t_to_nr(dd->dev));
++      if (!dd->bdev)
 +              return -ENOMEM;
 +
-+      if ((err = blkdev_get(d->bd, d->mode, 0, BDEV_FILE)))
-+              return err;
-+
-+      return 0;
++      return blkdev_get(dd->bdev, dd->mode, 0, BDEV_RAW);
 +}
 +
 +/*
 + * Close a device that we've been using.
 + */
-+static void close_dev(struct dm_dev *d)
++static void close_dev(struct dm_dev *dd)
 +{
-+      if (!d->bd)
++      if (!dd->bdev)
 +              return;
 +
-+      blkdev_put(d->bd, BDEV_FILE);
-+      d->bd = NULL;
++      blkdev_put(dd->bdev, BDEV_RAW);
++      dd->bdev = NULL;
 +}
 +
 +/*
-+ * If possible (ie. blk_size[major] is set), this
-+ * checks an area of a destination device is
-+ * valid.
++ * If possible (ie. blk_size[major] is set), this checks an area
++ * of a destination device is valid.
 + */
-+static int check_device_area(kdev_t dev, offset_t start, offset_t len)
++static int check_device_area(kdev_t dev, sector_t start, sector_t len)
 +{
 +      int *sizes;
-+      offset_t dev_size;
++      sector_t dev_size;
 +
-+      if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)]))
++      if (!(sizes = blk_size[major(dev)]) || !(dev_size = sizes[minor(dev)]))
 +              /* we don't know the device details,
 +               * so give the benefit of the doubt */
 +              return 1;
@@ -3611,7 +3999,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      memcpy(&dd_copy, dd, sizeof(dd_copy));
 +
 +      dd->mode |= new_mode;
-+      dd->bd = NULL;
++      dd->bdev = NULL;
 +      r = open_dev(dd);
 +      if (!r)
 +              close_dev(&dd_copy);
@@ -3622,21 +4010,24 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * 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, int mode,
-+                      struct dm_dev **result)
++int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
++                sector_t len, int mode, struct dm_dev **result)
 +{
 +      int r;
 +      kdev_t dev;
 +      struct dm_dev *dd;
 +      int major, minor;
++      struct dm_table *t = ti->table;
++
++      if (!t)
++              BUG();
 +
 +      if (sscanf(path, "%x:%x", &major, &minor) == 2) {
 +              /* Extract the major/minor numbers */
-+              dev = MKDEV(major, minor);
++              dev = mk_kdev(major, minor);
 +      } else {
 +              /* convert the path to a device */
 +              if ((r = lookup_device(path, &dev)))
@@ -3649,9 +4040,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              if (!dd)
 +                      return -ENOMEM;
 +
-+              dd->mode = mode;
 +              dd->dev = dev;
-+              dd->bd = NULL;
++              dd->mode = mode;
++              dd->bdev = NULL;
 +
 +              if ((r = open_dev(dd))) {
 +                      kfree(dd);
@@ -3670,7 +4061,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      if (!check_device_area(dd->dev, start, len)) {
 +              DMWARN("device %s too small for target", path);
-+              dm_table_put_device(t, dd);
++              dm_put_device(ti, dd);
 +              return -EINVAL;
 +      }
 +
@@ -3682,7 +4073,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * Decrement a devices use count and remove it if neccessary.
 + */
-+void dm_table_put_device(struct dm_table *t, struct dm_dev *dd)
++void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
 +{
 +      if (atomic_dec_and_test(&dd->count)) {
 +              close_dev(dd);
@@ -3692,28 +4083,126 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Adds a target to the map
++ * Checks to see if the target joins onto the end of the table.
++ */
++static int adjoin(struct dm_table *table, struct dm_target *ti)
++{
++      struct dm_target *prev;
++
++      if (!table->num_targets)
++              return !ti->begin;
++
++      prev = &table->targets[table->num_targets - 1];
++      return (ti->begin == (prev->begin + prev->len));
++}
++
++/*
++ * Destructively splits up the argument list to pass to ctr.
 + */
-+int dm_table_add_target(struct dm_table *t, offset_t highs,
-+                      struct target_type *type, void *private)
++static int split_args(int max, int *argc, char **argv, char *input)
++{
++      char *start, *end = input, *out;
++      *argc = 0;
++
++      while (1) {
++              start = end;
++
++              /* Skip whitespace */
++              while (*start && isspace(*start))
++                      start++;
++
++              if (!*start)
++                      break;  /* success, we hit the end */
++
++              /* 'out' is used to remove any back-quotes */
++              end = out = start;
++              while (*end) {
++                      /* Everything apart from '\0' can be quoted */
++                      if (*end == '\\' && *(end + 1)) {
++                              *out++ = *(end + 1);
++                              end += 2;
++                              continue;
++                      }
++
++                      if (isspace(*end))
++                              break;  /* end of token */
++
++                      *out++ = *end++;
++              }
++
++              /* have we already filled the array ? */
++              if ((*argc + 1) > max)
++                      return -EINVAL;
++
++              /* we know this is whitespace */
++              if (*end)
++                      end++;
++
++              /* terminate the string and put it in the array */
++              *out = '\0';
++              argv[*argc] = start;
++              (*argc)++;
++      }
++
++      return 0;
++}
++
++int dm_table_add_target(struct dm_table *t, const char *type,
++                      sector_t start, sector_t len, char *params)
 +{
-+      int r, n;
++      int r, argc;
++      char *argv[32];
++      struct target_type *tt;
++      struct dm_target *tgt;
 +
 +      if ((r = check_space(t)))
 +              return r;
 +
-+      n = t->num_targets++;
-+      t->highs[n] = highs;
-+      t->targets[n].type = type;
-+      t->targets[n].private = private;
++      tgt = t->targets + t->num_targets;
++      memset(tgt, 0, sizeof(*tgt));
++
++      tt = dm_get_target_type(type);
++      if (!tt) {
++              tgt->error = "unknown target type";
++              return -EINVAL;
++      }
++
++      tgt->table = t;
++      tgt->type = tt;
++      tgt->begin = start;
++      tgt->len = len;
++      tgt->error = "Unknown error";
++
++      /*
++       * Does this target adjoin the previous one ?
++       */
++      if (!adjoin(t, tgt)) {
++              DMERR("Gap in table");
++              dm_put_target_type(tt);
++              return -EINVAL;
++      }
++
++      r = split_args(ARRAY_SIZE(argv), &argc, argv, params);
++      if (r) {
++              tgt->error = "couldn't split parameters";
++              dm_put_target_type(tt);
++              return r;
++      }
++
++      r = tt->ctr(tgt, argc, argv);
++      if (r) {
++              dm_put_target_type(tt);
++              return r;
++      }
 +
++      t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
 +      return 0;
 +}
 +
 +static int setup_indexes(struct dm_table *t)
 +{
 +      int i, total = 0;
-+      offset_t *indexes;
++      sector_t *indexes;
 +
 +      /* allocate the space for *all* the indexes */
 +      for (i = t->depth - 2; i >= 0; i--) {
@@ -3721,7 +4210,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +              total += t->counts[i];
 +      }
 +
-+      indexes = (offset_t *) vcalloc(total, (unsigned long) NODE_SIZE);
++      indexes = (sector_t *) vcalloc(total, (unsigned long) NODE_SIZE);
 +      if (!indexes)
 +              return -ENOMEM;
 +
@@ -3736,7 +4225,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Builds the btree to index the map
++ * Builds the btree to index the map.
 + */
 +int dm_table_complete(struct dm_table *t)
 +{
@@ -3761,85 +4250,89 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      wake_up_interruptible(&t->eventq);
 +}
 +
-+EXPORT_SYMBOL(dm_table_get_device);
-+EXPORT_SYMBOL(dm_table_put_device);
-+EXPORT_SYMBOL(dm_table_event);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm-target.c linux-2.4.19-dm/drivers/md/dm-target.c
---- linux-2.4.19/drivers/md/dm-target.c        Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm-target.c     Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,242 @@
-+/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited
-+ *
-+ * This file is released under the GPL.
-+ */
-+
-+#include "dm.h"
-+
-+#include <linux/kmod.h>
-+
-+struct tt_internal {
-+      struct target_type tt;
-+
-+      struct list_head list;
-+      long use;
-+};
++sector_t dm_table_get_size(struct dm_table *t)
++{
++      return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0;
++}
 +
-+static LIST_HEAD(_targets);
-+static rwlock_t _lock = RW_LOCK_UNLOCKED;
++struct dm_target *dm_table_get_target(struct dm_table *t, int index)
++{
++      if (index > t->num_targets)
++              return NULL;
 +
-+#define DM_MOD_NAME_SIZE 32
++      return t->targets + index;
++}
 +
 +/*
-+ * Destructively splits up the argument list to pass to ctr.
++ * Search the btree for the correct target.
 + */
-+int split_args(int max, int *argc, char **argv, char *input)
++struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector)
 +{
-+      char *start, *end = input, *out;
-+      *argc = 0;
++      int l, n = 0, k = 0;
++      sector_t *node;
 +
-+      while (1) {
-+              start = end;
++      for (l = 0; l < t->depth; l++) {
++              n = get_child(n, k);
++              node = get_node(t, l, n);
 +
-+              /* Skip whitespace */
-+              while (*start && isspace(*start))
-+                      start++;
++              for (k = 0; k < KEYS_PER_NODE; k++)
++                      if (node[k] >= sector)
++                              break;
++      }
 +
-+              if (!*start)
-+                      break;  /* success, we hit the end */
++      return &t->targets[(KEYS_PER_NODE * n) + k];
++}
 +
-+              /* 'out' is used to remove any back-quotes */
-+              end = out = start;
-+              while (*end) {
-+                      /* Everything apart from '\0' can be quoted */
-+                      if (*end == '\\' && *(end + 1)) {
-+                              *out++ = *(end + 1);
-+                              end += 2;
-+                              continue;
-+                      }
++unsigned int dm_table_get_num_targets(struct dm_table *t)
++{
++      return t->num_targets;
++}
 +
-+                      if (isspace(*end))
-+                              break;  /* end of token */
++struct list_head *dm_table_get_devices(struct dm_table *t)
++{
++      return &t->devices;
++}
 +
-+                      *out++ = *end++;
-+              }
++int dm_table_get_mode(struct dm_table *t)
++{
++      return t->mode;
++}
 +
-+              /* have we already filled the array ? */
-+              if ((*argc + 1) > max)
-+                      return -EINVAL;
++void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq)
++{
++      add_wait_queue(&t->eventq, wq);
++}
 +
-+              /* we know this is whitespace */
-+              if (*end)
-+                      end++;
++EXPORT_SYMBOL(dm_get_device);
++EXPORT_SYMBOL(dm_put_device);
++EXPORT_SYMBOL(dm_table_event);
+diff -ruN linux-2.4.19/drivers/md/dm-target.c linux-2.4.19-dm-test1/drivers/md/dm-target.c
+--- linux-2.4.19/drivers/md/dm-target.c        Thu Jan  1 01:00:00 1970
++++ linux-2.4.19-dm-test1/drivers/md/dm-target.c       Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,190 @@
++/*
++ * Copyright (C) 2001 Sistina Software (UK) Limited
++ *
++ * This file is released under the GPL.
++ */
 +
-+              /* terminate the string and put it in the array */
-+              *out = '\0';
-+              argv[*argc] = start;
-+              (*argc)++;
-+      }
++#include "dm.h"
 +
-+      return 0;
-+}
++#include <linux/module.h>
++#include <linux/kmod.h>
++#include <linux/slab.h>
++
++struct tt_internal {
++      struct target_type tt;
++
++      struct list_head list;
++      long use;
++};
++
++static LIST_HEAD(_targets);
++static rwlock_t _lock = RW_LOCK_UNLOCKED;
++
++#define DM_MOD_NAME_SIZE 32
 +
 +static inline struct tt_internal *__find_target_type(const char *name)
 +{
@@ -3968,33 +4461,30 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +/*
 + * io-err: always fails an io, useful for bringing
-+ * up LV's that have holes in them.
++ * up LVs that have holes in them.
 + */
-+static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
-+                    int argc, char **args, void **context)
++static int io_err_ctr(struct dm_target *ti, int argc, char **args)
 +{
-+      *context = NULL;
 +      return 0;
 +}
 +
-+static void io_err_dtr(struct dm_table *t, void *c)
++static void io_err_dtr(struct dm_target *ti)
 +{
 +      /* empty */
 +      return;
 +}
 +
-+static int io_err_map(struct buffer_head *bh, int rw, void *context)
++static int io_err_map(struct dm_target *ti, struct buffer_head *bh, int rw)
 +{
 +      buffer_IO_error(bh);
 +      return 0;
 +}
 +
 +static struct target_type error_target = {
-+      name:   "error",
-+      ctr:    io_err_ctr,
-+      dtr:    io_err_dtr,
-+      map:    io_err_map,
-+      status: NULL,
++      .name = "error",
++      .ctr  = io_err_ctr,
++      .dtr  = io_err_dtr,
++      .map  = io_err_map,
 +};
 +
 +int dm_target_init(void)
@@ -4010,228 +4500,114 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +EXPORT_SYMBOL(dm_register_target);
 +EXPORT_SYMBOL(dm_unregister_target);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm.c linux-2.4.19-dm/drivers/md/dm.c
+diff -ruN linux-2.4.19/drivers/md/dm.c linux-2.4.19-dm-test1/drivers/md/dm.c
 --- linux-2.4.19/drivers/md/dm.c       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm.c    Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,1173 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm.c      Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,868 @@
 +/*
-+ * Copyright (C) 2001 Sistina Software (UK) Limited.
++ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
 +#include "dm.h"
 +
++#include <linux/init.h>
++#include <linux/module.h>
 +#include <linux/blk.h>
 +#include <linux/blkpg.h>
-+
-+/* we only need this for the lv_bmap struct definition, not happy */
++#include <linux/mempool.h>
++#include <linux/slab.h>
++#include <linux/kdev_t.h>
 +#include <linux/lvm.h>
 +
-+#define DEFAULT_READ_AHEAD 64
++#include <asm/uaccess.h>
 +
 +static const char *_name = DM_NAME;
++#define MAX_DEVICES (1 << MINORBITS)
++#define SECTOR_SHIFT 9
++#define DEFAULT_READ_AHEAD 64
 +
 +static int major = 0;
 +static int _major = 0;
 +
-+struct io_hook {
++struct dm_io {
 +      struct mapped_device *md;
-+      struct target *target;
-+      int rw;
 +
 +      void (*end_io) (struct buffer_head * bh, int uptodate);
 +      void *context;
 +};
 +
-+static kmem_cache_t *_io_hook_cache;
-+
-+static struct mapped_device *_devs[MAX_DEVICES];
-+static struct rw_semaphore _dev_locks[MAX_DEVICES];
-+
-+/*
-+ * This lock is only held by dm_create and dm_set_name to avoid
-+ * race conditions where someone else may create a device with
-+ * the same name.
-+ */
-+static spinlock_t _create_lock = SPIN_LOCK_UNLOCKED;
-+
-+/* block device arrays */
-+static int _block_size[MAX_DEVICES];
-+static int _blksize_size[MAX_DEVICES];
-+static int _hardsect_size[MAX_DEVICES];
-+
-+static devfs_handle_t _dev_dir;
-+
-+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);
-+
-+/*
-+ * Protect the mapped_devices referenced from _dev[]
-+ */
-+struct mapped_device *dm_get_r(int minor)
-+{
-+      struct mapped_device *md;
-+
-+      if (minor >= MAX_DEVICES)
-+              return NULL;
-+
-+      down_read(_dev_locks + minor);
-+      md = _devs[minor];
-+      if (!md)
-+              up_read(_dev_locks + minor);
-+      return md;
-+}
-+
-+struct mapped_device *dm_get_w(int minor)
-+{
-+      struct mapped_device *md;
-+
-+      if (minor >= MAX_DEVICES)
-+              return NULL;
-+
-+      down_write(_dev_locks + minor);
-+      md = _devs[minor];
-+      if (!md)
-+              up_write(_dev_locks + minor);
-+      return md;
-+}
-+
-+static int namecmp(struct mapped_device *md, const char *name, int nametype)
-+{
-+      switch (nametype) {
-+      case DM_LOOKUP_BY_NAME:
-+              return strcmp(md->name, name);
-+              break;
-+
-+      case DM_LOOKUP_BY_UUID:
-+              if (!md->uuid)
-+                      return -1;      /* never equal */
-+
-+              return strcmp(md->uuid, name);
-+              break;
-+
-+      default:
-+              DMWARN("Unknown comparison type in namecmp: %d", nametype);
-+              BUG();
-+      }
-+
-+      return -1;
-+}
++struct deferred_io {
++      int rw;
++      struct buffer_head *bh;
++      struct deferred_io *next;
++};
 +
 +/*
-+ * The interface (eg, ioctl) will probably access the devices
-+ * through these slow 'by name' locks, this needs improving at
-+ * some point if people start playing with *large* numbers of dm
-+ * devices.
++ * Bits for the md->flags field.
 + */
-+struct mapped_device *dm_get_name_r(const char *name, int nametype)
-+{
-+      int i;
-+      struct mapped_device *md;
++#define DMF_BLOCK_IO 0
++#define DMF_SUSPENDED 1
 +
-+      for (i = 0; i < MAX_DEVICES; i++) {
-+              md = dm_get_r(i);
-+              if (md) {
-+                      if (!namecmp(md, name, nametype))
-+                              return md;
-+
-+                      dm_put_r(md);
-+              }
-+      }
-+
-+      return NULL;
-+}
++struct mapped_device {
++      struct rw_semaphore lock;
++      atomic_t holders;
 +
-+struct mapped_device *dm_get_name_w(const char *name, int nametype)
-+{
-+      int i;
-+      struct mapped_device *md;
++      kdev_t dev;
++      unsigned long flags;
 +
 +      /*
-+       * To avoid getting write locks on all the devices we try
-+       * and promote a read lock to a write lock, this can
-+       * fail, in which case we just start again.
++       * A list of ios that arrived while we were suspended.
 +       */
++      atomic_t pending;
++      wait_queue_head_t wait;
++      struct deferred_io *deferred;
 +
-+      restart:
-+      for (i = 0; i < MAX_DEVICES; i++) {
-+              md = dm_get_r(i);
-+              if (!md)
-+                      continue;
-+
-+              if (namecmp(md, name, nametype)) {
-+                      dm_put_r(md);
-+                      continue;
-+              }
-+
-+              /* found it */
-+              dm_put_r(md);
-+
-+              md = dm_get_w(i);
-+              if (!md)
-+                      goto restart;
-+
-+              if (namecmp(md, name, nametype)) {
-+                      dm_put_w(md);
-+                      goto restart;
-+              }
-+
-+              return md;
-+      }
-+
-+      return NULL;
-+}
-+
-+void dm_put_r(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
-+
-+      if (minor >= MAX_DEVICES)
-+              return;
-+
-+      up_read(_dev_locks + minor);
-+}
-+
-+void dm_put_w(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
++      /*
++       * The current mapping.
++       */
++      struct dm_table *map;
++};
 +
-+      if (minor >= MAX_DEVICES)
-+              return;
++#define MIN_IOS 256
++static kmem_cache_t *_io_cache;
++static mempool_t *_io_pool;
 +
-+      up_write(_dev_locks + minor);
-+}
++/* block device arrays */
++static int _block_size[MAX_DEVICES];
++static int _blksize_size[MAX_DEVICES];
++static int _hardsect_size[MAX_DEVICES];
 +
-+/*
-+ * Setup and tear down the driver
-+ */
-+static __init void init_locks(void)
-+{
-+      int i;
++static struct mapped_device *get_kdev(kdev_t dev);
++static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh);
++static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb);
 +
-+      for (i = 0; i < MAX_DEVICES; i++)
-+              init_rwsem(_dev_locks + i);
-+}
 +
 +static __init int local_init(void)
 +{
 +      int r;
 +
-+      init_locks();
++      /* allocate a slab for the dm_ios */
++      _io_cache = kmem_cache_create("dm io",
++                                    sizeof(struct dm_io), 0, 0, NULL, NULL);
++
++      if (!_io_cache)
++              return -ENOMEM;
 +
-+      /* 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)))
++      _io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
++                                mempool_free_slab, _io_cache);
++      if (!_io_pool) {
++              kmem_cache_destroy(_io_cache);
 +              return -ENOMEM;
++      }
 +
 +      _major = major;
-+      r = devfs_register_blkdev(_major, _name, &dm_blk_dops);
++      r = register_blkdev(_major, _name, &dm_blk_dops);
 +      if (r < 0) {
 +              DMERR("register_blkdev failed");
-+              kmem_cache_destroy(_io_hook_cache);
++              mempool_destroy(_io_pool);
++              kmem_cache_destroy(_io_cache);
 +              return r;
 +      }
 +
@@ -4244,20 +4620,17 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      blksize_size[_major] = _blksize_size;
 +      hardsect_size[_major] = _hardsect_size;
 +
-+      blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request);
-+
-+      _dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
++      blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), dm_request);
 +
 +      return 0;
 +}
 +
 +static void local_exit(void)
 +{
-+      if (kmem_cache_destroy(_io_hook_cache))
-+              DMWARN("io_hooks still allocated during unregistration");
-+      _io_hook_cache = NULL;
++      mempool_destroy(_io_pool);
++      kmem_cache_destroy(_io_cache);
 +
-+      if (devfs_unregister_blkdev(_major, _name) < 0)
++      if (unregister_blkdev(_major, _name) < 0)
 +              DMERR("devfs_unregister_blkdev failed");
 +
 +      read_ahead[_major] = 0;
@@ -4275,8 +4648,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * expands a prefix into a pair of function names.
 + */
 +static struct {
-+      int (*init)(void);
-+      void (*exit)(void);
++      int (*init) (void);
++      void (*exit) (void);
 +
 +} _inits[] = {
 +#define xx(n) {n ## _init, n ## _exit},
@@ -4285,14 +4658,13 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      xx(dm_linear)
 +      xx(dm_stripe)
 +      xx(dm_snapshot)
-+/*    xx(dm_mirror) */
 +      xx(dm_interface)
 +#undef xx
 +};
 +
 +static int __init dm_init(void)
 +{
-+      const int count = sizeof(_inits) / sizeof(*_inits);
++      const int count = ARRAY_SIZE(_inits);
 +
 +      int r, i;
 +
@@ -4313,9 +4685,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static void __exit dm_exit(void)
 +{
-+      int i = sizeof(_inits) / sizeof(*_inits);
++      int i = ARRAY_SIZE(_inits);
 +
-+      dm_destroy_all();
 +      while (i--)
 +              _inits[i].exit();
 +}
@@ -4327,13 +4698,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct mapped_device *md;
 +
-+      md = dm_get_w(MINOR(inode->i_rdev));
++      md = get_kdev(inode->i_rdev);
 +      if (!md)
 +              return -ENXIO;
 +
-+      md->use_count++;
-+      dm_put_w(md);
-+
 +      return 0;
 +}
 +
@@ -4341,22 +4709,36 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct mapped_device *md;
 +
-+      md = dm_get_w(MINOR(inode->i_rdev));
-+      if (!md)
-+              return -ENXIO;
++      md = get_kdev(inode->i_rdev);
++      dm_put(md);             /* put the reference gained by dm_blk_open */
++      dm_put(md);
++      return 0;
++}
 +
-+      if (md->use_count < 1)
-+              DMWARN("incorrect reference count found in mapped_device");
++static inline struct dm_io *alloc_io(void)
++{
++      return mempool_alloc(_io_pool, GFP_NOIO);
++}
 +
-+      md->use_count--;
-+      dm_put_w(md);
++static inline void free_io(struct dm_io *io)
++{
++      mempool_free(io, _io_pool);
++}
 +
-+      return 0;
++static inline struct deferred_io *alloc_deferred(void)
++{
++      return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
++}
++
++static inline void free_deferred(struct deferred_io *di)
++{
++      kfree(di);
 +}
 +
 +/* In 512-byte units */
 +#define VOLUME_SIZE(minor) (_block_size[(minor)] << 1)
 +
++/* FIXME: check this */
 +static int dm_blk_ioctl(struct inode *inode, struct file *file,
 +                      uint command, unsigned long a)
 +{
@@ -4408,42 +4790,32 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      return 0;
 +}
 +
-+static inline struct io_hook *alloc_io_hook(void)
-+{
-+      return kmem_cache_alloc(_io_hook_cache, GFP_NOIO);
-+}
-+
-+static inline void free_io_hook(struct io_hook *ih)
-+{
-+      kmem_cache_free(_io_hook_cache, ih);
-+}
-+
 +/*
-+ * 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.
++ * Add the buffer to the list of deferred io.
 + */
-+static inline struct deferred_io *alloc_deferred(void)
++static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
 +{
-+      return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
-+}
++      struct deferred_io *di;
 +
-+static inline void free_deferred(struct deferred_io *di)
-+{
-+      kfree(di);
-+}
++      di = alloc_deferred();
++      if (!di)
++              return -ENOMEM;
 +
-+/*
-+ * 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;
++      down_write(&md->lock);
 +
-+      if (err)
-+              return err(bh, ih->rw, ih->target->private);
++      if (!test_bit(DMF_SUSPENDED, &md->flags)) {
++              up_write(&md->lock);
++              free_deferred(di);
++              return 1;
++      }
 +
-+      return 0;
++      di->bh = bh;
++      di->rw = rw;
++      di->next = md->deferred;
++      md->deferred = di;
++
++      up_write(&md->lock);
++      return 0;               /* deferred successfully */
 +}
 +
 +/*
@@ -4452,192 +4824,134 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static void dec_pending(struct buffer_head *bh, int uptodate)
 +{
-+      struct io_hook *ih = bh->b_private;
-+
-+      if (!uptodate && call_err_fn(ih, bh))
-+              return;
++      struct dm_io *io = bh->b_private;
 +
-+      if (atomic_dec_and_test(&ih->md->pending))
++      if (atomic_dec_and_test(&io->md->pending))
 +              /* nudge anyone waiting on suspend queue */
-+              wake_up(&ih->md->wait);
++              wake_up(&io->md->wait);
 +
-+      bh->b_end_io = ih->end_io;
-+      bh->b_private = ih->context;
-+      free_io_hook(ih);
++      bh->b_end_io = io->end_io;
++      bh->b_private = io->context;
++      free_io(io);
 +
 +      bh->b_end_io(bh, uptodate);
 +}
 +
 +/*
-+ * Add the bh to the list of deferred io.
-+ */
-+static int queue_io(struct buffer_head *bh, int rw)
-+{
-+      struct deferred_io *di = alloc_deferred();
-+      struct mapped_device *md;
-+
-+      if (!di)
-+              return -ENOMEM;
-+
-+      md = dm_get_w(MINOR(bh->b_rdev));
-+      if (!md) {
-+              free_deferred(di);
-+              return -ENXIO;
-+      }
-+
-+      if (!md->suspended) {
-+              dm_put_w(md);
-+              free_deferred(di);
-+              return 1;
-+      }
-+
-+      di->bh = bh;
-+      di->rw = rw;
-+      di->next = md->deferred;
-+      md->deferred = di;
-+
-+      dm_put_w(md);
-+
-+      return 0;               /* deferred successfully */
-+}
-+
-+/*
 + * 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)
++                             int rw, struct buffer_head *bh)
 +{
 +      int r;
-+      dm_map_fn fn;
-+      void *context;
-+      struct io_hook *ih = NULL;
-+      struct target *ti = md->map->targets + leaf;
++      struct dm_io *io;
++      struct dm_target *ti;
 +
-+      fn = ti->type->map;
-+      context = ti->private;
-+
-+      ih = alloc_io_hook();
++      ti = dm_table_find_target(md->map, bh->b_rsector);
++      if (!ti)
++              return -EINVAL;
 +
-+      if (!ih)
-+              return -1;
++      io = alloc_io();
++      if (!io)
++              return -ENOMEM;
 +
-+      ih->md = md;
-+      ih->rw = rw;
-+      ih->target = ti;
-+      ih->end_io = bh->b_end_io;
-+      ih->context = bh->b_private;
++      io->md = md;
++      io->end_io = bh->b_end_io;
++      io->context = bh->b_private;
 +
-+      r = fn(bh, rw, context);
++      r = ti->type->map(ti, bh, rw);
 +
 +      if (r > 0) {
 +              /* hook the end io request fn */
 +              atomic_inc(&md->pending);
 +              bh->b_end_io = dec_pending;
-+              bh->b_private = ih;
++              bh->b_private = io;
 +
-+      } else if (r == 0)
++      } else
 +              /* we don't need to hook */
-+              free_io_hook(ih);
-+
-+      else if (r < 0) {
-+              free_io_hook(ih);
-+              return -1;
-+      }
++              free_io(io);
 +
 +      return r;
 +}
 +
 +/*
-+ * Search the btree for the correct target.
++ * Checks to see if we should be deferring io, if so it queues it
++ * and returns 1.
 + */
-+static inline int __find_node(struct dm_table *t, struct buffer_head *bh)
++static inline int __deferring(struct mapped_device *md, int rw,
++                            struct buffer_head *bh)
 +{
-+      int l, n = 0, k = 0;
-+      offset_t *node;
++      int r;
 +
-+      for (l = 0; l < t->depth; l++) {
-+              n = get_child(n, k);
-+              node = get_node(t, l, n);
++      /*
++       * If we're suspended we have to queue this io for later.
++       */
++      while (test_bit(DMF_BLOCK_IO, &md->flags)) {
++              up_read(&md->lock);
++
++              /*
++               * There's no point deferring a read ahead
++               * request, just drop it.
++               */
++              if (rw == READA) {
++                      down_read(&md->lock);
++                      return -EIO;
++              }
++
++              r = queue_io(md, bh, rw);
++              down_read(&md->lock);
++
++              if (r < 0)
++                      return r;
++
++              if (r == 0)
++                      return 1;       /* deferred successfully */
 +
-+              for (k = 0; k < KEYS_PER_NODE; k++)
-+                      if (node[k] >= bh->b_rsector)
-+                              break;
 +      }
 +
-+      return (KEYS_PER_NODE * n) + k;
++      return 0;
 +}
 +
-+static int request(request_queue_t * q, int rw, struct buffer_head *bh)
++static int dm_request(request_queue_t *q, int rw, struct buffer_head *bh)
 +{
++      int r;
 +      struct mapped_device *md;
-+      int r, minor = MINOR(bh->b_rdev);
-+      unsigned int block_size = _blksize_size[minor];
 +
-+      md = dm_get_r(minor);
++      md = get_kdev(bh->b_rdev);
 +      if (!md) {
 +              buffer_IO_error(bh);
 +              return 0;
 +      }
 +
-+      /*
-+       * Sanity checks.
-+       */
-+      if (bh->b_size > block_size)
-+              DMERR("request is larger than block size "
-+                    "b_size (%d), block size (%d)",
-+                    bh->b_size, block_size);
++      down_read(&md->lock);
 +
-+      if (bh->b_rsector & ((bh->b_size >> 9) - 1))
-+              DMERR("misaligned block requested logical "
-+                    "sector (%lu), b_size (%d)",
-+                    bh->b_rsector, bh->b_size);
-+
-+      /*
-+       * If we're suspended we have to queue
-+       * this io for later.
-+       */
-+      while (md->suspended) {
-+              dm_put_r(md);
-+
-+              if (rw == READA)
-+                      goto bad_no_lock;
-+
-+              r = queue_io(bh, rw);
++      r = __deferring(md, rw, bh);
++      if (r < 0)
++              goto bad;
 +
++      else if (!r) {
++              /* not deferring */
++              r = __map_buffer(md, rw, bh);
 +              if (r < 0)
-+                      goto bad_no_lock;
-+
-+              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.
-+               */
-+              md = dm_get_r(minor);
-+              if (!md) {
-+                      buffer_IO_error(bh);
-+                      return 0;
-+              }
-+      }
-+
-+      if ((r = __map_buffer(md, bh, rw, __find_node(md->map, bh))) < 0)
-+              goto bad;
++                      goto bad;
++      } else
++              r = 0;
 +
-+      dm_put_r(md);
++      up_read(&md->lock);
++      dm_put(md);
 +      return r;
 +
 +      bad:
-+      dm_put_r(md);
-+
-+      bad_no_lock:
 +      buffer_IO_error(bh);
++      up_read(&md->lock);
++      dm_put(md);
 +      return 0;
 +}
 +
-+static int check_dev_size(int minor, unsigned long block)
++static int check_dev_size(kdev_t dev, unsigned long block)
 +{
 +      /* FIXME: check this */
++      int minor = MINOR(dev);
 +      unsigned long max_sector = (_block_size[minor] << 1) + 1;
 +      unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9);
 +
@@ -4647,25 +4961,18 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +/*
 + * 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)
++static int __bmap(struct mapped_device *md, kdev_t dev, unsigned long block,
++                kdev_t *r_dev, unsigned long *r_block)
 +{
-+      struct mapped_device *md;
 +      struct buffer_head bh;
-+      int minor = MINOR(dev), r;
-+      struct target *t;
-+
-+      md = dm_get_r(minor);
-+      if (!md)
-+              return -ENXIO;
++      struct dm_target *ti;
++      int r;
 +
-+      if (md->suspended) {
-+              dm_put_r(md);
++      if (test_bit(DMF_BLOCK_IO, &md->flags)) {
 +              return -EPERM;
 +      }
 +
-+      if (!check_dev_size(minor, block)) {
-+              dm_put_r(md);
++      if (!check_dev_size(dev, block)) {
 +              return -EINVAL;
 +      }
 +
@@ -4673,19 +4980,20 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      memset(&bh, 0, sizeof(bh));
 +      bh.b_blocknr = block;
 +      bh.b_dev = bh.b_rdev = dev;
-+      bh.b_size = _blksize_size[minor];
++      bh.b_size = _blksize_size[MINOR(dev)];
 +      bh.b_rsector = block * (bh.b_size >> 9);
 +
 +      /* find target */
-+      t = md->map->targets + __find_node(md->map, &bh);
++      ti = dm_table_find_target(md->map, bh.b_rsector);
 +
 +      /* do the mapping */
-+      r = t->type->map(&bh, READ, t->private);
++      r = ti->type->map(ti, &bh, READ);
 +
-+      *r_dev = bh.b_rdev;
-+      *r_block = bh.b_rsector / (bh.b_size >> 9);
++      if (!r) {
++              *r_dev = bh.b_rdev;
++              *r_block = bh.b_rsector / (bh.b_size >> 9);
++      }
 +
-+      dm_put_r(md);
 +      return r;
 +}
 +
@@ -4694,6 +5002,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb)
 +{
++      struct mapped_device *md;
 +      unsigned long block, r_block;
 +      kdev_t r_dev;
 +      int r;
@@ -4701,143 +5010,141 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      if (get_user(block, &lvb->lv_block))
 +              return -EFAULT;
 +
-+      if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block)))
-+              return r;
++      md = get_kdev(inode->i_rdev);
++      if (!md)
++              return -ENXIO;
 +
-+      if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
-+          put_user(r_block, &lvb->lv_block))
-+              return -EFAULT;
++      down_read(&md->lock);
++      r = __bmap(md, inode->i_rdev, block, &r_dev, &r_block);
++      up_read(&md->lock);
++      dm_put(md);
 +
-+      return 0;
++      if (!r && (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
++                 put_user(r_block, &lvb->lv_block)))
++              r = -EFAULT;
++
++      return r;
++}
++
++/*-----------------------------------------------------------------
++ * A bitset is used to keep track of allocated minor numbers.
++ *---------------------------------------------------------------*/
++static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED;
++static struct mapped_device *_mds[MAX_DEVICES];
++
++static void free_minor(int minor)
++{
++      spin_lock(&_minor_lock);
++      _mds[minor] = NULL;
++      spin_unlock(&_minor_lock);
 +}
 +
 +/*
-+ * See if the device with a specific minor # is free.  The write
-+ * lock is held when it returns successfully.
++ * See if the device with a specific minor # is free.
 + */
-+static inline int specific_dev(int minor, struct mapped_device *md)
++static int specific_minor(int minor, struct mapped_device *md)
 +{
++      int r = -EBUSY;
++
 +      if (minor >= MAX_DEVICES) {
 +              DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
 +                     MAX_DEVICES);
-+              return -1;
++              return -EINVAL;
 +      }
 +
-+      down_write(_dev_locks + minor);
-+      if (_devs[minor]) {
-+              /* in use */
-+              up_write(_dev_locks + minor);
-+              return -1;
++      spin_lock(&_minor_lock);
++      if (!_mds[minor]) {
++              _mds[minor] = md;
++              r = minor;
 +      }
++      spin_unlock(&_minor_lock);
 +
-+      return minor;
++      return r;
 +}
 +
-+/*
-+ * Find the first free device.  Again the write lock is held on
-+ * success.
-+ */
-+static int any_old_dev(struct mapped_device *md)
++static int next_free_minor(struct mapped_device *md)
 +{
 +      int i;
 +
-+      for (i = 0; i < MAX_DEVICES; i++)
-+              if (specific_dev(i, md) != -1)
-+                      return i;
++      spin_lock(&_minor_lock);
++      for (i = 0; i < MAX_DEVICES; i++) {
++              if (!_mds[i]) {
++                      _mds[i] = md;
++                      break;
++              }
++      }
++      spin_unlock(&_minor_lock);
 +
-+      return -1;
++      return (i < MAX_DEVICES) ? i : -EBUSY;
++}
++
++static struct mapped_device *get_kdev(kdev_t dev)
++{
++      struct mapped_device *md;
++
++      if (major(dev) != _major)
++              return NULL;
++
++      spin_lock(_minor_lock);
++      md = _mds[minor(dev)];
++      if (md)
++              dm_get(md);
++      spin_unlock(_minor_lock);
++
++      return md;
 +}
 +
 +/*
-+ * Allocate and initialise a blank device.
-+ * Caller must ensure uuid is null-terminated.
-+ * Device is returned with a write lock held.
++ * Allocate and initialise a blank device with a given minor.
 + */
-+static struct mapped_device *alloc_dev(const char *name, const char *uuid,
-+                                     int minor)
++static struct mapped_device *alloc_dev(int minor)
 +{
 +      struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
-+      int len;
 +
 +      if (!md) {
 +              DMWARN("unable to allocate device, out of memory.");
 +              return NULL;
 +      }
 +
-+      memset(md, 0, sizeof(*md));
-+
-+      /*
-+       * This grabs the write lock if it succeeds.
-+       */
-+      minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md);
++      /* get a minor number for the dev */
++      minor = (minor < 0) ? next_free_minor(md) : specific_minor(minor, md);
 +      if (minor < 0) {
 +              kfree(md);
 +              return NULL;
 +      }
 +
-+      md->dev = MKDEV(_major, minor);
-+      md->suspended = 0;
-+
-+      strncpy(md->name, name, sizeof(md->name) - 1);
-+      md->name[sizeof(md->name) - 1] = '\0';
-+
-+      /*
-+       * Copy in the uuid.
-+       */
-+      if (uuid && *uuid) {
-+              len = strlen(uuid) + 1;
-+              if (!(md->uuid = kmalloc(len, GFP_KERNEL))) {
-+                      DMWARN("unable to allocate uuid - out of memory.");
-+                      kfree(md);
-+                      return NULL;
-+              }
-+              strcpy(md->uuid, uuid);
-+      }
-+
++      memset(md, 0, sizeof(*md));
++      md->dev = mk_kdev(_major, minor);
++      init_rwsem(&md->lock);
++      atomic_set(&md->holders, 1);
++      atomic_set(&md->pending, 0);
 +      init_waitqueue_head(&md->wait);
-+      return md;
-+}
 +
-+static int __register_device(struct mapped_device *md)
-+{
-+      md->devfs_entry =
-+          devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER,
-+                         MAJOR(md->dev), MINOR(md->dev),
-+                         S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-+                         &dm_blk_dops, NULL);
-+
-+      return 0;
++      return md;
 +}
 +
-+static int __unregister_device(struct mapped_device *md)
++static void free_dev(struct mapped_device *md)
 +{
-+      devfs_unregister(md->devfs_entry);
-+      return 0;
++      free_minor(minor(md->dev));
++      kfree(md);
 +}
 +
 +/*
-+ * The hardsect size for a mapped device is the smallest hardsect size
++ * The hardsect size for a mapped device is the largest hardsect size
 + * from the devices it maps onto.
 + */
 +static int __find_hardsect_size(struct list_head *devices)
 +{
-+      int result = INT_MAX, size;
++      int result = 512, size;
 +      struct list_head *tmp;
 +
 +      list_for_each(tmp, devices) {
 +              struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
 +              size = get_hardsect_size(dd->dev);
-+              if (size < result)
++              if (size > result)
 +                      result = size;
 +      }
 +
-+      /*
-+       * I think it's safe to assume that no block devices have
-+       * a hard sector size this large.
-+       */
-+      if (result == INT_MAX)
-+              result = 512;
-+
 +      return result;
 +}
 +
@@ -4846,226 +5153,68 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + */
 +static int __bind(struct mapped_device *md, struct dm_table *t)
 +{
-+      int minor = MINOR(md->dev);
-+
++      int minor = minor(md->dev);
 +      md->map = t;
 +
-+      if (!t->num_targets) {
-+              _block_size[minor] = 0;
-+              _blksize_size[minor] = BLOCK_SIZE;
-+              _hardsect_size[minor] = 0;
-+              return 0;
-+      }
-+
 +      /* in k */
-+      _block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
-+
-+      _blksize_size[minor] = BLOCK_SIZE;
-+      _hardsect_size[minor] = __find_hardsect_size(&t->devices);
-+      register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
-+
-+      return 0;
-+}
-+
-+static void __unbind(struct mapped_device *md)
-+{
-+      int minor = MINOR(md->dev);
-+
-+      dm_table_destroy(md->map);
-+      md->map = NULL;
-+
-+      _block_size[minor] = 0;
-+      _blksize_size[minor] = 0;
-+      _hardsect_size[minor] = 0;
-+}
-+
-+static int check_name(const char *name)
-+{
-+      struct mapped_device *md;
-+
-+      if (strchr(name, '/') || strlen(name) > DM_NAME_LEN) {
-+              DMWARN("invalid device name");
-+              return -1;
-+      }
-+
-+      md = dm_get_name_r(name, DM_LOOKUP_BY_NAME);
-+      if (md) {
-+              dm_put_r(md);
-+              DMWARN("device name already in use");
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+static int check_uuid(const char *uuid)
-+{
-+      struct mapped_device *md;
-+
-+      if (uuid) {
-+              md = dm_get_name_r(uuid, DM_LOOKUP_BY_UUID);
-+              if (md) {
-+                      dm_put_r(md);
-+                      DMWARN("device uuid already in use");
-+                      return -1;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * Constructor for a new device.
-+ */
-+int dm_create(const char *name, const char *uuid, int minor, int ro,
-+            struct dm_table *table)
-+{
-+      int r;
-+      struct mapped_device *md;
-+
-+      spin_lock(&_create_lock);
-+      if (check_name(name) || check_uuid(uuid)) {
-+              spin_unlock(&_create_lock);
-+              return -EINVAL;
-+      }
-+
-+      md = alloc_dev(name, uuid, minor);
-+      if (!md) {
-+              spin_unlock(&_create_lock);
-+              return -ENXIO;
-+      }
-+      minor = MINOR(md->dev);
-+      _devs[minor] = md;
-+
-+      r = __register_device(md);
-+      if (r)
-+              goto err;
-+
-+      r = __bind(md, table);
-+      if (r)
-+              goto err;
-+
-+      dm_set_ro(md, ro);
-+
-+      spin_unlock(&_create_lock);
-+      dm_put_w(md);
-+      return 0;
-+
-+      err:
-+      _devs[minor] = NULL;
-+      if (md->uuid)
-+              kfree(md->uuid);
-+
-+      dm_put_w(md);
-+      kfree(md);
-+      spin_unlock(&_create_lock);
-+      return r;
-+}
-+
-+/*
-+ * Renames the device.  No lock held.
-+ */
-+int dm_set_name(const char *name, int nametype, const char *newname)
-+{
-+      int r;
-+      struct mapped_device *md;
-+
-+      spin_lock(&_create_lock);
-+      if (check_name(newname) < 0) {
-+              spin_unlock(&_create_lock);
-+              return -EINVAL;
-+      }
-+
-+      md = dm_get_name_w(name, nametype);
-+      if (!md) {
-+              spin_unlock(&_create_lock);
-+              return -ENXIO;
-+      }
-+
-+      r = __unregister_device(md);
-+      if (r)
-+              goto out;
-+
-+      strcpy(md->name, newname);
-+      r = __register_device(md);
-+
-+      out:
-+      dm_put_w(md);
-+      spin_unlock(&_create_lock);
-+      return r;
-+}
-+
-+/*
-+ * Destructor for the device.  You cannot destroy an open
-+ * device.  Write lock must be held before calling.
-+ * Caller must dm_put_w(md) then kfree(md) if call was successful.
-+ */
-+int dm_destroy(struct mapped_device *md)
-+{
-+      int minor, r;
-+
-+      if (md->use_count)
-+              return -EPERM;
++      _block_size[minor] = dm_table_get_size(t) >> 1;
++      _blksize_size[minor] = BLOCK_SIZE;
++      _hardsect_size[minor] = __find_hardsect_size(dm_table_get_devices(t));
++      register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
 +
-+      r = __unregister_device(md);
-+      if (r)
-+              return r;
++      dm_table_get(t);
++      return 0;
++}
 +
-+      minor = MINOR(md->dev);
-+      _devs[minor] = NULL;
-+      __unbind(md);
++static void __unbind(struct mapped_device *md)
++{
++      int minor = minor(md->dev);
 +
-+      if (md->uuid)
-+              kfree(md->uuid);
++      dm_table_put(md->map);
++      md->map = NULL;
 +
-+      return 0;
++      _block_size[minor] = 0;
++      _blksize_size[minor] = 0;
++      _hardsect_size[minor] = 0;
 +}
 +
 +/*
-+ * Destroy all devices - except open ones
++ * Constructor for a new device.
 + */
-+void dm_destroy_all(void)
++int dm_create(int minor, struct dm_table *table, struct mapped_device **result)
 +{
-+      int i, some_destroyed, r;
++      int r;
 +      struct mapped_device *md;
 +
-+      do {
-+              some_destroyed = 0;
-+              for (i = 0; i < MAX_DEVICES; i++) {
-+                      md = dm_get_w(i);
-+                      if (!md)
-+                              continue;
++      md = alloc_dev(minor);
++      if (!md)
++              return -ENXIO;
 +
-+                      r = dm_destroy(md);
-+                      dm_put_w(md);
++      r = __bind(md, table);
++      if (r) {
++              free_dev(md);
++              return r;
++      }
 +
-+                      if (!r) {
-+                              kfree(md);
-+                              some_destroyed = 1;
-+                      }
-+              }
-+      } while (some_destroyed);
++      *result = md;
++      return 0;
 +}
 +
-+/*
-+ * Sets or clears the read-only flag for the device.  Write lock
-+ * must be held.
-+ */
-+void dm_set_ro(struct mapped_device *md, int ro)
++void dm_get(struct mapped_device *md)
 +{
-+      md->read_only = ro;
-+      set_device_ro(md->dev, ro);
++      atomic_inc(&md->holders);
 +}
 +
-+/*
-+ * A target is notifying us of some event
-+ */
-+void dm_notify(void *target)
++void dm_put(struct mapped_device *md)
 +{
++      if (atomic_dec_and_test(&md->holders)) {
++              __unbind(md);
++              free_dev(md);
++      }
 +}
 +
 +/*
-+ * Requeue the deferred buffer_heads by calling generic_make_request.
++ * Requeue the deferred io by calling generic_make_request.
 + */
 +static void flush_deferred_io(struct deferred_io *c)
 +{
@@ -5080,100 +5229,136 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +}
 +
 +/*
-+ * Swap in a new table (destroying old one).  Write lock must be
-+ * held.
++ * Swap in a new table (destroying old one).
 + */
 +int dm_swap_table(struct mapped_device *md, struct dm_table *table)
 +{
 +      int r;
 +
++      down_write(&md->lock);
++
 +      /* device must be suspended */
-+      if (!md->suspended)
++      if (!test_bit(DMF_SUSPENDED, &md->flags)) {
++              up_write(&md->lock);
 +              return -EPERM;
++      }
 +
 +      __unbind(md);
-+
 +      r = __bind(md, table);
 +      if (r)
 +              return r;
 +
++      up_write(&md->lock);
 +      return 0;
 +}
 +
 +/*
 + * We need to be able to change a mapping table under a mounted
-+ * filesystem.  for example we might want to move some data in
++ * filesystem.  For example we might want to move some data in
 + * the background.  Before the table can be swapped with
 + * dm_bind_table, dm_suspend must be called to flush any in
-+ * flight buffer_heads and ensure that any further io gets
-+ * deferred.  Write lock must be held.
++ * flight io and ensure that any further io gets deferred.
 + */
 +int dm_suspend(struct mapped_device *md)
 +{
-+      int minor = MINOR(md->dev);
 +      DECLARE_WAITQUEUE(wait, current);
 +
-+      if (md->suspended)
++      down_write(&md->lock);
++
++      /*
++       * First we set the BLOCK_IO flag so no more ios will be
++       * mapped.
++       */
++      if (test_bit(DMF_BLOCK_IO, &md->flags)) {
++              up_write(&md->lock);
 +              return -EINVAL;
++      }
++
++      set_bit(DMF_BLOCK_IO, &md->flags);
++      up_write(&md->lock);
 +
-+      md->suspended = 1;
-+      dm_put_w(md);
++      /*
++       * Then we wait for the already mapped ios to
++       * complete.
++       */
++      down_read(&md->lock);
 +
-+      /* wait for all the pending io to flush */
 +      add_wait_queue(&md->wait, &wait);
-+      current->state = TASK_UNINTERRUPTIBLE;
-+      do {
-+              md = dm_get_w(minor);
-+              if (!md) {
-+                      /* Caller expects to free this lock. Yuck. */
-+                      down_write(_dev_locks + minor);
-+                      return -ENXIO;
-+              }
++      while (1) {
++              set_current_state(TASK_INTERRUPTIBLE);
 +
 +              if (!atomic_read(&md->pending))
 +                      break;
 +
-+              dm_put_w(md);
 +              schedule();
-+
-+      } while (1);
++      }
 +
 +      current->state = TASK_RUNNING;
 +      remove_wait_queue(&md->wait, &wait);
++      up_read(&md->lock);
++
++      /* set_bit is atomic */
++      set_bit(DMF_SUSPENDED, &md->flags);
 +
 +      return 0;
 +}
 +
 +int dm_resume(struct mapped_device *md)
 +{
-+      int minor = MINOR(md->dev);
 +      struct deferred_io *def;
 +
-+      if (!md->suspended || !md->map->num_targets)
++      down_write(&md->lock);
++      if (!test_bit(DMF_SUSPENDED, &md->flags) ||
++          !dm_table_get_size(md->map)) {
++              up_write(&md->lock);
 +              return -EINVAL;
++      }
 +
-+      md->suspended = 0;
++      clear_bit(DMF_SUSPENDED, &md->flags);
++      clear_bit(DMF_BLOCK_IO, &md->flags);
 +      def = md->deferred;
 +      md->deferred = NULL;
++      up_write(&md->lock);
 +
-+      dm_put_w(md);
 +      flush_deferred_io(def);
 +      run_task_queue(&tq_disk);
 +
-+      if (!dm_get_w(minor)) {
-+              /* FIXME: yuck */
-+              down_write(_dev_locks + minor);
-+              return -ENXIO;
-+      }
-+
 +      return 0;
 +}
 +
++struct dm_table *dm_get_table(struct mapped_device *md)
++{
++      struct dm_table *t;
++
++      down_read(&md->lock);
++      t = md->map;
++      dm_table_get(t);
++      up_read(&md->lock);
++
++      return t;
++}
++
++kdev_t dm_kdev(struct mapped_device *md)
++{
++      kdev_t dev;
++
++      down_read(&md->lock);
++      dev = md->dev;
++      up_read(&md->lock);
++
++      return dev;
++}
++
++int dm_suspended(struct mapped_device *md)
++{
++      return test_bit(DMF_SUSPENDED, &md->flags);
++}
++
 +struct block_device_operations dm_blk_dops = {
-+      open:           dm_blk_open,
-+      release:        dm_blk_close,
-+      ioctl:          dm_blk_ioctl,
-+      owner:          THIS_MODULE
++      .open = dm_blk_open,
++      .release = dm_blk_close,
++      .ioctl = dm_blk_ioctl,
++      .owner = THIS_MODULE
 +};
 +
 +/*
@@ -5187,14 +5372,14 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +MODULE_DESCRIPTION(DM_NAME " driver");
 +MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>");
 +MODULE_LICENSE("GPL");
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/dm.h linux-2.4.19-dm/drivers/md/dm.h
+diff -ruN linux-2.4.19/drivers/md/dm.h linux-2.4.19-dm-test1/drivers/md/dm.h
 --- linux-2.4.19/drivers/md/dm.h       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/dm.h    Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,242 @@
++++ linux-2.4.19-dm-test1/drivers/md/dm.h      Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,150 @@
 +/*
 + * Internal header file for device mapper
 + *
-+ * Copyright (C) 2001 Sistina Software
++ * Copyright (C) 2001, 2002 Sistina Software
 + *
 + * This file is released under the LGPL.
 + */
@@ -5202,213 +5387,134 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef DM_INTERNAL_H
 +#define DM_INTERNAL_H
 +
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/major.h>
-+#include <linux/iobuf.h>
-+#include <linux/module.h>
 +#include <linux/fs.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/compatmac.h>
-+#include <linux/cache.h>
-+#include <linux/devfs_fs_kernel.h>
-+#include <linux/ctype.h>
 +#include <linux/device-mapper.h>
 +#include <linux/list.h>
-+#include <linux/init.h>
-+
-+#define DM_NAME "device-mapper"       /* Name for messaging */
-+#define DM_DRIVER_EMAIL "lvm-devel@lists.sistina.com"
-+#define MAX_DEPTH 16
-+#define NODE_SIZE L1_CACHE_BYTES
-+#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
-+#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
-+#define MAX_ARGS 32
-+#define MAX_DEVICES 256
-+
-+/*
-+ * List of devices that a metadevice uses and should open/close.
-+ */
-+struct dm_dev {
-+      atomic_t count;
-+      struct list_head list;
-+
-+      int mode;
++#include <linux/blkdev.h>
 +
-+      kdev_t dev;
-+      struct block_device *bd;
-+};
++#define DM_NAME "device-mapper"
++#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
++#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
++#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
 +
 +/*
-+ * I/O that had to be deferred while we were suspended
++ * FIXME: I think this should be with the definition of sector_t
++ * in types.h.
 + */
-+struct deferred_io {
-+      int rw;
-+      struct buffer_head *bh;
-+      struct deferred_io *next;
-+};
++#ifdef CONFIG_LBD
++#define SECTOR_FORMAT "%Lu"
++#else
++#define SECTOR_FORMAT "%lu"
++#endif
 +
-+/*
-+ * Btree leaf - this does the actual mapping
-+ */
-+struct target {
-+      struct target_type *type;
-+      void *private;
-+};
++extern struct block_device_operations dm_blk_dops;
 +
 +/*
-+ * The btree
++ * List of devices that a metadevice uses and should open/close.
 + */
-+struct dm_table {
-+      /* btree table */
-+      int depth;
-+      int counts[MAX_DEPTH];  /* in nodes */
-+      offset_t *index[MAX_DEPTH];
-+
-+      int num_targets;
-+      int num_allocated;
-+      offset_t *highs;
-+      struct target *targets;
++struct dm_dev {
++      struct list_head list;
 +
-+      /*
-+       * Indicates the rw permissions for the new logical
-+       * device.  This should be a combination of FMODE_READ
-+       * and FMODE_WRITE.
-+       */
++      atomic_t count;
 +      int mode;
-+
-+      /* a list of devices used by this table */
-+      struct list_head devices;
-+
-+      /*
-+       * A waitqueue for processes waiting for something
-+       * interesting to happen to this table.
-+       */
-+      wait_queue_head_t eventq;
-+};
-+
-+/*
-+ * The actual device struct
-+ */
-+struct mapped_device {
 +      kdev_t dev;
-+      char name[DM_NAME_LEN];
-+      char *uuid;
-+
-+      int use_count;
-+      int suspended;
-+      int read_only;
-+
-+      /* a list of io's that arrived while we were suspended */
-+      atomic_t pending;
-+      wait_queue_head_t wait;
-+      struct deferred_io *deferred;
-+
-+      struct dm_table *map;
-+
-+      /* used by dm-fs.c */
-+      devfs_handle_t devfs_entry;
++      struct block_device *bdev;
 +};
 +
-+extern struct block_device_operations dm_blk_dops;
-+
-+/* dm-target.c */
-+int dm_target_init(void);
-+struct target_type *dm_get_target_type(const char *name);
-+void dm_put_target_type(struct target_type *t);
-+void dm_target_exit(void);
-+
-+/*
-+ * Destructively splits argument list to pass to ctr.
-+ */
-+int split_args(int max, int *argc, char **argv, char *input);
++struct dm_table;
++struct mapped_device;
 +
-+/* dm.c */
-+struct mapped_device *dm_get_r(int minor);
-+struct mapped_device *dm_get_w(int minor);
++/*-----------------------------------------------------------------
++ * Functions for manipulating a struct mapped_device.
++ * Drop the reference with dm_put when you finish with the object.
++ *---------------------------------------------------------------*/
++int dm_create(int minor, struct dm_table *table, struct mapped_device **md);
 +
 +/*
-+ * There are two ways to lookup a device.
++ * Reference counting for md.
 + */
-+enum {
-+      DM_LOOKUP_BY_NAME,
-+      DM_LOOKUP_BY_UUID
-+};
-+
-+struct mapped_device *dm_get_name_r(const char *name, int nametype);
-+struct mapped_device *dm_get_name_w(const char *name, int nametype);
-+
-+void dm_put_r(struct mapped_device *md);
-+void dm_put_w(struct mapped_device *md);
++void dm_get(struct mapped_device *md);
++void dm_put(struct mapped_device *md);
 +
 +/*
-+ * Call with no lock.
++ * A device can still be used while suspended, but I/O is deferred.
 + */
-+int dm_create(const char *name, const char *uuid, int minor, int ro,
-+            struct dm_table *table);
-+int dm_set_name(const char *name, int nametype, const char *newname);
-+void dm_destroy_all(void);
++int dm_suspend(struct mapped_device *md);
++int dm_resume(struct mapped_device *md);
 +
 +/*
-+ * You must have the write lock before calling the remaining md
-+ * methods.
++ * The device must be suspended before calling this method.
 + */
-+int dm_destroy(struct mapped_device *md);
-+void dm_set_ro(struct mapped_device *md, int ro);
++int dm_swap_table(struct mapped_device *md, struct dm_table *t);
 +
 +/*
-+ * The device must be suspended before calling this method.
++ * Drop a reference on the table when you've finished with the
++ * result.
 + */
-+int dm_swap_table(struct mapped_device *md, struct dm_table *t);
++struct dm_table *dm_get_table(struct mapped_device *md);
 +
 +/*
-+ * A device can still be used while suspended, but I/O is deferred.
++ * Info functions.
 + */
-+int dm_suspend(struct mapped_device *md);
-+int dm_resume(struct mapped_device *md);
++kdev_t dm_kdev(struct mapped_device *md);
++int dm_suspended(struct mapped_device *md);
 +
-+/* dm-table.c */
++/*-----------------------------------------------------------------
++ * Functions for manipulating a table.  Tables are also reference
++ * counted.
++ *---------------------------------------------------------------*/
 +int dm_table_create(struct dm_table **result, int mode);
-+void dm_table_destroy(struct dm_table *t);
 +
-+int dm_table_add_target(struct dm_table *t, offset_t highs,
-+                      struct target_type *type, void *private);
-+int dm_table_complete(struct dm_table *t);
++void dm_table_get(struct dm_table *t);
++void dm_table_put(struct dm_table *t);
 +
-+/*
-+ * Event handling
-+ */
++int dm_table_add_target(struct dm_table *t, const char *type,
++                      sector_t start, sector_t len, char *params);
++int dm_table_complete(struct dm_table *t);
 +void dm_table_event(struct dm_table *t);
++sector_t dm_table_get_size(struct dm_table *t);
++struct dm_target *dm_table_get_target(struct dm_table *t, int index);
++struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
++unsigned int dm_table_get_num_targets(struct dm_table *t);
++struct list_head *dm_table_get_devices(struct dm_table *t);
++int dm_table_get_mode(struct dm_table *t);
++void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq);
 +
-+#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
-+#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
-+#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
++/*-----------------------------------------------------------------
++ * A registry of target types.
++ *---------------------------------------------------------------*/
++int dm_target_init(void);
++void dm_target_exit(void);
++struct target_type *dm_get_target_type(const char *name);
++void dm_put_target_type(struct target_type *t);
 +
-+/*
-+ * Calculate the index of the child node of the n'th node k'th key.
-+ */
-+static inline int get_child(int n, int k)
++/*-----------------------------------------------------------------
++ * Useful inlines.
++ *---------------------------------------------------------------*/
++static inline int array_too_big(unsigned long fixed, unsigned long obj,
++                              unsigned long num)
 +{
-+      return (n * CHILDREN_PER_NODE) + k;
++      return (num > (ULONG_MAX - fixed) / obj);
 +}
 +
 +/*
-+ * Return the n'th node of level l from table t.
++ * ceiling(n / size) * size
 + */
-+static inline offset_t *get_node(struct dm_table *t, int l, int n)
++static inline unsigned long dm_round_up(unsigned long n, unsigned long size)
 +{
-+      return t->index[l] + (n * KEYS_PER_NODE);
++      unsigned long r = n % size;
++      return n + (r ? (size - r) : 0);
 +}
 +
-+static inline int array_too_big(unsigned long fixed, unsigned long obj,
-+                              unsigned long num)
-+{
-+      return (num > (ULONG_MAX - fixed) / obj);
-+}
++/*
++ * 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);
 +
 +/*
-+ * Targets
++ * Targets for linear and striped mappings
 + */
 +int dm_linear_init(void);
 +void dm_linear_exit(void);
@@ -5419,42 +5525,31 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +int dm_snapshot_init(void);
 +void dm_snapshot_exit(void);
 +
-+/* Future */
-+/* int dm_mirror_init(void); */
-+/* void dm_mirror_exit(void); */
-+
-+/*
-+ * Init functions for the user interface to device-mapper.  At
-+ * the moment an ioctl interface on a special char device is
-+ * used.  A filesystem based interface would be a nicer way to
-+ * go.
-+ */
-+int __init dm_interface_init(void);
-+void dm_interface_exit(void);
-+
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/kcopyd.c linux-2.4.19-dm/drivers/md/kcopyd.c
+diff -ruN linux-2.4.19/drivers/md/kcopyd.c linux-2.4.19-dm-test1/drivers/md/kcopyd.c
 --- linux-2.4.19/drivers/md/kcopyd.c   Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/kcopyd.c        Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,841 @@
++++ linux-2.4.19-dm-test1/drivers/md/kcopyd.c  Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,843 @@
 +/*
 + * Copyright (C) 2002 Sistina Software (UK) Limited.
 + *
 + * This file is released under the GPL.
 + */
 +
++#include <asm/atomic.h>
++
++#include <linux/blkdev.h>
 +#include <linux/config.h>
-+#include <linux/module.h>
++#include <linux/device-mapper.h>
++#include <linux/fs.h>
 +#include <linux/init.h>
-+#include <linux/slab.h>
 +#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/device-mapper.h>
++#include <linux/locks.h>
 +#include <linux/mempool.h>
-+#include <asm/atomic.h>
++#include <linux/module.h>
 +#include <linux/pagemap.h>
-+#include <linux/locks.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
 +
 +#include "kcopyd.h"
 +
@@ -5694,7 +5789,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +{
 +      struct kcopyd_job *job;
 +
-+      job = mempool_alloc(_job_pool, GFP_KERNEL);
++      job = mempool_alloc(_job_pool, GFP_NOIO);
 +      if (!job)
 +              return NULL;
 +
@@ -6050,7 +6145,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +static inline struct copy_info *alloc_copy_info(void)
 +{
-+      return mempool_alloc(_copy_pool, GFP_KERNEL);
++      return mempool_alloc(_copy_pool, GFP_NOIO);
 +}
 +
 +static inline void free_copy_info(struct copy_info *info)
@@ -6278,9 +6373,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +      up(&_client_count_sem);
 +}
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/drivers/md/kcopyd.h linux-2.4.19-dm/drivers/md/kcopyd.h
+diff -ruN linux-2.4.19/drivers/md/kcopyd.h linux-2.4.19-dm-test1/drivers/md/kcopyd.h
 --- linux-2.4.19/drivers/md/kcopyd.h   Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/drivers/md/kcopyd.h        Wed Aug 14 17:42:59 2002
++++ linux-2.4.19-dm-test1/drivers/md/kcopyd.h  Wed Nov 13 19:21:59 2002
 @@ -0,0 +1,101 @@
 +/*
 + * Copyright (C) 2001 Sistina Software
@@ -6299,8 +6394,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +struct kcopyd_region {
 +      kdev_t dev;
-+      offset_t sector;
-+      offset_t count;
++      sector_t sector;
++      sector_t count;
 +};
 +
 +#define MAX_KCOPYD_PAGES 128
@@ -6330,11 +6425,11 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Shifts and masks that will be useful when dispatching
 +       * each buffer_head.
 +       */
-+      offset_t offset;
-+      offset_t block_size;
-+      offset_t block_shift;
-+      offset_t bpp_shift;     /* blocks per page */
-+      offset_t bpp_mask;
++      sector_t offset;
++      sector_t block_size;
++      sector_t block_shift;
++      sector_t bpp_shift;     /* blocks per page */
++      sector_t bpp_mask;
 +
 +      /*
 +       * nr_blocks is how many buffer heads will have to be
@@ -6350,7 +6445,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +       * Set this to ensure you are notified when the job has
 +       * completed.  'context' is for callback to use.
 +       */
-+      void (*callback)(struct kcopyd_job *job);
++      void (*callback) (struct kcopyd_job *job);
 +      void *context;
 +};
 +
@@ -6366,7 +6461,7 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 + * Submit a copy job to kcopyd.  This is built on top of the
 + * previous three fns.
 + */
-+typedef void (*kcopyd_notify_fn)(int err, void *context);
++typedef void (*kcopyd_notify_fn) (int err, void *context);
 +
 +int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to,
 +              kcopyd_notify_fn fn, void *context);
@@ -6383,9 +6478,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +void kcopyd_dec_client_count(void);
 +
 +#endif
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/fs/buffer.c linux-2.4.19-dm/fs/buffer.c
+diff -ruN linux-2.4.19/fs/buffer.c linux-2.4.19-dm-test1/fs/buffer.c
 --- linux-2.4.19/fs/buffer.c   Wed Aug 14 11:51:40 2002
-+++ linux-2.4.19-dm/fs/buffer.c        Wed Aug 14 17:42:49 2002
++++ linux-2.4.19-dm-test1/fs/buffer.c  Wed Nov 13 19:34:39 2002
 @@ -587,9 +587,10 @@
  void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
  {
@@ -6457,9 +6552,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
                BUG();
        if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
                kmem_cache_free(bh_cachep, bh);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/fs/jbd/journal.c linux-2.4.19-dm/fs/jbd/journal.c
+diff -ruN linux-2.4.19/fs/jbd/journal.c linux-2.4.19-dm-test1/fs/jbd/journal.c
 --- linux-2.4.19/fs/jbd/journal.c      Wed Aug 14 11:51:43 2002
-+++ linux-2.4.19-dm/fs/jbd/journal.c   Wed Aug 14 17:42:49 2002
++++ linux-2.4.19-dm-test1/fs/jbd/journal.c     Wed Nov 13 19:04:21 2002
 @@ -1625,8 +1625,8 @@
   *
   * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit
@@ -6510,10 +6605,10 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
                        jh->b_bh = NULL;        /* debug, really */
                        clear_bit(BH_JBD, &bh->b_state);
                        __brelse(bh);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/device-mapper.h linux-2.4.19-dm/include/linux/device-mapper.h
+diff -ruN linux-2.4.19/include/linux/device-mapper.h linux-2.4.19-dm-test1/include/linux/device-mapper.h
 --- linux-2.4.19/include/linux/device-mapper.h Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/include/linux/device-mapper.h      Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,63 @@
++++ linux-2.4.19-dm-test1/include/linux/device-mapper.h        Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,85 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -6523,40 +6618,48 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef _LINUX_DEVICE_MAPPER_H
 +#define _LINUX_DEVICE_MAPPER_H
 +
-+#define DM_DIR "mapper"       /* Slashes not supported */
-+#define DM_MAX_TYPE_NAME 16
-+#define DM_NAME_LEN 128
-+#define DM_UUID_LEN 129
-+
 +#ifdef __KERNEL__
 +
++typedef unsigned long sector_t;
++
++struct dm_target;
 +struct dm_table;
 +struct dm_dev;
-+typedef unsigned long offset_t;
 +
 +typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 +
 +/*
-+ * Prototypes for functions for a target
++ * In the constructor the target parameter will already have the
++ * table, type, begin and len fields filled in.
++ */
++typedef int (*dm_ctr_fn) (struct dm_target *target, int argc, char **argv);
++
++/*
++ * The destructor doesn't need to free the dm_target, just
++ * anything hidden ti->private.
 + */
-+typedef int (*dm_ctr_fn) (struct dm_table *t, offset_t b, offset_t l,
-+                        int argc, char **argv, 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_status_fn) (status_type_t status_type, char *result,
-+                           int maxlen, void *context);
++typedef void (*dm_dtr_fn) (struct dm_target *ti);
++
++/*
++ * The map function must return:
++ * < 0: error
++ * = 0: The target will handle the io by resubmitting it later
++ * > 0: simple remap complete
++ */
++typedef int (*dm_map_fn) (struct dm_target *ti, struct buffer_head *bh, int rw);
++typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
++                           char *result, int maxlen);
 +
 +void dm_error(const char *message);
 +
 +/*
 + * Constructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * are opened/closed correctly.
++ * FIXME: too many arguments.
 + */
-+int dm_table_get_device(struct dm_table *t, const char *path,
-+                      offset_t start, offset_t len,
-+                      int mode, struct dm_dev **result);
-+void dm_table_put_device(struct dm_table *table, struct dm_dev *d);
++int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
++                sector_t len, int mode, struct dm_dev **result);
++void dm_put_device(struct dm_target *ti, struct dm_dev *d);
 +
 +/*
 + * Information about a target type
@@ -6567,20 +6670,34 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +      dm_ctr_fn ctr;
 +      dm_dtr_fn dtr;
 +      dm_map_fn map;
-+      dm_err_fn err;
 +      dm_status_fn status;
 +};
 +
++struct dm_target {
++      struct dm_table *table;
++      struct target_type *type;
++
++      /* target limits */
++      sector_t begin;
++      sector_t len;
++
++      /* target specific data */
++      void *private;
++
++      /* Used to provide an error string from the ctr */
++      char *error;
++};
++
 +int dm_register_target(struct target_type *t);
 +int dm_unregister_target(struct target_type *t);
 +
 +#endif                                /* __KERNEL__ */
 +
 +#endif                                /* _LINUX_DEVICE_MAPPER_H */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/dm-ioctl.h linux-2.4.19-dm/include/linux/dm-ioctl.h
+diff -ruN linux-2.4.19/include/linux/dm-ioctl.h linux-2.4.19-dm-test1/include/linux/dm-ioctl.h
 --- linux-2.4.19/include/linux/dm-ioctl.h      Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/include/linux/dm-ioctl.h   Wed Aug 14 17:42:59 2002
-@@ -0,0 +1,145 @@
++++ linux-2.4.19-dm-test1/include/linux/dm-ioctl.h     Wed Nov 13 19:21:59 2002
+@@ -0,0 +1,149 @@
 +/*
 + * Copyright (C) 2001 Sistina Software (UK) Limited.
 + *
@@ -6590,9 +6707,13 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#ifndef _LINUX_DM_IOCTL_H
 +#define _LINUX_DM_IOCTL_H
 +
-+#include "device-mapper.h"
 +#include <linux/types.h>
 +
++#define DM_DIR "mapper"               /* Slashes not supported */
++#define DM_MAX_TYPE_NAME 16
++#define DM_NAME_LEN 128
++#define DM_UUID_LEN 129
++
 +/*
 + * Implements a traditional ioctl interface to the device mapper.
 + */
@@ -6710,8 +6831,8 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +
 +#define DM_VERSION_MAJOR      1
 +#define DM_VERSION_MINOR      0
-+#define DM_VERSION_PATCHLEVEL 3
-+#define DM_VERSION_EXTRA      "-ioctl (2002-08-14)"
++#define DM_VERSION_PATCHLEVEL 7
++#define DM_VERSION_EXTRA      "-ioctl (2002-11-13)"
 +
 +/* Status bits */
 +#define DM_READONLY_FLAG      0x00000001
@@ -6726,9 +6847,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +#define DM_STATUS_TABLE_FLAG  0x00000010
 +
 +#endif                                /* _LINUX_DM_IOCTL_H */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/fs.h linux-2.4.19-dm/include/linux/fs.h
+diff -ruN linux-2.4.19/include/linux/fs.h linux-2.4.19-dm-test1/include/linux/fs.h
 --- linux-2.4.19/include/linux/fs.h    Wed Aug 14 11:52:06 2002
-+++ linux-2.4.19-dm/include/linux/fs.h Wed Aug 14 17:42:49 2002
++++ linux-2.4.19-dm-test1/include/linux/fs.h   Wed Nov 13 19:34:39 2002
 @@ -219,6 +219,7 @@
        BH_Wait_IO,     /* 1 if we should write out this buffer */
        BH_Launder,     /* 1 if we can throttle on this buffer */
@@ -6772,9 +6893,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  }
  
  /*
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/jbd.h linux-2.4.19-dm/include/linux/jbd.h
+diff -ruN linux-2.4.19/include/linux/jbd.h linux-2.4.19-dm-test1/include/linux/jbd.h
 --- linux-2.4.19/include/linux/jbd.h   Wed Aug 14 11:52:07 2002
-+++ linux-2.4.19-dm/include/linux/jbd.h        Wed Aug 14 17:42:49 2002
++++ linux-2.4.19-dm-test1/include/linux/jbd.h  Wed Nov 13 19:04:21 2002
 @@ -246,7 +246,7 @@
  
  static inline struct journal_head *bh2jh(struct buffer_head *bh)
@@ -6784,9 +6905,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  }
  
  struct jbd_revoke_table_s;
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/mempool.h linux-2.4.19-dm/include/linux/mempool.h
+diff -ruN linux-2.4.19/include/linux/mempool.h linux-2.4.19-dm-test1/include/linux/mempool.h
 --- linux-2.4.19/include/linux/mempool.h       Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/include/linux/mempool.h    Wed Aug 14 17:43:19 2002
++++ linux-2.4.19-dm-test1/include/linux/mempool.h      Wed Nov 13 19:04:55 2002
 @@ -0,0 +1,41 @@
 +/*
 + * memory buffer pool support
@@ -6829,9 +6950,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +void mempool_free_slab(void *element, void *pool_data);
 +
 +#endif /* _LINUX_MEMPOOL_H */
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/include/linux/vmalloc.h linux-2.4.19-dm/include/linux/vmalloc.h
+diff -ruN linux-2.4.19/include/linux/vmalloc.h linux-2.4.19-dm-test1/include/linux/vmalloc.h
 --- linux-2.4.19/include/linux/vmalloc.h       Wed Aug 14 11:52:09 2002
-+++ linux-2.4.19-dm/include/linux/vmalloc.h    Wed Aug 14 17:43:23 2002
++++ linux-2.4.19-dm-test1/include/linux/vmalloc.h      Wed Nov 13 19:05:03 2002
 @@ -25,6 +25,7 @@
  extern void vmfree_area_pages(unsigned long address, unsigned long size);
  extern int vmalloc_area_pages(unsigned long address, unsigned long size,
@@ -6840,9 +6961,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  
  /*
   *    Allocate any pages
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/kernel/ksyms.c linux-2.4.19-dm/kernel/ksyms.c
+diff -ruN linux-2.4.19/kernel/ksyms.c linux-2.4.19-dm-test1/kernel/ksyms.c
 --- linux-2.4.19/kernel/ksyms.c        Wed Aug 14 11:52:12 2002
-+++ linux-2.4.19-dm/kernel/ksyms.c     Wed Aug 14 17:43:23 2002
++++ linux-2.4.19-dm-test1/kernel/ksyms.c       Wed Nov 13 19:34:39 2002
 @@ -109,6 +109,7 @@
  EXPORT_SYMBOL(vfree);
  EXPORT_SYMBOL(__vmalloc);
@@ -6851,9 +6972,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  EXPORT_SYMBOL(mem_map);
  EXPORT_SYMBOL(remap_page_range);
  EXPORT_SYMBOL(max_mapnr);
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/mm/Makefile linux-2.4.19-dm/mm/Makefile
+diff -ruN linux-2.4.19/mm/Makefile linux-2.4.19-dm-test1/mm/Makefile
 --- linux-2.4.19/mm/Makefile   Wed Aug 14 11:52:12 2002
-+++ linux-2.4.19-dm/mm/Makefile        Wed Aug 14 17:43:15 2002
++++ linux-2.4.19-dm-test1/mm/Makefile  Wed Nov 13 19:04:52 2002
 @@ -9,12 +9,12 @@
  
  O_TARGET := mm.o
@@ -6869,9 +6990,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
  
  obj-$(CONFIG_HIGHMEM) += highmem.o
  
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/mm/mempool.c linux-2.4.19-dm/mm/mempool.c
+diff -ruN linux-2.4.19/mm/mempool.c linux-2.4.19-dm-test1/mm/mempool.c
 --- linux-2.4.19/mm/mempool.c  Thu Jan  1 01:00:00 1970
-+++ linux-2.4.19-dm/mm/mempool.c       Wed Aug 14 17:43:19 2002
++++ linux-2.4.19-dm-test1/mm/mempool.c Wed Nov 13 19:04:55 2002
 @@ -0,0 +1,295 @@
 +/*
 + *  linux/mm/mempool.c
@@ -7168,9 +7289,9 @@ diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -r
 +EXPORT_SYMBOL(mempool_alloc_slab);
 +EXPORT_SYMBOL(mempool_free_slab);
 +
-diff --exclude .depend --exclude BitKeeper --exclude SCCS --exclude ChangeSet -ruN linux-2.4.19/mm/vmalloc.c linux-2.4.19-dm/mm/vmalloc.c
+diff -ruN linux-2.4.19/mm/vmalloc.c linux-2.4.19-dm-test1/mm/vmalloc.c
 --- linux-2.4.19/mm/vmalloc.c  Wed Aug 14 11:52:13 2002
-+++ linux-2.4.19-dm/mm/vmalloc.c       Wed Aug 14 17:43:23 2002
++++ linux-2.4.19-dm-test1/mm/vmalloc.c Wed Nov 13 19:05:03 2002
 @@ -321,3 +321,22 @@
        read_unlock(&vmlist_lock);
        return buf - buf_start;
This page took 0.272756 seconds and 5 git commands to generate.