[lvm-devel] master - lvconvert: add segtype raid5_n and conversions to/from it

Heinz Mauelshagen mauelsha at fedoraproject.org
Fri Feb 3 19:40:49 UTC 2017


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=60ddd05f163cbf53670e5c8deabfc384168eae0f
Commit:        60ddd05f163cbf53670e5c8deabfc384168eae0f
Parent:        875ce04c61fb40436bf4d6308356c800d08c1f7e
Author:        Heinz Mauelshagen <heinzm at redhat.com>
AuthorDate:    Fri Feb 3 20:39:40 2017 +0100
Committer:     Heinz Mauelshagen <heinzm at redhat.com>
CommitterDate: Fri Feb 3 20:40:26 2017 +0100

lvconvert: add segtype raid5_n and conversions to/from it

Add:
- support for segment type raid5_n (striped raid with dedicated last parity SubLVs)
- conversion support from striped/raid0/raid0_meta/raid4 to/from raid5_n
- related tests to lvconvert-raid-takeover.sh

Related: rhbz1366296
---
 lib/metadata/merge.c                  |    7 +-
 lib/metadata/raid_manip.c             |  252 +++++++++++++++++++++++----------
 lib/raid/raid.c                       |   15 +-
 libdm/libdm-deptree.c                 |    7 +-
 test/shell/lvconvert-raid-takeover.sh |   63 ++++++++-
 5 files changed, 259 insertions(+), 85 deletions(-)

diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 59c0885..dbd91db 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -148,7 +148,8 @@ static void _check_raid1_seg(struct lv_segment *seg, int *error_count)
 static void _check_raid45610_seg(struct lv_segment *seg, int *error_count)
 {
 	/* Checks applying to any raid4/5/6/10 */
-	if (!seg->meta_areas)
+	/* Allow raid4 + raid5_n to get activated w/o metadata (mandatory during conversion between them) */
+	if (!(seg_is_raid4(seg) || seg_is_raid5_n(seg)) && !seg->meta_areas)
 		raid_seg_error("no meta areas");
 	if (!seg->stripe_size)
 		raid_seg_error("zero stripe size");
@@ -610,7 +611,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 				continue;
 			if (lv == seg_lv(seg, s))
 				seg_found++;
-			if (seg_is_raid_with_meta(seg) && (lv == seg_metalv(seg, s)))
+			if (seg->meta_areas && seg_is_raid_with_meta(seg) && (lv == seg_metalv(seg, s)))
 				seg_found++;
 		}
 		if (seg_is_replicator_dev(seg)) {
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 8c88280..f845164 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -2175,6 +2175,7 @@ static int _convert_mirror_to_raid1(struct logical_volume *lv,
 	lv->status &= ~MIRROR;
 	lv->status &= ~MIRRORED;
 	lv->status |= RAID;
+	seg->status |= RAID;
 
 	if (!lv_update_and_reload(lv))
 		return_0;
@@ -2567,44 +2568,22 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
 	  .possible_types = SEG_RAID0|SEG_RAID0_META,
 	  .current_areas = 1,
 	  .options = ALLOW_STRIPE_SIZE },
-	{ .current_types  = SEG_STRIPED_TARGET, /* striped -> raid0*, i.e. seg->area_count > 1 */
-	  .possible_types = SEG_RAID0|SEG_RAID0_META,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE },
-	{ .current_types  = SEG_STRIPED_TARGET, /* striped -> raid4 , i.e. seg->area_count > 1 */
-	  .possible_types = SEG_RAID4,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
+
 	/* raid0* -> */
 	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
 	  .possible_types = SEG_RAID1,
 	  .current_areas = 1,
 	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
-	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> striped, i.e. seg->area_count > 1 */
-	  .possible_types = SEG_STRIPED_TARGET,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE },
-	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid0*, i.e. seg->area_count > 1 */
-	  .possible_types = SEG_RAID0_META|SEG_RAID0,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE },
-	{ .current_types  = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid4, i.e. seg->area_count > 1 */
-	  .possible_types = SEG_RAID4,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
-	/* raid4 -> -> */
-	{ .current_types  = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */
-	  .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
-	  .current_areas = ~0U,
-	  .options = ALLOW_NONE },
-	/* raid1 -> mirror */
-	{ .current_types  = SEG_RAID1,
-	  .possible_types = SEG_MIRROR,
+
+	/* striped,raid0*,raid4,raid5_n <-> striped,raid0*,raid4,raid5_n */
+	{ .current_types  = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META|SEG_RAID4|SEG_RAID5_N,
+	  .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META|SEG_RAID4|SEG_RAID5_N,
 	  .current_areas = ~0U,
 	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
-	/* mirror -> raid1 with arbitrary number of legs */
-	{ .current_types  = SEG_MIRROR,
-	  .possible_types = SEG_RAID1,
+
+	/* mirror <-> raid1 with arbitrary number of legs */
+	{ .current_types  = SEG_MIRROR|SEG_RAID1,
+	  .possible_types = SEG_MIRROR|SEG_RAID1,
 	  .current_areas = ~0U,
 	  .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */
 
@@ -2724,6 +2703,15 @@ static const char *_get_segtype_alias(const struct segment_type *segtype)
 	return "";
 }
 
+/* Return "linear" for striped segtype with 1 area instead of "striped" */
+static const char *_get_segtype_name(const struct segment_type *segtype, unsigned new_image_count)
+{
+	if (!segtype || (segtype_is_striped(segtype) && new_image_count == 1))
+		return "linear";
+
+	return segtype->name;
+}
+
 static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
 {
 	unsigned possible_conversions = 0;
@@ -2744,7 +2732,7 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const
 
 			log_error("Converting %s from %s%s%s%s is "
 				  "directly possible to the following layout%s:",
-				  display_lvname(lv), lvseg_name(seg),
+				  display_lvname(lv), _get_segtype_name(seg->segtype, seg->area_count),
 				  *alias ? " (same as " : "", alias, *alias ? ")" : "",
 				  possible_conversions > 1 ? "s" : "");
 
@@ -2911,6 +2899,8 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
  * parity device to lv segment area 0 and thus changing MD
  * array roles, detach the MetaLVs and reload as raid0 in
  * order to wipe them then reattach and set back to raid0_meta.
+ *
+ * Same applies to raid4 <-> raid5.
  */
 static int _clear_meta_lvs(struct logical_volume *lv)
 {
@@ -2920,16 +2910,18 @@ static int _clear_meta_lvs(struct logical_volume *lv)
 	const struct segment_type *tmp_segtype;
 	struct dm_list meta_lvs;
 	struct lv_list *lvl_array, *lvl;
+	int is_raid4_or_5N = seg_is_raid4(seg) || seg_is_raid5_n(seg);
 
-	/* Reject non-raid0_meta segment types cautiously */
-	if (!seg_is_raid0_meta(seg) ||
-	    !seg->meta_areas)
+	/* Reject non-raid0_meta/raid4/raid5_n segment types cautiously */
+	if (!seg->meta_areas ||
+	    (!seg_is_raid0_meta(seg) && !is_raid4_or_5N))
 		return_0;
 
 	if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, seg->area_count * sizeof(*lvl_array))))
 		return_0;
 
 	dm_list_init(&meta_lvs);
+	tmp_segtype = seg->segtype;
 	tmp_areas = seg->meta_areas;
 
 	/* Extract all MetaLVs listing them on @meta_lvs */
@@ -2940,10 +2932,12 @@ static int _clear_meta_lvs(struct logical_volume *lv)
 
 	/* Memorize meta areas and segtype to set again after initializing. */
 	seg->meta_areas = NULL;
-	tmp_segtype = seg->segtype;
 
-	if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)) ||
-	    !lv_update_and_reload(lv))
+	if (seg_is_raid0_meta(seg) &&
+	    !(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)))
+		return_0;
+
+	if (!lv_update_and_reload(lv))
 		return_0;
 
 	/* Note: detached rmeta are NOT renamed */
