All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] lvm2 support for snapshot-merge
@ 2009-11-20 22:35 Mike Snitzer
  2009-11-20 22:35 ` [PATCH 01/15] use snapshot metadata usage to determine if snapshot is empty Mike Snitzer
                   ` (14 more replies)
  0 siblings, 15 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

This patchset adds libdm and lvm support for snapshot-merge target.
It also adds --merge flag to lvconvert; lvconvert is the command that
one will use to merge a snapshot in its origin device.  The lvconvert
manpage has been updated accordingly.

For more details please see the individual patch headers.

The LVM2 snapshot-merge quilt tree has been maintained here:
http://people.redhat.com/msnitzer/patches/snapshot-merge/lvm2/LVM2-2.02.55/

* Aside from snapshot-merge specific testing, these patches have
  survived 75+ iterations of lvm2's testsuite without any failures.
  The test kernel was 2.6.32-rc8 and lvm2 was 2.0.55 (with udev_sync
  enabled and dmeventd disabled).

Mike Snitzer (5):
  use snapshot metadata usage to determine if snapshot is empty
  Add support for "snapshot-merge" target.
  device-mapper-merging-store-needs-cow-suffix
  lvm-merge-onactivate
  lvm-merge-man-lvconvert

Mikulas Patocka (10):
  lvm-merge-metadata
  device-mapper-merge-activation
  lvm-merge-lvconvert
  lvm-merge-check-for-mounted-lv
  lvm-merge-reporting
  lvm-merge-origin-report-progress
  lvm-merge-background-poll
  lvm-merge-background-poll-on-lvvgchange
  lvm-merge-reload-if-stopped-merging
  lvm-merge-reload-proper-order

 lib/activate/activate.c          |    2 +-
 lib/activate/dev_manager.c       |   94 +++++++++++++++--
 lib/format_text/flags.c          |    1 +
 lib/metadata/lv_manip.c          |   31 ++++--
 lib/metadata/metadata-exported.h |    6 +-
 lib/metadata/snapshot_manip.c    |   13 ++-
 lib/report/report.c              |   31 ++++--
 lib/snapshot/snapshot.c          |   41 +++++---
 libdm/.exported_symbols          |    1 +
 libdm/libdevmapper.h             |    6 +
 libdm/libdm-deptree.c            |   72 +++++++++++--
 man/lvconvert.8.in               |   29 +++++-
 tools/args.h                     |    1 +
 tools/commands.h                 |   11 ++-
 tools/lvconvert.c                |  214 ++++++++++++++++++++++++++++++++++++--
 tools/toollib.c                  |   14 +++-
 tools/vgchange.c                 |    3 +-
 17 files changed, 505 insertions(+), 65 deletions(-)



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 01/15] use snapshot metadata usage to determine if snapshot is empty
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 02/15] lvm-merge-metadata Mike Snitzer
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

