[lvm-devel] dev-lvmguy-raid-takeover-reshape-resize - bz1168959: v2 fix replaced rimage allocation

Heinz Mauelshagen mauelsha at fedoraproject.org
Sat Jan 31 14:10:28 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f8e0b7b75afd379b69bc9efb0b2767b5a139a132
Commit:        f8e0b7b75afd379b69bc9efb0b2767b5a139a132
Parent:        df53bd845aeeedee83776a6fe63ce704d788f8f2
Author:        Heinz Mauelshagen <heinzm at redhat.com>
AuthorDate:    Fri Jan 16 13:05:12 2015 +0100
Committer:     Heinz Mauelshagen <heinzm at redhat.com>
CommitterDate: Fri Jan 16 13:05:12 2015 +0100

bz1168959: v2 fix replaced rimage allocation

---
 lib/metadata/metadata-exported.h |    6 +-
 lib/metadata/pv_map.c            |    5 +-
 lib/metadata/raid_manip.c        |  284 +++++++++++++++++++++++++-------------
 lib/metadata/segtype.h           |    2 +
 4 files changed, 202 insertions(+), 95 deletions(-)

diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 0fe83bf..a48f31b 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -122,7 +122,11 @@
 #define LV_RESHAPE_DELTA_DISKS_PLUS		UINT64_C(0x0008000000000000)    /* LV reshape flag delta disks plus image(s) */
 #define LV_RESHAPE_DELTA_DISKS_MINUS		UINT64_C(0x0010000000000000)    /* LV reshape flag delta disks minus image(s) */
 
-/* Next unused flag:		UINT64_C(0x0020000000000000)    */
+#define PV_ALLOCATION_PROHIBITED	UINT64_C(0x0020000000000000)	/* PV - internal use only - allocation prohibited
+									e.g. to prohibit allocation of a RAID image
+									on a PV already holing an image of the RAID set */
+
+/* Next unused flag:		UINT64_C(0x0040000000000000)    */
 
 /* Format features flags */
 #define FMT_SEGMENTS		0x00000001U	/* Arbitrary segment params? */
diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c
index 4423a7d..db9f84e 100644
--- a/lib/metadata/pv_map.c
+++ b/lib/metadata/pv_map.c
@@ -133,8 +133,11 @@ static int _create_maps(struct dm_pool *mem, struct dm_list *pvs, struct dm_list
 	struct pv_list *pvl;
 
 	dm_list_iterate_items(pvl, pvs) {
-		if (!(pvl->pv->status & ALLOCATABLE_PV))
+		if (!(pvl->pv->status & ALLOCATABLE_PV) ||
+		    (pvl->pv->status & PV_ALLOCATION_PROHIBITED)) {
+			pvl->pv->status &= ~PV_ALLOCATION_PROHIBITED;
 			continue;
+		}
 		if (is_missing_pv(pvl->pv))
 			continue;
 		assert(pvl->pv->dev);
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 60f80c6..cf0de89 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -1017,26 +1017,32 @@ static int _raid_add_images(struct logical_volume *lv, struct segment_type *segt
 		goto fail;
 
 	/* Reshape adding image component pairs to raid set changing size accordingly */
-	if (!seg_is_raid1(seg) && seg->segtype == segtype) {
-		uint32_t extents = lv->le_count / __data_rimages_count(seg, old_count);
+	if (!seg_is_raid1(seg)) {
+		if (seg->segtype == segtype) {
+			uint32_t extents = lv->le_count / __data_rimages_count(seg, old_count);
 
-		for (s = old_count; s < new_count; s++) {
-			seg_lv(seg, s)->status &= ~LV_REBUILD;
-			seg_lv(seg, s)->status |= LV_RESHAPE_DELTA_DISKS_PLUS;
+			for (s = old_count; s < new_count; s++) {
+				seg_lv(seg, s)->status &= ~LV_REBUILD;
+				seg_lv(seg, s)->status |= LV_RESHAPE_DELTA_DISKS_PLUS;
 
-			lv->le_count += extents;
-			seg->len += extents;
-			seg->area_len += extents;
+				lv->le_count += extents;
+				seg->len += extents;
+				seg->area_len += extents;
+			}
 		}
 	}
 
 #if 1
 	/* HM FIXME: TESTME reshape of a raid5 to add disks after a raid1 -> raid5 takeover */
-	if (seg_is_raid1(seg) && segtype_is_any_raid5(segtype) &&
-	    count == 1 && old_count == 2) {
-		lv->le_count *= 2;
-		seg->len *= 2;
-		seg->area_len *= 2;
+	else if (segtype_is_any_raid5(segtype) &&
+		 count == 1 && old_count == 2) {
+			s = seg->area_count - 1;
+			seg_lv(seg, s)->status &= ~LV_REBUILD;
+			seg_lv(seg, s)->status |= LV_RESHAPE_DELTA_DISKS_PLUS;
+
+			lv->le_count *= 2;
+			seg->len *= 2;
+			seg->area_len *= 2;
 	}
 #endif
 	/* HM FIXME: really needed? */
@@ -2182,7 +2188,7 @@ static int __adjust_segtype_for_takeover(struct logical_volume *lv, struct segme
 	if (is_level_up(seg->segtype, segtype)){
 		/* To raid1 */
 		if (segtype_is_raid1(segtype)) {
-			/* From linear/raid0 */
+			/* From raid0 */
 			if (!seg_is_raid0(seg))
 				return 0;
 
@@ -2209,12 +2215,13 @@ static int __adjust_segtype_for_takeover(struct logical_volume *lv, struct segme
 				segtype_name = SEG_TYPE_NAME_RAID5_N;
 			else if (seg_is_raid1(seg)) {
 				if (seg->area_count != 2) {
-					log_error("raid1 LV %s/%s has to have 2 devices for conversion; use \"lvconvert -m1 %s/%s\"",
+					log_error("raid1 LV %s/%s has to have 2 devices for conversion;"
+						  " use \"lvconvert -m1 %s/%s\"",
 						  lv->vg->name, lv->name, lv->vg->name, lv->name);
 					return 0;
 				}
 
-				segtype_name = SEG_TYPE_NAME_RAID5_LS;
+				segtype_name = SEG_TYPE_NAME_RAID5_N;
 			} else
 				return 0;
 
@@ -2257,8 +2264,6 @@ static int __adjust_segtype_for_takeover(struct logical_volume *lv, struct segme
 			    seg->area_count != 3)
 				return 0;
 
-			// lv->le_count /= 2;
-
 		/* To raid4 */
 		} else if (segtype_is_any_raid4(segtype)) {
 			/* From raid6_0_6 */
@@ -2343,6 +2348,157 @@ static int __convert_reshape(struct logical_volume *lv,
 	return 1;
 }
 
+/* Process one level up takeover on @lv to @segtype allocating fron @allocate_pvs */
+static int __raid_level_up(struct logical_volume *lv,
+			   struct segment_type *segtype,
+			   struct dm_list *allocate_pvs)
+{
+	struct lv_segment *seg = first_seg(lv);
+	uint32_t new_count = seg->area_count + 1;
+
+	/* Make sure to set default region size on takeover from raid0 */
+	__check_and_init_region_size(lv);
+
+	/*
+	 * In case of raid1 -> raid5, takeover will run a degraded 2 disk raid5 set
+	 * which will get an additional disk allocated afterwards and reloaded starting
+	 * resynchronization to reach full redundance.
+	 *
+	 * FIXME: fully redundant raid5_ls set does not double-fold capacity after takeover from raid1 yet!!!
+	 */
+	if (seg_is_raid1(seg)) {
+		seg->segtype = segtype;
+		seg->stripe_size = 64*2;
+
+		/* This causes the raid1 -> raid5 (2 disks) takeover */
+		if (!lv_update_and_reload_origin(lv))
+			return_0;
+
+		/* Leave 2 legged RAID5 as is. Reshape to > 2 legged optional */
+		return 1;
+	}
+
+	/*
+	 * The top-level LV is being reloaded and the VG
+	 * written and committed in the course of this call
+	 */
+	return __lv_raid_change_image_count(lv, segtype, new_count, allocate_pvs);
+}
+
+/* Process one level down takeover on @lv to @segtype */
+static int __raid_level_down(struct logical_volume *lv,
+			    struct segment_type *segtype,
+			    struct dm_list *allocate_pvs)
+{
+	struct lv_segment *seg = first_seg(lv);
+	uint32_t new_count = seg->area_count - 1;
+
+	if (segtype_is_raid1(segtype)) {
+		/* FIXME: delta_disks = -1 mandatory! */
+		/* Reduce image count to 2 first */
+		if (!__lv_raid_change_image_count(lv, NULL, new_count, NULL))
+			return 0;
+
+		seg->segtype = segtype;
+
+		/* This causes the raid5 -> raid1 (2 disks) takeover */
+		if (!lv_update_and_reload_origin(lv))
+			return_0;
+
+		return 1;
+	}
+
+	seg->segtype = segtype;
+
+	/* This causes any !raid1 -> raid takeover */
+	if (!lv_update_and_reload(lv))
+		return_0;
+
+	return __lv_raid_change_image_count(lv, segtype, new_count, NULL);
+}
+
+static struct segment_type *__get_next_up_segtype(struct logical_volume *lv,
+						 const struct segment_type *segtype,
+						 const struct segment_type *new_segtype)
+{
+	const char *segtype_name;
+
+	if (segtype_is_raid0(segtype) ||
+	    segtype_is_raid1(segtype))
+		segtype_name = SEG_TYPE_NAME_RAID5;
+
+	else if (segtype_is_raid4(segtype) ||
+		 segtype_is_any_raid5(segtype))
+		segtype_name = SEG_TYPE_NAME_RAID6;
+
+	else
+		segtype_name = NULL;
+
+	return segtype_name ? get_segtype_from_string(lv->vg->cmd, segtype_name) : NULL;
+}
+
+static struct segment_type *__get_next_down_segtype(struct logical_volume *lv,
+						   const struct segment_type *segtype,
+						   const struct segment_type *new_segtype)
+{
+	const char *segtype_name;
+
+	if (segtype_is_any_raid6(segtype))
+		segtype_name = SEG_TYPE_NAME_RAID5;
+
+	else if (segtype_is_any_raid5(segtype))
+		segtype_name = segtype_is_raid1(new_segtype) ? SEG_TYPE_NAME_RAID1 : SEG_TYPE_NAME_RAID0;
+
+	else
+		segtype_name = NULL;
+
+	return segtype_name ? get_segtype_from_string(lv->vg->cmd, segtype_name) : NULL;
+}
+
+static struct segment_type *__get_next_segtype(struct logical_volume *lv,
+					      const struct segment_type *segtype,
+					      const struct segment_type *new_segtype,
+					      int up)
+{
+	return (up ? __get_next_up_segtype : __get_next_down_segtype)(lv, segtype, new_segtype);
+}
+
+/* Adjust @segtype to takeover compatible one */
+struct possible_takeover {
+	const char *current_name;
+	const char *possible_names[5];
+};
+
+#define	ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
+static const struct segment_type *__adjust_final_segtype(struct logical_volume *lv,
+							const struct segment_type *segtype,
+							const struct segment_type *new_segtype)
+{
+	unsigned cn, pn;
+	struct possible_takeover pt[] = {
+		{ .current_name = SEG_TYPE_NAME_RAID0,
+		  .possible_names = { SEG_TYPE_NAME_RAID5_N, SEG_TYPE_NAME_RAID6_N_6, NULL } },
+		{ .current_name = SEG_TYPE_NAME_RAID1,
+		  .possible_names = { SEG_TYPE_NAME_RAID5_N, NULL } },
+		{ .current_name = SEG_TYPE_NAME_RAID5_N,
+		  .possible_names = { SEG_TYPE_NAME_RAID0, SEG_TYPE_NAME_RAID1,
+				      SEG_TYPE_NAME_STRIPED, SEG_TYPE_NAME_RAID6_N_6, NULL } },
+		{ .current_name = SEG_TYPE_NAME_RAID6_N_6,
+		  .possible_names = { SEG_TYPE_NAME_RAID5_N, SEG_TYPE_NAME_RAID0, SEG_TYPE_NAME_STRIPED, NULL } },
+	};
+
+
+	for (cn = 0; cn < ARRAY_SIZE(pt); cn++) {
+		if (!strcmp(segtype->name, pt[cn].current_name)) {
+			for (pn = 0; pt[cn].possible_names[pn]; pn++)
+				if (!strncmp(new_segtype->name, pt[cn].possible_names[pn], 5))
+					return get_segtype_from_string(lv->vg->cmd, pt[cn].possible_names[pn]);
+		}
+	}
+
+	return NULL;
+}
+
 /*
  * Convert a RAID set to another RAID alogoritm or stripe size
  *
@@ -2354,9 +2510,11 @@ static int _convert_raid_to_raid(struct logical_volume *lv,
 				 const unsigned new_stripe_size,
 				 struct dm_list *allocate_pvs)
 {
-	int new_count;
+	int up;
 	struct lv_segment *seg = first_seg(lv);
 	struct segment_type *new_segtype = (struct segment_type *) requested_segtype;
+	struct segment_type *next_segtype;
+	const struct segment_type *final_segtype;
 	unsigned stripes = new_stripes ?: __data_rimages_count(seg, seg->area_count);
 	unsigned stripe_size = new_stripe_size ?: seg->stripe_size;
 
@@ -2404,93 +2562,33 @@ static int _convert_raid_to_raid(struct logical_volume *lv,
 
 	}
 
-	/* Takeover (i.e. level switch) requested */
-	if (!__adjust_segtype_for_takeover(lv, &new_segtype))
-		return 0;
-
 	/*
 	 * HM
 	 *
-	 * Up takeover of raid levels
+	 * Up/down takeover of raid levels
 	 *
 	 * In order to takeover the raid set level N to M (M > N) in @lv, all existing
 	 * rimages in that set need to be paired with rmeta devs (if not yet present)
-	 * to store superblocks* and bitmaps of the to be taken over raid4/raid5/raid6
+	 * to store superblocks and bitmaps of the to be taken over raid0/raid1/raid4/raid5/raid6
 	 * set plus another rimage/rmeta pair has to be allocated for dedicated xor/q.
-	 */
-	if (is_level_up(seg->segtype, new_segtype)) {
-		new_count = seg->area_count + 1;
-
-		/* Make sure to set default region size on takeover from raid0 */
-		__check_and_init_region_size(lv);
-
-		/*
-		 * In case of raid1 -> raid5, takeover will run a degraded 2 disk raid5 set
-		 * which will get an additional disk allocated afterwards and reloaded starting
-		 * resynchronization to reach full redundance.
-		 *
-		 * FIXME: fully redundant raid5_ls set does not double-fold capacity after takeover from raid1 yet!!!
-		 */
-		if (seg_is_raid1(seg)) {
-			seg->segtype = new_segtype;
-			seg->stripe_size = 64*2;
-
-			/* This causes the raid1 -> raid5 (2 disks) takeover */
-			if (!lv_update_and_reload_origin(lv))
-				return_0;
-
-		}
-
-		/*
-		 * The top-level LV is being reloaded and the VG
-		 * written and committed in the course of this call
-		 */
-		if (!__lv_raid_change_image_count(lv, new_segtype, new_count, allocate_pvs))
-			return 0;
-
-
-	/*
-	 * HM
-	 *
-	 * Down takeover of raid levels
 	 *
 	 * In order to postprocess the takeover of a raid set from level M to M (M > N)
 	 * in @lv, the last rimage/rmeta devs pair need to be droped in the metadata.
 	 */
-	} else {
-		new_count = seg->area_count - 1;
-
-		if (segtype_is_raid1(new_segtype)) {
-			/* FIXME: delta_disks = -1 mandatory! */
-			/* Reduce image count to 2 first */
-			if (!__lv_raid_change_image_count(lv, NULL, new_count, allocate_pvs))
-				return 0;
-
-			seg->segtype = new_segtype;
-
-			/* This causes the raid5 -> raid1 (2 disks) takeover */
-			if (!lv_update_and_reload_origin(lv))
-				return_0;
-
-			return 1;
-		}
-
-		seg->segtype = new_segtype;
-
-		/* This causes any !raid1 -> raid takeover */
-		if (!lv_update_and_reload(lv))
-			return_0;
-
-		if (!__lv_raid_change_image_count(lv, new_segtype, new_count, allocate_pvs))
+	if (!(final_segtype = __adjust_final_segtype(lv, seg->segtype, new_segtype)))
+		return 0;
+	up = is_level_up(seg->segtype, final_segtype);
+	do {
+		if (!(next_segtype = __get_next_segtype(lv, seg->segtype, final_segtype, up)) ||
+		    !__adjust_segtype_for_takeover(lv, &next_segtype) ||
+		    !__raid_level_up(lv, next_segtype, allocate_pvs))
 			return 0;
-	} 
+	} while (next_segtype != final_segtype);
 
 	return 1;
 }
 /******* END: raid <-> raid conversion *******/
 
-
-
 /*
  * lv_raid_reshape
  * @lv
@@ -2651,19 +2749,19 @@ has_enough_space:
 static int _avoid_pvs_of_lv(struct logical_volume *lv, void *data)
 {
 	struct dm_list *allocate_pvs = (struct dm_list *) data;
-	struct pv_list *pvl;
+	struct pv_list *pvl, *tmp;
 
-	dm_list_iterate_items(pvl, allocate_pvs)
+	dm_list_iterate_items_safe(pvl, tmp, allocate_pvs)
 		if (!(lv->status & PARTIAL_LV) &&
 		    lv_is_on_pv(lv, pvl->pv))
-			pvl->pv->status &= ~ALLOCATABLE_PV;
+			pvl->pv->status |= PV_ALLOCATION_PROHIBITED;
 
 	return 1;
 }
 
 /*
  * Prevent any PVs holding other image components of @lv from being used for allocation,
- * I.e. reset ALLOCATABLE_PV flag on respective PVs listed on @allocatable_pvs
+ * I.e. remove respective PVs from @allocatable_pvs
  */
 static void __avoid_pvs_with_other_images_of_lv(struct logical_volume *lv, struct dm_list *allocate_pvs)
 {
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index 509de96..dd60c38 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -156,6 +156,8 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
 int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
 #endif
 
+#define SEG_TYPE_NAME_STRIPED		"striped"
+
 #define SEG_TYPE_NAME_RAID0		"raid0"
 #define SEG_TYPE_NAME_RAID1		"raid1"
 #define SEG_TYPE_NAME_RAID10		"raid10"




More information about the lvm-devel mailing list