[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH] (1/5) partial volume group metadata handling



Hi,

this is the patch I have sent previously (on 5th May), with coding style and
naming cleanups (and one backward compatibility fix to flag reading), plus
rebased to current CVS. It provides the basic library support for improved
partial volume group handling. Patches for tools that build on the new
capabilities will follow soon.

The basic new features are:
- PVs are flagged with MISSING_PV appropriately
- LVs are flagged with PARTIAL_LV if they are incomplete (in any way)
- partial VGs will be read in by default and will have PARTIAL_VG status flag
  set (previously, they would be ignored by tools without activating special
  "partial mode", which is now deprecated)

Tue Jul  8 13:46:12 CEST 2008  me mornfall net
  * Add a missed period.
Tue Jul  8 13:41:24 CEST 2008  me mornfall net
  * Add an exception for reading PARTIAL_VG flag to flags.c.
Mon Jul  7 15:14:21 CEST 2008  me mornfall net
  * Clarify the MISSING_PV, PARTIAL_LV and POSTORDER_FLAG #defines, sync metadata.h with metadata-exported.h.
Mon Jul  7 15:06:45 CEST 2008  me mornfall net
  * Rename various _lv_mark_partial functions to _lv_mark_if_partial*.
Mon Jul  7 15:05:57 CEST 2008  me mornfall net
  * Rename _vg_mark_partial to _vg_mark_if_partial.
Mon Jul  7 15:05:39 CEST 2008  me mornfall net
  * Rename vg_consolidate_partial to _vg_mark_partial_lvs.
Mon Jul  7 15:05:07 CEST 2008  me mornfall net
  * <agk> DFS sells furniture.
Mon Jul  7 15:02:29 CEST 2008  me mornfall net
  * Naming: fun -> fn, d -> data.
Thu Jul  3 18:40:53 CEST 2008  me mornfall net
  * Resolve conflict in metadata.c.
Sun May  4 23:52:54 CEST 2008  me mornfall net
  * Add a comment to _lv_postorder.
Sun May  4 23:52:31 CEST 2008  me mornfall net
  * Rename all mark_missing bits to mark_partial.
Thu Apr 24 22:13:25 CEST 2008  me mornfall net
  * Even better (more resilient) approach to the activation issue.
Thu Apr 24 21:25:38 CEST 2008  me mornfall net
  * A correct fix for the lvconvert --repair vs activation issue.
Thu Apr 24 19:24:56 CEST 2008  me mornfall net
  * Try to fix the lvconvert --repair vs. activation issue.
Sun Apr 20 10:01:09 CEST 2008  me mornfall net
  * Generalize _lv_mark_missing to _lv_postorder with callback.
Sun Mar 23 19:53:26 CET 2008  me mornfall net
  * Update comment for _lv_mark_missing.
Sun Mar 23 19:53:12 CET 2008  me mornfall net
  * Improve error message when partial metadata cannot be written.
Thu Mar 13 17:12:41 CET 2008  me mornfall net
  * The log_lv, origin and cow links are in segments, not in LVs.
Thu Mar 13 17:11:44 CET 2008  me mornfall net
  * Actually mark VG with MISSING_PV in it as PARTIAL_VG.
Thu Mar 13 17:08:00 CET 2008  me mornfall net
  * Don't export PARTIAL_VG, we recompute it every time. Enough to persist MISSING_PV.
Thu Mar 13 17:07:21 CET 2008  me mornfall net
  * Don't forget to mark COMPLETE_LV as non-exported flag.
Thu Mar 13 15:16:34 CET 2008  me mornfall net
  * Simplify and optimize _lv_mark_missing.
Fri Feb 15 10:07:46 CET 2008  me mornfall net
  * Clean up commented out code.
Fri Feb 15 09:49:02 CET 2008  me mornfall net
  * Fix _lv_mark_missing in metadata.c.
Fri Feb 15 09:47:54 CET 2008  me mornfall net
  * Add PARTIAL_LV to flags.c, as NULL (ie. not stored in metadata).
Thu Feb 14 17:37:06 CET 2008  me mornfall net
  * Make the PARTIAL_LV marking transitive.
Thu Feb 14 16:21:19 CET 2008  me mornfall net
  * Mark partial LVs with PARTIAL_LV status flag.
