[lvm-devel] LVM2 lib/metadata/lv_manip.c lib/metadata/meta ...

agk at sourceware.org agk at sourceware.org
Thu Jan 17 13:13:55 UTC 2008


CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk at sourceware.org	2008-01-17 13:13:55

Modified files:
	lib/metadata   : lv_manip.c metadata-exported.h mirror.c 
	tools          : vgreduce.c 

Log message:
	lvconvert/vgreduce fixes

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.142&r2=1.143
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.37&r2=1.38
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.59&r2=1.60
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/vgreduce.c.diff?cvsroot=lvm2&r1=1.73&r2=1.74

--- LVM2/lib/metadata/lv_manip.c	2008/01/16 20:00:01	1.142
+++ LVM2/lib/metadata/lv_manip.c	2008/01/17 13:13:54	1.143
@@ -459,6 +459,24 @@
 }
 
 /*
+ * Empty an LV and add error segment.
+ */
+int lv_remap_error(struct logical_volume *lv)
+{
+	uint32_t len = lv->le_count;
+
+	if (!lv_empty(lv))
+		return_0;
+
+	if (!lv_add_virtual_segment(lv, 0, len,
+				    get_segtype_from_string(lv->vg->cmd,
+							    "error")))
+		return_0;
+
+	return 1;
+}
+
+/*
  * Remove given number of extents from LV.
  */
 int lv_reduce(struct logical_volume *lv, uint32_t extents)
--- LVM2/lib/metadata/metadata-exported.h	2008/01/16 19:54:39	1.37
+++ LVM2/lib/metadata/metadata-exported.h	2008/01/17 13:13:54	1.38
@@ -378,6 +378,9 @@
 /* Empty an LV prior to deleting it */
 int lv_empty(struct logical_volume *lv);
 
+/* Empty an LV and add error segment */
+int lv_remap_error(struct logical_volume *lv);
+
 /* Entry point for all LV extent allocations */
 int lv_extend(struct logical_volume *lv,
 	      const struct segment_type *segtype,
--- LVM2/lib/metadata/mirror.c	2008/01/16 19:50:23	1.59
+++ LVM2/lib/metadata/mirror.c	2008/01/17 13:13:54	1.60
@@ -373,11 +373,34 @@
 
 /*
  * Remove num_removed images from mirrored_seg
+ *
+ * Arguments:
+ *   num_removed:   the requested (maximum) number of mirrors to be removed
+ *   removable_pvs: if not NULL, only mirrors using PVs in this list
+ *                  will be removed
+ *   remove_log:    if non-zero, log_lv will be removed
+ *                  (even if it's 0, log_lv will be removed if there is no
+ *                   mirror remaining after the removal)
+ *   collapse:      if non-zero, instead of removing, remove the temporary
+ *                  mirror layer and merge mirrors to the original LV.
+ *                  removable_pvs should be NULL and num_removed should be
+ *                  seg->area_count - 1.
+ *   removed:       if non NULL, the number of removed mirror images is set
+ *                  as a result
+ *
+ * If collapse is non-zero, <removed> is guaranteed to be equal to num_removed.
+ *
+ * Return values:
+ *   Failure (0) means something unexpected has happend and
+ *   the caller should abort.
+ *   Even if no mirror was removed (e.g. no LV matches to 'removable_pvs'),
+ *   returns success (1).
  */
 static int _remove_mirror_images(struct logical_volume *lv,
 				 uint32_t num_removed,
 				 struct list *removable_pvs,
-				 unsigned remove_log, unsigned collapse)
+				 unsigned remove_log, unsigned collapse,
+				 uint32_t *removed)
 {
 	uint32_t m;
 	uint32_t s;
@@ -391,6 +414,9 @@
 	struct lv_list *lvl;
 	struct list tmp_orphan_lvs;
 
+	if (removed)
+		*removed = 0;
+
 	log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
 			 PRIu32 " image(s)%s.",
 			 old_area_count, old_area_count - num_removed,
@@ -407,7 +433,8 @@
 		for (s = 0; s < mirrored_seg->area_count &&
 			    old_area_count - new_area_count < num_removed; s++) {
 			sub_lv = seg_lv(mirrored_seg, s);
-			if (_is_mirror_image_removable(sub_lv, removable_pvs)) {
+			if (!is_temporary_mirror_layer(sub_lv) &&
+			    _is_mirror_image_removable(sub_lv, removable_pvs)) {
 				/* Swap segment to end */
 				new_area_count--;
 				area = mirrored_seg->areas[new_area_count];
@@ -415,10 +442,8 @@
 				mirrored_seg->areas[s] = area;
 			}
 		}
-		if (num_removed && old_area_count == new_area_count) {
-			log_error("No mirror images found using specified PVs.");
-			return 0;
-		}
+		if (num_removed && old_area_count == new_area_count)
+			return 1;
 	} else
 		new_area_count = old_area_count - num_removed;
 
@@ -442,7 +467,10 @@
 	log_lv = mirrored_seg->log_lv;
 
 	/* If no more mirrors, remove mirror layer */
-	if (new_area_count == 1) {
+	/* As an exceptional case, if the lv is temporary layer,
+	 * leave the LV as mirrored and let the lvconvert completion
+	 * to remove the layer. */
+	if (new_area_count == 1 && !is_temporary_mirror_layer(lv)) {
 		lv1 = seg_lv(mirrored_seg, 0);
 		_remove_mirror_log(mirrored_seg);
 		if (!remove_layer_from_lv(lv, lv1))
@@ -454,6 +482,15 @@
 			log_error("Failed to add mirror images");
 			return 0;
 		}
+	} else if (new_area_count == 0) {
+		/* All mirror images are gone.
+		 * It can happen for vgreduce --removemissing. */
+		_remove_mirror_log(mirrored_seg);
+		lv->status &= ~MIRRORED;
+		lv->status &= ~MIRROR_NOTSYNCED;
+		if (!lv_remap_error(lv))
+			return_0;
+		remove_log = 1;
 	} else if (remove_log)
 		_remove_mirror_log(mirrored_seg);
 
@@ -502,6 +539,20 @@
 	if (remove_log && log_lv && !_delete_lv(lv, log_lv))
 		return 0;
 
+	/* Mirror with only 1 area is 'in sync'. */
+	if (!remove_log && log_lv &&
+	    new_area_count == 1 && is_temporary_mirror_layer(lv)) {
+		if (!_init_mirror_log(lv->vg->cmd, log_lv, 1, &lv->tags, 0)) {
+			/* As a result, unnecessary sync may run after
+			 * collapsing. But safe.*/
+			log_error("Failed to initialize log device");
+			return_0;
+		}
+	}
+
+	if (removed)
+		*removed = old_area_count - new_area_count;
+
 	return 1;
 }
 
