mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
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
This commit is contained in:
parent
fe18e5e77a
commit
932db3db53
@ -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)))
|
||||
seg_flag = SEG_RAID6_N_6;
|
||||
goto replaced;
|
||||
|
||||
/* 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 -> 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)))
|
||||
return_0;
|
||||
/* ... 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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user