From: Mikulas Patocka <[email-masked]>

Merging more than one snapshot is not supported.
__find_merging_snapshot() will find the merging snapshot for a given
origin device.

Signed-off-by: Mikulas Patocka <[email-masked]>
Signed-off-by: Mike Snitzer <[email-masked]>

---
drivers/md/dm-snap.c |   36 +++++++++++++++++++++++++++++++++++-
 drivers/md/dm-snap.c |   47 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

Index: linux/drivers/md/dm-snap.c
===================================================================
--- linux.orig/drivers/md/dm-snap.c
+++ linux/drivers/md/dm-snap.c
@@ -342,9 +342,33 @@ out:
 	return count;
 }
 
+static struct dm_snapshot *__find_merging_snapshot(struct block_device *origin)
+{
+	struct dm_snapshot *s, *merging_snap = NULL;
+	struct origin *o;
+
+	o = __lookup_origin(origin);
+	if (!o)
+		return NULL;
+
+	list_for_each_entry(s, &o->snapshots, list) {
+		if (dm_target_is_snapshot_merge(s->ti)) {
+			merging_snap = s;
+			break;
+		}
+	}
+
+	return merging_snap;
+}
+
+/*
+ * On success, returns 1 if this snapshot is a handover destination,
+ * otherwise returns 0.
+ */
 static int __validate_exception_handover(struct dm_snapshot *snap)
 {
 	struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
+	struct block_device *bdev = snap->origin->bdev;
 	int r = 0;
 
 	/* Does snapshot need exceptions handed over to it? */
@@ -356,8 +380,27 @@ static int __validate_exception_handover
 		goto out;
 	}
 
-	if (snap_src)
-		r = 1;
+	/*
+	 * If snap_src is set, then snap has to become a handover
+	 * destination.
+	 */
+	if (!snap_src)
+		goto out;	/* No handover */
+
+	r = 1;
+
+	/*
+	 * Non-snapshot-merge handover?
+	 */
+	if (!dm_target_is_snapshot_merge(snap->ti))
+		goto out;
+
+	/* Do not allow more than one merging snapshot */
+	if (__find_merging_snapshot(bdev)) {
+		snap->ti->error = "A snapshot is already merging.";
+		r = -EINVAL;
+		goto out;
+	}
 
 out:
 	return r;