diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in
--- linux-2.4.16/drivers/md/Config.in Fri Sep 14 22:22:18 2001
-+++ linux/drivers/md/Config.in Mon Jan 14 14:33:57 2002
++++ linux/drivers/md/Config.in Tue Jan 15 15:37:33 2002
@@ -14,5 +14,6 @@
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
endmenu
diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile
--- linux-2.4.16/drivers/md/Makefile Thu Dec 6 15:57:55 2001
-+++ linux/drivers/md/Makefile Mon Jan 14 14:33:57 2002
++++ linux/drivers/md/Makefile Tue Jan 15 15:37:33 2002
@@ -4,9 +4,12 @@
O_TARGET := mddev.o
+EXPORT_SYMBOL(dm_unregister_target);
diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c
--- linux-2.4.16/drivers/md/dm.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.c Mon Jan 14 14:33:44 2002
-@@ -0,0 +1,1025 @@
++++ linux/drivers/md/dm.c Tue Jan 15 15:37:16 2002
+@@ -0,0 +1,1031 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+#define DEFAULT_READ_AHEAD 64
+
+static const char *_name = DM_NAME;
-+static const char *_version = "0.92.02-fs (2002-01-14)";
++static const char *_version = "0.94.00-fs (2002-01-15)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int major = 0;
+ dm_lock_r();
+
+ md = _devs[minor];
-+ __dm_get(md);
+ if (!md)
-+ goto bad;
++ goto bad_no_put;
++
++ __dm_get(md);
+
+ /*
+ * If we're suspended we have to queue
+ buffer_IO_error(bh);
+ return 0;
+
++ bad_no_put:
++ dm_unlock_r();
++ buffer_IO_error(bh);
++ return 0;
++
+ bad_no_lock:
+ dm_put(md);
+ buffer_IO_error(bh);
+#endif /* LINUX_DMFS_H */
diff -ruN linux-2.4.16/fs/namespace.c linux/fs/namespace.c
--- linux-2.4.16/fs/namespace.c Thu Dec 6 15:57:56 2001
-+++ linux/fs/namespace.c Mon Jan 14 14:33:57 2002
++++ linux/fs/namespace.c Tue Jan 15 15:37:33 2002
@@ -332,7 +332,7 @@
}
}
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.16/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.16/include/linux/fs.h Thu Dec 6 15:57:58 2001
-+++ linux/include/linux/fs.h Mon Jan 14 14:33:57 2002
++++ linux/include/linux/fs.h Tue Jan 15 15:37:33 2002
@@ -980,6 +980,7 @@
extern struct vfsmount *kern_mount(struct file_system_type *);
extern int may_umount(struct vfsmount *);
diff -ruN linux-2.4.16/include/linux/seq_file.h linux/include/linux/seq_file.h
--- linux-2.4.16/include/linux/seq_file.h Thu Dec 6 15:57:56 2001
-+++ linux/include/linux/seq_file.h Mon Jan 14 14:33:57 2002
++++ linux/include/linux/seq_file.h Tue Jan 15 15:37:33 2002
@@ -12,6 +12,7 @@
loff_t index;
struct semaphore sem;
struct seq_operations {
diff -ruN linux-2.4.16/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.16/kernel/ksyms.c Thu Dec 6 15:57:56 2001
-+++ linux/kernel/ksyms.c Mon Jan 14 14:33:57 2002
++++ linux/kernel/ksyms.c Tue Jan 15 15:37:33 2002
@@ -46,6 +46,7 @@
#include <linux/tty.h>
#include <linux/in6.h>
diff -ruN linux-2.4.16/drivers/md/Config.in linux/drivers/md/Config.in
--- linux-2.4.16/drivers/md/Config.in Fri Sep 14 22:22:18 2001
-+++ linux/drivers/md/Config.in Mon Jan 14 14:33:42 2002
++++ linux/drivers/md/Config.in Tue Jan 15 15:37:14 2002
@@ -14,5 +14,6 @@
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
endmenu
diff -ruN linux-2.4.16/drivers/md/Makefile linux/drivers/md/Makefile
--- linux-2.4.16/drivers/md/Makefile Thu Dec 6 15:57:55 2001
-+++ linux/drivers/md/Makefile Mon Jan 14 14:33:42 2002
++++ linux/drivers/md/Makefile Tue Jan 15 15:37:14 2002
@@ -4,9 +4,11 @@
O_TARGET := mddev.o
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.16/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c
--- linux-2.4.16/drivers/md/dm-ioctl.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-ioctl.c Mon Jan 14 13:46:17 2002
-@@ -0,0 +1,419 @@
++++ linux/drivers/md/dm-ioctl.c Tue Jan 15 14:22:17 2002
+@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ vfree(p);
+}
+
++static int version(struct dm_ioctl *user)
++{
++ return copy_to_user(user, DM_IOCTL_VERSION, sizeof(DM_IOCTL_VERSION));
++}
++
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **result)
+{
+ struct dm_ioctl tmp, *dmi;
+ if (copy_from_user(&tmp, user, sizeof(tmp)))
+ return -EFAULT;
+
++ if (strcmp(DM_IOCTL_VERSION, tmp.version)) {
++ DMWARN("dm_ctl_ioctl: struct dm_ioctl version incompatible");
++ return -EINVAL;
++ }
++
+ if (tmp.data_size < sizeof(tmp))
+ return -EINVAL;
+
+ if (!dmi)
+ return -ENOMEM;
+
-+ if (copy_from_user(dmi, user, tmp.data_size))
++ if (copy_from_user(dmi, user, tmp.data_size)) {
++ vfree(dmi);
+ return -EFAULT;
++ }
+
+ *result = dmi;
+ return 0;
+ return -EINVAL;
+}
+
-+static int first_target(struct dm_ioctl *a, void *begin, void *end,
-+ struct dm_target_spec **spec, char **params)
-+{
-+ *spec = (struct dm_target_spec *) (a + 1);
-+ *params = (char *) (*spec + 1);
-+
-+ return valid_str(*params, begin, end);
-+}
-+
-+static int next_target(struct dm_target_spec *last, void *begin, void *end,
++static int next_target(struct dm_target_spec *last, unsigned long next,
++ void *begin, void *end,
+ struct dm_target_spec **spec, char **params)
+{
+ *spec = (struct dm_target_spec *)
-+ (((unsigned char *) last) + last->next);
++ ((unsigned char *) last + next);
+ *params = (char *) (*spec + 1);
+
+ if (*spec < (last + 1) || ((void *)*spec > end))
+
+ for (i = 0; i < args->target_count; i++) {
+
-+ r = first ? first_target(args, begin, end, &spec, ¶ms) :
-+ next_target(spec, begin, end, &spec, ¶ms);
++ r = first ? next_target((struct dm_target_spec *)args,
++ args->data_start,
++ begin, end, &spec, ¶ms) :
++ next_target(spec, spec->next,
++ begin, end, &spec, ¶ms);
+
+ if (r)
+ PARSE_ERROR("unable to find target");
+ struct dm_ioctl param;
+ struct mapped_device *md = dm_get(name);
+
-+ if (!md) {
-+ param.exists = 0;
++ param.flags = 0;
++
++ strncpy(param.version, DM_IOCTL_VERSION, sizeof(param.version));
++
++ if (!md)
+ goto out;
-+ }
++
++ param.flags |= DM_EXISTS_FLAG;
++ if (md->suspended)
++ param.flags |= DM_SUSPEND_FLAG;
++ if (md->read_only)
++ param.flags |= DM_READONLY_FLAG;
+
+ param.data_size = 0;
+ strncpy(param.name, md->name, sizeof(param.name));
+ param.name[sizeof(param.name) - 1] = '\0';
-+ param.exists = 1;
-+ param.suspend = md->suspended;
++
+ param.open_count = md->use_count;
-+ param.major = MAJOR(md->dev);
-+ param.minor = MINOR(md->dev);
++ param.dev = kdev_t_to_nr(md->dev);
+ param.target_count = md->map->num_targets;
+
+ dm_put(md);
+ int r;
+ struct mapped_device *md;
+ struct dm_table *t;
++ int minor;
+
+ r = dm_table_create(&t);
+ if (r)
+ if (r)
+ goto bad;
+
-+ r = dm_create(param->name, param->minor, t, &md);
++ minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
++ minor = MINOR(to_kdev_t(param->dev)) : -1;
++
++ r = dm_create(param->name, minor, t, &md);
+ if (r)
+ goto bad;
+
-+ dm_set_ro(md, param->read_only);
++ dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+
+ r = info(param->name, user);
+ if (r) {
+ if (!md)
+ return -ENXIO;
+
-+ r = param->suspend ? dm_suspend(md) : dm_resume(md);
++ r = (param->flags & DM_SUSPEND_FLAG) ?
++ dm_suspend(md) : dm_resume(md);
+ dm_put(md);
+ return r;
+}
+ if (r)
+ goto bad;
+
-+ dm_set_ro(md, param->read_only);
++ dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+
+ dm_put(md);
+ return 0;
+
+static int rename(struct dm_ioctl *param)
+{
-+ char *newname = (char *) (param + 1);
++ char *newname = (char *) param + param->data_start;
+ struct mapped_device *md = dm_get(param->name);
+
+ if (!md)
+ int r;
+ struct dm_ioctl *p;
+
++ if (command == DM_VERSION)
++ return version((struct dm_ioctl *) a);
++
+ r = copy_params((struct dm_ioctl *) a, &p);
+ if (r)
+ return r;
+
-+ if (strcmp(DM_IOCTL_VERSION, p->version)) {
-+ DMWARN("dm_ctl_ioctl: struct dm_ioctl version incompatible");
-+ r = -EINVAL;
-+ goto out;
-+ }
-+
+ switch (command) {
+ case DM_CREATE:
+ r = create(p, (struct dm_ioctl *) a);
+ r = -EINVAL;
+ }
+
-+ out:
+ free_params(p);
+ return r;
+}
+EXPORT_SYMBOL(dm_unregister_target);
diff -ruN linux-2.4.16/drivers/md/dm.c linux/drivers/md/dm.c
--- linux-2.4.16/drivers/md/dm.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.c Mon Jan 14 14:33:31 2002
-@@ -0,0 +1,1025 @@
++++ linux/drivers/md/dm.c Tue Jan 15 15:36:49 2002
+@@ -0,0 +1,1031 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+#define DEFAULT_READ_AHEAD 64
+
+static const char *_name = DM_NAME;
-+static const char *_version = "0.92.02-ioctl (2002-01-14)";
++static const char *_version = "0.94.00-ioctl (2002-01-15)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int major = 0;
+ dm_lock_r();
+
+ md = _devs[minor];
-+ __dm_get(md);
+ if (!md)
-+ goto bad;
++ goto bad_no_put;
++
++ __dm_get(md);
+
+ /*
+ * If we're suspended we have to queue
+ buffer_IO_error(bh);
+ return 0;
+
++ bad_no_put:
++ dm_unlock_r();
++ buffer_IO_error(bh);
++ return 0;
++
+ bad_no_lock:
+ dm_put(md);
+ buffer_IO_error(bh);
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.16/include/linux/dm-ioctl.h linux/include/linux/dm-ioctl.h
--- linux-2.4.16/include/linux/dm-ioctl.h Thu Jan 1 01:00:00 1970
-+++ linux/include/linux/dm-ioctl.h Mon Jan 14 14:33:31 2002
-@@ -0,0 +1,59 @@
++++ linux/include/linux/dm-ioctl.h Tue Jan 15 15:36:49 2002
+@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+};
+
+struct dm_ioctl {
-+ unsigned long data_size; /* the size of this structure */
+ char version[16];
-+ char name[DM_NAME_LEN];
+
-+ int exists; /* out */
-+ int suspend; /* in/out */
-+ int open_count; /* out */
-+ int major; /* out */
-+ int minor; /* in/out */
-+ int read_only; /* in/out */
++ unsigned long data_size; /* total size of data passed in */
++ /* including this struct */
++
++ unsigned long data_start; /* offset to start of data */
++ /* relative to start of this struct */
++
++ char name[DM_NAME_LEN]; /* device name */
+
-+ int target_count; /* in/out */
++ unsigned int target_count; /* in/out */
++ unsigned int open_count; /* out */
++ unsigned int flags; /* in/out */
++
++ __kernel_dev_t dev; /* in/out */
+};
+
-+/* FIXME: find own numbers: LVM1 used 109 */
+#define DM_IOCTL 0xfd
+
+#define DM_CREATE _IOWR(DM_IOCTL, 0x00, struct dm_ioctl)
+#define DM_REMOVE _IOW(DM_IOCTL, 0x01, struct dm_ioctl)
+#define DM_SUSPEND _IOW(DM_IOCTL, 0x02, struct dm_ioctl)
-+#define DM_RELOAD _IOWR(DM_IOCTL, 0x03, struct dm_ioctl)
++#define DM_RELOAD _IOW(DM_IOCTL, 0x03, struct dm_ioctl)
+#define DM_INFO _IOWR(DM_IOCTL, 0x04, struct dm_ioctl)
-+#define DM_RENAME _IOWR(DM_IOCTL, 0x05, struct dm_ioctl)
++#define DM_RENAME _IOW(DM_IOCTL, 0x05, struct dm_ioctl)
++#define DM_VERSION _IOR(DM_IOCTL, 0x06, struct dm_ioctl)
++
++#define DM_IOCTL_VERSION "0.94"
+
-+#define DM_IOCTL_VERSION "0.92"
++/* Status bits */
++#define DM_READONLY_FLAG 0x00000001
++#define DM_SUSPEND_FLAG 0x00000002
++#define DM_EXISTS_FLAG 0x00000004
++#define DM_PERSISTENT_DEV_FLAG 0x00000008
+
+#endif /* _LINUX_DM_IOCTL_H */
diff -ruN linux-2.4.17/drivers/md/Config.in linux/drivers/md/Config.in
--- linux-2.4.17/drivers/md/Config.in Fri Sep 14 22:22:18 2001
-+++ linux/drivers/md/Config.in Mon Jan 14 14:34:19 2002
++++ linux/drivers/md/Config.in Tue Jan 15 15:38:04 2002
@@ -14,5 +14,6 @@
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
endmenu
diff -ruN linux-2.4.17/drivers/md/Makefile linux/drivers/md/Makefile
--- linux-2.4.17/drivers/md/Makefile Thu Dec 6 15:57:55 2001
-+++ linux/drivers/md/Makefile Mon Jan 14 14:34:19 2002
++++ linux/drivers/md/Makefile Tue Jan 15 15:38:04 2002
@@ -4,9 +4,12 @@
O_TARGET := mddev.o
+EXPORT_SYMBOL(dm_unregister_target);
diff -ruN linux-2.4.17/drivers/md/dm.c linux/drivers/md/dm.c
--- linux-2.4.17/drivers/md/dm.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.c Mon Jan 14 14:34:09 2002
-@@ -0,0 +1,1025 @@
++++ linux/drivers/md/dm.c Tue Jan 15 15:37:53 2002
+@@ -0,0 +1,1031 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+#define DEFAULT_READ_AHEAD 64
+
+static const char *_name = DM_NAME;
-+static const char *_version = "0.92.02-fs (2002-01-14)";
++static const char *_version = "0.94.00-fs (2002-01-15)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int major = 0;
+ dm_lock_r();
+
+ md = _devs[minor];
-+ __dm_get(md);
+ if (!md)
-+ goto bad;
++ goto bad_no_put;
++
++ __dm_get(md);
+
+ /*
+ * If we're suspended we have to queue
+ buffer_IO_error(bh);
+ return 0;
+
++ bad_no_put:
++ dm_unlock_r();
++ buffer_IO_error(bh);
++ return 0;
++
+ bad_no_lock:
+ dm_put(md);
+ buffer_IO_error(bh);
+#endif /* LINUX_DMFS_H */
diff -ruN linux-2.4.17/fs/namespace.c linux/fs/namespace.c
--- linux-2.4.17/fs/namespace.c Wed Jan 2 19:10:48 2002
-+++ linux/fs/namespace.c Mon Jan 14 14:34:19 2002
++++ linux/fs/namespace.c Tue Jan 15 15:38:04 2002
@@ -289,7 +289,7 @@
}
}
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.17/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.17/include/linux/fs.h Wed Jan 2 19:10:48 2002
-+++ linux/include/linux/fs.h Mon Jan 14 14:34:19 2002
++++ linux/include/linux/fs.h Tue Jan 15 15:38:04 2002
@@ -983,6 +983,7 @@
extern struct vfsmount *kern_mount(struct file_system_type *);
extern int may_umount(struct vfsmount *);
diff -ruN linux-2.4.17/include/linux/seq_file.h linux/include/linux/seq_file.h
--- linux-2.4.17/include/linux/seq_file.h Thu Dec 6 15:57:56 2001
-+++ linux/include/linux/seq_file.h Mon Jan 14 14:34:19 2002
++++ linux/include/linux/seq_file.h Tue Jan 15 15:38:04 2002
@@ -12,6 +12,7 @@
loff_t index;
struct semaphore sem;
struct seq_operations {
diff -ruN linux-2.4.17/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.17/kernel/ksyms.c Wed Jan 2 19:10:49 2002
-+++ linux/kernel/ksyms.c Mon Jan 14 14:34:19 2002
++++ linux/kernel/ksyms.c Tue Jan 15 15:38:04 2002
@@ -324,6 +324,7 @@
EXPORT_SYMBOL(register_filesystem);
EXPORT_SYMBOL(unregister_filesystem);
diff -ruN linux-2.4.17/drivers/md/Config.in linux/drivers/md/Config.in
--- linux-2.4.17/drivers/md/Config.in Fri Sep 14 22:22:18 2001
-+++ linux/drivers/md/Config.in Mon Jan 14 14:34:08 2002
++++ linux/drivers/md/Config.in Tue Jan 15 15:37:51 2002
@@ -14,5 +14,6 @@
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
endmenu
diff -ruN linux-2.4.17/drivers/md/Makefile linux/drivers/md/Makefile
--- linux-2.4.17/drivers/md/Makefile Thu Dec 6 15:57:55 2001
-+++ linux/drivers/md/Makefile Mon Jan 14 14:34:08 2002
++++ linux/drivers/md/Makefile Tue Jan 15 15:37:51 2002
@@ -4,9 +4,11 @@
O_TARGET := mddev.o
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.17/drivers/md/dm-ioctl.c linux/drivers/md/dm-ioctl.c
--- linux-2.4.17/drivers/md/dm-ioctl.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-ioctl.c Mon Jan 14 13:46:17 2002
-@@ -0,0 +1,419 @@
++++ linux/drivers/md/dm-ioctl.c Tue Jan 15 14:22:17 2002
+@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ vfree(p);
+}
+
++static int version(struct dm_ioctl *user)
++{
++ return copy_to_user(user, DM_IOCTL_VERSION, sizeof(DM_IOCTL_VERSION));
++}
++
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **result)
+{
+ struct dm_ioctl tmp, *dmi;
+ if (copy_from_user(&tmp, user, sizeof(tmp)))
+ return -EFAULT;
+
++ if (strcmp(DM_IOCTL_VERSION, tmp.version)) {
++ DMWARN("dm_ctl_ioctl: struct dm_ioctl version incompatible");
++ return -EINVAL;
++ }
++
+ if (tmp.data_size < sizeof(tmp))
+ return -EINVAL;
+
+ if (!dmi)
+ return -ENOMEM;
+
-+ if (copy_from_user(dmi, user, tmp.data_size))
++ if (copy_from_user(dmi, user, tmp.data_size)) {
++ vfree(dmi);
+ return -EFAULT;
++ }
+
+ *result = dmi;
+ return 0;
+ return -EINVAL;
+}
+
-+static int first_target(struct dm_ioctl *a, void *begin, void *end,
-+ struct dm_target_spec **spec, char **params)
-+{
-+ *spec = (struct dm_target_spec *) (a + 1);
-+ *params = (char *) (*spec + 1);
-+
-+ return valid_str(*params, begin, end);
-+}
-+
-+static int next_target(struct dm_target_spec *last, void *begin, void *end,
++static int next_target(struct dm_target_spec *last, unsigned long next,
++ void *begin, void *end,
+ struct dm_target_spec **spec, char **params)
+{
+ *spec = (struct dm_target_spec *)
-+ (((unsigned char *) last) + last->next);
++ ((unsigned char *) last + next);
+ *params = (char *) (*spec + 1);
+
+ if (*spec < (last + 1) || ((void *)*spec > end))
+
+ for (i = 0; i < args->target_count; i++) {
+
-+ r = first ? first_target(args, begin, end, &spec, ¶ms) :
-+ next_target(spec, begin, end, &spec, ¶ms);
++ r = first ? next_target((struct dm_target_spec *)args,
++ args->data_start,
++ begin, end, &spec, ¶ms) :
++ next_target(spec, spec->next,
++ begin, end, &spec, ¶ms);
+
+ if (r)
+ PARSE_ERROR("unable to find target");
+ struct dm_ioctl param;
+ struct mapped_device *md = dm_get(name);
+
-+ if (!md) {
-+ param.exists = 0;
++ param.flags = 0;
++
++ strncpy(param.version, DM_IOCTL_VERSION, sizeof(param.version));
++
++ if (!md)
+ goto out;
-+ }
++
++ param.flags |= DM_EXISTS_FLAG;
++ if (md->suspended)
++ param.flags |= DM_SUSPEND_FLAG;
++ if (md->read_only)
++ param.flags |= DM_READONLY_FLAG;
+
+ param.data_size = 0;
+ strncpy(param.name, md->name, sizeof(param.name));
+ param.name[sizeof(param.name) - 1] = '\0';
-+ param.exists = 1;
-+ param.suspend = md->suspended;
++
+ param.open_count = md->use_count;
-+ param.major = MAJOR(md->dev);
-+ param.minor = MINOR(md->dev);
++ param.dev = kdev_t_to_nr(md->dev);
+ param.target_count = md->map->num_targets;
+
+ dm_put(md);
+ int r;
+ struct mapped_device *md;
+ struct dm_table *t;
++ int minor;
+
+ r = dm_table_create(&t);
+ if (r)
+ if (r)
+ goto bad;
+
-+ r = dm_create(param->name, param->minor, t, &md);
++ minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
++ minor = MINOR(to_kdev_t(param->dev)) : -1;
++
++ r = dm_create(param->name, minor, t, &md);
+ if (r)
+ goto bad;
+
-+ dm_set_ro(md, param->read_only);
++ dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+
+ r = info(param->name, user);
+ if (r) {
+ if (!md)
+ return -ENXIO;
+
-+ r = param->suspend ? dm_suspend(md) : dm_resume(md);
++ r = (param->flags & DM_SUSPEND_FLAG) ?
++ dm_suspend(md) : dm_resume(md);
+ dm_put(md);
+ return r;
+}
+ if (r)
+ goto bad;
+
-+ dm_set_ro(md, param->read_only);
++ dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+
+ dm_put(md);
+ return 0;
+
+static int rename(struct dm_ioctl *param)
+{
-+ char *newname = (char *) (param + 1);
++ char *newname = (char *) param + param->data_start;
+ struct mapped_device *md = dm_get(param->name);
+
+ if (!md)
+ int r;
+ struct dm_ioctl *p;
+
++ if (command == DM_VERSION)
++ return version((struct dm_ioctl *) a);
++
+ r = copy_params((struct dm_ioctl *) a, &p);
+ if (r)
+ return r;
+
-+ if (strcmp(DM_IOCTL_VERSION, p->version)) {
-+ DMWARN("dm_ctl_ioctl: struct dm_ioctl version incompatible");
-+ r = -EINVAL;
-+ goto out;
-+ }
-+
+ switch (command) {
+ case DM_CREATE:
+ r = create(p, (struct dm_ioctl *) a);
+ r = -EINVAL;
+ }
+
-+ out:
+ free_params(p);
+ return r;
+}
+EXPORT_SYMBOL(dm_unregister_target);
diff -ruN linux-2.4.17/drivers/md/dm.c linux/drivers/md/dm.c
--- linux-2.4.17/drivers/md/dm.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.c Mon Jan 14 14:33:59 2002
-@@ -0,0 +1,1025 @@
++++ linux/drivers/md/dm.c Tue Jan 15 15:37:35 2002
+@@ -0,0 +1,1031 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+#define DEFAULT_READ_AHEAD 64
+
+static const char *_name = DM_NAME;
-+static const char *_version = "0.92.02-ioctl (2002-01-14)";
++static const char *_version = "0.94.00-ioctl (2002-01-15)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int major = 0;
+ dm_lock_r();
+
+ md = _devs[minor];
-+ __dm_get(md);
+ if (!md)
-+ goto bad;
++ goto bad_no_put;
++
++ __dm_get(md);
+
+ /*
+ * If we're suspended we have to queue
+ buffer_IO_error(bh);
+ return 0;
+
++ bad_no_put:
++ dm_unlock_r();
++ buffer_IO_error(bh);
++ return 0;
++
+ bad_no_lock:
+ dm_put(md);
+ buffer_IO_error(bh);
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.17/include/linux/dm-ioctl.h linux/include/linux/dm-ioctl.h
--- linux-2.4.17/include/linux/dm-ioctl.h Thu Jan 1 01:00:00 1970
-+++ linux/include/linux/dm-ioctl.h Mon Jan 14 14:33:59 2002
-@@ -0,0 +1,59 @@
++++ linux/include/linux/dm-ioctl.h Tue Jan 15 15:37:35 2002
+@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+};
+
+struct dm_ioctl {
-+ unsigned long data_size; /* the size of this structure */
+ char version[16];
-+ char name[DM_NAME_LEN];
+
-+ int exists; /* out */
-+ int suspend; /* in/out */
-+ int open_count; /* out */
-+ int major; /* out */
-+ int minor; /* in/out */
-+ int read_only; /* in/out */
++ unsigned long data_size; /* total size of data passed in */
++ /* including this struct */
++
++ unsigned long data_start; /* offset to start of data */
++ /* relative to start of this struct */
++
++ char name[DM_NAME_LEN]; /* device name */
+
-+ int target_count; /* in/out */
++ unsigned int target_count; /* in/out */
++ unsigned int open_count; /* out */
++ unsigned int flags; /* in/out */
++
++ __kernel_dev_t dev; /* in/out */
+};
+
-+/* FIXME: find own numbers: LVM1 used 109 */
+#define DM_IOCTL 0xfd
+
+#define DM_CREATE _IOWR(DM_IOCTL, 0x00, struct dm_ioctl)
+#define DM_REMOVE _IOW(DM_IOCTL, 0x01, struct dm_ioctl)
+#define DM_SUSPEND _IOW(DM_IOCTL, 0x02, struct dm_ioctl)
-+#define DM_RELOAD _IOWR(DM_IOCTL, 0x03, struct dm_ioctl)
++#define DM_RELOAD _IOW(DM_IOCTL, 0x03, struct dm_ioctl)
+#define DM_INFO _IOWR(DM_IOCTL, 0x04, struct dm_ioctl)
-+#define DM_RENAME _IOWR(DM_IOCTL, 0x05, struct dm_ioctl)
++#define DM_RENAME _IOW(DM_IOCTL, 0x05, struct dm_ioctl)
++#define DM_VERSION _IOR(DM_IOCTL, 0x06, struct dm_ioctl)
++
++#define DM_IOCTL_VERSION "0.94"
+
-+#define DM_IOCTL_VERSION "0.92"
++/* Status bits */
++#define DM_READONLY_FLAG 0x00000001
++#define DM_SUSPEND_FLAG 0x00000002
++#define DM_EXISTS_FLAG 0x00000004
++#define DM_PERSISTENT_DEV_FLAG 0x00000008
+
+#endif /* _LINUX_DM_IOCTL_H */