@@ -3066,7 +3060,7 @@ static void _shift_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2)
  */
 static int _shift_parity_dev(struct lv_segment *seg)
 {
-	if (seg_is_raid0_meta(seg))
+	if (seg_is_raid0_meta(seg) || seg_is_raid5_n(seg))
 		_shift_area_lvs(seg, seg->area_count - 1, 0);
 	else if (seg_is_raid4(seg))
 		_shift_area_lvs(seg, 0, seg->area_count - 1);
@@ -3082,10 +3076,13 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
 	int rename_sublvs = 0;
 	struct lv_segment *seg = first_seg(lv);
 	struct dm_list removal_lvs;
+	uint32_t region_size = seg->region_size;
 
 	dm_list_init(&removal_lvs);
 
-	if (!seg_is_raid4(seg) && !seg_is_raid5_n(seg) && !seg_is_raid6_n_6(seg)) {
+	if (!seg_is_raid4(seg) &&
+	    !seg_is_raid5_n(seg) &&
+	    !seg_is_raid6_n_6(seg)) {
 		log_error("LV %s has to be of type raid4/raid5_n/raid6_n_6 to allow for this conversion.",
 			  display_lvname(lv));
 		return 0;
@@ -3098,7 +3095,7 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
 	if (!yes && yes_no_prompt("Are you sure you want to convert \"%s\" LV %s to \"%s\" "
 				  "type losing all resilience? [y/n]: ",
 				  lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') {
-		log_error("Logical volume %s NOT converted to \"%s\".",
+		log_error("Logical volume %s NOT converted to \"%s\"",
 			  display_lvname(lv), new_segtype->name);
 		return 0;
 	}
@@ -3122,22 +3119,23 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
 
 		if (segtype_is_any_raid0(new_segtype) &&
 		    !(rename_sublvs = _rename_area_lvs(lv, "_"))) {
-			log_error("Failed to rename %s LV %s MetaLVs.",
-				  lvseg_name(seg), display_lvname(lv));
+			log_error("Failed to rename %s LV %s MetaLVs.", lvseg_name(seg), display_lvname(lv));
 			return 0;
 		}
-
 	}
 
 	/* Remove meta and data LVs requested */
 	if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0))
 		return 0;
 
-	if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0_META)))
-		return_0;
+	/* FIXME Hard-coded raid4/5/6 to striped/raid0 */
+	if (segtype_is_striped_target(new_segtype) || segtype_is_any_raid0(new_segtype)) {
+		seg->area_len = seg->extents_copied = seg->area_len / seg->area_count;
+		if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0_META)))
+			return_0;
 
-	/* FIXME Hard-coded raid4 to raid0 */
-	seg->area_len = seg->extents_copied = seg->area_len / seg->area_count;
+		region_size = 0;
+	}
 
 	if (segtype_is_striped_target(new_segtype)) {
 		if (!_convert_raid0_to_striped(lv, 0, &removal_lvs))
@@ -3146,15 +3144,15 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
 		   !_raid0_add_or_remove_metadata_lvs(lv, 0 /* update_and_reload */, allocate_pvs, &removal_lvs))
 		return_0;
 
-	seg->region_size = 0;
+	seg->region_size = region_size;
+	seg->segtype = new_segtype;
 
 	if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs))
 		return_0;
 
 	if (rename_sublvs) {
 		if (!_rename_area_lvs(lv, NULL)) {
-			log_error("Failed to rename %s LV %s MetaLVs.",
-				  lvseg_name(seg), display_lvname(lv));
+			log_error("Failed to rename %s LV %s MetaLVs.", lvseg_name(seg), display_lvname(lv));
 			return 0;
 		}
 		if (!lv_update_and_reload(lv))
@@ -3164,6 +3162,79 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
 	return 1;
 }
 
