dm snapshot: support barriers in snapshot merge target

Sets num_flush_requests=2 to support flushing both the origin and cow
devices used by the snapshot-merge target.

Also, snapshot_ctr() now gets the origin device using FMODE_WRITE if the
target is snapshot-merge (which writes to the origin device).

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 59d9ef6..23e3396 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -709,7 +709,8 @@
 	int i;
 	int r = -EINVAL;
 	char *origin_path, *cow_path;
-	unsigned args_used;
+	unsigned args_used, num_flush_requests = 1;
+	fmode_t origin_mode = FMODE_READ;
 
 	if (argc != 4) {
 		ti->error = "requires exactly 4 arguments";
@@ -717,6 +718,11 @@
 		goto bad;
 	}
 
+	if (dm_target_is_snapshot_merge(ti)) {
+		num_flush_requests = 2;
+		origin_mode = FMODE_WRITE;
+	}
+
 	origin_path = argv[0];
 	argv++;
 	argc--;
@@ -750,7 +756,7 @@
 	argv += args_used;
 	argc -= args_used;
 
-	r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
+	r = dm_get_device(ti, origin_path, 0, ti->len, origin_mode, &s->origin);
 	if (r) {
 		ti->error = "Cannot get origin device";
 		goto bad_origin;
@@ -801,7 +807,7 @@
 	INIT_WORK(&s->queued_bios_work, flush_queued_bios);
 
 	ti->private = s;
-	ti->num_flush_requests = 1;
+	ti->num_flush_requests = num_flush_requests;
 
 	/* Add snapshot to the list of snapshots for this origin */
 	/* Exceptions aren't triggered till snapshot_resume() is called */
@@ -1326,6 +1332,15 @@
 	int r = DM_MAPIO_REMAPPED;
 	chunk_t chunk;
 
+	if (unlikely(bio_empty_barrier(bio))) {
+		if (!map_context->flush_request)
+			bio->bi_bdev = s->origin->bdev;
+		else
+			bio->bi_bdev = s->cow->bdev;
+		map_context->ptr = NULL;
+		return DM_MAPIO_REMAPPED;
+	}
+
 	chunk = sector_to_chunk(s->store, bio->bi_sector);
 
 	down_read(&s->lock);