summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeinz Mauelshagen <heinzm@redhat.com>2017-02-24 03:11:41 +0100
committerHeinz Mauelshagen <heinzm@redhat.com>2017-02-24 05:20:58 +0100
commit932db3db535734f03cec973182dcc73adef9d3a5 (patch)
tree52d4da473866c880274a55147b190b2c6a051557
parentfe18e5e77a488618510648c7801ea3375ce5aac4 (diff)
downloadlvm2-932db3db535734f03cec973182dcc73adef9d3a5.tar.gz
lvconvert: add infrastructure for RaidLV reshaping support
In order to support striped raid5/6/10 LV reshaping (change of LV type, stripesize or number of legs), this patch introduces more local infrastructure to raid_manip.c used by followup patches. Changes: - add missing possible reshape conversions and conversion options to allow/prohibit changing stripesize or number fo stripes - enhance setting convenient riad types in reshape conversions (e.g. raid1 with 2 legs -> radi5_n) Related: rhbz834579 Related: rhbz1191935 Related: rhbz1191978
-rw-r--r--lib/metadata/raid_manip.c149
1 files changed, 117 insertions, 32 deletions
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index cc074f636..81360d225 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -26,6 +26,7 @@ typedef int (*fn_on_lv_t)(struct logical_volume *lv, void *data);
static int _eliminate_extracted_lvs_optional_write_vg(struct volume_group *vg,
struct dm_list *removal_lvs,
int vg_write_requested);
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
static int _check_restriping(uint32_t new_stripes, struct logical_volume *lv)
{
@@ -4211,37 +4212,68 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[]
{ .current_types = SEG_RAID4|SEG_RAID5_N|SEG_RAID6_N_6,
.possible_types = SEG_RAID4|SEG_RAID5_N|SEG_RAID6_N_6,
.current_areas = ~0U,
- .options = ALLOW_REGION_SIZE },
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
+
+ /* Reshape raid5* <-> raid5* */
+ { .current_types = SEG_RAID5_LS|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_LA|SEG_RAID5_N,
+ .possible_types = SEG_RAID5_LS|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_LA|SEG_RAID5_N,
+ .current_areas = ~0U,
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
+ /* Reshape raid6* <-> raid6* */
+ { .current_types = SEG_RAID6_ZR|SEG_RAID6_NR|SEG_RAID6_NC|SEG_RAID6_LS_6|\
+ SEG_RAID6_RS_6|SEG_RAID6_RA_6|SEG_RAID6_LA_6|SEG_RAID6_N_6,
+ .possible_types = SEG_RAID6_ZR|SEG_RAID6_NR|SEG_RAID6_NC|SEG_RAID6_LS_6|\
+ SEG_RAID6_RS_6|SEG_RAID6_RA_6|SEG_RAID6_LA_6|SEG_RAID6_N_6,
+ .current_areas = ~0U,
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
/* raid5_ls <-> raid6_ls_6 */
{ .current_types = SEG_RAID5_LS|SEG_RAID6_LS_6,
.possible_types = SEG_RAID5_LS|SEG_RAID6_LS_6,
.current_areas = ~0U,
- .options = ALLOW_REGION_SIZE },
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
/* raid5_rs -> raid6_rs_6 */
{ .current_types = SEG_RAID5_RS|SEG_RAID6_RS_6,
.possible_types = SEG_RAID5_RS|SEG_RAID6_RS_6,
.current_areas = ~0U,
- .options = ALLOW_REGION_SIZE },
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
/* raid5_ls -> raid6_la_6 */
{ .current_types = SEG_RAID5_LA|SEG_RAID6_LA_6,
.possible_types = SEG_RAID5_LA|SEG_RAID6_LA_6,
.current_areas = ~0U,
- .options = ALLOW_REGION_SIZE },
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
/* raid5_ls -> raid6_ra_6 */
{ .current_types = SEG_RAID5_RA|SEG_RAID6_RA_6,
.possible_types = SEG_RAID5_RA|SEG_RAID6_RA_6,
.current_areas = ~0U,
- .options = ALLOW_REGION_SIZE },
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
+
+ /* Reshape raid10 <-> raid10 */
+ { .current_types = SEG_RAID10_NEAR,
+ .possible_types = SEG_RAID10_NEAR,
+ .current_areas = ~0U,
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
/* mirror <-> raid1 with arbitrary number of legs */
{ .current_types = SEG_MIRROR|SEG_RAID1,
.possible_types = SEG_MIRROR|SEG_RAID1,
.current_areas = ~0U,
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPES|ALLOW_STRIPE_SIZE },
+
+ /* raid1 -> raid5* with 2 legs */
+ { .current_types = SEG_RAID1,
+ .possible_types = SEG_RAID5_LS|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_LA|SEG_RAID5_N,
+ .current_areas = 2U,
+ .options = ALLOW_REGION_SIZE|ALLOW_STRIPE_SIZE },
+
+ /* raid5* -> raid1 with 2 legs */
+ { .current_types = SEG_RAID5_LS|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_LA|SEG_RAID5_N,
+ .possible_types = SEG_RAID1,
+ .current_areas = 2U,
.options = ALLOW_REGION_SIZE },
/* END */
@@ -5323,7 +5355,7 @@ static int _takeover_from_striped_to_raid6(TAKEOVER_FN_ARGS)
/*
* Only if we decide to support raid01 at all.
-
+
static int _takeover_from_raid01_to_raid01(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
@@ -5437,11 +5469,51 @@ static int _log_prohibited_option(const struct lv_segment *seg_from,
return 1;
}
-/* Change segtype for raid4 <-> raid5 <-> raid6 takeover where necessary. */
-static int _set_convenient_raid456_segtype_to(const struct lv_segment *seg_from,
- const struct segment_type **segtype)
+/*
+ * Find takeover raid flag for segment type flag of @seg
+ */
+/* Segment type flag correspondence for raid5 <-> raid6 conversions */
+static uint64_t _r5_to_r6[][2] = {
+ { SEG_RAID5_LS, SEG_RAID6_LS_6 },
+ { SEG_RAID5_LA, SEG_RAID6_LA_6 },
+ { SEG_RAID5_RS, SEG_RAID6_RS_6 },
+ { SEG_RAID5_RA, SEG_RAID6_RA_6 },
+ { SEG_RAID5_N, SEG_RAID6_N_6 },
+};
+
+
+/* Return segment type flag for raid5 -> raid6 conversions */
+static uint64_t _get_r56_flag(const struct lv_segment *seg, unsigned idx)
+{
+ unsigned elems = ARRAY_SIZE(_r5_to_r6);
+
+ while (elems--)
+ if (seg->segtype->flags & _r5_to_r6[elems][idx])
+ return _r5_to_r6[elems][!idx];
+
+ return 0;
+}
+
+/* Return segment type flag for raid5 -> raid6 conversions */
+static uint64_t _raid_seg_flag_5_to_6(const struct lv_segment *seg)
+{
+ return _get_r56_flag(seg, 0);
+}
+
+/* Return segment type flag for raid6 -> raid5 conversions */
+static uint64_t _raid_seg_flag_6_to_5(const struct lv_segment *seg)
+{
+ return _get_r56_flag(seg, 1);
+}
+
+/* Change segtype for raid4 <-> raid5 <-> raid6 or raid1 <-> raid5 takeover where necessary. */
+static int _set_convenient_raid1456_segtype_to(const struct lv_segment *seg_from,
+ const struct segment_type **segtype,
+ int yes)
{
size_t len = min(strlen((*segtype)->name), strlen(lvseg_name(seg_from)));
+ uint64_t seg_flag;
+ struct cmd_context *cmd = seg_from->lv->vg->cmd;
const struct segment_type *segtype_sav = *segtype;
/* Bail out if same RAID level is requested. */
@@ -5451,54 +5523,66 @@ static int _set_convenient_raid456_segtype_to(const struct lv_segment *seg_from,
/* Striped/raid0 -> raid5/6 */
if (seg_is_striped(seg_from) || seg_is_any_raid0(seg_from)) {
/* If this is any raid5 conversion request -> enforce raid5_n, because we convert from striped */
- if (segtype_is_any_raid5(*segtype) &&
- !segtype_is_raid5_n(*segtype)) {
- if (!(*segtype = get_segtype_from_flag(seg_from->lv->vg->cmd, SEG_RAID5_N)))
- return_0;
+ if (segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype)) {
+ seg_flag = SEG_RAID5_N;
goto replaced;
/* If this is any raid6 conversion request -> enforce raid6_n_6, because we convert from striped */
- } else if (segtype_is_any_raid6(*segtype) &&
- !segtype_is_raid6_n_6(*segtype)) {
- if (!(*segtype = get_segtype_from_flag(seg_from->lv->vg->cmd, SEG_RAID6_N_6)))
- return_0;
+ } else if (segtype_is_any_raid6(*segtype) && !segtype_is_raid6_n_6(*segtype)) {
+ seg_flag = SEG_RAID6_N_6;
goto replaced;
}
+ /* raid1 -> raid5_n with 2 areas */
+ } else if (seg_is_raid1(seg_from) && seg_from->area_count == 2 &&
+ segtype_is_any_raid5(*segtype) && !segtype_is_raid5_n(*segtype)) {
+ seg_flag = SEG_RAID5_N;
+ goto replaced;
+
/* raid4 -> raid5_n */
- } else if (seg_is_raid4(seg_from) &&
- segtype_is_any_raid5(*segtype)) {
- if (!(*segtype = get_segtype_from_flag(seg_from->lv->vg->cmd, SEG_RAID5_N)))
- return_0;
+ } else if (seg_is_raid4(seg_from) && segtype_is_any_raid5(*segtype)) {
+ seg_flag = SEG_RAID5_N;
goto replaced;
/* raid4/raid5_n -> striped/raid0/raid6 */
} else if ((seg_is_raid4(seg_from) || seg_is_raid5_n(seg_from)) &&
!segtype_is_striped(*segtype) &&
!segtype_is_any_raid0(*segtype) &&
+ !segtype_is_raid1(*segtype) &&
!segtype_is_raid4(*segtype) &&
!segtype_is_raid5_n(*segtype) &&
!segtype_is_raid6_n_6(*segtype)) {
- if (!(*segtype = get_segtype_from_flag(seg_from->lv->vg->cmd, SEG_RAID6_N_6)))
- return_0;
+ seg_flag = SEG_RAID6_N_6;
goto replaced;
- /* ... and raid6 -> striped/raid0/raid4/raid5_n */
- } else if (seg_is_raid6_n_6(seg_from) &&
- !segtype_is_striped(*segtype) &&
- !segtype_is_any_raid0(*segtype) &&
- !segtype_is_raid4(*segtype) &&
- !segtype_is_raid5_n(*segtype)) {
- if (!(*segtype = get_segtype_from_flag(seg_from->lv->vg->cmd, SEG_RAID5_N)))
+ /* Got to do check for raid5 -> raid6 ... */
+ } else if (seg_is_any_raid5(seg_from) && segtype_is_any_raid6(*segtype)) {
+ if (!(seg_flag = _raid_seg_flag_5_to_6(seg_from)))
return_0;
goto replaced;
+
+ /* ... and raid6 -> raid5 */
+ } else if (seg_is_any_raid6(seg_from) && segtype_is_any_raid5(*segtype)) {
+ /* No result for raid6_{zr,nr,nc} */
+ if (!(seg_flag = _raid_seg_flag_6_to_5(seg_from)))
+ return 0;
+ goto replaced;
}
return 1;
replaced:
+ if (!(*segtype = get_segtype_from_flag(cmd, seg_flag)))
+ return_0;
log_warn("Replaced LV type %s with possible type %s.",
segtype_sav->name, (*segtype)->name);
+ if (!yes && yes_no_prompt("Do you want to convert %s LV %s to %s? [y/n]: ",
+ segtype_sav->name, display_lvname(seg_from->lv),
+ (*segtype)->name) == 'n') {
+ log_error("Logical volume %s NOT converted.", display_lvname(seg_from->lv));
+ return 0;
+ }
+
return 1;
}
@@ -5584,6 +5668,7 @@ static int _region_size_change_requested(struct logical_volume *lv, int yes, con
/* Check allowed conversion from seg_from to *segtype_to */
static int _conversion_options_allowed(const struct lv_segment *seg_from,
const struct segment_type **segtype_to,
+ int yes,
uint32_t new_image_count,
int new_data_copies, int new_region_size,
int stripes, unsigned new_stripe_size_supplied)
@@ -5591,7 +5676,7 @@ static int _conversion_options_allowed(const struct lv_segment *seg_from,
int r = 1;
uint32_t opts;
- if (!new_image_count && !_set_convenient_raid456_segtype_to(seg_from, segtype_to))
+ if (!new_image_count && !_set_convenient_raid1456_segtype_to(seg_from, segtype_to, yes))
return_0;
if (!_get_allowed_conversion_options(seg_from, *segtype_to, new_image_count, &opts)) {
@@ -5682,7 +5767,7 @@ int lv_raid_convert(struct logical_volume *lv,
* Check acceptible options mirrors, region_size,
* stripes and/or stripe_size have been provided.
*/
- if (!_conversion_options_allowed(seg, &new_segtype, 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size,
+ if (!_conversion_options_allowed(seg, &new_segtype, yes, 0 /* Takeover */, 0 /*new_data_copies*/, new_region_size,
new_stripes, new_stripe_size_supplied))
return _log_possible_conversion_types(lv, new_segtype);