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 Thu Dec 20 20:11:26 2001
++++ linux/drivers/md/Config.in Fri Dec 21 20:26:01 2001
@@ -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 Thu Dec 20 20:11:27 2001
++++ linux/drivers/md/Makefile Fri Dec 21 20:26:01 2001
@@ -4,9 +4,12 @@
O_TARGET := mddev.o
+
diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper.h
--- linux-2.4.16/drivers/md/device-mapper.h Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/device-mapper.h Wed Dec 19 19:42:09 2001
++++ linux/drivers/md/device-mapper.h Fri Dec 21 18:44:59 2001
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Prototypes for functions for a target
+ */
+typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context);
++ 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);
+void dm_error(const char *message);
+
+/*
-+ * Contructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * Constructors should call these functions to ensure destination devices
++ * are opened/closed correctly
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+ offset_t start, offset_t len, struct dm_dev **result);
+#endif /* _LINUX_DEVICE_MAPPER_H */
diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c
--- linux-2.4.16/drivers/md/dm-linear.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-linear.c Thu Dec 20 12:23:38 2001
-@@ -0,0 +1,118 @@
++++ linux/drivers/md/dm-linear.c Fri Dec 21 19:38:40 2001
+@@ -0,0 +1,117 @@
+/*
-+ * dm-linear.c
-+ *
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ * Construct a linear mapping: <dev_path> <offset>
+ */
+static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **argv, void **context)
+{
+ struct linear_c *lc;
-+ unsigned long start; /* FIXME: unsigned long long with sscanf fix */
++ unsigned long start; /* FIXME: unsigned long long */
++ char *end;
+
-+ int r = -EINVAL;
-+ char path[4096];
++ if (argc != 2) {
++ *context = "dm-linear: Not enough arguments";
++ return -EINVAL;
++ }
+
+ lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+ if (lc == NULL) {
+ return -ENOMEM;
+ }
+
-+ if (sscanf(args, "%4096s %lu", path, &start) != 2) {
-+ *context = "dm-linear: Missing target parms: dev_path sector";
-+ return -ENOMEM;
-+ }
++ start = simple_strtoul(argv[1], &end, 10);
++ if (*end) {
++ *context = "dm-linear: Invalid device sector";
++ goto bad;
++ }
+
-+ r = dm_table_get_device(t, path, start, l, &lc->dev);
-+ if (r) {
++ if (dm_table_get_device(t, argv[0], start, l, &lc->dev)) {
+ *context = "dm-linear: Device lookup failed";
-+ r = -ENXIO;
+ goto bad;
+ }
+
+
+ bad:
+ kfree(lc);
-+ return r;
++ return -EINVAL;
+}
+
+static void linear_dtr(struct dm_table *t, void *c)
+ ctr: linear_ctr,
+ dtr: linear_dtr,
+ map: linear_map,
-+ err: NULL
+};
+
+static int __init linear_init(void)
+ int r = dm_register_target(&linear_target);
+
+ if (r < 0)
-+ printk(KERN_ERR
-+ "Device mapper: Linear: register failed %d\n", r);
++ printk(KERN_ERR "Device mapper: Linear: "
++ "register failed %d\n", r);
+
+ return r;
+}
+ int r = dm_unregister_target(&linear_target);
+
+ if (r < 0)
-+ printk(KERN_ERR
-+ "Device mapper: Linear: unregister failed %d\n", r);
++ printk(KERN_ERR "Device mapper: Linear: "
++ "unregister failed %d\n", r);
+}
+
+module_init(linear_init);
+MODULE_LICENSE("GPL");
diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c
--- linux-2.4.16/drivers/md/dm-stripe.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-stripe.c Wed Dec 19 20:33:01 2001
-@@ -0,0 +1,192 @@
++++ linux/drivers/md/dm-stripe.c Fri Dec 21 19:09:00 2001
+@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * Parse a single <dev> <sector> pair
+ */
+static int get_stripe(struct dm_table *t, struct stripe_c *sc,
-+ int stripe, const char *args)
++ int stripe, char **argv)
+{
-+ int n, r;
-+ char path[4096];
++ char *end;
+ unsigned long start;
+
-+ if (sscanf(args, "%4096s %lu %n", path, &start, &n) != 2)
++ start = simple_strtoul(argv[1], &end, 10);
++ if (*end)
+ return -EINVAL;
+
-+ r = dm_table_get_device(t, path, start, sc->stripe_width,
-+ &sc->stripe[stripe].dev);
-+ if (r)
++ if (dm_table_get_device(t, argv[0], start, sc->stripe_width,
++ &sc->stripe[stripe].dev))
+ return -ENXIO;
+
+ sc->stripe[stripe].physical_start = start;
-+ return n;
++ return 0;
+}
+
+/*
+ * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
+ */
+static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **argv, void **context)
+{
+ struct stripe_c *sc;
+ uint32_t stripes;
+ uint32_t chunk_size;
-+ int n, i;
++ char *end;
++ int r, i;
+
-+ if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) {
-+ *context = "dm-stripe: Couldn't parse <stripes> <chunk size>";
++ if (argc < 2) {
++ *context = "dm-stripe: Not enough arguments";
++ return -EINVAL;
++ }
++
++ stripes = simple_strtoul(argv[0], &end, 10);
++ if (*end) {
++ *context = "dm-stripe: Invalid stripe count";
++ return -EINVAL;
++ }
++
++ chunk_size =simple_strtoul(argv[1], &end, 10);
++ if (*end) {
++ *context = "dm-stripe: Invalid chunk_size";
+ return -EINVAL;
+ }
+
+
+ sc = alloc_context(stripes);
+ if (!sc) {
-+ *context = "dm-stripe: Memory allocation for striped context"
++ *context = "dm-stripe: Memory allocation for striped context "
+ "failed";
+ return -ENOMEM;
+ }
+ /*
+ * chunk_size is a power of two
+ */
-+ if (!chunk_size || chunk_size & (chunk_size - 1)) {
++ if (!chunk_size || (chunk_size & (chunk_size - 1))) {
+ *context = "dm-stripe: Invalid chunk size";
+ kfree(sc);
+ return -EINVAL;
+ * Get the stripe destinations.
+ */
+ for (i = 0; i < stripes; i++) {
-+ args += n;
-+ n = get_stripe(t, sc, i, args);
++ if (argc < 2) {
++ *context = "dm-stripe: Not enough destinations "
++ "specified";
++ kfree(sc);
++ return -EINVAL;
++ }
++
++ argv += 2;
+
-+ if (n < 0) {
++ r = get_stripe(t, sc, i, argv);
++ if (r < 0) {
+ *context = "dm-stripe: Couldn't parse stripe "
+ "destination";
+ kfree(sc);
-+ return n;
++ return r;
+ }
+ }
+
+ ctr: stripe_ctr,
+ dtr: stripe_dtr,
+ map: stripe_map,
-+ err: NULL
+};
+
+static int __init stripe_init(void)
+EXPORT_SYMBOL(dm_table_put_device);
diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c
--- linux-2.4.16/drivers/md/dm-target.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-target.c Wed Dec 19 19:57:41 2001
-@@ -0,0 +1,190 @@
++++ linux/drivers/md/dm-target.c Fri Dec 21 19:29:01 2001
+@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited
+ *
+
+#define DM_MOD_NAME_SIZE 32
+
++/*
++ * Destructively splits up the argument list to pass to ctr.
++ */
++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;
++
++ /* terminate the string and put it in the array */
++ *out = '\0';
++ end++;
++ argv[*argc] = start;
++ (*argc)++;
++ }
++
++ return 0;
++}
++
+static inline struct tt_internal *__find_target_type(const char *name)
+{
+ struct list_head *tih;
+ * up LV's that have holes in them.
+ */
+static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **args, void **context)
+{
+ *context = NULL;
+ return 0;
+ ctr: io_err_ctr,
+ dtr: io_err_dtr,
+ map: io_err_map,
-+ err: NULL
+};
+
+int dm_target_init(void)
+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 Thu Dec 20 20:10:49 2001
++++ linux/drivers/md/dm.c Fri Dec 21 20:25:17 2001
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+#define DEVICE_NAME "device-mapper" /* Name for messaging */
+
+static const char *_name = DEVICE_NAME;
-+static const char *_version = "0.90.03-fs (2001-12-20)";
++static const char *_version = "0.90.04-fs (2001-12-21)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int _major = 0;
+ return 0;
+}
+
-+static void __exit local_exit(void)
++static void local_exit(void)
+{
+ if (kmem_cache_destroy(_io_hook_cache))
+ WARN("it looks like there are still some io_hooks allocated");
+MODULE_LICENSE("GPL");
diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h
--- linux-2.4.16/drivers/md/dm.h Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.h Wed Dec 19 19:42:58 2001
-@@ -0,0 +1,157 @@
++++ linux/drivers/md/dm.h Fri Dec 21 19:28:50 2001
+@@ -0,0 +1,164 @@
+/*
+ * Internal header file for device mapper
+ *
+#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
+
+/*
+ * List of devices that a metadevice uses and should open/close.
+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);
++
++
+/* dm.c */
+struct mapped_device *dm_get(const char *name);
+int dm_create(const char *name, int minor, struct dm_table *table,
+}
diff -ruN linux-2.4.16/drivers/md/dmfs-table.c linux/drivers/md/dmfs-table.c
--- linux-2.4.16/drivers/md/dmfs-table.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dmfs-table.c Thu Dec 20 18:59:15 2001
-@@ -0,0 +1,381 @@
++++ linux/drivers/md/dmfs-table.c Fri Dec 21 19:27:52 2001
+@@ -0,0 +1,388 @@
+/*
+ * dmfs-table.c
+ *
+ char *msg;
+ int pos = 0;
+ char target[33];
++ char *argv[MAX_ARGS];
++ int argc;
+
+ static char *err_table[] = {
+ "Missing/Invalid start argument",
+ msg = "Target type unknown";
+ ttype = dm_get_target_type(target);
+ if (ttype) {
++ msg = "Too many arguments";
++ rv = split_args(MAX_ARGS, &argc, argv, str);
++ if (rv < 0)
++ goto out;
++
+ msg = "This message should never appear (constructor error)";
-+ rv = ttype->ctr(t, start, size, str, &context);
++ rv = ttype->ctr(t, start, size, argc, argv, &context);
+ msg = context;
+ if (rv == 0) {
+ msg = "Error adding target to table";
+#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 Thu Dec 20 20:11:27 2001
++++ linux/fs/namespace.c Fri Dec 21 20:26:01 2001
@@ -332,7 +332,7 @@
}
}
int retval = 0;
diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device-mapper.h
--- linux-2.4.16/include/linux/device-mapper.h Thu Jan 1 01:00:00 1970
-+++ linux/include/linux/device-mapper.h Wed Dec 19 19:42:09 2001
++++ linux/include/linux/device-mapper.h Fri Dec 21 18:44:59 2001
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Prototypes for functions for a target
+ */
+typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context);
++ 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);
+void dm_error(const char *message);
+
+/*
-+ * Contructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * Constructors should call these functions to ensure destination devices
++ * are opened/closed correctly
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+ offset_t start, offset_t len, struct dm_dev **result);
+#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 Thu Dec 20 20:11:27 2001
++++ linux/include/linux/fs.h Fri Dec 21 20:26:01 2001
@@ -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 Thu Dec 20 20:11:27 2001
++++ linux/include/linux/seq_file.h Fri Dec 21 20:26:01 2001
@@ -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 Thu Dec 20 20:11:27 2001
++++ linux/kernel/ksyms.c Fri Dec 21 20:26:01 2001
@@ -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 Thu Dec 20 20:12:07 2001
++++ linux/drivers/md/Config.in Fri Dec 21 20:28:58 2001
@@ -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 Thu Dec 20 20:12:07 2001
++++ linux/drivers/md/Makefile Fri Dec 21 20:28:58 2001
@@ -4,9 +4,11 @@
O_TARGET := mddev.o
+ $(LD) -r -o $@ $(dm-mod-objs)
diff -ruN linux-2.4.16/drivers/md/device-mapper.h linux/drivers/md/device-mapper.h
--- linux-2.4.16/drivers/md/device-mapper.h Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/device-mapper.h Wed Dec 19 19:42:09 2001
++++ linux/drivers/md/device-mapper.h Fri Dec 21 18:44:59 2001
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Prototypes for functions for a target
+ */
+typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context);
++ 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);
+void dm_error(const char *message);
+
+/*
-+ * Contructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * Constructors should call these functions to ensure destination devices
++ * are opened/closed correctly
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+ offset_t start, offset_t len, struct dm_dev **result);
+#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 Thu Dec 20 12:23:14 2001
-@@ -0,0 +1,328 @@
++++ linux/drivers/md/dm-ioctl.c Fri Dec 21 19:29:43 2001
+@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
-+#include <linux/fs.h>
-+
+#include "dm.h"
++
+#include <linux/dm-ioctl.h>
+
+static void free_params(struct dm_ioctl *p)
+ * check a string doesn't overrun the chunk of
+ * memory we copied from userland.
+ */
-+static int valid_str(char *str, void *end)
++static int valid_str(char *str, void *begin, void *end)
+{
-+ while (((void *) str < end) && *str)
++ while (((void *) str >= begin) && ((void *) str < end) && *str)
+ str++;
+
+ return *str ? 0 : 1;
+}
+
-+static int first_target(struct dm_ioctl *a, void *end,
++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, end);
++ return valid_str(*params, begin, end);
+}
+
-+static int next_target(struct dm_target_spec *last, void *end,
++static int next_target(struct dm_target_spec *last, void *begin, void *end,
+ struct dm_target_spec **spec, char **params)
+{
+ *spec = (struct dm_target_spec *)
+ (((unsigned char *) last) + last->next);
+ *params = (char *) (*spec + 1);
+
-+ return valid_str(*params, end);
++ return valid_str(*params, begin, end);
+}
+
+void dm_error(const char *message)
+
+static int populate_table(struct dm_table *table, struct dm_ioctl *args)
+{
-+ int i = 0, r, first = 1;
++ int i = 0, r, first = 1, argc;
+ struct dm_target_spec *spec;
-+ char *params;
++ char *params, *argv[MAX_ARGS];
+ struct target_type *ttype;
-+ void *context, *end;
++ void *context, *begin, *end;
+ offset_t high = 0;
+
+ if (!args->target_count) {
+ return -EINVAL;
+ }
+
-+ end = ((void *) args) + args->data_size;
++ begin = (void *) args;
++ end = begin + args->data_size;
+
+#define PARSE_ERROR(msg) {dm_error(msg); return -EINVAL;}
+
+ for (i = 0; i < args->target_count; i++) {
+
-+ r = first ? first_target(args, end, &spec, ¶ms) :
-+ next_target(spec, end, &spec, ¶ms);
++ r = first ? first_target(args, begin, end, &spec, ¶ms) :
++ next_target(spec, begin, end, &spec, ¶ms);
+
+ if (!r)
+ PARSE_ERROR("unable to find target");
+
-+ /* lookup the target type */
-+ if (!(ttype = dm_get_target_type(spec->target_type)))
++ /* 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");
+
-+ /* build the target */
-+ if (ttype->ctr(table, spec->sector_start, spec->length, params,
-+ &context)) {
++ /* 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)) {
+ dm_error(context);
+ PARSE_ERROR("target constructor failed");
+ }
+
-+ /* add the target to the table */
++ /* Add the target to the table */
+ high = spec->sector_start + (spec->length - 1);
+ if (dm_table_add_target(table, high, ttype, context))
+ PARSE_ERROR("internal error adding target to table");
+}
diff -ruN linux-2.4.16/drivers/md/dm-linear.c linux/drivers/md/dm-linear.c
--- linux-2.4.16/drivers/md/dm-linear.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-linear.c Thu Dec 20 12:23:38 2001
-@@ -0,0 +1,118 @@
++++ linux/drivers/md/dm-linear.c Fri Dec 21 19:38:40 2001
+@@ -0,0 +1,117 @@
+/*
-+ * dm-linear.c
-+ *
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ * Construct a linear mapping: <dev_path> <offset>
+ */
+static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **argv, void **context)
+{
+ struct linear_c *lc;
-+ unsigned long start; /* FIXME: unsigned long long with sscanf fix */
++ unsigned long start; /* FIXME: unsigned long long */
++ char *end;
+
-+ int r = -EINVAL;
-+ char path[4096];
++ if (argc != 2) {
++ *context = "dm-linear: Not enough arguments";
++ return -EINVAL;
++ }
+
+ lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+ if (lc == NULL) {
+ return -ENOMEM;
+ }
+
-+ if (sscanf(args, "%4096s %lu", path, &start) != 2) {
-+ *context = "dm-linear: Missing target parms: dev_path sector";
-+ return -ENOMEM;
-+ }
++ start = simple_strtoul(argv[1], &end, 10);
++ if (*end) {
++ *context = "dm-linear: Invalid device sector";
++ goto bad;
++ }
+
-+ r = dm_table_get_device(t, path, start, l, &lc->dev);
-+ if (r) {
++ if (dm_table_get_device(t, argv[0], start, l, &lc->dev)) {
+ *context = "dm-linear: Device lookup failed";
-+ r = -ENXIO;
+ goto bad;
+ }
+
+
+ bad:
+ kfree(lc);
-+ return r;
++ return -EINVAL;
+}
+
+static void linear_dtr(struct dm_table *t, void *c)
+ ctr: linear_ctr,
+ dtr: linear_dtr,
+ map: linear_map,
-+ err: NULL
+};
+
+static int __init linear_init(void)
+ int r = dm_register_target(&linear_target);
+
+ if (r < 0)
-+ printk(KERN_ERR
-+ "Device mapper: Linear: register failed %d\n", r);
++ printk(KERN_ERR "Device mapper: Linear: "
++ "register failed %d\n", r);
+
+ return r;
+}
+ int r = dm_unregister_target(&linear_target);
+
+ if (r < 0)
-+ printk(KERN_ERR
-+ "Device mapper: Linear: unregister failed %d\n", r);
++ printk(KERN_ERR "Device mapper: Linear: "
++ "unregister failed %d\n", r);
+}
+
+module_init(linear_init);
+MODULE_LICENSE("GPL");
diff -ruN linux-2.4.16/drivers/md/dm-stripe.c linux/drivers/md/dm-stripe.c
--- linux-2.4.16/drivers/md/dm-stripe.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-stripe.c Wed Dec 19 20:33:01 2001
-@@ -0,0 +1,192 @@
++++ linux/drivers/md/dm-stripe.c Fri Dec 21 19:09:00 2001
+@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * Parse a single <dev> <sector> pair
+ */
+static int get_stripe(struct dm_table *t, struct stripe_c *sc,
-+ int stripe, const char *args)
++ int stripe, char **argv)
+{
-+ int n, r;
-+ char path[4096];
++ char *end;
+ unsigned long start;
+
-+ if (sscanf(args, "%4096s %lu %n", path, &start, &n) != 2)
++ start = simple_strtoul(argv[1], &end, 10);
++ if (*end)
+ return -EINVAL;
+
-+ r = dm_table_get_device(t, path, start, sc->stripe_width,
-+ &sc->stripe[stripe].dev);
-+ if (r)
++ if (dm_table_get_device(t, argv[0], start, sc->stripe_width,
++ &sc->stripe[stripe].dev))
+ return -ENXIO;
+
+ sc->stripe[stripe].physical_start = start;
-+ return n;
++ return 0;
+}
+
+/*
+ * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
+ */
+static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **argv, void **context)
+{
+ struct stripe_c *sc;
+ uint32_t stripes;
+ uint32_t chunk_size;
-+ int n, i;
++ char *end;
++ int r, i;
++
++ if (argc < 2) {
++ *context = "dm-stripe: Not enough arguments";
++ return -EINVAL;
++ }
+
-+ if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) {
-+ *context = "dm-stripe: Couldn't parse <stripes> <chunk size>";
++ stripes = simple_strtoul(argv[0], &end, 10);
++ if (*end) {
++ *context = "dm-stripe: Invalid stripe count";
++ return -EINVAL;
++ }
++
++ chunk_size =simple_strtoul(argv[1], &end, 10);
++ if (*end) {
++ *context = "dm-stripe: Invalid chunk_size";
+ return -EINVAL;
+ }
+
+
+ sc = alloc_context(stripes);
+ if (!sc) {
-+ *context = "dm-stripe: Memory allocation for striped context"
++ *context = "dm-stripe: Memory allocation for striped context "
+ "failed";
+ return -ENOMEM;
+ }
+ /*
+ * chunk_size is a power of two
+ */
-+ if (!chunk_size || chunk_size & (chunk_size - 1)) {
++ if (!chunk_size || (chunk_size & (chunk_size - 1))) {
+ *context = "dm-stripe: Invalid chunk size";
+ kfree(sc);
+ return -EINVAL;
+ * Get the stripe destinations.
+ */
+ for (i = 0; i < stripes; i++) {
-+ args += n;
-+ n = get_stripe(t, sc, i, args);
++ if (argc < 2) {
++ *context = "dm-stripe: Not enough destinations "
++ "specified";
++ kfree(sc);
++ return -EINVAL;
++ }
+
-+ if (n < 0) {
++ argv += 2;
++
++ r = get_stripe(t, sc, i, argv);
++ if (r < 0) {
+ *context = "dm-stripe: Couldn't parse stripe "
+ "destination";
+ kfree(sc);
-+ return n;
++ return r;
+ }
+ }
+
+ ctr: stripe_ctr,
+ dtr: stripe_dtr,
+ map: stripe_map,
-+ err: NULL
+};
+
+static int __init stripe_init(void)
+EXPORT_SYMBOL(dm_table_put_device);
diff -ruN linux-2.4.16/drivers/md/dm-target.c linux/drivers/md/dm-target.c
--- linux-2.4.16/drivers/md/dm-target.c Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm-target.c Wed Dec 19 19:57:41 2001
-@@ -0,0 +1,190 @@
++++ linux/drivers/md/dm-target.c Fri Dec 21 19:29:01 2001
+@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited
+ *
+
+#define DM_MOD_NAME_SIZE 32
+
++/*
++ * Destructively splits up the argument list to pass to ctr.
++ */
++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;
++
++ /* terminate the string and put it in the array */
++ *out = '\0';
++ end++;
++ argv[*argc] = start;
++ (*argc)++;
++ }
++
++ return 0;
++}
++
+static inline struct tt_internal *__find_target_type(const char *name)
+{
+ struct list_head *tih;
+ * up LV's that have holes in them.
+ */
+static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context)
++ int argc, char **args, void **context)
+{
+ *context = NULL;
+ return 0;
+ ctr: io_err_ctr,
+ dtr: io_err_dtr,
+ map: io_err_map,
-+ err: NULL
+};
+
+int dm_target_init(void)
+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 Thu Dec 20 20:11:36 2001
++++ linux/drivers/md/dm.c Fri Dec 21 20:28:26 2001
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+#define DEVICE_NAME "device-mapper" /* Name for messaging */
+
+static const char *_name = DEVICE_NAME;
-+static const char *_version = "0.90.03-ioctl (2001-12-20)";
++static const char *_version = "0.90.04-ioctl (2001-12-21)";
+static const char *_email = "lvm-devel@lists.sistina.com";
+
+static int _major = 0;
+ return 0;
+}
+
-+static void __exit local_exit(void)
++static void local_exit(void)
+{
+ if (kmem_cache_destroy(_io_hook_cache))
+ WARN("it looks like there are still some io_hooks allocated");
+MODULE_LICENSE("GPL");
diff -ruN linux-2.4.16/drivers/md/dm.h linux/drivers/md/dm.h
--- linux-2.4.16/drivers/md/dm.h Thu Jan 1 01:00:00 1970
-+++ linux/drivers/md/dm.h Wed Dec 19 19:42:58 2001
-@@ -0,0 +1,157 @@
++++ linux/drivers/md/dm.h Fri Dec 21 19:28:50 2001
+@@ -0,0 +1,164 @@
+/*
+ * Internal header file for device mapper
+ *
+#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
+
+/*
+ * List of devices that a metadevice uses and should open/close.
+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);
++
++
+/* dm.c */
+struct mapped_device *dm_get(const char *name);
+int dm_create(const char *name, int minor, struct dm_table *table,
+#endif
diff -ruN linux-2.4.16/include/linux/device-mapper.h linux/include/linux/device-mapper.h
--- linux-2.4.16/include/linux/device-mapper.h Thu Jan 1 01:00:00 1970
-+++ linux/include/linux/device-mapper.h Wed Dec 19 19:42:09 2001
++++ linux/include/linux/device-mapper.h Fri Dec 21 18:44:59 2001
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Prototypes for functions for a target
+ */
+typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
-+ const char *args, void **context);
++ 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);
+void dm_error(const char *message);
+
+/*
-+ * Contructors should call these functions to ensure destination devices
-+ * are opened/closed correctly
++ * Constructors should call these functions to ensure destination devices
++ * are opened/closed correctly
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+ offset_t start, offset_t len, struct dm_dev **result);