@@ -511,24 +562,43 @@
 int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
 			 struct list *removable_pvs, unsigned remove_log)
 {
-	uint32_t num_removed, removed_once;
+	uint32_t num_removed, removed_once, r;
 	uint32_t existing_mirrors = lv_mirror_count(lv);
+	struct logical_volume *next_lv = lv;
 
 	num_removed = existing_mirrors - num_mirrors;
 
 	/* num_removed can be 0 if the function is called just to remove log */
 	do {
-		if (num_removed < first_seg(lv)->area_count)
+		if (num_removed < first_seg(next_lv)->area_count)
 			removed_once = num_removed;
 		else
-			removed_once = first_seg(lv)->area_count - 1;
+			removed_once = first_seg(next_lv)->area_count - 1;
 
-		if (!_remove_mirror_images(lv, removed_once,
-				           removable_pvs, remove_log, 0))
+		if (!_remove_mirror_images(next_lv, removed_once,
+					   removable_pvs, remove_log, 0, &r))
 			return_0;
 
-		num_removed -= removed_once;
-	} while (num_removed);
+		if (r < removed_once) {
+			/* Some mirrors are removed from the temporary mirror,
+			 * but the temporary layer still exists.
+			 * Down the stack and retry for remainder. */
+			next_lv = find_tmp_mirror(next_lv);
+		}
+
+		num_removed -= r;
+	} while (next_lv && num_removed);
+
+	if (num_removed) {
+		if (num_removed == existing_mirrors - num_mirrors)
+			log_error("No mirror images found using specified PVs.");
+		else {
+			log_error("%u images are removed out of requested %u.",
+				  existing_mirrors - lv_mirror_count(lv),
+				  existing_mirrors - num_mirrors);
+		}
+		return 0;
+	}
 
 	return 1;
 }
@@ -581,7 +651,7 @@
 
 		if (!_remove_mirror_images(mirror_seg->lv,
 					   mirror_seg->area_count - 1,
-					   NULL, 1, 1)) {
+					   NULL, 1, 1, NULL)) {
 			log_error("Failed to release mirror images");
 			return 0;
 		}
@@ -701,8 +771,8 @@
 	 */
 	init_mirror_in_sync(in_sync);
 
-	r = remove_mirror_images(mirrored_seg->lv, num_mirrors,
-				 removable_pvs, remove_log);
+	r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors,
+				  removable_pvs, remove_log, 0, NULL);
 	if (!r)
 		/* Unable to remove bad devices */
 		return 0;
--- LVM2/tools/vgreduce.c	2008/01/16 19:00:59	1.73
+++ LVM2/tools/vgreduce.c	2008/01/17 13:13:54	1.74
@@ -255,8 +255,10 @@
 			}
 		}
 
+  lvs_changed_altered:
 		/* Remove lost mirror images from mirrors */
 		list_iterate_items(lvl, &vg->lvs) {
+  mirrored_seg_altered:
 			mirrored_seg = first_seg(lvl->lv);
 			if (!seg_is_mirrored(mirrored_seg))
 				continue;
@@ -315,6 +317,23 @@
 					vg_revert(vg);
 					return 0;
 				}
+
+				/* mirrored LV no longer has valid mimages.
+				 * So add it to lvs_changed for removal.
+				 * For this LV may be an area of other mirror,
+				 * restart the loop. */
+				if (!mimages) {
+					if (!_remove_lv(cmd, lvl->lv,
+						 &list_unsafe, &lvs_changed))
+						return_0;
+					goto lvs_changed_altered;
+				}
+
+				/* As a result of reconfigure_mirror_images(),
+				 * first_seg(lv) may now be different seg.
+				 * e.g. a temporary layer might be removed.
+				 * So check the mirrored_seg again. */
+				goto mirrored_seg_altered;
 			}
 		}
 




More information about the lvm-devel mailing list