mrc0mmand / rpms / lvm2

Forked from rpms/lvm2 2 years ago
Clone

Blame SOURCES/lvm2-2_02_167-fix-raid4-coversion-from-striped.patch

f15685
 WHATS_NEW                             |   2 +
f15685
 lib/metadata/raid_manip.c             | 277 +++++++++++++++++++++++++++++++---
f15685
 test/shell/lvconvert-raid-takeover.sh |  53 ++++++-
f15685
 tools/lvconvert.c                     |  24 +--
f15685
 4 files changed, 314 insertions(+), 42 deletions(-)
f15685
f15685
diff --git a/WHATS_NEW b/WHATS_NEW
f15685
index 5cbf4ec..6a0c311 100644
f15685
--- a/WHATS_NEW
f15685
+++ b/WHATS_NEW
f15685
@@ -1,5 +1,7 @@
f15685
 Version 2.02.167 - 
f15685
 ======================================
f15685
+  Add direct striped -> raid4 conversion
f15685
+  Fix raid4 parity image pair position on conversions from striped/raid0*
f15685
   Disable lvconvert of thin pool to raid while active.
f15685
 
f15685
 Version 2.02.166 - 26th September 2016
f15685
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
f15685
index 5fc520e..e5fd195 100644
f15685
--- a/lib/metadata/raid_manip.c
f15685
+++ b/lib/metadata/raid_manip.c
f15685
@@ -2459,7 +2459,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
f15685
 					   0 /* chunk_size */,
f15685
 					   0 /* seg->region_size */, 0u /* extents_copied */ ,
f15685
 					   NULL /* pvmove_source_seg */))) {
f15685
-		log_error("Failed to allocate new raid0 segement for LV %s.", display_lvname(lv));
f15685
+		log_error("Failed to allocate new raid0 segment for LV %s.", display_lvname(lv));
f15685
 		return NULL;
f15685
 	}
f15685
 
f15685
@@ -2519,42 +2519,51 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
f15685
 	{ .current_types  = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
f15685
 	  .possible_types = SEG_RAID1,
f15685
 	  .current_areas = 1,
f15685
-	  .options = ALLOW_NONE },
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
 	{ .current_types  = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
f15685
 	  .possible_types = SEG_RAID0|SEG_RAID0_META,
f15685
 	  .current_areas = 1,
f15685
 	  .options = ALLOW_STRIPE_SIZE },
f15685
-	{ .current_types  = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */
f15685
+	{ .current_types  = SEG_STRIPED_TARGET, /* striped -> raid0*, i.e. seg->area_count > 1 */
f15685
 	  .possible_types = SEG_RAID0|SEG_RAID0_META,
f15685
 	  .current_areas = ~0U,
f15685
 	  .options = ALLOW_NONE },
f15685
+	{ .current_types  = SEG_STRIPED_TARGET, /* striped -> raid4 , i.e. seg->area_count > 1 */
f15685
+	  .possible_types = SEG_RAID4,
f15685
+	  .current_areas = ~0U,
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
 	/* raid0* -> */
f15685
 	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
f15685
 	  .possible_types = SEG_RAID1,
f15685
 	  .current_areas = 1,
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
+	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> striped, i.e. seg->area_count > 1 */
f15685
+	  .possible_types = SEG_STRIPED_TARGET,
f15685
+	  .current_areas = ~0U,
f15685
 	  .options = ALLOW_NONE },
f15685
-	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* seg->area_count > 1 */
f15685
-	  .possible_types = SEG_RAID4,
f15685
+	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid0*, i.e. seg->area_count > 1 */
f15685
+	  .possible_types = SEG_RAID0_META|SEG_RAID0,
f15685
 	  .current_areas = ~0U,
f15685
 	  .options = ALLOW_NONE },
f15685
-	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
f15685
+	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid4, i.e. seg->area_count > 1 */
f15685
+	  .possible_types = SEG_RAID4,
f15685
+	  .current_areas = ~0U,
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
+	/* raid4 -> -> */
f15685
+	{ .current_types  = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
f15685
 	  .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
f15685
 	  .current_areas = ~0U,
f15685
 	  .options = ALLOW_NONE },