Future dm-snapshot will append metadata sectors used to a snapshot's
status.  This patch allows LVM2 to accurately determine if the snapshot
store is empty.  Knowing when a snapshot store is empty is important in
the context of snapshot-merge (means merge is complete).

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/snapshot/snapshot.c |   18 ++++++++++--------
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c
index d5bac31..6b1a0e2 100644
--- a/lib/snapshot/snapshot.c
+++ b/lib/snapshot/snapshot.c
@@ -95,15 +95,17 @@ static int _snap_target_percent(void **target_state __attribute((unused)),
 				char *params, uint64_t *total_numerator,
 				uint64_t *total_denominator)
 {
-	uint64_t numerator, denominator;
+	uint64_t total_sectors, sectors_allocated, metadata_sectors = 0;
+	int r;
 
-	if (sscanf(params, "%" PRIu64 "/%" PRIu64,
-		   &numerator, &denominator) == 2) {
-		*total_numerator += numerator;
-		*total_denominator += denominator;
-		if (!numerator)
+	r = sscanf(params, "%" PRIu64 "/%" PRIu64 " %" PRIu64,
+		   &sectors_allocated, &total_sectors, &metadata_sectors);
+	if (r == 2 || r == 3) {
+		*total_numerator += sectors_allocated;
+		*total_denominator += total_sectors;
+		if (sectors_allocated == metadata_sectors)
 			*percent_range = PERCENT_0;
-		else if (numerator == denominator)
+		else if (sectors_allocated == total_sectors)
 			*percent_range = PERCENT_100;
 		else
 			*percent_range = PERCENT_0_TO_100;
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 02/15] lvm-merge-metadata
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
  2009-11-20 22:35 ` [PATCH 01/15] use snapshot metadata usage to determine if snapshot is empty Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 23:26   ` Zdenek Kabelac
  2009-11-20 22:35 ` [PATCH 03/15] Add support for "snapshot-merge" target Mike Snitzer
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.

Make 'merging_snapshot' pointer that points from the origin to the
segment that represents the merging snapshot.

Import/export 'merging_store' metadata.

Do not allow creating snapshots while another snapshot is merging.
Snapshot created in this state would certainly contain invalid data.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/format_text/flags.c          |    1 +
 lib/metadata/lv_manip.c          |    6 ++++++
 lib/metadata/metadata-exported.h |    6 +++++-
 lib/metadata/snapshot_manip.c    |   13 +++++++++++--
 lib/snapshot/snapshot.c          |   15 +++++++++++----
 5 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index 829d44a..342dc5a 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -61,6 +61,7 @@ static struct flag _lv_flags[] = {
 	{MIRRORED, NULL, 0},
 	{VIRTUAL, NULL, 0},
 	{SNAPSHOT, NULL, 0},
+	{SNAPSHOT_MERGE, NULL, 0},
 	{ACTIVATE_EXCL, NULL, 0},
 	{CONVERTING, NULL, 0},
 	{PARTIAL_LV, NULL, 0},
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 260a9ee..ecaab29 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1873,6 +1873,7 @@ struct logical_volume *alloc_lv(struct dm_pool *mem)
 	}
 
 	lv->snapshot = NULL;
+	lv->merging_snapshot = NULL;
 	dm_list_init(&lv->snapshot_segs);
 	dm_list_init(&lv->segments);
 	dm_list_init(&lv->tags);
@@ -2937,6 +2938,11 @@ int lv_create_single(struct volume_group *vg,
 					  "supported yet");
 				return 0;
 			}
+			if (org->merging_snapshot) {
+				log_error("Snapshots while another snapshot "
+					  "is merging is not supported");
+				return 0;
+			}
 			if ((org->status & MIRROR_IMAGE) ||
 			    (org->status & MIRROR_LOG)) {
 				log_error("Snapshots of mirror %ss "
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index e9a3d5d..30073d3 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -60,6 +60,7 @@
 //#define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
 //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
 #define CONVERTING		0x00400000U	/* LV */
+#define SNAPSHOT_MERGE		0x00800000U	/* SEG */
 
 #define MISSING_PV              0x00800000U	/* PV */
 #define PARTIAL_LV              0x01000000U	/* LV - derived flag, not
@@ -328,6 +329,9 @@ struct logical_volume {
 	struct dm_list snapshot_segs;
 	struct lv_segment *snapshot;
 
+	/* A snapshot that is merging into this origin */
+	struct lv_segment *merging_snapshot;
+
 	struct dm_list segments;
 	struct dm_list tags;
 	struct dm_list segs_using_this_lv;
@@ -622,7 +626,7 @@ struct lv_segment *find_cow(const struct logical_volume *lv);
 struct logical_volume *origin_from_cow(const struct logical_volume *lv);
 
 void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
-		       struct logical_volume *cow, uint32_t chunk_size);
+		       struct logical_volume *cow, uint32_t chunk_size, int merge);
 
 int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
 		    union lvid *lvid, uint32_t extent_count,
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 8f902af..86cab6f 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -37,6 +37,9 @@ int lv_is_visible(const struct logical_volume *lv)
 		if (lv_is_virtual_origin(origin_from_cow(lv)))
 			return 1;
 
+		if (find_cow(lv)->status & SNAPSHOT_MERGE)
+			return 0;
+
 		return lv_is_visible(origin_from_cow(lv));
 	}
 
@@ -62,7 +65,7 @@ struct logical_volume *origin_from_cow(const struct logical_volume *lv)
 }
 
 void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
-		       struct logical_volume *cow, uint32_t chunk_size)
+		       struct logical_volume *cow, uint32_t chunk_size, int merge)
 {
 	seg->chunk_size = chunk_size;
 	seg->origin = origin;
@@ -79,6 +82,10 @@ void init_snapshot_seg(struct lv_segment *seg, struct logical_volume *origin,
 		origin->status |= VIRTUAL_ORIGIN;
 
 	seg->lv->status |= (SNAPSHOT | VIRTUAL);
+	if (merge) {
+		seg->status |= SNAPSHOT_MERGE;
+		origin->merging_snapshot = seg;
+	}
 
 	dm_list_add(&origin->snapshot_segs, &seg->origin_list);
 }
@@ -113,7 +120,7 @@ int vg_add_snapshot(struct logical_volume *origin,
 	if (!(seg = alloc_snapshot_seg(snap, 0, 0)))
 		return_0;
 
-	init_snapshot_seg(seg, origin, cow, chunk_size);
+	init_snapshot_seg(seg, origin, cow, chunk_size, 0);
 
 	return 1;
 }
@@ -122,6 +129,8 @@ int vg_remove_snapshot(struct logical_volume *cow)
 {
 	dm_list_del(&cow->snapshot->origin_list);
 	cow->snapshot->origin->origin_count--;
+	if (cow->snapshot->origin->merging_snapshot == cow->snapshot)
+		cow->snapshot->origin->merging_snapshot = NULL;
 
 	if (!lv_remove(cow->snapshot->lv)) {
 		log_error("Failed to remove internal snapshot LV %s",
diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c
index 6b1a0e2..8a3378c 100644
--- a/lib/snapshot/snapshot.c
+++ b/lib/snapshot/snapshot.c
@@ -37,7 +37,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
 	uint32_t chunk_size;
 	const char *org_name, *cow_name;
 	struct logical_volume *org, *cow;
-	int old_suppress;
+	int old_suppress, merge = 0;
 
 	if (!get_config_uint32(sn, "chunk_size", &chunk_size)) {
 		log_error("Couldn't read chunk size for snapshot.");
@@ -46,7 +46,10 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
 
 	old_suppress = log_suppress(1);
 
-	if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
+	cow_name = find_config_str(sn, "merging_store", NULL);
+	if (cow_name) {
+		merge = 1;
+	} else if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
 		log_suppress(old_suppress);
 		log_error("Snapshot cow storage not specified.");
 		return 0;
@@ -72,7 +75,7 @@ static int _snap_text_import(struct lv_segment *seg, const struct config_node *s
 		return 0;
 	}
 
-	init_snapshot_seg(seg, org, cow, chunk_size);
+	init_snapshot_seg(seg, org, cow, chunk_size, merge);
 
 	return 1;
 }
@@ -81,7 +84,11 @@ static int _snap_text_export(const struct lv_segment *seg, struct formatter *f)
 {
 	outf(f, "chunk_size = %u", seg->chunk_size);
 	outf(f, "origin = \"%s\"", seg->origin->name);
-	outf(f, "cow_store = \"%s\"", seg->cow->name);
+	if (!(seg->status & SNAPSHOT_MERGE)) {
+		outf(f, "cow_store = \"%s\"", seg->cow->name);
+	} else {
+		outf(f, "merging_store = \"%s\"", seg->cow->name);
+	}
 
 	return 1;
 }
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 03/15] Add support for "snapshot-merge" target.
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
  2009-11-20 22:35 ` [PATCH 01/15] use snapshot metadata usage to determine if snapshot is empty Mike Snitzer
  2009-11-20 22:35 ` [PATCH 02/15] lvm-merge-metadata Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 04/15] device-mapper-merge-activation Mike Snitzer
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

Introduces new libdevmapper function dm_tree_node_add_snapshot_merge_target

Verifies that the kernel (dm-snapshot) provides the 'snapshot-merge'
target.

Activate origin LV as snapshot-merge target.  Using snapshot-origin
target would be pointless because the origin contains volatile data
while a merge is in progress.

Because snapshot-merge target is activated in place of the
snapshot-origin target it must be resumed after all other snapshots
(just like snapshot-origin does) --- otherwise small window for data
corruption would exist.

Ideally the merging snapshot would not be activated at all but if it is
to be activated (because snapshot was already active) it _must_ be done
after the snapshot-merge.  This insures that DM's snapshot-merge target
will perform exception handover in the proper order (new->resume before
old->resume).  DM's snapshot-merge does support handover if the reverse
sequence is used (old->resume before new->resume) but DM will fail to
resume the old snapshot; leaving it suspended.

To insure the proper activation sequence dm_tree_activate_children() was
updated to accommodate an additional 'activation_priority' level.  All
regular snapshots are 0, snapshot-merge is 1, and merging snapshot is 2.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: Mikulas Patocka <mpatocka@redhat.com>
---
 lib/snapshot/snapshot.c |    8 ++++-
 libdm/.exported_symbols |    1 +
 libdm/libdevmapper.h    |    6 ++++
 libdm/libdm-deptree.c   |   72 ++++++++++++++++++++++++++++++++++++++++------
 4 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/lib/snapshot/snapshot.c b/lib/snapshot/snapshot.c
index 8a3378c..d058e4c 100644
--- a/lib/snapshot/snapshot.c
+++ b/lib/snapshot/snapshot.c
@@ -125,16 +125,22 @@ static int _snap_target_percent(void **target_state __attribute((unused)),
 }
 
 static int _snap_target_present(struct cmd_context *cmd,
-				const struct lv_segment *seg __attribute((unused)),
+				const struct lv_segment *seg,
 				unsigned *attributes __attribute((unused)))
 {
 	static int _snap_checked = 0;
+	static int _snap_merge_checked = 0;
 	static int _snap_present = 0;
 
 	if (!_snap_checked)
 		_snap_present = target_present(cmd, "snapshot", 1) &&
 		    target_present(cmd, "snapshot-origin", 0);
 
+	if (!_snap_merge_checked && seg && (seg->status & SNAPSHOT_MERGE)) {
+		_snap_present &= target_present(cmd, "snapshot-merge", 0);
+		_snap_merge_checked = 1;
+	}
+
 	_snap_checked = 1;
 
 	return _snap_present;
diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index 554b90a..4f051e9 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -70,6 +70,7 @@ dm_tree_suspend_children
 dm_tree_children_use_uuid
 dm_tree_node_add_snapshot_origin_target
 dm_tree_node_add_snapshot_target
+dm_tree_node_add_snapshot_merge_target
 dm_tree_node_add_error_target
 dm_tree_node_add_zero_target
 dm_tree_node_add_linear_target
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index c6546a6..1c4afa5 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -392,6 +392,12 @@ int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
 					const char *cow_uuid,
 					int persistent,
 					uint32_t chunk_size);
+int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node,
+					     uint64_t size,
+					     const char *origin_uuid,
+					     const char *cow_uuid,
+					     const char *merge_uuid,
+					     uint32_t chunk_size);
 int dm_tree_node_add_error_target(struct dm_tree_node *node,
 				     uint64_t size);
 int dm_tree_node_add_zero_target(struct dm_tree_node *node,
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index 91f7177..5207f0d 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -35,6 +35,7 @@ enum {
 	SEG_MIRRORED,
 	SEG_SNAPSHOT,
 	SEG_SNAPSHOT_ORIGIN,
+	SEG_SNAPSHOT_MERGE,
 	SEG_STRIPED,
 	SEG_ZERO,
 };
@@ -51,6 +52,7 @@ struct {
 	{ SEG_MIRRORED, "mirror" },
 	{ SEG_SNAPSHOT, "snapshot" },
 	{ SEG_SNAPSHOT_ORIGIN, "snapshot-origin" },
+	{ SEG_SNAPSHOT_MERGE, "snapshot-merge" },
 	{ SEG_STRIPED, "striped" },
 	{ SEG_ZERO, "zero"},
 };
@@ -81,6 +83,7 @@ struct load_segment {
 	uint32_t chunk_size;		/* Snapshot */
 	struct dm_tree_node *cow;	/* Snapshot */
 	struct dm_tree_node *origin;	/* Snapshot + Snapshot origin */
+	struct dm_tree_node *merge;	/* Snapshot */
 
 	struct dm_tree_node *log;	/* Mirror */
 	uint32_t region_size;		/* Mirror */
@@ -1166,7 +1169,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
 
 	handle = NULL;
 
-	for (priority = 0; priority < 2; priority++) {
+	for (priority = 0; priority < 3; priority++) {
 		while ((child = dm_tree_next_child(&handle, dnode, 0))) {
 			if (!(uuid = dm_tree_node_get_uuid(child))) {
 				stack;
@@ -1457,6 +1460,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
 			return_0;
 		break;
 	case SEG_SNAPSHOT:
+	case SEG_SNAPSHOT_MERGE:
 		if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
 			return_0;
 		if (!_build_dev_string(cowbuf, sizeof(cowbuf), seg->cow))
@@ -1485,6 +1489,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
 	case SEG_ERROR:
 	case SEG_SNAPSHOT:
 	case SEG_SNAPSHOT_ORIGIN:
+	case SEG_SNAPSHOT_MERGE:
 	case SEG_ZERO:
 		break;
 	case SEG_CRYPT:
@@ -1719,6 +1724,7 @@ static struct load_segment *_add_segment(struct dm_tree_node *dnode, unsigned ty
 	seg->chunk_size = 0;
 	seg->cow = NULL;
 	seg->origin = NULL;
+	seg->merge = NULL;
 
 	dm_list_add(&dnode->props.segs, &seg->list);
 	dnode->props.segment_count++;
@@ -1751,17 +1757,21 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
 	return 1;
 }
 
-int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
-                                        uint64_t size,
-                                        const char *origin_uuid,
-                                        const char *cow_uuid,
-                                        int persistent,
-                                        uint32_t chunk_size)
+static int _add_snapshot_target(struct dm_tree_node *node,
+				   uint64_t size,
+				   const char *origin_uuid,
+				   const char *cow_uuid,
+				   const char *merge_uuid,
+				   int persistent,
+				   uint32_t chunk_size)
 {
 	struct load_segment *seg;
-	struct dm_tree_node *origin_node, *cow_node;
+	struct dm_tree_node *origin_node, *cow_node, *merge_node;
+	unsigned seg_type;
+
+	seg_type = !merge_uuid ? SEG_SNAPSHOT : SEG_SNAPSHOT_MERGE;
 
-	if (!(seg = _add_segment(node, SEG_SNAPSHOT, size)))
+	if (!(seg = _add_segment(node, seg_type, size)))
 		return_0;
 
 	if (!(origin_node = dm_tree_find_node_by_uuid(node->dtree, origin_uuid))) {
@@ -1774,7 +1784,7 @@ int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
 		return_0;
 
 	if (!(cow_node = dm_tree_find_node_by_uuid(node->dtree, cow_uuid))) {
-		log_error("Couldn't find snapshot origin uuid %s.", cow_uuid);
+		log_error("Couldn't find snapshot COW device uuid %s.", cow_uuid);
 		return 0;
 	}
 
@@ -1782,12 +1792,54 @@ int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
 	if (!_link_tree_nodes(node, cow_node))
 		return_0;
 
+	if (merge_uuid) {
+		if (!(merge_node = dm_tree_find_node_by_uuid(node->dtree, merge_uuid))) {
+			/* not a pure error, merging snapshot may have been deactivated */
+			log_verbose("Couldn't find merging snapshot uuid %s.", merge_uuid);
+		} else {
+			seg->merge = merge_node;
+			/* must not link merging snapshot, would undermine activation_priority below */
+		}
+	}
+
 	seg->persistent = persistent ? 1 : 0;
 	seg->chunk_size = chunk_size;
 
+	if (merge_uuid) {
+		/* Resume snapshot-merge (acting origin) after other snapshots */
+		node->activation_priority = 1;
+		if (seg->merge) {
+			/* Resume merging snapshot after snapshot-merge */
+			seg->merge->activation_priority = 2;
+		}
+	}
+
 	return 1;
 }
 
+
+int dm_tree_node_add_snapshot_target(struct dm_tree_node *node,
+				     uint64_t size,
+				     const char *origin_uuid,
+				     const char *cow_uuid,
+				     int persistent,
+				     uint32_t chunk_size)
+{
+	return _add_snapshot_target(node, size, origin_uuid, cow_uuid,
+				    NULL, persistent, chunk_size);
+}
+
+int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node,
+					   uint64_t size,
+					   const char *origin_uuid,
+					   const char *cow_uuid,
+					   const char *merge_uuid,
+					   uint32_t chunk_size)
+{
+	return _add_snapshot_target(node, size, origin_uuid, cow_uuid,
+				    merge_uuid, 1, chunk_size);
+}
+
 int dm_tree_node_add_error_target(struct dm_tree_node *node,
                                      uint64_t size)
 {
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 04/15] device-mapper-merge-activation
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (2 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 03/15] Add support for "snapshot-merge" target Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 05/15] device-mapper-merging-store-needs-cow-suffix Mike Snitzer
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Conditionally push down either the "snapshot-origin" or
"snapshot-merge" target based on whether the LV is a merging snapshot.

When activating a snapshot-merge target do not attempt to monitor the
LV for events; the polldaemon will monitor the snapshot as it is
merged.

Allow "snapshot-merge" target's usage to be parsed via standard
"snapshot" methods.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/activate/activate.c    |    2 +-
 lib/activate/dev_manager.c |   58 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 7256dab..edad15d 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -750,7 +750,7 @@ int monitor_dev_for_events(struct cmd_context *cmd,
 	 * In case of a snapshot device, we monitor lv->snapshot->lv,
 	 * not the actual LV itself.
 	 */
-	if (lv_is_cow(lv))
+	if (lv_is_cow(lv) && !(find_cow(lv)->status & SNAPSHOT_MERGE))
 		return monitor_dev_for_events(cmd, lv->snapshot->lv, monitor);
 
 	/*
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index af05f5c..ed05f95 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -395,10 +395,16 @@ static int _percent_run(struct dev_manager *dm, const char *name,
 			seg = dm_list_item(segh, struct lv_segment);
 		}
 
-		if (!type || !params || strcmp(type, target_type))
+                /*
+                 * If target status doesn't have 'params' or 'type' is not in the same
+                 * target base class as 'target_type' (e.g. snapshot*, mirror*) skip it
+                 * - allows the situation when 'type' is "snapshot-merge" and
+                 *   'target_type' is "snapshot"
+                 */
+		if (!type || !params || strncmp(type, target_type, strlen(target_type)))
 			continue;
 
-		if (!(segtype = get_segtype_from_string(dm->cmd, type)))
+		if (!(segtype = get_segtype_from_string(dm->cmd, target_type)))
 			continue;
 
 		if (segtype->ops->target_percent &&
@@ -876,6 +882,29 @@ static int _add_origin_target_to_dtree(struct dev_manager *dm,
 	return 1;
 }
 
+static int _add_snapshot_merge_target_to_dtree(struct dev_manager *dm,
+					       struct dm_tree_node *dnode,
+					       struct logical_volume *lv)
+{
+	const char *origin_dlid, *cow_dlid, *merge_dlid;
+
+	if (!(origin_dlid = build_dlid(dm, lv->lvid.s, "real")))
+		return_0;
+
+	if (!(cow_dlid = build_dlid(dm, lv->merging_snapshot->cow->lvid.s, "cow")))
+		return_0;
+
+	if (!(merge_dlid = build_dlid(dm, lv->merging_snapshot->cow->lvid.s, NULL)))
+		return_0;
+
+	if (!dm_tree_node_add_snapshot_merge_target(dnode, lv->size, origin_dlid,
+						    cow_dlid, merge_dlid,
+						    lv->merging_snapshot->chunk_size))
+		return_0;
+
+	return 1;
+}
+
 static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
 					   struct dm_tree_node *dnode,
 					   struct logical_volume *lv)
@@ -890,6 +919,9 @@ static int _add_snapshot_target_to_dtree(struct dev_manager *dm,
 		return 0;
 	}
 
+	if (snap_seg->status & SNAPSHOT_MERGE)
+		return 1;
+
 	if (!(origin_dlid = build_dlid(dm, snap_seg->origin->lvid.s, "real")))
 		return_0;
 
@@ -957,11 +989,21 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
 		return_0;
 
 	/* If this is a snapshot origin, add real LV */
+	/* If this is a snapshot origin w/ merging snapshot, add cow and real LV */
 	if (lv_is_origin(seg->lv) && !layer) {
 		if (vg_is_clustered(seg->lv->vg)) {
 			log_error("Clustered snapshots are not yet supported");
 			return 0;
 		}
+		if (seg->lv->merging_snapshot) {
+			if (!_add_new_lv_to_dtree(dm, dtree,
+			     seg->lv->merging_snapshot->cow, "cow"))
+				return_0;
+			/*
+			 * Must also add "real" LV for use when
+			 * snapshot-merge target is added
+			 */
+		}
 		if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, "real"))
 			return_0;
 	} else if (lv_is_cow(seg->lv) && !layer) {
@@ -977,8 +1019,13 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
 
 	/* Now we've added its dependencies, we can add the target itself */
 	if (lv_is_origin(seg->lv) && !layer) {
-		if (!_add_origin_target_to_dtree(dm, dnode, seg->lv))
-			return_0;
+		if (!seg->lv->merging_snapshot) {
+			if (!_add_origin_target_to_dtree(dm, dnode, seg->lv))
+				return_0;
+		} else {
+			if (!_add_snapshot_merge_target_to_dtree(dm, dnode, seg->lv))
+				return_0;
+		}
 	} else if (lv_is_cow(seg->lv) && !layer) {
 		if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv))
 			return_0;
@@ -1006,6 +1053,9 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
 	uint32_t read_ahead_flags = UINT32_C(0);
 	uint16_t udev_flags = 0;
 
+	if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE && !layer)
+		return 1;
+
 	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
 		return_0;
 
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 05/15] device-mapper-merging-store-needs-cow-suffix
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (3 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 04/15] device-mapper-merge-activation Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 06/15] lvm-merge-lvconvert Mike Snitzer
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

Merging device is loaded with "-cow" suffix and with base name of the
origin.  This is needed so that "-cow" device can be found and removed
when lvremove is performed.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
---
 lib/activate/dev_manager.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index ed05f95..7208ecd 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1047,16 +1047,28 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
 	struct lv_segment *seg;
 	struct lv_layer *lvlayer;
 	struct dm_tree_node *dnode;
-	char *name, *dlid;
+	char *name, *dlid, *lv_name;
 	uint32_t max_stripe_size = UINT32_C(0);
 	uint32_t read_ahead = lv->read_ahead;
 	uint32_t read_ahead_flags = UINT32_C(0);
 	uint16_t udev_flags = 0;
 
-	if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE && !layer)
-		return 1;
+	lv_name = lv->name;
+	if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE) {
+		if (layer) {
+			/*
+			 * use origin's name as basis for snapshot-merge device names;
+			 * this allows _clean_tree to automatically cleanup "-cow"
+			 * when the origin is resumed (after merge completes)
+			 */
+			lv_name = origin_from_cow(lv)->name;
+		} else {
+			/* top-level snapshot device is not needed during merge */
+			return 1;
+		}
+	}
 
-	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
+	if (!(name = build_dm_name(dm->mem, lv->vg->name, lv_name, layer)))
 		return_0;
 
 	if (!(dlid = build_dlid(dm, lv->lvid.s, layer)))
@@ -1068,7 +1080,7 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
 		return 1;
 
 	if (!(lvlayer = dm_pool_alloc(dm->mem, sizeof(*lvlayer)))) {
-		log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.", lv->name, layer);
+		log_error("_add_new_lv_to_dtree: pool alloc failed for %s %s.", lv_name, layer);
 		return 0;
 	}
 
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 06/15] lvm-merge-lvconvert
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (4 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 05/15] device-mapper-merging-store-needs-cow-suffix Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 07/15] lvm-merge-check-for-mounted-lv Mike Snitzer
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Add --merge support to lvconvert to start merging a snapshot into its
origin, example usage:  lvconvert --merge vg/snaplv

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 tools/args.h      |    1 +
 tools/commands.h  |   11 ++++-
 tools/lvconvert.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 115 insertions(+), 9 deletions(-)

diff --git a/tools/args.h b/tools/args.h
index 1f2427b..d2476ad 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -103,6 +103,7 @@ arg(list_ARG, 'l', "list", NULL, 0)
 arg(size_ARG, 'L', "size", size_mb_arg, 0)
 arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0)
 arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0)
+arg(merge_ARG, '\0', "merge", NULL, 0)
 arg(major_ARG, 'j', "major", major_arg, 0)
 arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0)
 arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 85222e4..93e9019 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -119,11 +119,16 @@ xx(lvconvert,
    "\t[-v|--verbose]\n"
    "\t[-Z|--zero {y|n}]\n"
    "\t[--version]" "\n"
-   "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
+   "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n\n"
+
+   "lvconvert "
+   "--merge\n"
+   "\tSnapshotLogicalVolume[Path]\n",
 
    alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
-   mirrorlog_ARG, mirrors_ARG, noudevsync_ARG, regionsize_ARG, repair_ARG,
-   snapshot_ARG, test_ARG, use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
+   merge_ARG, mirrorlog_ARG, mirrors_ARG, noudevsync_ARG, regionsize_ARG,
+   repair_ARG, snapshot_ARG, test_ARG, use_policies_ARG, yes_ARG, force_ARG,
+   zero_ARG)
 
 xx(lvcreate,
    "Create a logical volume",
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index d1b86bf..517b4f3 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -18,6 +18,7 @@
 
 struct lvconvert_params {
 	int snapshot;
+	int merge;
 	int zero;
 
 	const char *origin;
@@ -49,7 +50,7 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
 	char *ptr;
 	const char *vg_name = NULL;
 
-	if (lp->snapshot) {
+	if (lp->snapshot && !lp->merge) {
 		if (!*pargc) {
 			log_error("Please specify a logical volume to act as "
 				  "the snapshot origin.");
@@ -99,6 +100,11 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
 	if (!apply_lvname_restrictions(lp->lv_name))
 		return_0;
 
+	if (*pargc && (lp->snapshot || lp->merge)) {
+		log_error("Extra arguments for snapshots");
+		return 0;
+	}
+
 	return 1;
 }
 
@@ -110,10 +116,10 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 
 	memset(lp, 0, sizeof(*lp));
 
-	if (arg_count(cmd, snapshot_ARG) &&
+	if ((arg_count(cmd, snapshot_ARG) || arg_count(cmd, merge_ARG)) &&
 	    (arg_count(cmd, mirrorlog_ARG) || arg_count(cmd, mirrors_ARG) ||
 	     arg_count(cmd, repair_ARG))) {
-		log_error("--snapshot argument cannot be mixed "
+		log_error("--snapshot or --merge argument cannot be mixed "
 			  "with --mirrors, --repair or --log");
 		return 0;
 	}
@@ -124,6 +130,9 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 	if (arg_count(cmd, snapshot_ARG))
 		lp->snapshot = 1;
 
+	if (arg_count(cmd, merge_ARG))
+		lp->merge = 1;
+
 	if (arg_count(cmd, mirrors_ARG)) {
 		lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
 		lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
@@ -131,7 +140,17 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 
 	lp->alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
 
-	if (lp->snapshot) {
+	if (lp->merge) {
+		if (arg_count(cmd, regionsize_ARG) || arg_count(cmd, chunksize_ARG) ||
+		    arg_count(cmd, zero_ARG) || arg_count(cmd, regionsize_ARG)) {
+			log_error("invalid arguments for snapshot merge");
+			return 0;
+		}
+
+		if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
+			return_0;
+
+	} else if (lp->snapshot) {
 		if (arg_count(cmd, regionsize_ARG)) {
 			log_error("--regionsize is only available with mirrors");
 			return 0;
@@ -894,6 +913,73 @@ out:
 	return r;
 }
 
+static int lvconvert_merge(struct cmd_context *cmd,
+			   struct logical_volume *lv,
+			   struct lvconvert_params *lp)
+{
+	int r = 0;
+	struct logical_volume *origin = origin_from_cow(lv);
+	struct lv_segment *cow_seg = find_cow(lv);
+
+	/* Check if merge is possible */
+	if (cow_seg->status & SNAPSHOT_MERGE) {
+		log_error("Snapshot %s is already merging", lv->name);
+		return 0;
+	}
+	if (origin->merging_snapshot) {
+		log_error("Snapshot %s is already merging into the origin",
+			  origin->merging_snapshot->cow->name);
+		return 0;
+	}
+
+	/*
+	 * Even though lv_is_visible(cow_seg->lv) returns 0,
+	 * the cow_seg->lv (name: snapshotX) is _not_ hidden;
+	 * this is part of the lvm2 snapshot fiction.  Must
+	 * clear VISIBLE_LV directly (lv_set_visible can't)
+	 * - cow_seg->lv->status is used to control whether 'lv'
+	 *   (with user provided snapshot LV name) is visible
+	 * - this also enables vg_validate() to succeed with
+	 *   merge metadata (cow_seg->lv is now "internal")
+	 */
+	cow_seg->lv->status &= ~VISIBLE_LV;
+	cow_seg->status |= SNAPSHOT_MERGE;
+	origin->merging_snapshot = cow_seg;
+
+	/* store vg on disk(s) */
+	if (!vg_write(lv->vg))
+		return_0;
+
+	/* Perform merge */
+	if (!suspend_lv(cmd, origin)) {
+		log_error("Failed to suspend origin %s", origin->name);
+		vg_revert(lv->vg);
+		goto out;
+	}
+
+	if (!vg_commit(lv->vg)) {
+		if (!resume_lv(cmd, origin))
+			stack;
+		goto_out;
+	}
+
+	if (!resume_lv(cmd, origin)) {
+		log_error("Failed to reactivate origin %s", origin->name);
+		goto out;
+	}
+
+	if (!deactivate_lv(cmd, lv)) {
+		log_warn("WARNING: Unable to deactivate merging snapshot %s", lv->name);
+		/* merge is running regardless of this deactivation failure */
+	}
+
+	r = 1;
+	log_print("Merging of volume %s started.", lv->name);
+out:
+	backup(lv->vg);
+	return r;
+}
+
 static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 			    void *handle)
 {
@@ -904,7 +990,7 @@ static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 		return ECMD_FAILED;
 	}
 
-	if (lv_is_cow(lv)) {
+	if (lv_is_cow(lv) && !lp->merge) {
 		log_error("Can't convert snapshot logical volume \"%s\"",
 			  lv->name);
 		return ECMD_FAILED;
@@ -920,7 +1006,21 @@ static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 		return ECMD_FAILED;
 	}
 
-	if (lp->snapshot) {
+	if (lp->merge) {
+		if (!lv_is_cow(lv)) {
+			log_error("Logical volume \"%s\" is not a snapshot",
+				  lv->name);
+			return ECMD_FAILED;
+		}
+		if (!archive(lv->vg)) {
+			stack;
+			return ECMD_FAILED;
+		}
+		if (!lvconvert_merge(cmd, lv, lp)) {
+			stack;
+			return ECMD_FAILED;
+		}
+	} else if (lp->snapshot) {
 		if (lv->status & MIRRORED) {
 			log_error("Unable to convert mirrored LV \"%s\" into a snapshot.", lv->name);
 			return ECMD_FAILED;
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 07/15] lvm-merge-check-for-mounted-lv
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (5 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 06/15] lvm-merge-lvconvert Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 08/15] lvm-merge-reporting Mike Snitzer
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Do not allow merging over mounted logical volumes.
When preserving origin, check that the snapshot is not mounted.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 tools/lvconvert.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 517b4f3..49b22a7 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -920,6 +920,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
 	int r = 0;
 	struct logical_volume *origin = origin_from_cow(lv);
 	struct lv_segment *cow_seg = find_cow(lv);
+	struct lvinfo info;
 
 	/* Check if merge is possible */
 	if (cow_seg->status & SNAPSHOT_MERGE) {
@@ -932,6 +933,19 @@ static int lvconvert_merge(struct cmd_context *cmd,
 		return 0;
 	}
 
+	if (lv_info(cmd, origin, &info, 1, 0)) {
+		if (info.open_count) {
+			log_error("Can't merge over open origin volume");
+			return 0;
+		}
+	}
+	if (lv_info(cmd, lv, &info, 1, 0)) {
+		if (info.open_count) {
+			log_error("Can't merge when snapshot is open");
+			return 0;
+		}
+	}
+
 	/*
 	 * Even though lv_is_visible(cow_seg->lv) returns 0,
 	 * the cow_seg->lv (name: snapshotX) is _not_ hidden;
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 08/15] lvm-merge-reporting
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (6 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 07/15] lvm-merge-check-for-mounted-lv Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 09/15] lvm-merge-origin-report-progress Mike Snitzer
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Report merging snapshot as 'S' instead of 's':
This is useful for when the snapshot is still active and merging hasn't
started yet; it shows a merge is pending.  Once merging starts the
merging snapshot will be hidden but can still be displayed with 'lvs -a'

Report snapshot origin with merging snapshot as 'O' instead of 'o':
Before merge starts this shows that a merge is pending.  While merging
the snapshot will be hidden, 'O' enables a user to see that there is a
snapshot merging.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/report/report.c |   17 ++++++++++++-----
 1 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lib/report/report.c b/lib/report/report.c
index 54192d5..9b3fd0d 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -314,8 +314,12 @@ static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
 	else if (lv->status & VIRTUAL)
 		repstr[0] = 'v';
 	/* Origin takes precedence over Mirror */
-	else if (lv_is_origin(lv))
-		repstr[0] = 'o';
+	else if (lv_is_origin(lv)) {
+		if (lv->merging_snapshot)
+			repstr[0] = 'O';
+		else
+			repstr[0] = 'o';
+	}
 	else if (lv->status & MIRRORED) {
 		if (lv->status & MIRROR_NOTSYNCED)
 			repstr[0] = 'M';
@@ -328,9 +332,12 @@ static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
 			repstr[0] = 'I';
 	else if (lv->status & MIRROR_LOG)
 		repstr[0] = 'l';
-	else if (lv_is_cow(lv))
-		repstr[0] = 's';
-	else
+	else if (lv_is_cow(lv)) {
+		if (find_cow(lv)->status & SNAPSHOT_MERGE)
+			repstr[0] = 'S';
+		else
+			repstr[0] = 's';
+	} else
 		repstr[0] = '-';
 
 	if (lv->status & PVMOVE)
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 09/15] lvm-merge-origin-report-progress
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (7 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 08/15] lvm-merge-reporting Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 10/15] lvm-merge-background-poll Mike Snitzer
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

When there is merging snapshot, report percentage on the origin LV.
Because the snapshot LV will be hidden this is needed so the user can
see merging progress with "lvs" command.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/report/report.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/report/report.c b/lib/report/report.c
index 9b3fd0d..b65b492 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1032,7 +1032,7 @@ static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm
 		return 0;
 	}
 
-	if (!lv_is_cow(lv) ||
+	if ((!lv_is_cow(lv) && !lv->merging_snapshot) ||
 	    (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) {
 		*sortval = UINT64_C(0);
 		dm_report_field_set_value(field, "", sortval);
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 10/15] lvm-merge-background-poll
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (8 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 09/15] lvm-merge-origin-report-progress Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 11/15] lvm-merge-background-poll-on-lvvgchange Mike Snitzer
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Background poll for lvconvert --merge command.
The merging snapshot is removed when the merge finishes.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 tools/lvconvert.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 49b22a7..7447007 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -41,6 +41,8 @@ struct lvconvert_params {
 	int pv_count;
 	char **pvs;
 	struct dm_list *pvh;
+
+	struct logical_volume *lv_to_poll;
 };
 
 static int _lvconvert_name_params(struct lvconvert_params *lp,
@@ -329,6 +331,54 @@ out:
 	return r;
 }
 
+static int _finish_lvconvert_merge(struct cmd_context *cmd,
+				   struct volume_group *vg,
+				   struct logical_volume *lv,
+				   struct dm_list *lvs_changed __attribute((unused)))
+{
+	struct lv_segment *snap_seg = lv->merging_snapshot;
+	if (!snap_seg) {
+		log_error("Logical volume %s has no merging snapshot.", lv->name);
+		return 0;
+	}
+
+	log_print("Merge into logical volume %s finished.", lv->name);
+	if (!lv_remove_single(cmd, snap_seg->cow, DONT_PROMPT)) {
+		log_error("Could not remove snapshot %s merged into %s.",
+			  snap_seg->cow->name, lv->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+static progress_t _poll_merge_progress(struct cmd_context *cmd,
+				       struct logical_volume *lv,
+				       const char *name __attribute((unused)),
+				       struct daemon_parms *parms)
+{
+	float percent = 0.0;
+	percent_range_t percent_range;
+
+	if (!lv_snapshot_percent(lv, &percent, &percent_range)) {
+		log_error("%s: Failed query for merging percentage", lv->name);
+		return PROGRESS_CHECK_FAILED;
+	} else if (percent_range == PERCENT_INVALID) {
+		log_error("%s: Merging snapshot invalidated, aborting merge", lv->name);
+		return PROGRESS_CHECK_FAILED;
+	}
+
+	if (parms->progress_display)
+		log_print("%s: %s: %.1f%%", lv->name, parms->progress_title, percent);
+	else
+		log_verbose("%s: %s: %.1f%%", lv->name, parms->progress_title, percent);
+
+	if (percent_range == PERCENT_0)
+		return PROGRESS_FINISHED_ALL;
+
+	return PROGRESS_UNFINISHED;
+}
+
 static struct poll_functions _lvconvert_mirror_fns = {
 	.get_copy_vg = _get_lvconvert_vg,
 	.get_copy_lv = _get_lvconvert_lv,
@@ -337,6 +387,13 @@ static struct poll_functions _lvconvert_mirror_fns = {
 	.finish_copy = _finish_lvconvert_mirror,
 };
 
+static struct poll_functions _lvconvert_merge_fns = {
+	.get_copy_vg = _get_lvconvert_vg,
+	.get_copy_lv = _get_lvconvert_lv,
+	.poll_progress = _poll_merge_progress,
+	.finish_copy = _finish_lvconvert_merge,
+};
+
 int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
 		   unsigned background)
 {
@@ -353,8 +410,12 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
 
 	memcpy(uuid, &lv->lvid, sizeof(lv->lvid));
 
-	return poll_daemon(cmd, lv_full_name, uuid, background, 0,
-			   &_lvconvert_mirror_fns, "Converted");
+	if (!lv->merging_snapshot)
+		return poll_daemon(cmd, lv_full_name, uuid, background, 0,
+				   &_lvconvert_mirror_fns, "Converted");
+	else
+		return poll_daemon(cmd, lv_full_name, uuid, background, 0,
+				   &_lvconvert_merge_fns, "Merged");
 }
 
 static int _insert_lvconvert_layer(struct cmd_context *cmd,
@@ -987,6 +1048,9 @@ static int lvconvert_merge(struct cmd_context *cmd,
 		/* merge is running regardless of this deactivation failure */
 	}
 
+	lp->need_polling = 1;
+	lp->lv_to_poll = origin;
+
 	r = 1;
 	log_print("Merging of volume %s started.", lv->name);
 out:
@@ -1099,17 +1163,18 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv)
 	} else
 		lp.pvh = &vg->pvs;
 
+	lp.lv_to_poll = lvl->lv;
 	ret = lvconvert_single(cmd, lvl->lv, &lp);
 
 bad:
 	unlock_vg(cmd, lp.vg_name);
 
 	if (ret == ECMD_PROCESSED && lp.need_polling) {
-		if (!lv_info(cmd, lvl->lv, &info, 1, 0) || !info.exists) {
+		if (!lv_info(cmd, lp.lv_to_poll, &info, 1, 0) || !info.exists) {
 			log_print("Conversion starts after activation");
 			goto out;
 		}
-		ret = lvconvert_poll(cmd, lvl->lv,
+		ret = lvconvert_poll(cmd, lp.lv_to_poll,
 				     lp.wait_completion ? 0 : 1U);
 	}
 out:
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 11/15] lvm-merge-background-poll-on-lvvgchange
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (9 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 10/15] lvm-merge-background-poll Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 12/15] lvm-merge-reload-if-stopped-merging Mike Snitzer
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Start background polling of merging stores on:
- lvchange -ay or vgchange -ay.
- lvchange --refresh or vgchange --refresh.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 tools/toollib.c  |   14 +++++++++++++-
 tools/vgchange.c |    3 ++-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/tools/toollib.c b/tools/toollib.c
index ada1302..85220eb 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -1262,6 +1262,18 @@ int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv)
 	if (!r)
 		goto_out;
 
+	/*
+	 * check if snapshot merge should be polled
+	 * - unfortunately: even though the dev_manager will clear
+	 *   the lv's merge attributes if a merge is not possible;
+	 *   it is clearing a different instance of the lv (as
+	 *   retrieved with lv_from_lvid)
+	 * - fortunately: polldaemon will immediately shutdown if the
+	 *   origin doesn't have a status with a snapshot percentage
+	 */
+	if (lv_is_origin(lv) && lv->merging_snapshot)
+		lv_spawn_background_polling(cmd, lv);
+
 out:
 	return r;
 }
@@ -1296,7 +1308,7 @@ void lv_spawn_background_polling(struct cmd_context *cmd,
 		pvmove_poll(cmd, pvname, 1);
 	}
 
-	if (lv->status & CONVERTING) {
+	if (lv->status & CONVERTING || lv->merging_snapshot) {
 		log_verbose("Spawning background lvconvert process for %s",
 			lv->name);
 		lvconvert_poll(cmd, lv, 1);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index c1aa5cf..de1f418 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -104,7 +104,8 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
 		}
 
 		if (activate != CHANGE_AN && activate != CHANGE_ALN &&
-		    (lv->status & (PVMOVE|CONVERTING)))
+		    (lv->status & (PVMOVE|CONVERTING) ||
+		     lv->merging_snapshot))
 			lv_spawn_background_polling(cmd, lv);
 
 		count++;
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 12/15] lvm-merge-reload-if-stopped-merging
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (10 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 11/15] lvm-merge-background-poll-on-lvvgchange Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 13/15] lvm-merge-reload-proper-order Mike Snitzer
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

Reload origin if merging has stopped.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/metadata/lv_manip.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index ecaab29..7990863 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -2061,6 +2061,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 	struct volume_group *vg;
 	struct lvinfo info;
 	struct logical_volume *origin = NULL;
+	int was_merging = 0;
 
 	vg = lv->vg;
 
@@ -2122,6 +2123,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 
 	if (lv_is_cow(lv)) {
 		origin = origin_from_cow(lv);
+		was_merging = !!origin->merging_snapshot;
 		log_verbose("Removing snapshot %s", lv->name);
 		if (!vg_remove_snapshot(lv))
 			return_0;
@@ -2139,8 +2141,8 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 
 	backup(vg);
 
-	/* If no snapshots left, reload without -real. */
-	if (origin && !lv_is_origin(origin)) {
+	/* If no snapshots left or if we stopped merging, reload */
+	if (origin && (!lv_is_origin(origin) || was_merging)) {
 		if (!suspend_lv(cmd, origin))
 			log_error("Failed to refresh %s without snapshot.", origin->name);
 		else if (!resume_lv(cmd, origin))
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 13/15] lvm-merge-reload-proper-order
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (11 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 12/15] lvm-merge-reload-if-stopped-merging Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 14/15] lvm-merge-onactivate Mike Snitzer
  2009-11-20 22:35 ` [PATCH 15/15] lvm-merge-man-lvconvert Mike Snitzer
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

From: Mikulas Patocka <mpatocka@redhat.com>

When turning merging origin into non-merging origin, there is bad sequence:
snapshots are suspended, new origin is created, snapshots are resumed, new
origin is resumed.  So it allocates memory while suspended.

To fix it, move vg_commit after suspend_lv, so that the suspend code will
treat it as precommitted vg and will preload new origin prior to suspend.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 lib/metadata/lv_manip.c |   19 ++++++++++++++-----
 1 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 7990863..a036022 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -2136,19 +2136,28 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 	}
 
 	/* store it on disks */
-	if (!vg_write(vg) || !vg_commit(vg))
+	if (!vg_write(vg))
 		return_0;
 
-	backup(vg);
-
 	/* If no snapshots left or if we stopped merging, reload */
 	if (origin && (!lv_is_origin(origin) || was_merging)) {
-		if (!suspend_lv(cmd, origin))
+		if (!suspend_lv(cmd, origin)) {
 			log_error("Failed to refresh %s without snapshot.", origin->name);
-		else if (!resume_lv(cmd, origin))
+			return 0;
+		}
+		if (!vg_commit(vg))
+			return_0;
+		if (!resume_lv(cmd, origin)) {
 			log_error("Failed to resume %s.", origin->name);
+			return 0;
+		}
+	} else {
+		if (!vg_commit(vg))
+			return_0;
 	}
 
+	backup(vg);
+
 	if (lv_is_visible(lv))
 		log_print("Logical volume \"%s\" successfully removed", lv->name);
 
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 14/15] lvm-merge-onactivate
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (12 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 13/15] lvm-merge-reload-proper-order Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  2009-11-20 22:35 ` [PATCH 15/15] lvm-merge-man-lvconvert Mike Snitzer
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

Merge on activate support.

If either the origin or snapshot that is to be merged is open the merge
will not start; only the merge metadata will be written.  The merge will
start on the next activation of the origin (or via lvchange --refresh)
IFF both the origin and snapshot are closed.

Merge on activate is particularly important if we want to merge over a
mounted filesystem that cannot be unmounted (until next boot) --- for
example root.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: Mikulas Patocka <mpatocka@redhat.com>
---
 lib/activate/dev_manager.c |   18 ++++++++++++++++++
 lib/report/report.c        |   12 ++++++++++--
 tools/lvconvert.c          |   23 +++++++++++++++++++----
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 7208ecd..52103e3 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1047,12 +1047,30 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
 	struct lv_segment *seg;
 	struct lv_layer *lvlayer;
 	struct dm_tree_node *dnode;
+	struct dm_info dinfo;
 	char *name, *dlid, *lv_name;
 	uint32_t max_stripe_size = UINT32_C(0);
 	uint32_t read_ahead = lv->read_ahead;
 	uint32_t read_ahead_flags = UINT32_C(0);
 	uint16_t udev_flags = 0;
 
+	if (lv_is_origin(lv) && lv->merging_snapshot && !layer) {
+		/*
+		 * Clear merge attributes if merge isn't currently possible:
+		 * either origin or merging snapshot are open
+		 * (must refresh info's open_count, so using the tree's
+		 *  existing nodes' info isn't an option)
+		 */
+		if ((dev_manager_info(dm->mem, NULL, lv,
+				      0, 1, 0, &dinfo, NULL) && dinfo.open_count) ||
+		    (dev_manager_info(dm->mem, NULL, lv->merging_snapshot->cow,
+				      0, 1, 0, &dinfo, NULL) && dinfo.open_count)) {
+			/* clear merge attributes */
+			lv->merging_snapshot->status &= ~SNAPSHOT_MERGE;
+			lv->merging_snapshot = NULL;
+		}
+	}
+
 	lv_name = lv->name;
 	if (lv_is_cow(lv) && find_cow(lv)->status & SNAPSHOT_MERGE) {
 		if (layer) {
diff --git a/lib/report/report.c b/lib/report/report.c
index b65b492..878c7e0 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1041,8 +1041,16 @@ static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm
 
 	if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) ||
 				 (percent_range == PERCENT_INVALID)) {
-		*sortval = UINT64_C(100);
-		dm_report_field_set_value(field, "100.00", sortval);
+		if (!lv->merging_snapshot) {
+			*sortval = UINT64_C(100);
+			dm_report_field_set_value(field, "100.00", sortval);
+		} else {
+			/* onactivate merge that hasn't started yet would
+			 * otherwise display incorrect snap% in origin
+			 */
+			*sortval = UINT64_C(0);
+			dm_report_field_set_value(field, "", sortval);
+		}
 		return 1;
 	}
 
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 7447007..b398775 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -979,6 +979,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
 			   struct lvconvert_params *lp)
 {
 	int r = 0;
+	int merge_on_activate = 0;
 	struct logical_volume *origin = origin_from_cow(lv);
 	struct lv_segment *cow_seg = find_cow(lv);
 	struct lvinfo info;
@@ -994,16 +995,20 @@ static int lvconvert_merge(struct cmd_context *cmd,
 		return 0;
 	}
 
+	/*
+	 * merge on origin's next activation if either the
+	 * origin or snapshot LV are currently open
+	 */
 	if (lv_info(cmd, origin, &info, 1, 0)) {
 		if (info.open_count) {
-			log_error("Can't merge over open origin volume");
-			return 0;
+			log_print("Can't merge over open origin volume");
+			merge_on_activate = 1;
 		}
 	}
 	if (lv_info(cmd, lv, &info, 1, 0)) {
 		if (info.open_count) {
-			log_error("Can't merge when snapshot is open");
-			return 0;
+			log_print("Can't merge when snapshot is open");
+			merge_on_activate = 1;
 		}
 	}
 
@@ -1025,6 +1030,16 @@ static int lvconvert_merge(struct cmd_context *cmd,
 	if (!vg_write(lv->vg))
 		return_0;
 
+	if (merge_on_activate) {
+		/* commit vg but skip starting the merge */
+		if (!vg_commit(lv->vg))
+			return_0;
+		r = 1;
+		log_print("Merging of snapshot %s will start "
+			  "next activation.", lv->name);
+		goto out;
+	}
+
 	/* Perform merge */
 	if (!suspend_lv(cmd, origin)) {
 		log_error("Failed to suspend origin %s", origin->name);
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 15/15] lvm-merge-man-lvconvert
  2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
                   ` (13 preceding siblings ...)
  2009-11-20 22:35 ` [PATCH 14/15] lvm-merge-onactivate Mike Snitzer
@ 2009-11-20 22:35 ` Mike Snitzer
  14 siblings, 0 replies; 21+ messages in thread
