From: Milan Broz <mbroz@redhat.com>

Release memory if snapshot is invalidated.

All I/O operations on the full (invalidated) snapshot will
cause -EIO so no memory is needed anymore.

Snapshot is marked invalid and in workqueue is scheduled its
deallocation.

Signed-off-by: Milan Broz <mbroz@redhat.com>
---

---
 drivers/md/dm-snap.c |   46 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 10 deletions(-)

Index: linux-2.6.22/drivers/md/dm-snap.c
===================================================================
--- linux-2.6.22.orig/drivers/md/dm-snap.c	2007-05-14 17:17:29.000000000 +0200
+++ linux-2.6.22/drivers/md/dm-snap.c	2007-05-14 18:51:47.000000000 +0200
@@ -563,7 +563,7 @@ static int snapshot_ctr(struct dm_target
  bad1:
 	return r;
 }
-
+/*
 static void __free_exceptions(struct dm_snapshot *s)
 {
 	kcopyd_client_destroy(s->kcopyd_client);
@@ -574,18 +574,31 @@ static void __free_exceptions(struct dm_
 
 	s->store.destroy(&s->store);
 }
+*/
+static void __schedule_drop_snapshot(struct dm_snapshot *s)
+{
+	/* invalidated -> already scheduled */
+	if (!s->valid)
+		return;
+
+	s->valid = 0;
+
+	queue_work(ksnapd, &s->queued_bios_work);
+}
 
 static void snapshot_dtr(struct dm_target *ti)
 {
 	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
 
-	flush_workqueue(ksnapd);
-
 	/* Prevent further origin writes from using this snapshot. */
 	/* After this returns there can be no new kcopyd jobs. */
 	unregister_snapshot(s);
 
-	__free_exceptions(s);
+	down_write(&s->lock);
+	__schedule_drop_snapshot(s);
+	up_write(&s->lock);
+
+	flush_workqueue(ksnapd);
 
 	dm_put_device(ti, s->origin);
 	dm_put_device(ti, s->cow);
@@ -612,6 +625,7 @@ static void flush_queued_bios(struct wor
 {
 	struct dm_snapshot *s =
 		container_of(work, struct dm_snapshot, queued_bios_work);
+/*
 	struct bio *queued_bios;
 	unsigned long flags;
 
@@ -620,6 +634,23 @@ static void flush_queued_bios(struct wor
 	spin_unlock_irqrestore(&s->pe_lock, flags);
 
 	flush_bios(queued_bios);
+*/
+	BUG_ON(!s->kcopyd_client);
+	BUG_ON(s->valid);
+
+	kcopyd_client_destroy(s->kcopyd_client);
+	s->kcopyd_client = NULL;
+
+//	down_write(&s->lock);
+	if (s->store.drop_snapshot)
+		s->store.drop_snapshot(&s->store);
+
+	exit_exception_table(&s->pending, pending_cache);
+	exit_exception_table(&s->complete, exception_cache);
+
+	s->store.destroy(&s->store);
+	dm_table_event(s->table);
+//	up_write(&s->lock);
 }
 
 /*
@@ -647,12 +678,7 @@ static void __invalidate_snapshot(struct
 	else if (err == -ENOMEM)
 		DMERR("Invalidating snapshot: Unable to allocate exception.");
 
-	if (s->store.drop_snapshot)
-		s->store.drop_snapshot(&s->store);
-
-	s->valid = 0;
-
-	dm_table_event(s->table);
+	__schedule_drop_snapshot(s);
 }
 
 static void get_pending_exception(struct pending_exception *pe)