+/*
+ * raid4 <-> raid5_n helper
+ *
+ * On conversions between raid4 and raid5_n, the parity SubLVs need
+ * to be switched between beginning and end of the segment areas.
+ *
+ * The metadata devices reflect the previous positions within the RaidLV,
+ * thus need to be cleared in order to allow the kernel to start the new
+ * mapping and recreate metadata with the proper new position stored.
+ */
+static int _raid45_to_raid54_wrapper(TAKEOVER_FN_ARGS)
+{
+	struct lv_segment *seg = first_seg(lv);
+	struct dm_list removal_lvs;
+	uint32_t region_size = seg->region_size;
+
+	dm_list_init(&removal_lvs);
+
+	if (!(seg_is_raid4(seg) && segtype_is_raid5_n(new_segtype)) &&
+	    !(seg_is_raid5_n(seg) && segtype_is_raid4(new_segtype))) {
+		log_error("LV %s has to be of type raid4 or raid5_n to allow for this conversion.",
+			  display_lvname(lv));
+		return 0;
+	}
+
+
+	/* Necessary when convering to raid0/striped w/o redundancy? */
+	if (!_raid_in_sync(lv)) {
+		log_error("Unable to convert %s while it is not in-sync.",
+			  display_lvname(lv));
+		return 0;
+	}
+
+	log_debug_metadata("Converting LV %s from %s to %s.", display_lvname(lv),
+			   (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID4 : SEG_TYPE_NAME_RAID5_N),
+			   (seg_is_raid4(seg) ? SEG_TYPE_NAME_RAID5_N : SEG_TYPE_NAME_RAID4));
+
+	/* Archive metadata */
+	if (!archive(lv->vg))
+		return_0;
+
+	if (!_rename_area_lvs(lv, "_")) {
+		log_error("Failed to rename %s LV %s MetaLVs.", lvseg_name(seg), display_lvname(lv));
+		return 0;
+	}
+
+	if (!_clear_meta_lvs(lv))
+		return_0;
+
+	/* Shift parity SubLV pair "PDD..." <-> "DD...P" on raid4 <-> raid5_n conversion */
+	if( !_shift_parity_dev(seg))
+		return 0;
+
+	/* Don't resync */
+	init_mirror_in_sync(1);
+	seg->region_size = new_region_size ?: region_size;
+	seg->segtype = new_segtype;
+
+	if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs))
+		return_0;
+
+	init_mirror_in_sync(0);
+
+	if (!_rename_area_lvs(lv, NULL)) {
+		log_error("Failed to rename %s LV %s MetaLVs.", lvseg_name(seg), display_lvname(lv));
+		return 0;
+	}
+	if (!lv_update_and_reload(lv))
+		return_0;
+
+	return 1;
+}
+
 static int _striped_to_raid0_wrapper(struct logical_volume *lv,
 				     const struct segment_type *new_segtype,
 				     uint32_t new_stripes,
@@ -3188,14 +3259,31 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
 /* Helper: striped/raid0* -> raid4/5/6/10 */
 static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 {
+	uint32_t extents_copied, region_size, seg_len, stripe_size;
 	struct lv_segment *seg = first_seg(lv);
 	struct dm_list removal_lvs;
 
 	dm_list_init(&removal_lvs);
 
+	if (!seg_is_striped_target(seg) &&
+	    !seg_is_any_raid0(seg) &&
+	    !seg_is_raid4(seg) &&
+	    !seg_is_any_raid5(seg)) {
+		log_error("Can't convert %s LV %s.", lvseg_name(seg), display_lvname(lv));
+		return 0;
+	}
+
 	if (seg_is_raid10(seg))
 		return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
 
+	if (!segtype_is_raid4(new_segtype) &&
+	    !segtype_is_raid5_n(new_segtype) &&
+	    !segtype_is_raid6_n_6(new_segtype)) {
+		/* Can't convert to e.g. raid10_offset */
+		log_error("Can't convert %s to %s.", display_lvname(lv), new_segtype->name);
+		return 0;
+	}
+
 	if (new_data_copies > new_image_count) {
 		log_error("N number of data_copies \"--mirrors N-1\" may not be larger than number of stripes.");
 		return 0;
@@ -3206,8 +3294,9 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 		return 0;
 	}
 
-	/* FIXME: restricted to raid4 for the time being... */
-	if (!segtype_is_raid4(new_segtype)) {
+	/* FIXME: restricted to raid4 and raid5_n for the time being... */
+	if (!segtype_is_raid4(new_segtype) &&
+	    !segtype_is_raid5_n(new_segtype)) {
 		/* Can't convert striped/raid0* to e.g. raid10_offset */
 		log_error("Can't convert %s to %s.", display_lvname(lv), new_segtype->name);
 		return 0;
@@ -3219,7 +3308,7 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 
 	/* This helper can be used to convert from striped/raid0* -> raid10 too */
 	if (seg_is_striped_target(seg)) {
-		log_debug_metadata("Converting LV %s from %s to %s",
+		log_debug_metadata("Converting LV %s from %s to %s.",
 				   display_lvname(lv), SEG_TYPE_NAME_STRIPED, SEG_TYPE_NAME_RAID0);
 		if (!(seg = _convert_striped_to_raid0(lv, 1 /* alloc_metadata_devs */, 0 /* update_and_reload */, allocate_pvs)))
 			return_0;
@@ -3229,18 +3318,32 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 	if (seg_is_raid0(seg)) {
 		log_debug_metadata("Adding metadata LVs to %s.", display_lvname(lv));
 		if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL))
-			return_0;
-	/* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role cahnge issues in the kernel */
+			return 0;
+	/* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role change issues in the kernel */
 	} else if (segtype_is_raid4(new_segtype) &&
 		   !_clear_meta_lvs(lv))
 		return_0;
 
+
 	/* Add the additional component LV pairs */
 	log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s.",
 			   new_image_count - lv_raid_image_count(lv),
 			   display_lvname(lv));
+	extents_copied = seg->extents_copied;
+	region_size = seg->region_size;
+	seg_len = seg->len;
+	stripe_size = seg->stripe_size;
+
+	if (seg_is_raid4(seg) || seg_is_any_raid5(seg)) {
+		if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0_META)))
+			return_0;
+		seg->area_len = seg_lv(seg, 0)->le_count;
+		lv->le_count = seg->len = seg->area_len * seg->area_count;
+		seg->extents_copied = seg->region_size = 0;
+	}
+
 	if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