f15685
-	/* raid1 -> */
f15685
+	/* raid1 -> mirror */
f15685
 	{ .current_types  = SEG_RAID1,
f15685
-	  .possible_types = SEG_RAID1|SEG_MIRROR,
f15685
+	  .possible_types = SEG_MIRROR,
f15685
 	  .current_areas = ~0U,
f15685
-	  .options = ALLOW_NONE },
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
 	/* mirror -> raid1 with arbitrary number of legs */
f15685
 	{ .current_types  = SEG_MIRROR,
f15685
-	  .possible_types = SEG_MIRROR|SEG_RAID1,
f15685
-	  .current_areas = ~0U,
f15685
-	  .options = ALLOW_NONE },
f15685
-	{ .current_types  = SEG_RAID4,
f15685
-	  .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
f15685
+	  .possible_types = SEG_RAID1,
f15685
 	  .current_areas = ~0U,
f15685
-	  .options = ALLOW_NONE },
f15685
+	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
f15685
 
f15685
 	/* END */
f15685
 	{ .current_types  = 0 }
f15685
@@ -2861,9 +2870,176 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
f15685
 					allocate_pvs, 1, &removal_lvs);
f15685
 }
f15685
 
f15685
+/*
f15685
+ * HM Helper: (raid0_meta -> raid4)
f15685
+ *
f15685
+ * To convert raid0_meta to raid4, which involves shifting the
f15685
+ * parity device to lv segment area 0 and thus changing MD
f15685
+ * array roles, detach the MetaLVs and reload as raid0 in
f15685
+ * order to wipe them then reattach and set back to raid0_meta.
f15685
+ */
f15685
+static int _clear_meta_lvs(struct logical_volume *lv)
f15685
+{
f15685
+	uint32_t s;
f15685
+	struct lv_segment *seg = first_seg(lv);
f15685
+	struct lv_segment_area *tmp_areas;
f15685
+	const struct segment_type *tmp_segtype;
f15685
+	struct dm_list meta_lvs;
f15685
+	struct lv_list *lvl_array, *lvl;
f15685
+
f15685
+	/* Reject non-raid0_meta segment types cautiously */
f15685
+	if (!seg_is_raid0_meta(seg) ||
f15685
+	    !seg->meta_areas)
f15685
+		return_0;
f15685
+
f15685
+	if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, seg->area_count * sizeof(*lvl_array))))
f15685
+		return_0;
f15685
+
f15685
+	dm_list_init(&meta_lvs);
f15685
+	tmp_areas = seg->meta_areas;
f15685
+
f15685
+	/* Extract all MetaLVs listing them on @meta_lvs */
f15685
+	log_debug_metadata("Extracting all MetaLVs of %s to activate as raid0",
f15685
+			   display_lvname(lv));
f15685
+	if (!_extract_image_component_sublist(seg, RAID_META, 0, seg->area_count, &meta_lvs, 0))
f15685
+		return_0;
f15685
+
f15685
+	/* Memorize meta areas and segtype to set again after initializing. */
f15685
+	seg->meta_areas = NULL;
f15685
+	tmp_segtype = seg->segtype;
f15685
+
f15685
+	if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)) ||
f15685
+	    !lv_update_and_reload(lv))
f15685
+		return_0;
f15685
+
f15685
+	/*
f15685
+	 * Now deactivate the MetaLVs before clearing, so
f15685
+	 * that _clear_lvs() will activate them visible.
f15685
+	 */
f15685
+	log_debug_metadata("Deactivating pulled out MetaLVs of %s before initializing.",
f15685
+			   display_lvname(lv));
f15685
+	dm_list_iterate_items(lvl, &meta_lvs)
f15685
+		if (!deactivate_lv(lv->vg->cmd, lvl->lv))
f15685
+			return_0;
f15685
+
f15685
+	log_debug_metadata("Clearing allocated raid0_meta metadata LVs for conversion to raid4");
f15685
+	if (!_clear_lvs(&meta_lvs)) {
f15685
+		log_error("Failed to initialize metadata LVs");
f15685
+		return 0;
f15685
+	}
f15685
+
f15685
+	/* Set memorized meta areas and raid0_meta segtype */
f15685
+	seg->meta_areas = tmp_areas;
f15685
+	seg->segtype = tmp_segtype;
f15685
+
f15685
+	log_debug_metadata("Adding metadata LVs back into %s", display_lvname(lv));
f15685
+	s = 0;
f15685
+	dm_list_iterate_items(lvl, &meta_lvs) {
f15685
+		lv_set_hidden(lvl->lv);
f15685
+		if (!set_lv_segment_area_lv(seg, s++, lvl->lv, 0, RAID_META))
f15685
+			return 0;
f15685
+	}
f15685
+
f15685
+	return 1;
f15685
+}
f15685
+
f15685
+/*
f15685
+ * HM Helper: (raid0* <-> raid4)
f15685
+ *
f15685
+ * Rename SubLVs (pairs) allowing to shift names w/o collisions with active ones.
f15685
+ */
f15685
+#define	SLV_COUNT	2
f15685
+static int _rename_area_lvs(struct logical_volume *lv, const char *suffix)
f15685
+{
f15685
+	uint32_t s;
f15685
+	size_t sz = strlen("rimage") + (suffix ? strlen(suffix) : 0) + 1;
f15685
+	char *sfx[SLV_COUNT] = { NULL, NULL };
f15685
+	struct lv_segment *seg = first_seg(lv);
f15685
+
f15685
+	/* Create _generate_raid_name() suffixes w/ or w/o passed in @suffix */
f15685
+	for (s = 0; s < SLV_COUNT; s++)
f15685
+		if (!(sfx[s] = dm_pool_alloc(lv->vg->cmd->mem, sz)) ||
f15685
+		    dm_snprintf(sfx[s], sz, suffix ? "%s%s" : "%s", s ? "rmeta" : "rimage", suffix) < 0)
f15685
+			return_0;
f15685
+
f15685
+	/* Change names (temporarily) to be able to shift numerical name suffixes */
f15685
+	for (s = 0; s < seg->area_count; s++) {
f15685
+		if (!(seg_lv(seg, s)->name = _generate_raid_name(lv, sfx[0], s)))
f15685
+			return_0;
f15685
+		if (seg->meta_areas &&
f15685
+		    !(seg_metalv(seg, s)->name = _generate_raid_name(lv, sfx[1], s)))
f15685
+			return_0;
f15685
+	}
f15685
+
f15685
+	for (s = 0; s < SLV_COUNT; s++)
f15685
+		dm_pool_free(lv->vg->cmd->mem, sfx[s]);
f15685
+
f15685
+	return 1;
f15685
+}
f15685
+
f15685
+/*
f15685
+ * HM Helper: (raid0* <-> raid4)
f15685
+ *
f15685
+ * Switch area LVs in lv segment @seg indexed by @s1 and @s2
f15685
+ */
f15685
+static void _switch_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
f15685
+{
f15685
+	struct logical_volume *lvt;
f15685
+
f15685
+	lvt = seg_lv(seg, s1);
f15685
+	seg_lv(seg, s1) = seg_lv(seg, s2);
f15685
+	seg_lv(seg, s2) = lvt;
f15685
+
f15685
+	/* Be cautious */
f15685
+	if (seg->meta_areas) {
f15685
+		lvt = seg_metalv(seg, s1);
f15685
+		seg_metalv(seg, s1) = seg_metalv(seg, s2);
f15685
+		seg_metalv(seg, s2) = lvt;
f15685
+	}
f15685
+}
f15685
+
f15685
+/*
f15685
+ * HM Helper:
f15685
+ *
f15685
+ * shift range of area LVs in @seg in range [ @s1, @s2 ] up if @s1 < @s2,
f15685
+ * else down  bubbling the parity SubLVs up/down whilst shifting.
f15685
+ */
f15685
+static void _shift_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
f15685
+{
f15685
+	uint32_t s;
f15685
+
f15685
+	if (s1 < s2)
f15685
+		/* Forward shift n+1 -> n */
f15685
+		for (s = s1; s < s2; s++)
f15685
+			_switch_area_lvs(seg, s, s + 1);
f15685
+	else
f15685
+		/* Reverse shift n-1 -> n */
f15685
+		for (s = s1; s > s2; s--)
f15685
+			_switch_area_lvs(seg, s, s - 1);
f15685
+}
f15685
+
f15685
+/*
f15685
+ * Switch position of first and last area lv within
f15685
+ * @lv to move parity SubLVs from end to end.
f15685
+ *
f15685
+ * Direction depends on segment type raid4 / raid0_meta.
f15685
+ */
f15685
+static int _shift_parity_dev(struct lv_segment *seg)
f15685
+{
f15685
+	if (seg_is_raid0_meta(seg))
f15685
+		_shift_area_lvs(seg, seg->area_count - 1, 0);
f15685
+	else if (seg_is_raid4(seg))
f15685
+		_shift_area_lvs(seg, 0, seg->area_count - 1);
f15685
+	else
f15685
+		return 0;
f15685
+
f15685
+	return 1;
f15685
+}
f15685
+
f15685
 /* raid45 -> raid0* / striped */
