EVMS snapshot patch.
- VFS-locking fixes.
- Allow origins to be activated without any snapshots.

--- diff/drivers/md/dm-snapshot.c	2004-08-09 09:20:49.918397008 -0500
+++ source/drivers/md/dm-snapshot.c	2004-08-09 09:21:44.901038376 -0500
@@ -92,6 +92,9 @@
 
 	/* List of snapshots for this origin */
 	struct list_head snapshots;
+
+	/* Count of snapshots and origins referrencing this structure. */
+	unsigned int count;
 };
 
 /*
@@ -155,6 +158,35 @@
 }
 
 /*
+ * Allocate and initialize an origin structure.
+ */
+static struct origin * __alloc_origin(kdev_t dev)
+{
+	struct origin *o = kmalloc(sizeof(*o), GFP_KERNEL);
+	if (o) {
+		o->dev = dev;
+		INIT_LIST_HEAD(&o->hash_list);
+		INIT_LIST_HEAD(&o->snapshots);
+		__insert_origin(o);
+	}
+	return o;
+}
+
+static void __get_origin(struct origin *o)
+{
+	o->count++;
+}
+
+static void __put_origin(struct origin *o)
+{
+	o->count--;
+	if (o->count == 0) {
+		list_del(&o->hash_list);
+		kfree(o);
+	}
+}
+
+/*
  * Make a note of the snapshot and its origin so we can look it
  * up when the origin has a write on it.
  */
@@ -168,20 +200,37 @@
 
 	if (!o) {
 		/* New origin */
-		o = kmalloc(sizeof(*o), GFP_KERNEL);
+		o = __alloc_origin(dev);
 		if (!o) {
 			up_write(&_origins_lock);
 			return -ENOMEM;
 		}
+	}
 
-		/* Initialise the struct */
-		INIT_LIST_HEAD(&o->snapshots);
-		o->dev = dev;
+	__get_origin(o);
+	list_add_tail(&snap->list, &o->snapshots);
 
-		__insert_origin(o);
+	up_write(&_origins_lock);
+	return 0;
+}
+
+static int register_origin(kdev_t dev)
+{
+	struct origin *o;
+
+	down_write(&_origins_lock);
+	o = __lookup_origin(dev);
+
+	if (!o) {
+		/* New origin */
+		o = __alloc_origin(dev);
+		if (!o) {
+			up_write(&_origins_lock);
+			return -ENOMEM;
+		}
 	}
 
-	list_add_tail(&snap->list, &o->snapshots);
+	__get_origin(o);
 
 	up_write(&_origins_lock);
 	return 0;
@@ -195,11 +244,18 @@
 	o = __lookup_origin(s->origin->dev);
 
 	list_del(&s->list);
-	if (list_empty(&o->snapshots)) {
-		list_del(&o->hash_list);
-		kfree(o);
-	}
+	__put_origin(o);
+
+	up_write(&_origins_lock);
+}
+
+static void unregister_origin(kdev_t dev)
+{
+	struct origin *o;
 
+	down_write(&_origins_lock);
+	o = __lookup_origin(dev);
+	__put_origin(o);
 	up_write(&_origins_lock);
 }
 
@@ -524,22 +580,17 @@
 		goto bad5;
 	}
 
-	/* Flush IO to the origin device */
-	fsync_dev_lockfs(s->origin->dev);
-
 	/* Add snapshot to the list of snapshots for this origin */
 	if (register_snapshot(s)) {
 		r = -EINVAL;
 		ti->error = "Cannot register snapshot origin";
 		goto bad6;
 	}
-	unlockfs(s->origin->dev);
 
 	ti->private = s;
 	return 0;
 
  bad6:
-	unlockfs(s->origin->dev);
 	kcopyd_client_destroy(s->kcopyd_client);
 
  bad5:
@@ -1095,6 +1146,13 @@
 		return r;
 	}
 
+	r = register_origin(dev->dev);
+	if (r) {
+		ti->error = "Cannot register origin";
+		dm_put_device(ti, dev);
+		return r;
+	}
+
 	ti->private = dev;
 	return 0;
 }
@@ -1102,6 +1160,7 @@
 static void origin_dtr(struct dm_target *ti)
 {
 	struct dm_dev *dev = (struct dm_dev *) ti->private;
+	unregister_origin(dev->dev);
 	dm_put_device(ti, dev);
 }
 
--- diff/drivers/md/dm.c	2004-08-09 09:20:14.114839976 -0500
+++ source/drivers/md/dm.c	2004-08-09 09:21:44.902038224 -0500
@@ -951,13 +951,23 @@
 	int r = 0;
 	DECLARE_WAITQUEUE(wait, current);
 
-	down_write(&md->lock);
+	/* Flush IO to the origin device */
+	down_read(&md->lock);
+	if (test_bit(DMF_BLOCK_IO, &md->flags)) {
+		up_read(&md->lock);
+		return -EINVAL;
+	}
+
+	fsync_dev_lockfs(md->dev);
+	up_read(&md->lock);
+
 
 	/*
-	 * First we set the BLOCK_IO flag so no more ios will be
-	 * mapped.
+	 * Set the BLOCK_IO flag so no more ios will be mapped.
 	 */
+	down_write(&md->lock);
 	if (test_bit(DMF_BLOCK_IO, &md->flags)) {
+		unlockfs(md->dev);
 		up_write(&md->lock);
 		return -EINVAL;
 	}
@@ -986,6 +996,7 @@
 
 	/* did we flush everything ? */
 	if (atomic_read(&md->pending)) {
+		unlockfs(md->dev);
 		clear_bit(DMF_BLOCK_IO, &md->flags);
 		r = -EINTR;
 	} else {
@@ -1017,6 +1028,7 @@
 	md->deferred = NULL;
 	up_write(&md->lock);
 
+	unlockfs(md->dev);
 	flush_deferred_io(def);
 	run_task_queue(&tq_disk);
 