From: Mike Snitzer @ 2009-11-20 22:35 UTC (permalink / raw)
  To: lvm-devel

Update lvconvert manpage for snapshot --merge

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 man/lvconvert.8.in |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/man/lvconvert.8.in b/man/lvconvert.8.in
index 879064b..8fd3729 100644
--- a/man/lvconvert.8.in
+++ b/man/lvconvert.8.in
@@ -24,7 +24,18 @@ LogicalVolume[Path] [PhysicalVolume[Path][:PE[-PE]]...]
 [\-\-version]
 .br
 OriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]
+.br
 
+.br
+.B lvconvert
+\-\-merge [\-b|\-\-background] [\-i|\-\-interval Seconds]
+[\-h|\-?|\-\-help]
+[\-v|\-\-verbose]
+[\-\-version]
+SnapshotLogicalVolume[Path]
+.br
+
+.br
 .B lvconvert
 \-\-repair
 [\-h|\-?|\-\-help]
@@ -47,7 +58,7 @@ the freed extents come first from the specified PhysicalVolumes.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .br
-Exactly one of \-\-mirrors, \-\-repair or \-\-snapshot arguments required.
+Exactly one of \-\-mirrors, \-\-repair, \-\-snapshot or \-\-merge arguments required.
 .br
 .TP
 .I \-m, \-\-mirrors Mirrors
