diff -Naur linux-2.4.20-dm-10/drivers/md/dm-ioctl.c linux-2.4.20-evms-2.0.0/drivers/md/dm-ioctl.c
--- linux-2.4.20-dm-10/drivers/md/dm-ioctl.c	Fri Mar 28 15:27:32 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/dm-ioctl.c	Fri Mar 28 15:26:38 2003
@@ -401,7 +401,7 @@
  * Round up the ptr to the next 'align' boundary.  Obviously
  * 'align' must be a power of 2.
  */
-static inline void *align_ptr(void *ptr, unsigned int align)
+static inline void *align_ptr(void *ptr, unsigned long align)
 {
 	align--;
 	return (void *) (((unsigned long) (ptr + align)) & ~align);
@@ -549,7 +549,7 @@
 
 static int check_name(const char *name)
 {
-	if (strchr(name, '/')) {
+	if (name[0] == '/') {
 		DMWARN("invalid device name");
 		return -EINVAL;
 	}
@@ -888,7 +888,16 @@
 		return -ENXIO;
 	}
 
+	if (param->flags & DM_SUSPEND_FLAG) {
+		dm_suspend(md);
+	}
+
 	r = dm_swap_table(md, t);
+
+	if (param->flags & DM_SUSPEND_FLAG) {
+		dm_resume(md);
+	}
+
 	if (r) {
 		dm_put(md);
 		dm_table_put(t);
diff -Naur linux-2.4.20-dm-10/drivers/md/dm-snapshot.c linux-2.4.20-evms-2.0.0/drivers/md/dm-snapshot.c
--- linux-2.4.20-dm-10/drivers/md/dm-snapshot.c	Fri Mar 28 15:27:32 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/dm-snapshot.c	Fri Mar 28 15:26:39 2003
@@ -386,22 +386,28 @@
 	return (n + size) & ~size;
 }
 
+struct mapped_device *get_kdev(kdev_t dev);
+
 /*
- * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
+ * Construct a snapshot mapping:
+ * <origin-dev> <COW-dev> <p/n> <chunk-size> [<origin-parent-dev>]
  */
 static int snapshot_ctr(struct dm_target *ti, int argc, char **argv)
 {
 	struct dm_snapshot *s;
+	struct dm_dev * origin_dev;
+	struct mapped_device * origin_md = NULL;
 	unsigned long chunk_size;
 	int r = -EINVAL;
 	char persistent;
 	char *origin_path;
+	char *origin_parent_path;
 	char *cow_path;
 	char *value;
 	int blocksize;
 
 	if (argc < 4) {
-		ti->error = "dm-snapshot: requires exactly 4 arguments";
+		ti->error = "dm-snapshot: requires at least 4 arguments";
 		r = -EINVAL;
 		goto bad;
 	}
@@ -446,6 +452,29 @@
 		goto bad_free;
 	}
 
+	if (argc > 4) {
+		origin_parent_path = argv[4];
+		r = dm_get_device(ti, origin_parent_path, 0, 0,
+				  FMODE_READ, &origin_dev);
+		if (r) {
+			dm_put_device(ti, s->cow);
+			dm_put_device(ti, s->origin);
+			ti->error = "Cannot get origin-parent device";
+			goto bad_free;
+		}
+
+		origin_md = get_kdev(origin_dev->dev);
+		if (!origin_md) {
+			dm_put_device(ti, origin_dev);
+			dm_put_device(ti, s->cow);
+			dm_put_device(ti, s->origin);
+			ti->error = "Cannot get origin-parent MD";
+			goto bad_free;
+		}
+	} else {
+		origin_dev = s->origin;
+	}
+
 	/*
 	 * Chunk size must be multiple of page size.  Silently
 	 * round up if it's not.
@@ -511,31 +540,50 @@
 		goto bad_free1;
 	}
 
+	kcopyd_inc_client_count();
+
 	/* Flush IO to the origin device */
 #if LVM_VFS_ENHANCEMENT
-	fsync_dev_lockfs(s->origin->dev);
+	fsync_dev_lockfs(origin_dev->dev);
 #else
-	fsync_dev(s->origin->dev);
+	fsync_dev(origin_dev->dev);
 #endif
 
+	if (origin_md) {
+		dm_suspend(origin_md);
+	}
+
 	/* Add snapshot to the list of snapshots for this origin */
 	if (register_snapshot(s)) {
 		r = -EINVAL;
 		ti->error = "Cannot register snapshot origin";
 		goto bad_free2;
 	}
+
+	if (origin_md) {
+		dm_resume(origin_md);
+	}
+
 #if LVM_VFS_ENHANCEMENT
-	unlockfs(s->origin->dev);
+	unlockfs(origin_dev->dev);
 #endif
-	kcopyd_inc_client_count();
+
+	if (origin_md) {
+		dm_put(origin_md);
+		dm_put_device(ti, origin_dev);
+	}
 
 	ti->private = s;
 	return 0;
 
       bad_free2:
+	if (origin_md) {
+		dm_resume(origin_md);
+	}
 #if LVM_VFS_ENHANCEMENT
 	unlockfs(s->origin->dev);
 #endif
+	kcopyd_dec_client_count();
 	s->store.destroy(&s->store);
 
       bad_free1:
@@ -543,6 +591,10 @@
 	exit_exception_table(&s->complete, exception_cache);
 
       bad_putdev:
+	if (origin_md) {
+		dm_put(origin_md);
+		dm_put_device(ti, origin_dev);
+	}
 	dm_put_device(ti, s->cow);
 	dm_put_device(ti, s->origin);
 
@@ -978,14 +1030,12 @@
 int do_origin(struct dm_dev *origin, struct buffer_head *bh)
 {
 	struct origin *o;
-	int r;
+	int r = 1;
 
 	down_read(&_origins_lock);
 	o = __lookup_origin(origin->dev);
-	if (!o)
-		BUG();
-
-	r = __origin_write(&o->snapshots, bh);
+	if (o)
+		r = __origin_write(&o->snapshots, bh);
 	up_read(&_origins_lock);
 
 	return r;
diff -Naur linux-2.4.20-dm-10/drivers/md/dm-table.c linux-2.4.20-evms-2.0.0/drivers/md/dm-table.c
--- linux-2.4.20-dm-10/drivers/md/dm-table.c	Fri Mar 28 15:27:33 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/dm-table.c	Fri Mar 28 15:26:40 2003
@@ -640,7 +642,7 @@
 	return &t->targets[(KEYS_PER_NODE * n) + k];
 }
 
-unsigned int dm_table_get_num_targets(struct dm_table *t)
+int dm_table_get_num_targets(struct dm_table *t)
 {
 	return t->num_targets;
 }
diff -Naur linux-2.4.20-dm-10/drivers/md/dm.c linux-2.4.20-evms-2.0.0/drivers/md/dm.c
--- linux-2.4.20-dm-10/drivers/md/dm.c	Fri Mar 28 15:27:33 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/dm.c	Fri Mar 28 15:26:41 2003
@@ -79,7 +79,7 @@
 static int _blksize_size[MAX_DEVICES];
 static int _hardsect_size[MAX_DEVICES];
 
-static struct mapped_device *get_kdev(kdev_t dev);
+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);
 
@@ -575,7 +575,7 @@
 	return (i < MAX_DEVICES) ? i : -EBUSY;
 }
 
