From: FUJITA Tomonori <[email-masked]>

The current two exception store implementations (persistent and
transient) always keep completed exceptions in memory. This patch
enables exception store implementations to use the own function to
look for a completed exception so that they can store exceptions at
any place such as disk.

Signed-off-by: FUJITA Tomonori <[email-masked]>
---
 drivers/md/dm-snap.c |   38 +++++++++++++++++++++++++-------------
 drivers/md/dm-snap.h |    6 ++++++
 2 files changed, 31 insertions(+), 13 deletions(-)

Index: linux-2.6.28-rc3/drivers/md/dm-snap.c
===================================================================
--- linux-2.6.28-rc3.orig/drivers/md/dm-snap.c	2008-11-06 17:30:26.000000000 +0000
+++ linux-2.6.28-rc3/drivers/md/dm-snap.c	2008-11-07 13:15:35.000000000 +0000
@@ -349,6 +349,15 @@ static struct dm_snap_exception *lookup_
 	return NULL;
 }
 
+struct dm_snap_exception *lookup_complete_exception(struct dm_snapshot *s,
+						    chunk_t chunk)
+{
+	if (s->store.lookup_completed_exception)
+		return s->store.lookup_completed_exception(&s->store, chunk);
+	else
+		return lookup_exception(&s->complete, chunk);
+}
+
 static struct dm_snap_exception *alloc_exception(void)
 {
 	struct dm_snap_exception *e;
@@ -856,7 +865,7 @@ static struct bio *put_pending_exception
 
 static void pending_complete(struct dm_snap_pending_exception *pe, int success)
 {
-	struct dm_snap_exception *e;
+	struct dm_snap_exception *e = NULL;
 	struct dm_snapshot *s = pe->snap;
 	struct bio *origin_bios = NULL;
 	struct bio *snapshot_bios = NULL;
@@ -870,18 +879,21 @@ static void pending_complete(struct dm_s
 		goto out;
 	}
 
-	e = alloc_exception();
-	if (!e) {
-		down_write(&s->lock);
-		__invalidate_snapshot(s, -ENOMEM);
-		error = 1;
-		goto out;
+	if (!s->store.lookup_completed_exception) {
+		e = alloc_exception();
+		if (!e) {
+			down_write(&s->lock);
+			__invalidate_snapshot(s, -ENOMEM);
+			error = 1;
+			goto out;
+		}
+		*e = pe->e;
 	}
-	*e = pe->e;
 
 	down_write(&s->lock);
 	if (!s->valid) {
-		free_exception(e);
+		if (e)
+			free_exception(e);
 		error = 1;
 		goto out;
 	}
@@ -897,8 +909,8 @@ static void pending_complete(struct dm_s
 	 * Add a proper exception, and remove the
 	 * in-flight exception from the list.
 	 */
-	insert_completed_exception(s, e);
-
+	if (e)
+		insert_completed_exception(s, e);
  out:
 	remove_exception(&pe->e);
 	snapshot_bios = bio_list_get(&pe->snapshot_bios);
@@ -1064,7 +1076,7 @@ static int snapshot_map(struct dm_target
 	}
 
 	/* If the block is already remapped - use that, else remap it */
-	e = lookup_exception(&s->complete, chunk);
+	e = lookup_complete_exception(s, chunk);
 	if (e) {
 		remap_exception(s, e, bio, chunk);
 		goto out_unlock;
@@ -1206,7 +1218,7 @@ static int __origin_write(struct list_he
 		 * ref_count is initialised to 1 so pending_complete()
 		 * won't destroy the primary_pe while we're inside this loop.
 		 */
-		e = lookup_exception(&snap->complete, chunk);
+		e = lookup_complete_exception(snap, chunk);
 		if (e)
 			goto next_snapshot;
 
Index: linux-2.6.28-rc3/drivers/md/dm-snap.h
===================================================================
--- linux-2.6.28-rc3.orig/drivers/md/dm-snap.h	2008-11-04 14:10:54.000000000 +0000
+++ linux-2.6.28-rc3/drivers/md/dm-snap.h	2008-11-07 13:15:35.000000000 +0000
@@ -126,6 +126,12 @@ struct exception_store {
 			       sector_t *numerator,
 			       sector_t *denominator);
 
+	/*
+	 * look up if a chunk is in completed exception.
+	 */
+	struct dm_snap_exception *(*lookup_completed_exception)
+	(struct exception_store *store, chunk_t chunk);
+
 	struct dm_snapshot *snap;
 	void *context;
 };