Wed Jan 23 16:56:44 CET 2008  me mornfall net
  * Stub out first pieces of consistent partial VG support.
diff -rN -u -p old-hotspare-two/lib/format_text/flags.c new-hotspare-two/lib/format_text/flags.c
--- old-hotspare-two/lib/format_text/flags.c	2008-07-08 14:27:35.542695520 +0200
+++ new-hotspare-two/lib/format_text/flags.c	2008-07-08 14:27:35.602695811 +0200
@@ -30,19 +30,20 @@ struct flag {
 static struct flag _vg_flags[] = {
 	{EXPORTED_VG, "EXPORTED"},
 	{RESIZEABLE_VG, "RESIZEABLE"},
-	{PARTIAL_VG, "PARTIAL"},
 	{PVMOVE, "PVMOVE"},
 	{LVM_READ, "READ"},
 	{LVM_WRITE, "WRITE"},
 	{CLUSTERED, "CLUSTERED"},
 	{SHARED, "SHARED"},
 	{PRECOMMITTED, NULL},
+	{PARTIAL_VG, NULL},
 	{0, NULL}
 };
 
 static struct flag _pv_flags[] = {
 	{ALLOCATABLE_PV, "ALLOCATABLE"},
 	{EXPORTED_VG, "EXPORTED"},
+	{MISSING_PV, "MISSING"},
 	{0, NULL}
 };
 
@@ -61,6 +62,8 @@ static struct flag _lv_flags[] = {
 	{SNAPSHOT, NULL},
 	{ACTIVATE_EXCL, NULL},
 	{CONVERTING, NULL},
+	{PARTIAL_LV, NULL},
+	{POSTORDER_FLAG, NULL},
 	{0, NULL}
 };
 
@@ -151,7 +154,16 @@ int read_flags(uint32_t *status, int typ
 				break;
 			}
 
-		if (!flags[f].description) {
+		if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
+			/*
+			 * Exception: We no longer write this flag out, but it
+			 * might be encountered in old backup files, so restore
+			 * it in that case. It is never part of live metadata
+			 * though, so only vgcfgrestore needs to be concerned
+			 * by this case.
+			 */
+			s |= PARTIAL_VG;
+		} else if (!flags[f].description) {
 			log_err("Unknown status flag '%s'.", cv->v.str);
 			return 0;
 		}
diff -rN -u -p old-hotspare-two/lib/format_text/import_vsn1.c new-hotspare-two/lib/format_text/import_vsn1.c
--- old-hotspare-two/lib/format_text/import_vsn1.c	2008-07-08 14:27:35.542695520 +0200
+++ new-hotspare-two/lib/format_text/import_vsn1.c	2008-07-08 14:27:35.602695811 +0200
@@ -170,10 +170,7 @@ static int _read_pv(struct format_instan
 			log_error("Couldn't find device with uuid '%s'.",
 				  buffer);
 
-		if (partial_mode())
-			vg->status |= PARTIAL_VG;
-		else
-			return 0;
+		vg->status |= PARTIAL_VG;
 	}
 
 	if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@@ -191,6 +188,9 @@ static int _read_pv(struct format_instan
 		return 0;
 	}
 
+	if (!pv->dev)
+		pv->status |= MISSING_PV;
+
 	/* Late addition */
 	_read_int64(pvn, "dev_size", &pv->size);
 
@@ -790,7 +790,6 @@ static struct volume_group *_read_vg(str
 	dm_hash_destroy(pv_hash);
 
 	if (vg->status & PARTIAL_VG) {
-		vg->status &= ~LVM_WRITE;
 		vg->status |= LVM_READ;
 	}
 
diff -rN -u -p old-hotspare-two/lib/metadata/metadata.c new-hotspare-two/lib/metadata/metadata.c
--- old-hotspare-two/lib/metadata/metadata.c	2008-07-08 14:27:35.542695520 +0200
+++ new-hotspare-two/lib/metadata/metadata.c	2008-07-08 14:27:35.618695194 +0200
@@ -1171,6 +1171,155 @@ int vgs_are_compatible(struct cmd_contex
 	return 1;
 }
 
+struct _lv_postorder_baton {
+	int (*fn)(struct logical_volume *lv, void *data);
+	void *data;
+};
+
+static int _lv_postorder_visit(struct logical_volume *,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data);
+
+static int _lv_postorder_level(struct logical_volume *lv, void *data)
+{
+	struct _lv_postorder_baton *baton = data;
+	return _lv_postorder_visit(lv, baton->fn, baton->data);
+};
+
+static int _lv_each_dependency(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	int i, s;
+	struct lv_segment *lvseg;
+
+	list_iterate_items(lvseg, &lv->segments) {
+		struct logical_volume *deps[] = {
+			lvseg->log_lv, lvseg->origin, lvseg->cow };
+		for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) {
+			if (deps[i]) {
+				if (!fn(deps[i], data))
+					return 0;
+			}
+		}
+		for (s = 0; s < lvseg->area_count; ++s) {
+			if (seg_type(lvseg, s) == AREA_LV) {
+				if (!fn(seg_lv(lvseg,s), data))
+					return 0;
+			}
+		}
+	}
+}
+
+static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
+{
+	if (!(lv->status & POSTORDER_FLAG))
+		return 1;
+
+	_lv_each_dependency(lv, _lv_postorder_cleanup, data);
+	lv->status &= ~POSTORDER_FLAG;
+	return 1;
+}
+
+static int _lv_postorder_visit(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	struct _lv_postorder_baton baton;
+	int r;
+
+	if (lv->status & POSTORDER_FLAG)
+		return 1;
+
+	baton.fn = fn;
+	baton.data = data;
+	r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
+	if (r) {
+		r = fn(lv, data);
+		log_verbose("visited %s", lv->name);
+	}
+	return r;
+}
+
+/*
+ * This will walk the LV dependency graph in depth-first order and in the
+ * postorder, call a callback function "fn". The void *data is passed along all
+ * the calls. The callback may return zero to indicate an error and terminate
+ * the depth-first walk. The error is propagated to return value of
+ * _lv_postorder.
+ */
+static int _lv_postorder(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	int r;
+	r = _lv_postorder_visit(lv, fn, data);
+	_lv_postorder_cleanup(lv, 0);
+	return r;
+}
+
+struct _lv_mark_if_partial_baton {
+	int partial;
+};
+
+static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
+{
+	struct _lv_mark_if_partial_baton *baton = data;
+	if (lv->status & PARTIAL_LV)
+		baton->partial = 1;
+
+	return 1;
+}
+
+static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
+{
+	int s;
+	struct _lv_mark_if_partial_baton baton;
+	struct lv_segment *lvseg;
+
+	baton.partial = 0;
+	_lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
+
+	if (baton.partial)
+		lv->status |= PARTIAL_LV;
+
+	list_iterate_items(lvseg, &lv->segments) {
+		for (s = 0; s < lvseg->area_count; ++s) {
+			if (seg_type(lvseg, s) == AREA_PV) {
+				if (seg_pv(lvseg, s)->status & MISSING_PV)
+					lv->status |= PARTIAL_LV;
+			}
+		}
+	}
+
+	return 1;
+}
+
+static int _lv_mark_if_partial(struct logical_volume *lv)
+{
+	return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
+}
+
+/*
+ * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
+ * propagated transitively, so LVs referencing other LVs are marked
+ * partial as well, if any of their referenced LVs are marked partial.
+ */
+static int _vg_mark_partial_lvs(struct volume_group *vg)
+{
+	struct physical_volume *pv;
+	struct logical_volume *lv;
+	struct lv_list *lvl;
+	struct pv_list *pvl;
+	struct pv_segment *peg;
+
+	list_iterate_items(lvl, &vg->lvs) {
+		lv = lvl->lv;
+		if (!_lv_mark_if_partial(lv))
+			return_0;
+	}
+}
+
 int vg_validate(struct volume_group *vg)
 {
 	struct pv_list *pvl, *pvl2;
@@ -1268,8 +1417,8 @@ int vg_write(struct volume_group *vg)
 		return_0;
 
 	if (vg->status & PARTIAL_VG) {
-		log_error("Cannot change metadata for partial volume group %s",
-			  vg->name);
+		log_error("Cannot update volume group %s while physical "
+			  "volumes are missing.", vg->name);
 		return 0;
 	}
 
@@ -1468,6 +1617,26 @@ static int _update_pv_list(struct list *
 	return 1;
 }
 
+static void _vg_mark_if_partial(struct volume_group *vg)
+{
+	struct pv_list *pvl;
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->status & MISSING_PV)
+			vg->status |= PARTIAL_VG;
+	}
+}
+
+static int _vg_missing_pv_count(struct volume_group *vg)
+{
+	int ret = 0;
+	struct pv_list *pvl;
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->status & MISSING_PV)
+			++ ret;
+	}
+	return ret;
+}
+
 /* Caller sets consistent to 1 if it's safe for vg_read to correct
  * inconsistent metadata on disk (i.e. the VG write lock is held).
  * This guarantees only consistent metadata is returned unless PARTIAL_VG.
@@ -1604,7 +1773,8 @@ static struct volume_group *_vg_read(str
 			}
 		}
 
-		if (list_size(&correct_vg->pvs) != list_size(pvids)) {
+		if (list_size(&correct_vg->pvs) != list_size(pvids)
+		    + _vg_missing_pv_count(correct_vg)) {
 			log_debug("Cached VG %s had incorrect PV list",
 				  vgname);
 
@@ -1613,6 +1783,8 @@ static struct volume_group *_vg_read(str
 			else
 				correct_vg = NULL;
 		} else list_iterate_items(pvl, &correct_vg->pvs) {
+			if (pvl->pv->status & MISSING_PV)
+				continue;
 			if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
 				log_debug("Cached VG %s had incorrect PV list",
 					  vgname);
@@ -1742,6 +1914,13 @@ static struct volume_group *_vg_read(str
 		}
 	}
 
+	_vg_mark_if_partial(correct_vg);
+
+	if (correct_vg->status & PARTIAL_VG) {
+		if (*consistent)
+			_vg_mark_partial_lvs(correct_vg);
+	}
+
 	if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
 		log_error("WARNING: Interrupted pvmove detected in "
 			  "volume group %s", correct_vg->name);
diff -rN -u -p old-hotspare-two/lib/metadata/metadata-exported.h new-hotspare-two/lib/metadata/metadata-exported.h
--- old-hotspare-two/lib/metadata/metadata-exported.h	2008-07-08 14:27:35.542695520 +0200
+++ new-hotspare-two/lib/metadata/metadata-exported.h	2008-07-08 14:27:35.614697671 +0200
@@ -71,6 +71,13 @@ struct pv_segment;
 //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
 #define CONVERTING		0x00400000U	/* LV */
 