@@ -106,6 +117,17 @@ Power of 2 chunk size for the snapshot logical volume between 4k and 512k.
 .I \-Z, \-\-zero y|n
 Controls zeroing of the first KB of data in the snapshot.
 If the volume is read-only the snapshot will not be zeroed.
+.TP
+.I \-\-merge
+Merges a snapshot into its origin volume. If both the origin and snapshot volume
+are not open the merge will start immediately.  Otherwise, the merge will start
+the first time either the origin or snapshot are activated and both are closed.
+Merging a snapshot into an origin that cannot be closed, for example a root
+filesystem, is deferred until the next time the origin volume is activated.
+When merging starts, the resulting logical volume will have the origin's name,
+minor number and UUID.  While the merge is in progress, reads or writes to the
+origin appear as they were directed to the snapshot being merged.  When the
+merge finishes, the merged snapshot is removed.
 .br
 .SH Examples
 "lvconvert -m1 vg00/lvol1"
@@ -146,6 +168,11 @@ extents /dev/sda:0-15 and /dev/sdb:0-15 for allocation of new extents.
 converts mirror logical volume "vg00/lvmirror1" to linear, freeing physical
 extents from /dev/sda.
 
+.br
+"lvconvert --merge vg00/lvol1_snap"
+.br
+merges "vg00/lvol1_snap" into its origin.
+
 .SH SEE ALSO
 .BR lvm (8),
 .BR vgcreate (8),