f15685
 static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
f15685
 {
f15685
+	int rename_sublvs = 0;
f15685
 	struct lv_segment *seg = first_seg(lv);
f15685
 	struct dm_list removal_lvs;
f15685
 
f15685
@@ -2879,10 +3055,39 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
f15685
 	if (!_raid_in_sync(lv))
f15685
 		return 0;
f15685
 
f15685
+	if (!yes && yes_no_prompt("Are you sure you want to convert \"%s\" LV %s to \"%s\" "
f15685
+				  "type using all resilience? [y/n]: ",
f15685
+				  lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') {
f15685
+		log_error("Logical volume %s NOT converted to \"%s\"",
f15685
+			  display_lvname(lv), new_segtype->name);
f15685
+		return 0;
f15685
+	}
f15685
+	if (sigint_caught())
f15685
+		return_0;
f15685
+
f15685
 	/* Archive metadata */
f15685
 	if (!archive(lv->vg))
f15685
 		return_0;
f15685
 
f15685
+	/*
f15685
+	 * raid4 (which actually gets mapped to raid5/dedicated first parity disk)
f15685
+	 * needs shifting of SubLVs to move the parity SubLV pair in the first area
f15685
+	 * to the last one before conversion to raid0[_meta]/striped to allow for
f15685
+	 * SubLV removal from the end of the areas arrays.
f15685
+	 */
f15685
+	if (seg_is_raid4(seg)) {
f15685
+		/* Shift parity SubLV pair "PDD..." -> "DD...P" to be able to remove it off the end */
f15685
+		if (!_shift_parity_dev(seg))
f15685
+			return 0;
f15685
+
f15685
+		if (segtype_is_any_raid0(new_segtype) &&
f15685
+		    !(rename_sublvs = _rename_area_lvs(lv, "_"))) {
f15685
+			log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
f15685
+			return 0;
f15685
+		}
f15685
+
f15685
+	}
f15685
+
f15685
 	/* Remove meta and data LVs requested */
f15685
 	if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
f15685
 		return 0;
f15685
@@ -2902,7 +3107,19 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
f15685
 
f15685
 	seg->region_size = 0;
f15685
 
f15685
-	return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs);
f15685
+	if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs))
f15685
+		return_0;
f15685
+
f15685
+	if (rename_sublvs) {
f15685
+		if (!_rename_area_lvs(lv, NULL)) {
f15685
+			log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv));
f15685
+			return 0;
f15685
+		}
f15685
+		if (!lv_update_and_reload(lv))
f15685
+			return_0;
f15685
+	}
f15685
+
f15685
+	return 1;
f15685
 }
