From: Milan Broz <[email-masked]>

Release memory if snapshot is invalidated.

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

If there are no kcopyd jobs running, memory is released immediately.
Otherwise it gets freed later in the workqueue.

Signed-off-by: Milan Broz <[email-masked]>
---

[Still problems with this]

 drivers/md/dm-snap.c |   28 +++++++++++++++++++++++-----
 1 files changed, 23 insertions(+), 5 deletions(-)

Index: linux-2.6.19/drivers/md/dm-snap.c
===================================================================
--- linux-2.6.19.orig/drivers/md/dm-snap.c	2006-12-06 20:49:41.000000000 +0000
+++ linux-2.6.19/drivers/md/dm-snap.c	2006-12-06 20:49:41.000000000 +0000
@@ -564,9 +564,17 @@ static int snapshot_ctr(struct dm_target
 	return r;
 }
 
-static void __free_exceptions(struct dm_snapshot *s)
+/*
+ * If async is set, return immediately.
+ */
+static void __free_exceptions(struct dm_snapshot *s, unsigned async)
 {
-	kcopyd_client_destroy(s->kcopyd_client, 0);
+	async = kcopyd_client_destroy(s->kcopyd_client, async);
+	if (async) {
+		queue_work(ksnapd, &s->queued_bios_work);
+		return;
+	}
+
 	s->kcopyd_client = NULL;
 
 	exit_exception_table(&s->pending, pending_cache);
@@ -585,7 +593,8 @@ static void snapshot_dtr(struct dm_targe
 	/* After this returns there can be no new kcopyd jobs. */
 	unregister_snapshot(s);
 
-	__free_exceptions(s);
+	if (s->valid)
+		__free_exceptions(s, 1);
 
 	dm_put_device(ti, s->origin);
 	dm_put_device(ti, s->cow);
@@ -611,14 +620,20 @@ static void flush_bios(struct bio *bio)
 static void flush_queued_bios(void *data)
 {
 	struct dm_snapshot *s = (struct dm_snapshot *) data;
-	struct bio *queued_bios;
-	unsigned long flags;
+//	struct bio *queued_bios;
+//	unsigned long flags;
 
+	if (!s->valid && s->kcopyd_client) {
+		__free_exceptions(s, 0);
+		return;
+	}
+/*
 	spin_lock_irqsave(&s->pe_lock, flags);
 	queued_bios = bio_list_get(&s->queued_bios);
 	spin_unlock_irqrestore(&s->pe_lock, flags);
 
 	flush_bios(queued_bios);
+*/
 }
 
 /*
@@ -651,6 +666,9 @@ static void __invalidate_snapshot(struct
 
 	s->valid = 0;
 
+	/* schedule release memory */
+	__free_exceptions(s, 1);
+
 	dm_table_event(s->table);
 }