@@ -663,12 +663,13 @@ static void merge_callback(int read_err, unsigned long write_err,
static void snapshot_merge_process(struct dm_snapshot *s)
{
- int r;
+ int r, i, linear_chunks;
chunk_t old_chunk, new_chunk;
struct origin *o;
chunk_t min_chunksize;
int must_wait;
struct dm_io_region src, dest;
+ sector_t io_size;
BUG_ON(!s->merge_running);
if (s->merge_shutdown)
@@ -684,34 +685,41 @@ static void snapshot_merge_process(struct dm_snapshot *s)
DMERR("target store does not support merging");
goto shut;
}
- r = s->store->type->prepare_merge(s->store, &old_chunk, &new_chunk);
- if (r <= 0) {
- if (r < 0)
+ linear_chunks = s->store->type->prepare_merge(s->store,
+ &old_chunk, &new_chunk);
+ if (linear_chunks <= 0) {
+ if (linear_chunks < 0)
DMERR("Read error in exception store, "
"shutting down merge");
goto shut;
}
+ /* Adjust old_chunk and new_chunk to reflect start of linear region */
+ old_chunk = old_chunk + 1 - linear_chunks;
+ new_chunk = new_chunk + 1 - linear_chunks;
- /* TODO: use larger I/O size once we verify that kcopyd handles it */
+ /*
+ * Use one (potentially large) I/O to copy all 'linear_chunks'
+ * from the exception store to the origin
+ */
+ io_size = linear_chunks * s->store->chunk_size;
dest.bdev = s->origin->bdev;
dest.sector = chunk_to_sector(s->store, old_chunk);
- dest.count = min((sector_t)s->store->chunk_size,
- get_dev_size(dest.bdev) - dest.sector);
+ dest.count = min(io_size, get_dev_size(dest.bdev) - dest.sector);
src.bdev = s->cow->bdev;
src.sector = chunk_to_sector(s->store, new_chunk);
src.count = dest.count;
test_again:
- /* Reallocate other snapshots */
+ /* Reallocate other snapshots; must account for all 'linear_chunks' */
down_read(&_origins_lock);
o = __lookup_origin(s->origin->bdev);
must_wait = 0;
min_chunksize = __minimum_chunk_size(o);
if (min_chunksize) {
chunk_t n;
- for (n = 0; n < s->store->chunk_size; n += min_chunksize) {
+ for (n = 0; n < io_size; n += min_chunksize) {
r = __origin_write(&o->snapshots, dest.sector + n,
NULL);
if (r == DM_MAPIO_SUBMITTED)
@@ -726,11 +734,14 @@ test_again:
down_write(&s->lock);
s->merge_write_interlock = old_chunk;
- s->merge_write_interlock_n = 1;
+ s->merge_write_interlock_n = linear_chunks;
up_write(&s->lock);
- while (__chunk_is_tracked(s, old_chunk))
- msleep(1);
+ /* Wait until writes to all 'linear_chunks' drain */
+ for (i = 0; i < linear_chunks; i++) {
+ while (__chunk_is_tracked(s, old_chunk + i))
+ msleep(1);
+ }
dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, merge_callback, s);
return;