-- 
1.6.5.2



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 02/15] lvm-merge-metadata
  2009-11-20 22:35 ` [PATCH 02/15] lvm-merge-metadata Mike Snitzer
@ 2009-11-20 23:26   ` Zdenek Kabelac
  2009-11-21  2:06     ` Mike Snitzer
  0 siblings, 1 reply; 21+ messages in thread
From: Zdenek Kabelac @ 2009-11-20 23:26 UTC (permalink / raw)
  To: lvm-devel

Dne 20.11.2009 23:35, Mike Snitzer napsal(a):
> From: Mikulas Patocka <mpatocka@redhat.com>
> 
> Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.
> 
> Make 'merging_snapshot' pointer that points from the origin to the
> segment that represents the merging snapshot.
> 
> Import/export 'merging_store' metadata.
> 
> Do not allow creating snapshots while another snapshot is merging.
> Snapshot created in this state would certainly contain invalid data.
> 
> diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
> index e9a3d5d..30073d3 100644
> --- a/lib/metadata/metadata-exported.h
> +++ b/lib/metadata/metadata-exported.h
> @@ -60,6 +60,7 @@
>  //#define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
>  //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
>  #define CONVERTING		0x00400000U	/* LV */
> +#define SNAPSHOT_MERGE		0x00800000U	/* SEG */
>  
>  #define MISSING_PV              0x00800000U	/* PV */

I think reusing these bitfields might lead to unexpected troubles.

Zdenek



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 02/15] lvm-merge-metadata
  2009-11-20 23:26   ` Zdenek Kabelac
