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

[lvm-devel] [PATCH 1/2] Fix 'vgreduce --removemissing' on stacked mirror



'vgreduce --removemissing' is similar to lvconvert but is different in:
  - it removes any mirror images, not specifying the number
  - all images may be removed from the mirrored LV
  - mirrored LV itself may be removed

reconfigure_mirror_images() is the underlying function of vgreduce.

However, even with the recent patches of mine, reconfigure_mirror_images()
doesn't work well for stacked mirror.

Attached patch fixes it.

Thanks,
--
Jun'ichi Nomura, NEC Corporation of America
Multiple fixes for 'vgreduce --removemissing' on stacked mirror

* reconfigure_mirror_images() should call _remove_mirror_images()

  The existing user of reconfigure_mirror_images() (i.e. vgreduce)
  expects it to remove the specified number of mirror images from
  the given mirror segment.

  vgreduce is responsible to check LVs on missing PVs and sort the
  seg->areas so that the images being removed become last.
  It passes removable_pvs=NULL for reconfigure_mirror_images().
  So, reconfigure_mirror_images() should just takes care of the
  given segment, not walking down the stack.

* _remove_mirror_images() to handle '0 area' case

  Under the context of 'vgreduce --removemissing', it's possible that
  the mirrored LV no longer has valid mirror images.
  In this case, vgreduce should call reconfigure_mirror_images() and
  it calls _remove_mirror_images() to remove all mirror images.
  _remove_mirror_images() should empty the LV and add error segment.

* _make_vg_consistent() for stacked mirror

  _make_vg_consistent() is a core function for 'vgreduce --removemissing'.
  For mirrored LV, the function is 2-pass.
  First, it goes through LVs and marks those which are on missing PVs.
  Second, for any mirrored LVs, reorder areas so that marked LVs become
  the last areas and call reconfigure_mirror_images() to remove them.
  As a result of the 2nd pass, 2 things could happen:
    - all images are removed from the mirrored LV
      -> the mirrored LV should be marked and restart the 2nd pass
    - a temporary layer below the mirrored LV is removed
      -> need to recheck the areas

Index: LVM2.work/lib/metadata/mirror.c
===================================================================
--- LVM2.work.orig/lib/metadata/mirror.c
+++ LVM2.work/lib/metadata/mirror.c
@@ -515,6 +515,15 @@ static int _remove_mirror_images(struct 
 			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);
 
@@ -795,8 +804,8 @@ int reconfigure_mirror_images(struct lv_
 	 */
 	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;
Index: LVM2.work/tools/vgreduce.c
===================================================================
--- LVM2.work.orig/tools/vgreduce.c
+++ LVM2.work/tools/vgreduce.c
@@ -255,8 +255,10 @@ static int _make_vg_consistent(struct cm
 			}
 		}
 
+  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 @@ static int _make_vg_consistent(struct cm
 					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;
 			}
 		}
 
Index: LVM2.work/lib/metadata/lv_manip.c
===================================================================
--- LVM2.work.orig/lib/metadata/lv_manip.c
+++ LVM2.work/lib/metadata/lv_manip.c
@@ -459,6 +459,24 @@ int lv_empty(struct logical_volume *lv)
 }
 
 /*
+ * 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)
Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -378,6 +378,9 @@ int lv_reduce(struct logical_volume *lv,
 /* 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,

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