f15685
 
f15685
 static int _striped_to_raid0_wrapper(struct logical_volume *lv,
f15685
@@ -2930,6 +3147,9 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
f15685
 static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
f15685
 {
f15685
 	struct lv_segment *seg = first_seg(lv);
f15685
+	struct dm_list removal_lvs;
f15685
+
f15685
+	dm_list_init(&removal_lvs);
f15685
 
f15685
 	if (seg_is_raid10(seg))
f15685
 		return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
f15685
@@ -2944,6 +3164,13 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
f15685
 		return 0;
f15685
 	}
f15685
 
f15685
+	/* FIXME: restricted to raid4 for the time being... */
f15685
+	if (!segtype_is_raid4(new_segtype)) {
f15685
+		/* Can't convert striped/raid0* to e.g. raid10_offset */
f15685
+		log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
f15685
+		return 0;
f15685
+	}
f15685
+
f15685
 	/* Archive metadata */
f15685
 	if (!archive(lv->vg))
f15685
 		return_0;
f15685
@@ -2961,7 +3188,10 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
f15685
 		log_debug_metadata("Adding metadata LVs to %s", display_lvname(lv));
f15685
 		if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL))
f15685
 			return 0;
f15685
-	}
f15685
+	/* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role cahnge issues in the kernel */
f15685
+	} else if (segtype_is_raid4(new_segtype) &&
f15685
+		   !_clear_meta_lvs(lv))
f15685
+		return 0;
f15685
 