@ 2009-11-21  2:06     ` Mike Snitzer
  2009-11-22 20:43       ` Zdenek Kabelac
  0 siblings, 1 reply; 21+ messages in thread
From: Mike Snitzer @ 2009-11-21  2:06 UTC (permalink / raw)
  To: lvm-devel

On Fri, Nov 20 2009 at  6:26pm -0500,
Zdenek Kabelac <zkabelac@redhat.com> wrote:

> Dne 20.11.2009 23:35, Mike Snitzer napsal(a):
> > From: Mikulas Patocka <mpatocka@redhat.com>
> > 
> > Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.
> > 
> > Make 'merging_snapshot' pointer that points from the origin to the
> > segment that represents the merging snapshot.
> > 
> > Import/export 'merging_store' metadata.
> > 
> > Do not allow creating snapshots while another snapshot is merging.
> > Snapshot created in this state would certainly contain invalid data.
> > 
> > diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
> > index e9a3d5d..30073d3 100644
> > --- a/lib/metadata/metadata-exported.h
> > +++ b/lib/metadata/metadata-exported.h
> > @@ -60,6 +60,7 @@
> >  //#define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
> >  //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
> >  #define CONVERTING		0x00400000U	/* LV */
> > +#define SNAPSHOT_MERGE		0x00800000U	/* SEG */
> >  
> >  #define MISSING_PV              0x00800000U	/* PV */
> 
> I think reusing these bitfields might lead to unexpected troubles.