-static struct mapped_device *get_kdev(kdev_t dev)
+struct mapped_device *get_kdev(kdev_t dev)
 {
 	struct mapped_device *md;
 
diff -Naur linux-2.4.20-dm-10/drivers/md/dm.h linux-2.4.20-evms-2.0.0/drivers/md/dm.h
--- linux-2.4.20-dm-10/drivers/md/dm.h	Fri Mar 28 15:27:33 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/dm.h	Fri Mar 28 15:26:42 2003
@@ -100,7 +100,7 @@
 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);
+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);
diff -Naur linux-2.4.20-dm-10/drivers/md/kcopyd.c linux-2.4.20-evms-2.0.0/drivers/md/kcopyd.c
--- linux-2.4.20-dm-10/drivers/md/kcopyd.c	Fri Mar 28 15:27:33 2003
+++ linux-2.4.20-evms-2.0.0/drivers/md/kcopyd.c	Fri Mar 28 15:26:42 2003
@@ -155,7 +155,7 @@
 static struct buffer_head *alloc_buffer(void)
 {
 	struct buffer_head *r;
-	int flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&_buffer_lock, flags);
 
@@ -177,7 +177,8 @@
  */
 static void free_buffer(struct buffer_head *bh)
 {
-	int flags, was_empty;
+	unsigned long flags;
+	int was_empty;
 
 	spin_lock_irqsave(&_buffer_lock, flags);
 	was_empty = (_free_buffers == NULL) ? 1 : 0;
@@ -273,7 +274,7 @@
 static inline struct kcopyd_job *pop(struct list_head *jobs)
 {
 	struct kcopyd_job *job = NULL;
-	int flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&_job_lock, flags);
 
@@ -288,7 +289,7 @@
 
 static inline void push(struct list_head *jobs, struct kcopyd_job *job)
 {
-	int flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&_job_lock, flags);
 	list_add(&job->list, jobs);
diff -Naur linux-2.4.20-dm-10/include/linux/dm-ioctl.h linux-2.4.20-evms-2.0.0/include/linux/dm-ioctl.h
--- linux-2.4.20-dm-10/include/linux/dm-ioctl.h	Fri Mar 28 15:27:33 2003
+++ linux-2.4.20-evms-2.0.0/include/linux/dm-ioctl.h	Fri Mar 28 14:48:10 2003
@@ -46,11 +46,11 @@
 	uint32_t data_start;	/* offset to start of data
 				 * relative to start of this struct */
 
-	uint32_t target_count;	/* in/out */
-	uint32_t open_count;	/* out */
+	int32_t target_count;	/* in/out */
+	int32_t open_count;	/* out */
 	uint32_t flags;		/* in/out */
 
-	__kernel_dev_t dev;	/* in/out */
+	uint64_t dev;		/* in/out */
 
 	char name[DM_NAME_LEN];	/* device name */
 	char uuid[DM_UUID_LEN];	/* unique identifier for
@@ -62,9 +62,9 @@
  * dm_ioctl.
  */
 struct dm_target_spec {
-	int32_t status;		/* used when reading from kernel only */
 	uint64_t sector_start;
-	uint32_t length;
+	uint64_t length;
+	int32_t status;		/* used when reading from kernel only */
 
 	/*
 	 * Offset in bytes (from the start of this struct) to
@@ -85,9 +85,9 @@
  * Used to retrieve the target dependencies.
  */
 struct dm_target_deps {
-	uint32_t count;
-
-	__kernel_dev_t dev[0];	/* out */
+	uint32_t count;		/* Array size */
+	uint32_t padding;	/* unused */
+	uint64_t dev[0];	/* out */
 };
 
 /*
@@ -129,10 +129,10 @@
 #define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl)
 #define DM_TARGET_WAIT   _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl)
 
-#define DM_VERSION_MAJOR	1
+#define DM_VERSION_MAJOR	3
 #define DM_VERSION_MINOR	0
-#define DM_VERSION_PATCHLEVEL	10
-#define DM_VERSION_EXTRA	"-ioctl (2003-03-26)"
+#define DM_VERSION_PATCHLEVEL	0
+#define DM_VERSION_EXTRA	"-ioctl (2003-03-28)"
 
 /* Status bits */
 #define DM_READONLY_FLAG	0x00000001
