From: Mikulas Patocka Merging more than one snapshot is not supported, so prevent this happening. Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 36 +++++++++++++++++++++++++++++++++++- drivers/md/dm-snap.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) Index: linux-2.6.32/drivers/md/dm-snap.c =================================================================== --- linux-2.6.32.orig/drivers/md/dm-snap.c +++ linux-2.6.32/drivers/md/dm-snap.c @@ -300,8 +300,10 @@ static void __insert_origin(struct origi * Returns number of snapshots registered using the supplied cow device, plus: * snap_src - a snapshot suitable for use as a source of exception handover * snap_dest - a snapshot capable of receiving exception handover. + * snap_merge - an existing snapshot-merge target linked to the same origin. + * There can be at most one snapshot-merge target. The parameter is optional. * - * Possible return values and states: + * Possible return values and states of snap_src and snap_dest. * 0: NULL, NULL - first new snapshot * 1: snap_src, NULL - normal snapshot * 2: snap_src, snap_dest - waiting for handover @@ -310,7 +312,8 @@ static void __insert_origin(struct origi */ static int __find_snapshots_sharing_cow(struct dm_snapshot *snap, struct dm_snapshot **snap_src, - struct dm_snapshot **snap_dest) + struct dm_snapshot **snap_dest, + struct dm_snapshot **snap_merge) { struct dm_snapshot *s; struct origin *o; @@ -322,6 +325,8 @@ static int __find_snapshots_sharing_cow( goto out; list_for_each_entry(s, &o->snapshots, list) { + if (dm_target_is_snapshot_merge(s->ti) && snap_merge) + *snap_merge = s; if (!bdev_equal(s->cow->bdev, snap->cow->bdev)) continue; @@ -349,9 +354,11 @@ out: static int __validate_exception_handover(struct dm_snapshot *snap) { struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; + struct dm_snapshot *snap_merge = NULL; /* Does snapshot need exceptions handed over to it? */ - if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest) == 2) || + if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest, + &snap_merge) == 2) || snap_dest) { snap->ti->error = "Snapshot cow pairing for exception " "table handover failed"; @@ -365,6 +372,20 @@ static int __validate_exception_handover if (!snap_src) return 0; + /* + * Non-snapshot-merge handover? + */ + if (!dm_target_is_snapshot_merge(snap->ti)) + return 1; + + /* + * Do not allow more than one merging snapshot. + */ + if (snap_merge) { + snap->ti->error = "A snapshot is already merging."; + return -EINVAL; + } + return 1; } @@ -933,7 +954,7 @@ static void snapshot_dtr(struct dm_targe down_read(&_origins_lock); /* Check whether exception handover must be cancelled */ - (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); + (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest && (s == snap_src)) { down_write(&snap_dest->lock); snap_dest->valid = 0; @@ -1399,7 +1420,7 @@ static int snapshot_preresume(struct dm_ struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; down_read(&_origins_lock); - (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); + (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest) { down_read(&snap_src->lock); if (s == snap_src) { @@ -1424,7 +1445,7 @@ static void snapshot_resume(struct dm_ta struct dm_snapshot *snap_src = NULL, *snap_dest = NULL; down_read(&_origins_lock); - (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest); + (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL); if (snap_src && snap_dest) { down_write(&snap_src->lock); down_write_nested(&snap_dest->lock, SINGLE_DEPTH_NESTING);