f15685
 	/* Add the additional component LV pairs */
f15685
 	log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s", new_image_count - lv_raid_image_count(lv),
f15685
@@ -2969,8 +3199,9 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
f15685
 	if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
f15685
 		return 0;
f15685
 
f15685
-	if (!segtype_is_raid4(new_segtype)) {
f15685
-		/* Can't convert striped/raid0* to e.g. raid10_offset */
f15685
+	if (segtype_is_raid4(new_segtype) &&
f15685
+	    (!_shift_parity_dev(seg) ||
f15685
+	     !_rename_area_lvs(lv, "_"))) {
f15685
 		log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name);
f15685
 		return 0;
f15685
 	}
f15685
@@ -2987,6 +3218,14 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
f15685
 	if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
f15685
 		return_0;
f15685
 
f15685
+	if (segtype_is_raid4(new_segtype)) {
f15685
+		/* We had to rename SubLVs because of collision free sgifting, rename back... */
f15685
+		if (!_rename_area_lvs(lv, NULL))
f15685
+			return 0;
f15685
+		if (!lv_update_and_reload(lv))
f15685
+			return_0;
f15685
+	}
f15685
+
f15685
 	return 1;
f15685
 }
f15685
 
f15685
diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh
f15685
index 19a65d3..0140e22 100644
f15685
--- a/test/shell/lvconvert-raid-takeover.sh
f15685
+++ b/test/shell/lvconvert-raid-takeover.sh
f15685
@@ -78,22 +78,58 @@ aux wait_for_sync $vg $lv1
f15685
 # Clean up
f15685
 lvremove --yes $vg/$lv1
f15685
 
f15685
-# Create 3-way raid0
f15685
-lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg
f15685
-check lv_field $vg/$lv1 segtype "raid0"
f15685
+# Create 3-way striped
f15685
+lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg
f15685
+check lv_field $vg/$lv1 segtype "striped"
f15685
 check lv_field $vg/$lv1 stripes 3
f15685
 echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
f15685
 fsck -fn  /dev/mapper/$vg-$lv1
f15685
 
f15685
-# Convert raid0 -> raid4
f15685
+# Create 3-way raid0
f15685
+lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv2 $vg
f15685
+check lv_field $vg/$lv2 segtype "raid0"
f15685
+check lv_field $vg/$lv2 stripes 3
f15685
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv2
f15685
+fsck -fn  /dev/mapper/$vg-$lv2
f15685
+
f15685
+# Create 3-way raid0_meta
f15685
+lvcreate -y -aey --type raid0_meta -i 3 -L 64M -n $lv3 $vg
f15685
+check lv_field $vg/$lv3 segtype "raid0_meta"
f15685
+check lv_field $vg/$lv3 stripes 3
f15685
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv3
f15685
+fsck -fn  /dev/mapper/$vg-$lv3
f15685
+
f15685
+# Create 3-way raid4
f15685
+lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg
f15685
+check lv_field $vg/$lv4 segtype "raid4"
f15685
+check lv_field $vg/$lv4 stripes 4
f15685
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv4
f15685
+fsck -fn  /dev/mapper/$vg-$lv4
f15685
+aux wait_for_sync $vg $lv4
f15685
+fsck -fn  /dev/mapper/$vg-$lv4
f15685
+
f15685
+# Convert raid4 -> striped (correct raid4 mapping test!)
f15685
+lvconvert -y --ty striped $vg/$lv4
f15685
+check lv_field $vg/$lv4 segtype "striped"
f15685
+check lv_field $vg/$lv4 stripes 3
f15685
+fsck -fn  /dev/mapper/$vg-$lv4
f15685
+
f15685
+# Convert striped -> raid4
f15685
 lvconvert -y --ty raid4 $vg/$lv1
