[lvm-devel] [PATCH] fix following problems if max_lv is set

Milan Broz mbroz at redhat.com
Fri Mar 20 17:44:30 UTC 2009


Fix the last fix for max_lv....

The vg->lv_count is now confusing:
during the metadata parsing it counts all volumes, later
it contains only user visible ones.

Unfortunately change that is too risky, so for now use this workaround:

When checking for max_lv violation:
	- ignore the check if adding snapshot (import = 1 is set)
	(the check applies before when creating COW)
	- on other places, check max_lv against actual count
	of visible LVs (including snapshots)

Temporarily disable the vg_validate check, mirror conversion
violates max LV # (during downconversion it removes mirror image
flag and sets visible flag for all removed images, activates VG,
and later removes these "orphan" LVs...)

Signed-off-by: Milan Broz <mbroz at redhat.com>
---
 lib/metadata/lv_manip.c       |    2 +-
 lib/metadata/metadata.c       |   20 +++++++++++++++++---
 lib/metadata/metadata.h       |    2 ++
 lib/metadata/snapshot_manip.c |    9 ++++-----
 test/t-lvcreate-usage.sh      |    4 ++++
 tools/vgchange.c              |    5 +++--
 6 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 2661e0c..687a88b 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1832,7 +1832,7 @@ struct logical_volume *lv_create_empty(const char *name,
 	struct logical_volume *lv;
 	char dname[NAME_LEN];
 
-	if (vg->max_lv && (vg->max_lv == vg->lv_count)) {
+	if (!import && vg->max_lv && (vg->max_lv == visible_lvs_in_vg(vg))) {
 		log_error("Maximum number of logical volumes (%u) reached "
 			  "in volume group %s", vg->max_lv, vg->name);
 		return NULL;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 7848d82..c6991ab 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -1124,6 +1124,18 @@ unsigned displayable_lvs_in_vg(const struct volume_group *vg)
 	return lv_count;
 }
 
+unsigned visible_lvs_in_vg(const struct volume_group *vg)
+{
+	struct lv_list *lvl;
+	unsigned lv_count = 0;
+
+	dm_list_iterate_items(lvl, &vg->lvs)
+		if (lvl->lv->status & VISIBLE_LV)
+			lv_count++;
+
+	return lv_count;
+}
+
 /*
  * Determine whether two vgs are compatible for merging.
  */
@@ -1158,7 +1170,7 @@ int vgs_are_compatible(struct cmd_context *cmd __attribute((unused)),
 	}
 
 	if (vg_to->max_lv &&
-	    (vg_to->max_lv < vg_to->lv_count + vg_from->lv_count)) {
+	    (vg_to->max_lv < visible_lvs_in_vg(vg_to) + visible_lvs_in_vg(vg_from))) {
 		log_error("Maximum number of logical volumes (%d) exceeded "
 			  " for \"%s\" and \"%s\"", vg_to->max_lv, vg_to->name,
 			  vg_from->name);
@@ -1461,12 +1473,14 @@ int vg_validate(struct volume_group *vg)
 		r = 0;
 	}
 
-	if (vg->max_lv && (vg->max_lv < vg->lv_count)) {
+	/* FIXME: mirror conversion violates this temporarily
+	if (vg->max_lv && (vg->max_lv < visible_lvs_in_vg(vg))) {
 		log_error("Internal error: Volume group %s contains %u volumes"
 			  " but the limit is set to %u.",
-			  vg->name, vg->lv_count, vg->max_lv);
+			  vg->name, visible_lvs_in_vg(vg), vg->max_lv);
 		r = 0;
 	}
+	*/
 
 	return r;
 }
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index fbcf82b..11e9fe7 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -339,8 +339,10 @@ struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv);
 
 /*
  * Count LVs that are visible from user's perspective.
+ * FIXME: confusing, displayable doesn't count snapshots
  */
 unsigned displayable_lvs_in_vg(const struct volume_group *vg);
+unsigned visible_lvs_in_vg(const struct volume_group *vg);
 
 /*
  * For internal metadata caching.
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 3955382..d4441db 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -77,15 +77,15 @@ int vg_add_snapshot(const char *name, struct logical_volume *origin,
 	}
 
 	/*
-	 * Set origin lv count in advance to prevent fail because
+	 * Hide origin lv in advance to prevent fail because
 	 * of temporary violation of LV limits.
 	 */
-	origin->vg->lv_count--;
+	cow->status &= ~VISIBLE_LV;
 
 	if (!(snap = lv_create_empty(name ? name : "snapshot%d",
 				     lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
 				     ALLOC_INHERIT, 1, origin->vg))) {
-		origin->vg->lv_count++;
+		cow->status |= VISIBLE_LV;
 		return_0;
 	}
 
@@ -99,12 +99,11 @@ int vg_add_snapshot(const char *name, struct logical_volume *origin,
 	seg->cow = cow;
 	seg->lv->status |= SNAPSHOT;
 
+	origin->vg->lv_count--;
 	origin->origin_count++;
 	origin->vg->snapshot_count++;
 	cow->snapshot = seg;
 
-	cow->status &= ~VISIBLE_LV;
-
 	dm_list_add(&origin->snapshot_segs, &seg->origin_list);
 
 	return 1;
diff --git a/test/t-lvcreate-usage.sh b/test/t-lvcreate-usage.sh
index 13abbdf..cd3e3c7 100755
--- a/test/t-lvcreate-usage.sh
+++ b/test/t-lvcreate-usage.sh
@@ -65,5 +65,9 @@ lvcreate -l1 -s -n $lv2 $vg/$lv1
 lvcreate -l1 -n $lv3 $vg
 not lvcreate -l1 -n $lv4 $vg
 vgs $vg
+lvremove -ff $vg/$lv3
+lvcreate -l1 -s -n $lv3 $vg/$lv1
+not lvcreate -l1 -s -n $lv4 $vg/$lv1
+# FIXME add mirror & lvconvert tests
 lvremove -ff $vg
 vgchange -l 0 $vg
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 8831a23..27335c6 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -14,6 +14,7 @@
  */
 
 #include "tools.h"
+#include "metadata.h"
 
 static int _monitor_lvs_in_vg(struct cmd_context *cmd,
 			       struct volume_group *vg, int reg)
@@ -308,9 +309,9 @@ static int _vgchange_logicalvolume(struct cmd_context *cmd,
 		}
 	}
 
-	if (max_lv && max_lv < vg->lv_count) {
+	if (max_lv && max_lv < visible_lvs_in_vg(vg)) {
 		log_error("MaxLogicalVolume is less than the current number "
-			  "%d of LVs for \"%s\"", vg->lv_count,
+			  "%d of LVs for \"%s\"", visible_lvs_in_vg(vg),
 			  vg->name);
 		return ECMD_FAILED;
 	}





More information about the lvm-devel mailing list