-		return_0;
+		return 0;
 
 	if (segtype_is_raid4(new_segtype) &&
 	    (!_shift_parity_dev(seg) ||
@@ -3250,9 +3353,12 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 	}
 
 	seg->segtype = new_segtype;
-	seg->region_size = new_region_size;
-	/* FIXME Hard-coded raid0 to raid4 */
-	seg->area_len = seg->len;
+	seg->region_size = new_region_size ?: region_size;
+
+	/* FIXME Hard-coded raid0 to raid4/5/6 */
+	seg->stripe_size = stripe_size;
+	lv->le_count = seg->len = seg->area_len = seg_len;
+	seg->extents_copied = extents_copied;
 
 	_check_and_adjust_region_size(lv);
 
@@ -3262,7 +3368,7 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
 		return_0;
 
 	if (segtype_is_raid4(new_segtype)) {
-		/* We had to rename SubLVs because of collision free sgifting, rename back... */
+		/* We had to rename SubLVs because of collision free shifting, rename back... */
 		if (!_rename_area_lvs(lv, NULL))
 			return_0;
 		if (!lv_update_and_reload(lv))
@@ -3352,7 +3458,9 @@ static int _takeover_from_raid0_to_raid10(TAKEOVER_FN_ARGS)
 
 static int _takeover_from_raid0_to_raid45(TAKEOVER_FN_ARGS)
 {
-	return _striped_or_raid0_to_raid45610_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count + 1, 1 /* data_copies */, 0, 0, new_region_size, allocate_pvs);
+	return _striped_or_raid0_to_raid45610_wrapper(lv, new_segtype, yes, force,
+						      first_seg(lv)->area_count + 1 /* new_image_count */,
+						      2 /* data_copies */, 0, 0, new_region_size, allocate_pvs);
 }
 
 static int _takeover_from_raid0_to_raid6(TAKEOVER_FN_ARGS)
@@ -3398,7 +3506,9 @@ static int _takeover_from_raid0_meta_to_raid10(TAKEOVER_FN_ARGS)
 
 static int _takeover_from_raid0_meta_to_raid45(TAKEOVER_FN_ARGS)
 {
-	return _striped_or_raid0_to_raid45610_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count + 1, 1 /* data_copies */, 0, 0, new_region_size, allocate_pvs);
+	return _striped_or_raid0_to_raid45610_wrapper(lv, new_segtype, yes, force,
+						      first_seg(lv)->area_count + 1 /* new_image_count */,
+						      2 /* data_copies */, 0, 0, new_region_size, allocate_pvs);
 }
 
 static int _takeover_from_raid0_meta_to_raid6(TAKEOVER_FN_ARGS)
@@ -3481,7 +3591,7 @@ static int _takeover_from_raid45_to_raid1(TAKEOVER_FN_ARGS)
 
 static int _takeover_from_raid45_to_raid54(TAKEOVER_FN_ARGS)
 {
-	return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
+	return _raid45_to_raid54_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count, 2 /* data_copies */, 0, 0, 0, allocate_pvs);
 }
 
 static int _takeover_from_raid45_to_raid6(TAKEOVER_FN_ARGS)
