Add the ability to track writes to the snapshot-merged target which have been mapped to the COW device. Rationale is that we won't want to start merging a chunk until all writes to that chunk have completed. Reads don't matter because the contents of the chunk on the COW device is not affected by the merging process. Index: linux-2.6.16.i686/drivers/md/dm-snap.c =================================================================== --- linux-2.6.16.i686.orig/drivers/md/dm-snap.c 2006-05-05 14:45:22.000000000 +0100 +++ linux-2.6.16.i686/drivers/md/dm-snap.c 2006-05-05 14:45:27.000000000 +0100 @@ -1322,6 +1322,7 @@ static int merged_map(struct dm_target * struct dm_merged *merged = (struct dm_merged *) ti->private; struct dm_snapshot *s = &merged->snap; struct exception *e; + struct pending_exception *pe; chunk_t chunk; int r = 1; @@ -1330,28 +1331,53 @@ static int merged_map(struct dm_target * chunk = sector_to_chunk(s, bio->bi_sector); - down_read(&s->lock); + down_write(&s->lock); if (!s->valid) { - up_read(&s->lock); + up_write(&s->lock); return -EIO; } e = lookup_exception(&s->complete, chunk); - if (e) + if (e) { + if (bio_rw(bio) == WRITE) { + pe = __find_pending_exception(s, chunk, 0); + if (!pe) { + __invalidate_snapshot(s, pe, -ENOMEM); + r = -EIO; + goto out_unlock; + } + map_context->ptr = pe; + } + remap_exception(s, e, bio); - else { + } else { bio->bi_bdev = s->origin->bdev; if (bio_rw(bio) == WRITE) r = do_origin(s->origin, bio->bi_sector, bio); } - up_read(&s->lock); + out_unlock: + up_write(&s->lock); return r; } +static int merged_end_io(struct dm_target *ti, struct bio *bio, + int error, union map_info *map_context) +{ + struct pending_exception *pe = + (struct pending_exception *) map_context->ptr; + + if (bio_rw(bio) != WRITE || pe == NULL) + return error; + + unref_pending_exception(pe); + + return error; +} + static void merged_resume(struct dm_target *ti) { struct dm_merged *merged = (struct dm_merged *) ti->private; @@ -1419,6 +1445,7 @@ static struct target_type merged_target .ctr = merged_ctr, .dtr = merged_dtr, .map = merged_map, + .end_io = merged_end_io, .resume = merged_resume, .status = merged_status, };