f15685
-lvchange --refresh $vg/$lv1
f15685
 check lv_field $vg/$lv1 segtype "raid4"
f15685
 check lv_field $vg/$lv1 stripes 4
f15685
 fsck -fn  /dev/mapper/$vg-$lv1
f15685
 aux wait_for_sync $vg $lv1
f15685
 fsck -fn  /dev/mapper/$vg-$lv1
f15685
 
f15685
+# Convert raid0 -> raid4
f15685
+lvconvert -y --ty raid4 $vg/$lv2
f15685
+check lv_field $vg/$lv2 segtype "raid4"
f15685
+check lv_field $vg/$lv2 stripes 4
f15685
+fsck -fn  /dev/mapper/$vg-$lv2
f15685
+aux wait_for_sync $vg $lv2
f15685
+fsck -fn  /dev/mapper/$vg-$lv2
f15685
+
f15685
 # Convert raid4 -> raid0_meta
f15685
 lvconvert -y --ty raid0_meta $vg/$lv1
f15685
 check lv_field $vg/$lv1 segtype "raid0_meta"
f15685
@@ -116,11 +152,16 @@ fsck -fn  /dev/mapper/$vg-$lv1
f15685
 
f15685
 # Convert raid0 -> raid4
f15685
 lvconvert -y --ty raid4 $vg/$lv1
f15685
-lvchange --refresh $vg/$lv1
f15685
 check lv_field $vg/$lv1 segtype "raid4"
f15685
 check lv_field $vg/$lv1 stripes 4
f15685
 fsck -fn  /dev/mapper/$vg-$lv1
f15685
 aux wait_for_sync $vg $lv1
f15685
 fsck -fn  /dev/mapper/$vg-$lv1
f15685
 
f15685
+# Convert raid4 -> striped
f15685
+lvconvert -y --ty striped $vg/$lv1
f15685
+check lv_field $vg/$lv1 segtype "striped"
f15685
+check lv_field $vg/$lv1 stripes 3
f15685
+fsck -fn  /dev/mapper/$vg-$lv1
f15685
+
f15685
 vgremove -ff $vg
f15685
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
f15685
index 0d2a4d1..541df72 100644
f15685
--- a/tools/lvconvert.c
f15685
+++ b/tools/lvconvert.c
f15685
@@ -1931,7 +1931,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
f15685
 			return 1;
f15685
 		}
f15685
 		goto try_new_takeover_or_reshape;
f15685
-	} else if (!lp->repair && !lp->replace && (!*lp->type_str || seg->segtype == lp->segtype)) {
f15685
+	} else if (!lp->repair && !lp->replace && !*lp->type_str) {
f15685
 		log_error("Conversion operation not yet supported.");
f15685
 		return 0;
f15685
 	}
f15685
@@ -2017,28 +2017,18 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
f15685
 		return 1;
f15685
 	}
f15685
 
f15685
-
f15685
 try_new_takeover_or_reshape:
f15685
-
f15685
 	/* FIXME This needs changing globally. */
f15685
 	if (!arg_is_set(cmd, stripes_long_ARG))
f15685
 		lp->stripes = 0;
f15685
 
f15685
-	/* Only let raid4 through for now. */
f15685
-	if (lp->type_str && lp->type_str[0] && lp->segtype != seg->segtype &&
f15685
-	    ((seg_is_raid4(seg) && seg_is_striped(lp) && lp->stripes > 1) ||
f15685
-	     (seg_is_striped(seg) && seg->area_count > 1 && seg_is_raid4(lp)))) {
f15685
-		if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
f15685
-				     lp->region_size, lp->pvh))
f15685
-			return_0;
f15685
-
f15685
-		log_print_unless_silent("Logical volume %s successfully converted.",
f15685
-					display_lvname(lv));
f15685
-		return 1;
f15685
-	}
f15685
+	if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
f15685
+			     lp->region_size, lp->pvh))
f15685
+		return_0;
f15685
 
f15685
-	log_error("Conversion operation not yet supported.");
f15685
-	return 0;
f15685
+	log_print_unless_silent("Logical volume %s successfully converted.",
f15685
+				display_lvname(lv));
f15685
+	return 1;
f15685
 }
f15685
 
f15685
 static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow,