When there is one merging snapshot and other non-merging snapshots, make exceptions in non-merging snapshots while merging. This is not yet complete (the exception is not made when remapping directly to the origin), another patch fixes that. Signed-off-by: Mikulas Patocka --- drivers/md/dm-snap.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) Index: linux-2.6.28-rc3-devel/drivers/md/dm-snap.c =================================================================== --- linux-2.6.28-rc3-devel.orig/drivers/md/dm-snap.c 2008-11-05 09:03:06.000000000 +0100 +++ linux-2.6.28-rc3-devel/drivers/md/dm-snap.c 2008-11-05 09:03:10.000000000 +0100 @@ -157,6 +157,8 @@ struct origin { static struct list_head *_origins; static struct rw_semaphore _origins_lock; +static DECLARE_WAIT_QUEUE_HEAD(_pending_exception_done); + static int init_origin_hash(void) { int i; @@ -577,12 +579,17 @@ static int set_chunk_size(struct dm_snap static void flush_bios(struct bio *bio); static void error_bios(struct bio *bio); +static int __origin_write(struct list_head *snapshots, sector_t sector, struct bio *bio); + static void merge_callback(int read_err, unsigned long write_err, void *context); static void snapshot_merge_process(struct dm_snapshot *s) { int r; chunk_t old_chunk, new_chunk; + struct origin *o; + chunk_t min_chunksize; + int must_wait; struct dm_io_region src, dest; BUG_ON(!s->merge_running); @@ -615,6 +622,26 @@ static void snapshot_merge_process(struc src.sector = chunk_to_sector(s, new_chunk); src.count = dest.count; + test_again: + /* Reallocate other snapshots */ + 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->chunk_size; n += min_chunksize) { + r = __origin_write(&o->snapshots, dest.sector + n, NULL); + if (r == DM_MAPIO_SUBMITTED) + must_wait = 1; + } + } + up_read(&_origins_lock); + if (must_wait) { + sleep_on_timeout(&_pending_exception_done, HZ / 100 + 1); + goto test_again; + } + down_write(&s->lock); s->merge_write_interlock = old_chunk; s->merge_write_interlock_n = 1; @@ -1093,6 +1120,8 @@ static void pending_complete(struct dm_s origin_bios = bio_list_get(&pe->origin_bios); free_pending_exception(pe); + wake_up_all(&_pending_exception_done); + up_write(&s->lock); /* Submit any pending write bios */