From: Mikulas Patocka <[email-masked]>

We must first zero next chunk and then write current chunk.

For the purpose of zeroeing, allocate additional bdev_hardsect_size bytes.
These bytes will be always zero, they'll be written to the next chunk area.

We don't need to clear the whole chunk, just one sector is enough (loading of
exceptions stops after seeing the first zero ... it doesn't matter that the
rest of the chunk is not cleared).

Signed-off-by: Mikulas Patocka <[email-masked]>
---
 drivers/md/dm-exception-store.c |   52 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 46 insertions(+), 6 deletions(-)

Index: linux-2.6.27/drivers/md/dm-exception-store.c
===================================================================
--- linux-2.6.27.orig/drivers/md/dm-exception-store.c	2008-10-15 14:59:47.000000000 +0100
+++ linux-2.6.27/drivers/md/dm-exception-store.c	2008-10-15 15:00:38.000000000 +0100
@@ -104,6 +104,11 @@ struct pstore {
 	void *area;
 
 	/*
+	 * One area containing just zeros, used to clear next area chunk.
+	 */
+	void *zero_area;
+
+	/*
 	 * Used to keep track of which metadata area the data in
 	 * 'chunk' refers to.
 	 */
@@ -148,6 +153,13 @@ static int alloc_area(struct pstore *ps)
 	if (!ps->area)
 		return r;
 
+	ps->zero_area = vmalloc(len);
+	if (!ps->zero_area) {
+		vfree(ps->area);
+		return r;
+	}
+	memset(ps->zero_area, 0, len);
+
 	return 0;
 }
 
@@ -155,6 +167,8 @@ static void free_area(struct pstore *ps)
 {
 	vfree(ps->area);
 	ps->area = NULL;
+	vfree(ps->zero_area);
+	ps->zero_area = NULL;
 }
 
 struct mdata_req {
@@ -234,10 +248,28 @@ static int area_io(struct pstore *ps, ch
 	return 0;
 }
 
-static int zero_area(struct pstore *ps, chunk_t area)
+static void zero_memory_area(struct pstore *ps, chunk_t area)
 {
 	memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
-	return area_io(ps, area, WRITE);
+	ps->current_area = area;
+}
+
+static int zero_disk_area(struct pstore *ps, chunk_t area)
+{
+	struct dm_io_region where = {
+		.bdev = ps->snap->cow->bdev,
+		.sector = ps->snap->chunk_size * area_location(ps, area),
+		.count = ps->snap->chunk_size,
+	};
+	struct dm_io_request io_req = {
+		.bi_rw = WRITE,
+		.mem.type = DM_IO_VMA,
+		.mem.ptr.vma = ps->zero_area,
+		.client = ps->io_client,
+		.notify.fn = NULL,
+	};
+
+	return dm_io(&io_req, 1, &where, NULL);
 }
 
 static int read_header(struct pstore *ps, int *new_snapshot)
@@ -485,7 +517,8 @@ static int persistent_read_metadata(stru
 			return r;
 		}
 
-		r = zero_area(ps, 0);
+		zero_memory_area(ps, 0);
+		r = zero_disk_area(ps, 0);
 		if (r) {
 			DMWARN("zero_area(0) failed");
 			return r;
@@ -577,18 +610,25 @@ static void persistent_commit(struct exc
 	 */
 	if (atomic_dec_and_test(&ps->pending_count) ||
 	    (ps->current_committed == ps->exceptions_per_area)) {
+		if (ps->current_committed == ps->exceptions_per_area) {
+			r = zero_disk_area(ps, ps->current_area + 1);
+			if (r) {
+				ps->valid = 0;
+				goto skip_area_io;
+			}
+		}
+
 		r = area_io(ps, ps->current_area, WRITE);
 		if (r)
 			ps->valid = 0;
 
+skip_area_io:
 		/*
 		 * Have we completely filled the current area ?
 		 */
 		if (ps->current_committed == ps->exceptions_per_area) {
 			ps->current_committed = 0;
-			r = zero_area(ps, ps->current_area + 1);
-			if (r)
-				ps->valid = 0;
+			zero_memory_area(ps, ps->current_area + 1);
 		}
 
 		for (i = 0; i < ps->callback_count; i++) {