Track all IOs in the merging target (they may be IOs remapped from the origin). It is needed for correct shutdown of the merging target if the origin is not suspended --- this can happen with dmsetup, but it never happens with LVM. Signed-off-by: Mikulas Patocka --- drivers/md/dm-snap.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) Index: linux-2.6.26-rc5-devel/drivers/md/dm-snap.c =================================================================== --- linux-2.6.26-rc5-devel.orig/drivers/md/dm-snap.c 2008-06-17 01:20:14.000000000 +0200 +++ linux-2.6.26-rc5-devel/drivers/md/dm-snap.c 2008-06-17 01:20:19.000000000 +0200 @@ -137,6 +137,22 @@ return found; } +static int __anything_is_tracked(struct dm_snapshot *s) +{ + int i; + int found = 0; + + spin_lock_irq(&s->tracked_chunk_lock); + for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++) + if (!hlist_empty(&s->tracked_chunk_hash[i])) { + found = 1; + break; + } + spin_unlock_irq(&s->tracked_chunk_lock); + + return found; +} + /* * One of these per registered origin, held in the snapshot_origins hash */ @@ -964,7 +980,6 @@ static void snapshot_dtr(struct dm_target *ti) { - int i; struct dm_snapshot *s = ti->private; struct dm_snapshot *dup; @@ -986,8 +1001,13 @@ /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); - for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++) - BUG_ON(!hlist_empty(&s->tracked_chunk_hash[i])); + /* + * There may be IOs redirected by the origin - wait for them to drain + * This shouldn't happen with LVM (it suspends the origin before + * snapshots), but it can happen if the user uses dmsetup. + */ + while (__anything_is_tracked(s)) + yield(); mempool_destroy(s->tracked_chunk_pool); @@ -1342,6 +1362,8 @@ goto out_unlock; } + map_context->ptr = track_chunk(s, chunk); + /* If the block is already remapped - use that */ e = lookup_exception(&s->complete, chunk); if (e) { @@ -1358,8 +1380,6 @@ remap_exception(s, e, bio, chunk); - if (bio_rw(bio) == WRITE) - map_context->ptr = track_chunk(s, chunk); goto out_unlock; }