--- drivers/md/dm-exception-store.c | 52 +++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) Index: linux-2.6.26-fast/drivers/md/dm-exception-store.c =================================================================== --- linux-2.6.26-fast.orig/drivers/md/dm-exception-store.c 2008-07-23 22:59:45.000000000 +0200 +++ linux-2.6.26-fast/drivers/md/dm-exception-store.c 2008-07-23 22:59:47.000000000 +0200 @@ -105,6 +105,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. */ @@ -149,6 +154,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; } @@ -156,6 +168,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 { @@ -235,10 +249,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) @@ -489,7 +521,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; @@ -581,18 +614,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++) {