Handover of the exception store. This is needed for merging (to allow reload of the table) and it also enables origin or snapshot resize. The supported call sequences are: new_snapshot->ctr old_snapshot->suspend old_snapshot->dtr new_snapshot->resume and new_snapshot->ctr old_snapshot->suspend new_snapshot->resume old_snapshot->dtr There may not be more then two instances of a given snapshot. LVM always creates at most two; if there are more, the user abuses dmsetup. Signed-off-by: Mikulas Patocka --- drivers/md/dm-snap.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/dm-snap.h | 3 + 2 files changed, 83 insertions(+) Index: linux-2.6.26-devel/drivers/md/dm-snap.c =================================================================== --- linux-2.6.26-devel.orig/drivers/md/dm-snap.c 2008-07-14 20:06:47.000000000 +0200 +++ linux-2.6.26-devel/drivers/md/dm-snap.c 2008-07-14 20:08:25.000000000 +0200 @@ -247,6 +247,31 @@ static void unregister_snapshot(struct d up_write(&_origins_lock); } +/* _origins_lock must be held */ +static struct dm_snapshot *find_duplicate(struct dm_snapshot *snap) +{ + struct dm_snapshot *dup; + struct dm_snapshot *l; + struct origin *o; + + o = __lookup_origin(snap->origin->bdev); + if (!o) + return NULL; + + dup = NULL; + list_for_each_entry (l, &o->snapshots, list) + if (l != snap && bdev_equal(l->cow->bdev, snap->cow->bdev)) { + if (!dup) { + dup = l; + } else { + DMERR("Multiple active duplicates, user misuses dmsetup."); + return NULL; + } + } + + return dup; +} + #define min_not_zero(l, r) (((l) == 0) ? (r) : (((r) == 0) ? (l) : min(l, r))) /* @@ -568,6 +593,7 @@ static int snapshot_ctr(struct dm_target s->valid = 1; s->active = 0; + s->handover = 0; init_rwsem(&s->lock); s->ti = ti; @@ -616,6 +642,10 @@ static int snapshot_ctr(struct dm_target spin_lock_init(&s->tracked_chunk_lock); + down_read(&_origins_lock); + if (find_duplicate(s)) s->handover = 1; + up_read(&_origins_lock); + /* Metadata must only be loaded into one table at once */ r = s->store.read_metadata(&s->store); if (r < 0) { @@ -682,6 +712,28 @@ static void __free_exceptions(struct dm_ s->store.destroy(&s->store); } +static void handover_exceptions(struct dm_snapshot *old, struct dm_snapshot *new) +{ + union { + struct exception_table table_swap; + struct exception_store store_swap; + } u; + + u.table_swap = new->complete; + new->complete = old->complete; + old->complete = u.table_swap; + u.store_swap = new->store; + new->store = old->store; + old->store = u.store_swap; + new->store.snap = new; + old->store.snap = old; + new->store.handover(&new->store); + old->store.handover(&old->store); + + old->active = 0; + new->handover = 0; +} + static void snapshot_dtr(struct dm_target *ti) { #ifdef CONFIG_DM_DEBUG @@ -689,6 +741,19 @@ static void snapshot_dtr(struct dm_targe #endif struct dm_snapshot *s = ti->private; + struct dm_snapshot *dup; + + down_write(&_origins_lock); + down_write(&s->lock); + dup = find_duplicate(s); + if (dup && dup->handover) { + down_write_nested(&dup->lock, SINGLE_DEPTH_NESTING); + handover_exceptions(s, dup); + up_write(&dup->lock); + } + up_write(&s->lock); + up_write(&_origins_lock); + /* Prevent further origin writes from using this snapshot. */ /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); @@ -1042,9 +1107,24 @@ static void snapshot_resume(struct dm_ta { struct dm_snapshot *s = ti->private; + down_write(&_origins_lock); down_write(&s->lock); + if (s->handover) { + struct dm_snapshot *dup; + dup = find_duplicate(s); + if (!dup) { + DMERR("duplicate not found"); + s->valid = 0; + goto ret; + } + down_write_nested(&dup->lock, SINGLE_DEPTH_NESTING); + handover_exceptions(dup, s); + up_write(&dup->lock); + } s->active = 1; + ret: up_write(&s->lock); + up_write(&_origins_lock); } static int snapshot_status(struct dm_target *ti, status_type_t type, Index: linux-2.6.26-devel/drivers/md/dm-snap.h =================================================================== --- linux-2.6.26-devel.orig/drivers/md/dm-snap.h 2008-07-14 20:06:54.000000000 +0200 +++ linux-2.6.26-devel/drivers/md/dm-snap.h 2008-07-14 20:07:03.000000000 +0200 @@ -171,6 +171,9 @@ struct dm_snapshot { /* Origin writes don't trigger exceptions until this is set */ int active; + /* Exception store will be hand over from another snapshot */ + int handover; + /* Used for display of table */ char type;