Nice catch, surprised I missed that.

Looks like I'll go with:
#define SNAPSHOT_MERGE          0x10000000U



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 02/15] lvm-merge-metadata
  2009-11-21  2:06     ` Mike Snitzer
@ 2009-11-22 20:43       ` Zdenek Kabelac
  2009-11-23 14:30         ` Mike Snitzer
  0 siblings, 1 reply; 21+ messages in thread
From: Zdenek Kabelac @ 2009-11-22 20:43 UTC (permalink / raw)
  To: lvm-devel

Dne 21.11.2009 03:06, Mike Snitzer napsal(a):
> On Fri, Nov 20 2009 at  6:26pm -0500,
> Zdenek Kabelac <zkabelac@redhat.com> wrote:
> 
>> Dne 20.11.2009 23:35, Mike Snitzer napsal(a):
>>> From: Mikulas Patocka <mpatocka@redhat.com>
>>>
>>> Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.
>>>
>>> Make 'merging_snapshot' pointer that points from the origin to the
>>> segment that represents the merging snapshot.
>>>
>>> Import/export 'merging_store' metadata.
>>>
>>> Do not allow creating snapshots while another snapshot is merging.
>>> Snapshot created in this state would certainly contain invalid data.
>>>
>>> diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
>>> index e9a3d5d..30073d3 100644
>>> --- a/lib/metadata/metadata-exported.h
>>> +++ b/lib/metadata/metadata-exported.h
>>> @@ -60,6 +60,7 @@
>>>  //#define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
>>>  //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
>>>  #define CONVERTING		0x00400000U	/* LV */
>>> +#define SNAPSHOT_MERGE		0x00800000U	/* SEG */
>>>  
>>>  #define MISSING_PV              0x00800000U	/* PV */
>>
>> I think reusing these bitfields might lead to unexpected troubles.
> 
> Nice catch, surprised I missed that.
> 
> Looks like I'll go with:
> #define SNAPSHOT_MERGE          0x10000000U
> 

Yes - one small step for you :), but we run out-of-bits here - for replicator
I've tried to reduces bit usage just for 2 bits (instead of using separate bit
for  _rimage, _rlog, _slog, replicator-dev) - but together with crypto we are
out-of-space.

So either we might switch to 64bit status (simple) - or use some solution
based on function  calls instead of bit checks.

Zdenek



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 02/15] lvm-merge-metadata
  2009-11-22 20:43       ` Zdenek Kabelac