+#define MISSING_PV              0x00800000U	/* PV */
+#define PARTIAL_LV              0x01000000U	/* LV - derived flag, not
+						   written out in metadata*/
+
+//#define POSTORDER_FLAG	0x02000000U /* Not a real flag, reserved for
+//					       temporary use inside vg_read. */
+
 #define LVM_READ              	0x00000100U	/* LV VG */
 #define LVM_WRITE             	0x00000200U	/* LV VG */
 #define CLUSTERED         	0x00000400U	/* VG */
diff -rN -u -p old-hotspare-two/lib/metadata/metadata.h new-hotspare-two/lib/metadata/metadata.h
--- old-hotspare-two/lib/metadata/metadata.h	2008-07-08 14:27:35.498692518 +0200
+++ new-hotspare-two/lib/metadata/metadata.h	2008-07-08 14:27:35.618695194 +0200
@@ -61,6 +61,14 @@
 //#define MIRROR_NOTSYNCED	0x00080000U	/* LV */
 #define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
 #define PRECOMMITTED		0x00200000U	/* VG - internal use only */
+//#define CONVERTING		0x00400000U	/* LV */
+
+//#define MISSING_PV		0x00800000U	/* PV */
+//#define PARTIAL_LV		0x01000000U	/* LV - derived flag, not
+//						   written out in metadata*/
+
+#define POSTORDER_FLAG		0x02000000U /* Not a real flag, reserved for
+					       temporary use inside vg_read. */
 
 //#define LVM_READ              	0x00000100U	/* LV VG */
 //#define LVM_WRITE             	0x00000200U	/* LV VG */

-- 
Peter Rockai | me()mornfall!net | prockai()redhat!com
 http://blog.mornfall.net | http://web.mornfall.net

"In My Egotistical Opinion, most people's C programs should be
 indented six feet downward and covered with dirt."
     -- Blair P. Houghton on the subject of C program indentation

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]