1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvconvert: Support raid0<->raid4 and mirror<->raid1.

Only simple takeover cases so far.
This commit is contained in:
Alasdair G Kergon 2016-08-07 00:56:08 +01:00
parent de7f1deb80
commit 76ef2d15d8
3 changed files with 536 additions and 46 deletions

View File

@ -1,5 +1,7 @@
Version 2.02.163 -
=================================
Support straightforward lvconvert between striped and raid4 LVs.
Support straightforward lvconvert between raid1 and mirror LVs.
Report supported conversions when asked for unsupported raid lvconvert.
Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Preserve existing mirror region size when using --repair.

View File

@ -21,6 +21,7 @@
#include "activate.h"
#include "lv_alloc.h"
#include "lvm-string.h"
#include "lvm-signal.h"
static int _check_restriping(uint32_t new_stripes, struct logical_volume *lv)
{
@ -1884,13 +1885,118 @@ static int _raid0_add_or_remove_metadata_lvs(struct logical_volume *lv,
return 1;
}
/*
* Clear any rebuild disk flags on lv.
* If any flags were cleared, *flags_were_cleared is set to 1.
*/
/* FIXME Generalise into foreach_underlying_lv_segment_area. */
static void _clear_rebuild_flags(struct logical_volume *lv, int *flags_were_cleared)
{
struct lv_segment *seg = first_seg(lv);
struct logical_volume *sub_lv;
uint32_t s;
uint64_t flags_to_clear = LV_REBUILD;
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_PV)
continue;
sub_lv = seg_lv(seg, s);
/* Recurse into sub LVs */
_clear_rebuild_flags(sub_lv, flags_were_cleared);
if (sub_lv->status & flags_to_clear) {
sub_lv->status &= ~flags_to_clear;
*flags_were_cleared = 1;
}
}
}
/*
* Updates and reloads metadata, clears any flags passed to the kernel,
* eliminates any residual LVs and updates and reloads metadata again.
*
* lv removal_lvs
*
* This minimally involves 2 metadata commits.
*/
static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv, struct dm_list *removal_lvs)
{
int flags_were_cleared = 0, r = 0;
if (!lv_update_and_reload_origin(lv))
return_0;
/* Eliminate any residual LV and don't commit the metadata */
if (!_eliminate_extracted_lvs_optional_write_vg(lv->vg, removal_lvs, 0))
return_0;
/*
* Now that any 'REBUILD' or 'RESHAPE_DELTA_DISKS' etc.
* has/have made its/their way to the kernel, we must
* remove the flag(s) so that the individual devices are
* not rebuilt/reshaped/taken over upon every activation.
*
* Writes and commits metadata if any flags have been reset
* and if successful, performs metadata backup.
*/
/* FIXME This needs to be done through hooks in the metadata */
log_debug_metadata("Clearing any flags for %s passed to the kernel", display_lvname(lv));
_clear_rebuild_flags(lv, &flags_were_cleared);
log_debug_metadata("Updating metadata and reloading mappings for %s", display_lvname(lv));
if ((r != 2 || flags_were_cleared) && !lv_update_and_reload(lv)) {
log_error("Update and reload of LV %s failed", display_lvname(lv));
return 0;
}
return 1;
}
/*
* Adjust all data sub LVs of lv to mirror
* or raid name depending on direction
* adjusting their LV status
*/
enum mirror_raid_conv { MIRROR_TO_RAID1 = 0, RAID1_TO_MIRROR };
static int _adjust_data_lvs(struct logical_volume *lv, enum mirror_raid_conv direction)
{
uint32_t s;
char *sublv_name_suffix;
struct lv_segment *seg = first_seg(lv);
static struct {
char type_char;
uint64_t set_flag;
uint64_t reset_flag;
} conv[] = {
{ 'r', RAID_IMAGE, MIRROR_IMAGE },
{ 'm', MIRROR_IMAGE, RAID_IMAGE }
};
struct logical_volume *dlv;
for (s = 0; s < seg->area_count; ++s) {
dlv = seg_lv(seg, s);
if (!(sublv_name_suffix = first_substring(dlv->name, "_mimage_", "_rimage_", NULL))) {
log_error(INTERNAL_ERROR "name lags image part");
return 0;
}
*(sublv_name_suffix + 1) = conv[direction].type_char;
log_debug_metadata("data LV renamed to %s", dlv->name);
dlv->status &= ~conv[direction].reset_flag;
dlv->status |= conv[direction].set_flag;
}
return 1;
}
/*
* General conversion functions
*/
/*
* Convert a RAID0 set to striped
*/
static int _convert_mirror_to_raid1(struct logical_volume *lv,
const struct segment_type *new_segtype)
{
@ -1986,6 +2092,76 @@ static int _convert_mirror_to_raid1(struct logical_volume *lv,
return 1;
}
/*
* Convert lv with "raid1" mapping to "mirror"
* optionally changing number of data_copies
* defined by @new_image_count.
*/
static int _convert_raid1_to_mirror(struct logical_volume *lv,
const struct segment_type *new_segtype,
uint32_t new_image_count,
uint32_t new_region_size,
struct dm_list *allocate_pvs,
int update_and_reload,
struct dm_list *removal_lvs)
{
struct lv_segment *seg = first_seg(lv);
if (!seg_is_raid1(seg)) {
log_error(INTERNAL_ERROR "raid1 conversion supported only");
return 0;
}
if ((new_image_count = new_image_count ?: seg->area_count) < 2) {
log_error("can't convert %s to fewer than 2 data_copies", display_lvname(lv));
return 0;
}
if (!_check_max_mirror_devices(new_image_count)) {
log_error("Unable to convert %s LV %s with %u images to %s",
SEG_TYPE_NAME_RAID1, display_lvname(lv), new_image_count, SEG_TYPE_NAME_MIRROR);
log_error("At least reduce to the maximum of %u images with \"lvconvert -m%u %s\"",
DEFAULT_MIRROR_MAX_IMAGES, DEFAULT_MIRROR_MAX_IMAGES - 1, display_lvname(lv));
return 0;
}
init_mirror_in_sync(new_image_count > seg->area_count ? 0 : 1);
/* Change image pair count to requested # of images */
if (new_image_count != seg->area_count) {
log_debug_metadata("Changing image count to %u on %s",
new_image_count, display_lvname(lv));
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, removal_lvs, 0, 0))
return 0;
}
/* Remove rmeta LVs */
log_debug_metadata("Extracting and renaming metadata LVs");
if (!_extract_image_component_list(seg, RAID_META, 0, removal_lvs))
return 0;
seg->meta_areas = NULL;
/* Rename all data sub LVs from "*_rimage_*" to "*_mimage_*" and set their status */
log_debug_metadata("Adjust data LVs of %s", display_lvname(lv));
if (!_adjust_data_lvs(lv, RAID1_TO_MIRROR))
return 0;
seg->segtype = new_segtype;
seg->region_size = new_region_size;
lv->status &= ~RAID;
seg->status &= ~RAID;
lv->status |= (MIRROR | MIRRORED);
/* Add mirror_log LV (should happen in wih image allocation */
if (!add_mirror_log(lv->vg->cmd, lv, 1, seg->region_size, allocate_pvs, lv->vg->alloc)) {
log_error("Unable to add mirror log to %s", display_lvname(lv));
return 0;
}
return update_and_reload ? _lv_update_reload_fns_reset_eliminate_lvs(lv, removal_lvs) : 1;
}
/*
* All areas from LV segments are moved to new
* segments allocated with area_count=1 for data_lvs.
@ -2263,6 +2439,14 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
/*
* Takeover.
*
* Change the user's requested segment type to
* the appropriate more-refined one for takeover.
*
* raid0 can take over:
* raid4
*
* raid4 can take over:
* raid0 - if there is only one stripe zone
*/
#define ALLOW_NONE 0x0
#define ALLOW_STRIPES 0x2
@ -2284,23 +2468,43 @@ struct possible_type {
static struct possible_takeover_reshape_type _possible_takeover_reshape_types[] = {
/* striped -> */
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
.possible_types = SEG_RAID1,
.current_areas = 1,
.options = ALLOW_NONE },
{ .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */
.possible_types = SEG_RAID0|SEG_RAID0_META,
.current_areas = 1,
.options = ALLOW_STRIPE_SIZE },
{ .current_types = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */
.possible_types = SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
/* raid0* -> */
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */
.possible_types = SEG_RAID1,
.current_areas = 1,
.options = ALLOW_NONE },
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count > 1 */
.possible_types = SEG_RAID4,
.current_areas = ~0U,
.options = ALLOW_NONE },
{ .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
/* raid1 -> */
{ .current_types = SEG_RAID1,
.possible_types = SEG_RAID1,
.possible_types = SEG_RAID1|SEG_MIRROR,
.current_areas = ~0U,
.options = ALLOW_NONE },
/* mirror -> raid1 with arbitrary number of legs */
{ .current_types = SEG_MIRROR,
.possible_types = SEG_MIRROR,
.possible_types = SEG_MIRROR|SEG_RAID1,
.current_areas = ~0U,
.options = ALLOW_NONE },
{ .current_types = SEG_RAID4,
.possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
.current_areas = ~0U,
.options = ALLOW_NONE },
@ -2335,6 +2539,23 @@ static struct possible_type *_get_possible_type(const struct lv_segment *seg_fro
return (struct possible_type *) _get_possible_takeover_reshape_type(seg_from, segtype_to, last_pt);
}
/*
* Return allowed options (--stripes, ...) for conversion from @seg_from -> @seg_to
*/
static int _get_allowed_conversion_options(const struct lv_segment *seg_from,
const struct segment_type *segtype_to,
uint32_t new_image_count, uint32_t *options)
{
struct possible_type *pt;
if ((pt = _get_possible_type(seg_from, segtype_to, new_image_count, NULL))) {
*options = pt->options;
return 1;
}
return 0;
}
/*
* Log any possible conversions for @lv
*/
@ -2455,6 +2676,7 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const
int yes, \
int force, \
unsigned new_image_count, \
unsigned new_data_copies, \
const unsigned new_stripes, \
uint32_t new_stripe_size, \
const uint32_t new_region_size, \
@ -2517,7 +2739,6 @@ static int _takeover_not_possible(takeover_fn_t takeover_fn)
/*
* Wrapper functions that share conversion code.
*/
static int _raid0_meta_change_wrapper(struct logical_volume *lv,
const struct segment_type *new_segtype,
uint32_t new_stripes,
@ -2565,6 +2786,77 @@ static int _raid0_to_striped_wrapper(struct logical_volume *lv,
return 1;
}
/* raid1 -> mirror */
static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS)
{
struct dm_list removal_lvs;
dm_list_init(&removal_lvs);
if (!_raid_in_sync(lv))
return_0;
if (!yes && yes_no_prompt("Are you sure you want to convert %s back to the older \"%s\" type? [y/n]: ",
display_lvname(lv), SEG_TYPE_NAME_MIRROR) == 'n') {
log_error("Logical volume %s NOT converted to \"%s\"",
display_lvname(lv), SEG_TYPE_NAME_MIRROR);
return 0;
}
if (sigint_caught())
return_0;
/* Archive metadata */
if (!archive(lv->vg))
return_0;
return _convert_raid1_to_mirror(lv, new_segtype, new_image_count, new_region_size,
allocate_pvs, 1, &removal_lvs);
}
/* raid45 -> raid0* / striped */
static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS)
{
struct lv_segment *seg = first_seg(lv);
struct dm_list removal_lvs;
dm_list_init(&removal_lvs);
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;
}
/* Necessary when convering to raid0/striped w/o redundancy? */
if (!_raid_in_sync(lv))
return 0;
/* Archive metadata */
if (!archive(lv->vg))
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 to raid0 */
seg->area_len = seg->extents_copied = seg->area_len / seg->area_count;
if (segtype_is_striped_target(new_segtype)) {
if (!_convert_raid0_to_striped(lv, 0, &removal_lvs))
return_0;
} else if (segtype_is_raid0(new_segtype) &&
!_raid0_add_or_remove_metadata_lvs(lv, 0 /* update_and_reload */, allocate_pvs, &removal_lvs))
return_0;
seg->region_size = 0;
return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs);
}
static int _striped_to_raid0_wrapper(struct logical_volume *lv,
const struct segment_type *new_segtype,
uint32_t new_stripes,
@ -2586,8 +2878,69 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv,
return 1;
}
/* Helper: striped/raid0* -> raid4/5/6/10 */
static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS)
{
struct lv_segment *seg = first_seg(lv);
if (seg_is_raid10(seg))
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
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;
}
if (new_stripes && new_stripes != seg->area_count) {
log_error("Can't restripe LV %s during conversion", display_lvname(lv));
return 0;
}
/* Archive metadata */
if (!archive(lv->vg))
return_0;
/* 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",
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;
}
/* Add metadata LVs */
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;
}
/* 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));
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1))
return 0;
if (!segtype_is_raid4(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;
}
seg->segtype = new_segtype;
seg->region_size = new_region_size;
/* FIXME Hard-coded raid0 to raid4 */
seg->area_len = seg->len;
_check_and_adjust_region_size(lv);
log_debug_metadata("Updating VG metadata and reloading %s LV %s",
lvseg_name(seg), display_lvname(lv));
if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL))
return_0;
return 1;
}
/************************************************/
@ -2669,7 +3022,7 @@ static int _takeover_from_raid0_to_raid10(TAKEOVER_FN_ARGS)
static int _takeover_from_raid0_to_raid45(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
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);
}
static int _takeover_from_raid0_to_raid6(TAKEOVER_FN_ARGS)
@ -2715,7 +3068,7 @@ static int _takeover_from_raid0_meta_to_raid10(TAKEOVER_FN_ARGS)
static int _takeover_from_raid0_meta_to_raid45(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
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);
}
static int _takeover_from_raid0_meta_to_raid6(TAKEOVER_FN_ARGS)
@ -2738,7 +3091,7 @@ static int _takeover_from_raid1_to_linear(TAKEOVER_FN_ARGS)
static int _takeover_from_raid1_to_mirrored(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
return _raid1_to_mirrored_wrapper(lv, new_segtype, yes, force, new_image_count, new_data_copies, new_stripes, new_stripe_size, new_region_size, allocate_pvs);
}
static int _takeover_from_raid1_to_raid0(TAKEOVER_FN_ARGS)
@ -2783,12 +3136,12 @@ static int _takeover_from_raid45_to_mirrored(TAKEOVER_FN_ARGS)
static int _takeover_from_raid45_to_raid0(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
return _raid456_to_raid0_or_striped_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count - 1, 1 /* data_copies */, 0, 0, 0, allocate_pvs);
}
static int _takeover_from_raid45_to_raid0_meta(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
return _raid456_to_raid0_or_striped_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count - 1, 1 /* data_copies */, 0, 0, 0, allocate_pvs);
}
static int _takeover_from_raid45_to_raid1(TAKEOVER_FN_ARGS)
@ -2808,7 +3161,7 @@ static int _takeover_from_raid45_to_raid6(TAKEOVER_FN_ARGS)
static int _takeover_from_raid45_to_striped(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
return _raid456_to_raid0_or_striped_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count - 1, 1 /* data_copies */, 0, 0, 0, allocate_pvs);
}
static int _takeover_from_raid6_to_raid0(TAKEOVER_FN_ARGS)
@ -2859,7 +3212,8 @@ static int _takeover_from_striped_to_raid10(TAKEOVER_FN_ARGS)
static int _takeover_from_striped_to_raid45(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
return _striped_or_raid0_to_raid45610_wrapper(lv, new_segtype, yes, force, first_seg(lv)->area_count + 1,
2 /* data_copies*/, 0, 0, new_region_size, allocate_pvs);
}
static int _takeover_from_striped_to_raid6(TAKEOVER_FN_ARGS)
@ -2959,6 +3313,92 @@ static uint32_t _data_rimages_count(const struct lv_segment *seg, const uint32_t
return total_rimages - seg->segtype->parity_devs;
}
/*
* Determine whether data_copies, stripes, stripe_size are
* possible for conversion from seg_from to new_segtype.
*/
static int _log_prohibited_option(const struct lv_segment *seg_from,
const struct segment_type *new_segtype,
const char *opt_str)
{
if (seg_from->segtype == new_segtype)
log_error("%s not allowed when converting %s LV %s.",
opt_str, lvseg_name(seg_from), display_lvname(seg_from->lv));
else
log_error("%s not allowed for LV %s when converting from %s to %s.",
opt_str, display_lvname(seg_from->lv), lvseg_name(seg_from), new_segtype->name);
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)
{
if (seg_is_striped(seg_from) || seg_is_raid4(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)) {
log_error("Conversion to raid5_n not yet supported.");
return 0;
/* 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)) {
log_error("Conversion to raid6_n_6 not yet supported.");
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) &&
segtype_is_any_raid5(*segtype)) {
log_error("Conversion not supported.");
return_0;
}
return 1;
}
/* 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,
uint32_t new_image_count,
int new_data_copies, int region_size,
int stripes, unsigned new_stripe_size_supplied)
{
int r = 1;
uint32_t opts;
if (!new_image_count && !_set_convenient_raid456_segtype_to(seg_from, segtype_to))
return_0;
if (!_get_allowed_conversion_options(seg_from, *segtype_to, new_image_count, &opts)) {
log_error("Unable to convert LV %s from %s to %s.",
display_lvname(seg_from->lv), lvseg_name(seg_from), (*segtype_to)->name);
return 0;
}
if (stripes > 1 && !(opts & ALLOW_STRIPES)) {
if (!_log_prohibited_option(seg_from, *segtype_to, "--stripes"))
stack;
r = 0;
}
if (new_stripe_size_supplied && !(opts & ALLOW_STRIPE_SIZE)) {
if (!_log_prohibited_option(seg_from, *segtype_to, "-I/--stripesize"))
stack;
r = 0;
}
return r;
}
/*
* lv_raid_convert
*
@ -3001,11 +3441,19 @@ int lv_raid_convert(struct logical_volume *lv,
if (segtype_is_raid(new_segtype) && !_check_max_raid_devices(new_image_count))
return_0;
/*
* 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,
new_stripes, new_stripe_size_supplied))
return _log_possible_conversion_types(lv, new_segtype);
takeover_fn = _get_takeover_fn(first_seg(lv), new_segtype, new_image_count);
/* Exit without doing activation checks if the combination isn't possible */
if (_takeover_not_possible(takeover_fn))
return takeover_fn(lv, new_segtype, yes, force, new_image_count, new_stripes, stripe_size,
return takeover_fn(lv, new_segtype, yes, force, new_image_count, 0, new_stripes, stripe_size,
new_region_size, allocate_pvs);
log_verbose("Converting %s from %s to %s.",
@ -3036,7 +3484,7 @@ int lv_raid_convert(struct logical_volume *lv,
return 0;
}
return takeover_fn(lv, new_segtype, yes, force, new_image_count, new_stripes, stripe_size,
return takeover_fn(lv, new_segtype, yes, force, new_image_count, 0, new_stripes, stripe_size,
new_region_size, allocate_pvs);
}

View File

@ -311,17 +311,9 @@ static int _check_conversion_type(struct cmd_context *cmd, const char *type_str)
if (!type_str || !*type_str)
return 1;
if (!strcmp(type_str, SEG_TYPE_NAME_MIRROR)) {
if (!arg_is_set(cmd, mirrors_ARG)) {
log_error("Conversions to --type mirror require -m/--mirrors");
return 0;
}
return 1;
}
/* FIXME: Check thin-pool and thin more thoroughly! */
if (!strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT) || _striped_type_requested(type_str) ||
!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) ||
!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) || !strcmp(type_str, SEG_TYPE_NAME_MIRROR) ||
!strcmp(type_str, SEG_TYPE_NAME_CACHE_POOL) || !strcmp(type_str, SEG_TYPE_NAME_CACHE) ||
!strcmp(type_str, SEG_TYPE_NAME_THIN_POOL) || !strcmp(type_str, SEG_TYPE_NAME_THIN))
return 1;
@ -1770,6 +1762,9 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
if (!lp->need_polling)
log_print_unless_silent("Logical volume %s converted.",
display_lvname(lv));
else
log_print_unless_silent("Logical volume %s being converted.",
display_lvname(lv));
backup(lv->vg);
@ -1837,29 +1832,35 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
}
/* Can only change image count for raid1 and linear */
if (lp->mirrors_supplied && !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
log_error("'--mirrors/-m' is not compatible with %s.",
lvseg_name(seg));
goto try_new_takeover_or_reshape;
if (lp->mirrors_supplied) {
if (_raid0_type_requested(lp->type_str)) {
log_error("--mirrors/-m is not compatible with conversion to %s.",
lp->type_str);
return 0;
}
if (!seg_is_mirrored(seg) && !seg_is_linear(seg)) {
log_error("--mirrors/-m is not compatible with %s.",
lvseg_name(seg));
return 0;
}
}
if (!_lvconvert_validate_thin(lv, lp))
return_0;
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype)) {
log_error("Unable to convert %s from %s to %s.",
display_lvname(lv), lvseg_name(seg),
lp->segtype->name);
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype))
goto try_new_takeover_or_reshape;
}
if (seg_is_linear(seg) && !lp->merge_mirror && !lp->mirrors_supplied) {
if (_raid0_type_requested(lp->type_str))
if (_raid0_type_requested(lp->type_str)) {
log_error("Linear LV %s cannot be converted to %s.",
display_lvname(lv), lp->type_str);
else
return 0;
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_RAID1)) {
log_error("Raid conversions of LV %s require -m/--mirrors.",
display_lvname(lv));
return 0;
}
goto try_new_takeover_or_reshape;
}
@ -1896,19 +1897,38 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
if (lp->keep_mimages)
return lv_raid_split(lv, lp->lv_split_name, image_count, lp->pvh);
if (lp->mirrors_supplied)
return lv_raid_change_image_count(lv, image_count, lp->pvh);
if (lp->mirrors_supplied) {
if (!*lp->type_str || !strcmp(lp->type_str, SEG_TYPE_NAME_RAID1) || !strcmp(lp->type_str, SEG_TYPE_NAME_LINEAR)) {
if (!lv_raid_change_image_count(lv, image_count, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
}
goto try_new_takeover_or_reshape;
} else if (!*lp->type_str || seg->segtype == lp->segtype) {
log_error("Conversion operation not yet supported.");
return 0;
}
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
(lp->type_str && lp->type_str[0])) {
/* Activation is required later which precludes existing unsupported raid0 segment */
if (segtype_is_any_raid0(lp->segtype) &&
!(lp->target_attr & RAID_FEATURE_RAID0)) {
log_error("RAID module does not support RAID0.");
return 0;
}
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
lp->region_size, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
@ -1968,13 +1988,27 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
return 1;
}
log_error("Conversion operation not yet supported.");
try_new_takeover_or_reshape:
;
/* FIXME New takeover and reshape code is called from here */
/* FIXME This needs changing globally. */
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
/* Only let raid4 through for now. */
if (lp->type_str && lp->type_str[0] && lp->segtype != seg->segtype &&
((seg_is_raid4(seg) && seg_is_striped(lp) && lp->stripes > 1) ||
(seg_is_striped(seg) && seg->area_count > 1 && seg_is_raid4(lp)))) {
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
lp->region_size, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
display_lvname(lv));
return 1;
}
log_error("Conversion operation not yet supported.");
return 0;
}
@ -2409,9 +2443,6 @@ static int _lvconvert_merge_thin_snapshot(struct cmd_context *cmd,
if (!archive(lv->vg))
return_0;
// FIXME: allow origin to be specified
// FIXME: verify snapshot is descendant of specified origin
/*
* Prevent merge with open device(s) as it would likely lead
* to application/filesystem failure. Merge on origin's next
@ -4240,7 +4271,7 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL) || arg_is_set(cmd, cachepool_ARG))
return _convert_raid_cache_pool(cmd, lv, lp);
if (segtype_is_raid(lp->segtype))
if (segtype_is_raid(lp->segtype) || segtype_is_mirror(lp->segtype))
return _convert_raid_raid(cmd, lv, lp);
if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED))
@ -4264,6 +4295,7 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
" --type thin-pool\n"
" --type cache-pool\n"
" --type raid*\n"
" --type mirror\n"
" --type striped\n"
" --type linear\n");
return 0;
@ -4328,6 +4360,7 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
}
/*
* Main entry point.
* lvconvert performs a specific <operation> on a specific <lv_type>.
*
* The <operation> is specified by command line args.
@ -4345,7 +4378,6 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
* So, when the use of arg_type_str(type_ARG) here was replaced with
* lp->type_str, some commands are no longer identified/routed correctly.
*/
static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
@ -4393,6 +4425,13 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
return_0;
if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
if (!lp->mirrors_supplied && !seg_is_raid1(seg)) {
log_error("Conversions to --type mirror require -m/--mirrors");
return 0;
}
}
if (activation() && lp->segtype && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
log_error("%s: Required device-mapper target(s) not "
@ -4404,6 +4443,7 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
/* FIXME This is incomplete */
if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) ||
_striped_type_requested(lp->type_str) || lp->repair || lp->mirrorlog || lp->corelog) {
/* FIXME Handle +/- adjustments too? */
if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size))
return_0;
/* FIXME Move this into the get function */
@ -4412,7 +4452,7 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
/* The default keeps existing number of stripes, handled inside the library code */
if (!arg_is_set(cmd, stripes_long_ARG) && !_linear_type_requested(lp->type_str))
if (!arg_is_set(cmd, stripes_long_ARG))
lp->stripes = 0;
}