@@ -3679,14 +3789,10 @@ static int _set_convenient_raid456_segtype_to(const struct lv_segment *seg_from,
 			return 0;
 		}
 
-	/* Got to do check for raid5 -> raid6 ... */
-	} else if (seg_is_any_raid5(seg_from) &&
-		   segtype_is_any_raid6(*segtype)) {
-		log_error("Conversion not supported.");
-		return 0;
-
 	/* ... and raid6 -> raid5 */
-	} else if (seg_is_any_raid6(seg_from) &&
+	} else if ((seg_is_raid6_zr(seg_from) ||
+		    seg_is_raid6_nr(seg_from) ||
+		    seg_is_raid6_nc(seg_from)) &&
 		   segtype_is_any_raid5(*segtype)) {
 		log_error("Conversion not supported.");
 		return 0;
@@ -3927,7 +4033,7 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
 	const char *action_str = rebuild ? "rebuild" : "replace";
 
 	if (seg_is_any_raid0(raid_seg)) {
-		log_error("Can't replace any devices in %s LV %s",
+		log_error("Can't replace any devices in %s LV %s.",
 			  lvseg_name(raid_seg), display_lvname(lv));
 		return 0;
 	}
diff --git a/lib/raid/raid.c b/lib/raid/raid.c
index 1e562ff..7dfafef 100644
--- a/lib/raid/raid.c
+++ b/lib/raid/raid.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -87,13 +87,13 @@ static int _raid_text_import_areas(struct lv_segment *seg,
 		}
 
 		/* Metadata device comes first. */
-		if (!seg_is_raid0(seg)) {
-			if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
-				log_error("Couldn't find volume '%s' for segment '%s'.",
-					  cv->v.str ? : "NULL", seg_name);
-				return 0;
-			}
+		if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
+			log_error("Couldn't find volume '%s' for segment '%s'.",
+				  cv->v.str ? : "NULL", seg_name);
+			return 0;
+		}
 
+		if (strstr(lv->name, "_rmeta_")) {
 			if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_META))
 				return_0;
 			cv = cv->next;