@ 2009-11-23 14:30         ` Mike Snitzer
  2009-11-23 14:37           ` Alasdair G Kergon
  0 siblings, 1 reply; 21+ messages in thread
From: Mike Snitzer @ 2009-11-23 14:30 UTC (permalink / raw)
  To: lvm-devel

On Sun, Nov 22 2009 at  3:43pm -0500,
Zdenek Kabelac <zkabelac@redhat.com> wrote:

> Dne 21.11.2009 03:06, Mike Snitzer napsal(a):
> > On Fri, Nov 20 2009 at  6:26pm -0500,
> > Zdenek Kabelac <zkabelac@redhat.com> wrote:
> > 
> >> Dne 20.11.2009 23:35, Mike Snitzer napsal(a):
> >>> From: Mikulas Patocka <mpatocka@redhat.com>
> >>>
> >>> Add 'SNAPSHOT_MERGE' lv_segment 'status' flag.
> >>>
> >>> Make 'merging_snapshot' pointer that points from the origin to the
> >>> segment that represents the merging snapshot.
> >>>
> >>> Import/export 'merging_store' metadata.
> >>>
> >>> Do not allow creating snapshots while another snapshot is merging.
> >>> Snapshot created in this state would certainly contain invalid data.
> >>>
> >>> diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
> >>> index e9a3d5d..30073d3 100644
> >>> --- a/lib/metadata/metadata-exported.h
> >>> +++ b/lib/metadata/metadata-exported.h
> >>> @@ -60,6 +60,7 @@
> >>>  //#define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
> >>>  //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
> >>>  #define CONVERTING		0x00400000U	/* LV */
> >>> +#define SNAPSHOT_MERGE		0x00800000U	/* SEG */
> >>>  
> >>>  #define MISSING_PV              0x00800000U	/* PV */
> >>
> >> I think reusing these bitfields might lead to unexpected troubles.
> > 
> > Nice catch, surprised I missed that.
> > 
> > Looks like I'll go with:
> > #define SNAPSHOT_MERGE          0x10000000U
> > 
> 
> Yes - one small step for you :), but we run out-of-bits here - for replicator
> I've tried to reduces bit usage just for 2 bits (instead of using separate bit
> for  _rimage, _rlog, _slog, replicator-dev) - but together with crypto we are
> out-of-space.
> 
> So either we might switch to 64bit status (simple) - or use some solution
> based on function  calls instead of bit checks.

Right, I think we should just switch to 64-bit status.

Mike



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 02/15] lvm-merge-metadata
  2009-11-23 14:30         ` Mike Snitzer
@ 2009-11-23 14:37           ` Alasdair G Kergon
  0 siblings, 0 replies; 21+ messages in thread
From: Alasdair G Kergon @ 2009-11-23 14:37 UTC (permalink / raw)
  To: lvm-devel

On Mon, Nov 23, 2009 at 09:30:58AM -0500, Mike Snitzer wrote:
> Right, I think we should just switch to 64-bit status.
 
Ack.

Alasdair



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2009-11-23 14:37 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-20 22:35 [PATCH 00/15] lvm2 support for snapshot-merge Mike Snitzer
2009-11-20 22:35 ` [PATCH 01/15] use snapshot metadata usage to determine if snapshot is empty Mike Snitzer
2009-11-20 22:35 ` [PATCH 02/15] lvm-merge-metadata Mike Snitzer
2009-11-20 23:26   ` Zdenek Kabelac
2009-11-21  2:06     ` Mike Snitzer
2009-11-22 20:43       ` Zdenek Kabelac
2009-11-23 14:30         ` Mike Snitzer
2009-11-23 14:37           ` Alasdair G Kergon
2009-11-20 22:35 ` [PATCH 03/15] Add support for "snapshot-merge" target Mike Snitzer
2009-11-20 22:35 ` [PATCH 04/15] device-mapper-merge-activation Mike Snitzer
2009-11-20 22:35 ` [PATCH 05/15] device-mapper-merging-store-needs-cow-suffix Mike Snitzer
2009-11-20 22:35 ` [PATCH 06/15] lvm-merge-lvconvert Mike Snitzer
2009-11-20 22:35 ` [PATCH 07/15] lvm-merge-check-for-mounted-lv Mike Snitzer
2009-11-20 22:35 ` [PATCH 08/15] lvm-merge-reporting Mike Snitzer
2009-11-20 22:35 ` [PATCH 09/15] lvm-merge-origin-report-progress Mike Snitzer
2009-11-20 22:35 ` [PATCH 10/15] lvm-merge-background-poll Mike Snitzer
2009-11-20 22:35 ` [PATCH 11/15] lvm-merge-background-poll-on-lvvgchange Mike Snitzer
2009-11-20 22:35 ` [PATCH 12/15] lvm-merge-reload-if-stopped-merging Mike Snitzer
2009-11-20 22:35 ` [PATCH 13/15] lvm-merge-reload-proper-order Mike Snitzer
2009-11-20 22:35 ` [PATCH 14/15] lvm-merge-onactivate Mike Snitzer
2009-11-20 22:35 ` [PATCH 15/15] lvm-merge-man-lvconvert Mike Snitzer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.