[lvm-devel] [PATCH] Add invalid snapshot awareness to snapshot merge support

Mike Snitzer snitzer at redhat.com
Sat Jan 14 02:56:39 UTC 2012


Prevent an invalid snapshot from being merged via lvconvert.
Allow an merging snapshot that was invalidated to be removed (useful for
a snapshot merge that was deferred until next activation but the
snapshot was invalidated beforehand).

Signed-off-by: Mike Snitzer <snitzer at redhat.com>
---
 lib/activate/dev_manager.c       |   11 +++++++++--
 lib/metadata/lv.c                |    4 +---
 lib/metadata/lv_manip.c          |   15 +++++++++++----
 lib/metadata/metadata-exported.h |    1 +
 lib/metadata/snapshot_manip.c    |   10 ++++++++++
 tools/lvconvert.c                |    7 +++++++
 6 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 513aaa8..a1c3b90 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -742,6 +742,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
 				 const struct logical_volume *lv,
 				 percent_t *percent)
 {
+	const struct logical_volume *_lv;
 	char *name;
 	const char *dlid;
 	int fail_if_percent_unsupported = 0;
@@ -761,13 +762,19 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
 		fail_if_percent_unsupported = 1;
 	}
 
+	if (lv_is_merging_cow(lv)) {
+		/* must check percent of origin for a merging snapshot */
+		_lv = origin_from_cow(lv);
+	} else
+		_lv = lv;
+
 	/*
 	 * Build a name for the top layer.
 	 */
-	if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, NULL)))
+	if (!(name = dm_build_dm_name(dm->mem, _lv->vg->name, _lv->name, NULL)))
 		return_0;
 
-	if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL)))
+	if (!(dlid = build_dm_uuid(dm->mem, _lv->lvid.s, NULL)))
 		return_0;
 
 	/*
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index ed6b42d..9391d7f 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -348,7 +348,6 @@ static int _lv_raid_image_in_sync(const struct logical_volume *lv)
 }
 char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
 {
-	percent_t snap_percent;
 	struct lvinfo info;
 	struct lv_segment *seg;
 	char *repstr;
@@ -422,8 +421,7 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
 
 		/* Snapshot dropped? */
 		if (info.live_table && lv_is_cow(lv) &&
-		    (!lv_snapshot_percent(lv, &snap_percent) ||
-		     snap_percent == PERCENT_INVALID)) {
+		    lv_is_invalid_cow(lv)) {
 			repstr[0] = toupper(repstr[0]);
 			if (info.suspended)
 				repstr[4] = 'S'; /* Susp Inv snapshot */
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 0675350..8f0f452 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -3262,13 +3262,20 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 {
 	struct dm_list *snh, *snht;
 	struct seg_list *sl, *tsl;
+	struct lvinfo info;
 
 	if (lv_is_cow(lv)) {
-		/* A merging snapshot cannot be removed directly */
+		/*
+		 * A merging snapshot cannot be removed directly unless
+		 * it has been invalidated.
+		 */
 		if (lv_is_merging_cow(lv) && !level) {
-			log_error("Can't remove merging snapshot logical volume \"%s\"",
-				  lv->name);
-			return 0;
+			if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists &&
+			    info.live_table && !lv_is_invalid_cow(lv)) {
+				log_error("Can't remove merging snapshot logical volume \"%s\"",
+					  lv->name);
+				return 0;
+			}
 		}
 	}
 
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index f516f3d..2179663 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -678,6 +678,7 @@ int lv_is_virtual_origin(const struct logical_volume *lv);
 int lv_is_cow(const struct logical_volume *lv);
 int lv_is_merging_origin(const struct logical_volume *origin);
 int lv_is_merging_cow(const struct logical_volume *snapshot);
+int lv_is_invalid_cow(const struct logical_volume *lv);
 
 /* Test if given LV is visible from user's perspective */
 int lv_is_visible(const struct logical_volume *lv);
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 5766d0b..1e12aa1 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -30,6 +30,16 @@ int lv_is_cow(const struct logical_volume *lv)
 	return (!lv_is_origin(lv) && lv->snapshot) ? 1 : 0;
 }
 
+int lv_is_invalid_cow(const struct logical_volume *lv)
+{
+	percent_t snap_percent;
+
+	if (!lv_snapshot_percent(lv, &snap_percent) ||
+	    snap_percent == PERCENT_INVALID)
+		return 1;
+	return 0;
+}
+
 int lv_is_visible(const struct logical_volume *lv)
 {
 	if (lv->status & SNAPSHOT)
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 9553b9b..d2eb99b 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -1706,6 +1706,7 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 {
 	struct lvconvert_params *lp = handle;
 	struct dm_list *failed_pvs;
+	struct lvinfo info;
 
 	if (lv->status & LOCKED) {
 		log_error("Cannot convert locked LV %s", lv->name);
@@ -1739,6 +1740,12 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 				  lv->name);
 			return ECMD_FAILED;
 		}
+	        if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && info.exists) {
+                	if (info.live_table && lv_is_invalid_cow(lv)) {
+	                        log_error("Unable to merge invalidated snapshot LV \"%s\"", lv->name);
+        	                return ECMD_FAILED;
+                	}
+		}
 		if (!archive(lv->vg)) {
 			stack;
 			return ECMD_FAILED;




More information about the lvm-devel mailing list