@@ -537,6 +537,7 @@ static const struct raid_type {
 	{ SEG_TYPE_NAME_RAID10,     0, SEG_RAID10 | SEG_AREAS_MIRRORED },
 	{ SEG_TYPE_NAME_RAID4,      1, SEG_RAID4 },
 	{ SEG_TYPE_NAME_RAID5,      1, SEG_RAID5 },
+	{ SEG_TYPE_NAME_RAID5_N,    1, SEG_RAID5_N },
 	{ SEG_TYPE_NAME_RAID5_LA,   1, SEG_RAID5_LA },
 	{ SEG_TYPE_NAME_RAID5_LS,   1, SEG_RAID5_LS },
 	{ SEG_TYPE_NAME_RAID5_RA,   1, SEG_RAID5_RA },
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index c5226a7..8a32320 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2016 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005-2017 Red Hat, Inc. All rights reserved.
  *
  * This file is part of the device-mapper userspace tools.
  *
@@ -47,6 +47,7 @@ enum {
 	SEG_RAID1,
 	SEG_RAID10,
 	SEG_RAID4,
+	SEG_RAID5_N,
 	SEG_RAID5_LA,
 	SEG_RAID5_RA,
 	SEG_RAID5_LS,
@@ -81,6 +82,7 @@ static const struct {
 	{ SEG_RAID1, "raid1"},
 	{ SEG_RAID10, "raid10"},
 	{ SEG_RAID4, "raid4"},
+	{ SEG_RAID5_N,  "raid5_n"},
 	{ SEG_RAID5_LA, "raid5_la"},
 	{ SEG_RAID5_RA, "raid5_ra"},
 	{ SEG_RAID5_LS, "raid5_ls"},
@@ -2140,6 +2142,7 @@ static int _emit_areas_line(struct dm_task *dmt __attribute__((unused)),
 		case SEG_RAID1:
 		case SEG_RAID10:
 		case SEG_RAID4:
+		case SEG_RAID5_N:
 		case SEG_RAID5_LA:
 		case SEG_RAID5_RA:
 		case SEG_RAID5_LS:
@@ -2588,6 +2591,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
 	case SEG_RAID1:
 	case SEG_RAID10:
 	case SEG_RAID4:
+	case SEG_RAID5_N:
 	case SEG_RAID5_LA:
 	case SEG_RAID5_RA:
 	case SEG_RAID5_LS:
@@ -3869,6 +3873,7 @@ int dm_tree_node_add_null_area(struct dm_tree_node *node, uint64_t offset)
 	case SEG_RAID0_META:
 	case SEG_RAID1:
 	case SEG_RAID4:
+	case SEG_RAID5_N:
 	case SEG_RAID5_LA:
 	case SEG_RAID5_RA:
 	case SEG_RAID5_LS:
diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh
index c1cb1aa..0b7d326 100644
--- a/test/shell/lvconvert-raid-takeover.sh
+++ b/test/shell/lvconvert-raid-takeover.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2016,2017 Red Hat, Inc. All rights reserved.
 #
 # This copyrighted material is made available to anyone wishing to use,
 # modify, copy, or redistribute it subject to the terms and conditions
@@ -120,6 +120,7 @@ check lv_field $vg/$lv4 segtype "striped"
 check lv_field $vg/$lv4 stripes 3
 fsck -fn  /dev/mapper/$vg-$lv4
 
+
 # Convert striped -> raid4
 lvconvert -y --ty raid4 $vg/$lv1
 check lv_field $vg/$lv1 segtype "raid4"
@@ -128,6 +129,37 @@ fsck -fn  /dev/mapper/$vg-$lv1
 aux wait_for_sync $vg $lv1
 fsck -fn  /dev/mapper/$vg-$lv1
 
+# Convert raid4 -> raid5_n
+lvconvert -y --ty raid5_n $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 4
+fsck -fn  /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn  /dev/mapper/$vg-$lv1
+
+# Convert raid5 -> striped
+lvconvert -y --ty striped $vg/$lv1
+check lv_field $vg/$lv1 segtype "striped"
+check lv_field $vg/$lv1 stripes 3
+fsck -fn  /dev/mapper/$vg-$lv1
+
+# Convert striped -> raid5_n
+lvconvert -y --ty raid5_n $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 4
+fsck -fn  /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn  /dev/mapper/$vg-$lv1
+
+# Convert raid5_n -> raid4
+lvconvert -y --ty raid4 $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid4"
+check lv_field $vg/$lv1 stripes 4
+fsck -fn  /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn  /dev/mapper/$vg-$lv1
+
+
 # Convert raid0 -> raid4
 lvconvert -y --ty raid4 $vg/$lv2
 check lv_field $vg/$lv2 segtype "raid4"
@@ -136,6 +168,35 @@ fsck -fn  /dev/mapper/$vg-$lv2
 aux wait_for_sync $vg $lv2
 fsck -fn  /dev/mapper/$vg-$lv2
 
+# Convert raid4 -> raid0
+lvconvert -y --ty raid0 $vg/$lv2
+check lv_field $vg/$lv2 segtype "raid0"
+check lv_field $vg/$lv2 stripes 3
+fsck -fn  /dev/mapper/$vg-$lv2
+
+# Convert raid0 -> raid5_n
+lvconvert -y --ty raid5_n $vg/$lv2
+check lv_field $vg/$lv2 segtype "raid5_n"
+check lv_field $vg/$lv2 stripes 4
+fsck -fn  /dev/mapper/$vg-$lv2
+aux wait_for_sync $vg $lv2
+fsck -fn  /dev/mapper/$vg-$lv2
+
+# Convert raid5_n -> raid0_meta
+lvconvert -y --ty raid0_meta $vg/$lv2
+check lv_field $vg/$lv2 segtype "raid0_meta"
+check lv_field $vg/$lv2 stripes 3
+fsck -fn  /dev/mapper/$vg-$lv2
+
+# Convert raid0_meta -> raid5_n
+lvconvert -y --ty raid5_n $vg/$lv2
+check lv_field $vg/$lv2 segtype "raid5_n"
+check lv_field $vg/$lv2 stripes 4
+fsck -fn  /dev/mapper/$vg-$lv2
+aux wait_for_sync $vg $lv2
+fsck -fn  /dev/mapper/$vg-$lv2
+
+
 # Convert raid4 -> raid0_meta
 lvconvert -y --ty raid0_meta $vg/$lv1
 check lv_field $vg/$lv1 segtype "raid0_meta"




More information about the lvm-devel mailing list