1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +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 function to support disk adding reshapes
- add function to support disk removing reshapes
- add function to support layout (e.g. raid5ls -> raid5_rs)
  or stripesize reshaping

Related: rhbz834579
Related: rhbz1191935
Related: rhbz1191978
This commit is contained in:
Heinz Mauelshagen 2017-02-24 02:12:30 +01:00
parent 7d39b4d5e7
commit 4de0e692db

View File

@ -557,7 +557,7 @@ static void _swap_areas(struct lv_segment_area *a1, struct lv_segment_area *a2)
*
* raid10_{near,far} can only be reordered to raid0 if !mod(#total_devs, #mirrors)
*
* Examples with 6 disks indexed 0..5 with 3 stripes:
* Examples with 6 disks indexed 0..5 with 3 stripes and 2 data copies:
* raid0 (012345) -> raid10_{near,far} (031425) order
* idx 024135
* raid10_{near,far} (012345) -> raid0 (024135/135024) order depending on mirror leg selection (TBD)
@ -576,7 +576,7 @@ enum raid0_raid10_conversion { reorder_to_raid10_near, reorder_from_raid10_near
static int _reorder_raid10_near_seg_areas(struct lv_segment *seg, enum raid0_raid10_conversion conv)
{
unsigned dc, idx1, idx1_sav, idx2, s, ss, str, xchg;
uint32_t data_copies = 2; /* seg->data_copies */
uint32_t data_copies = seg->data_copies;
uint32_t *idx, stripes = seg->area_count;
unsigned i = 0;
@ -589,7 +589,7 @@ static int _reorder_raid10_near_seg_areas(struct lv_segment *seg, enum raid0_rai
/* FIXME: once more data copies supported with raid10 */
if (seg_is_raid10_near(seg) && (stripes % data_copies)) {
log_error("Can't convert %s LV %s with number of stripes not divisable by number of data copies",
log_error("Can't convert %s LV %s with number of stripes not divisable by number of data copies.",
lvseg_name(seg), display_lvname(seg->lv));
return 0;
}
@ -1544,6 +1544,314 @@ static int _reshape_adjust_to_size(struct logical_volume *lv,
return 1;
}
/*
* HM Helper:
*
* Reshape: add immages to existing raid lv
*
*/
static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
struct dm_list *allocate_pvs, struct dm_list *removal_lvs,
int commit, int use_existing_area_len);
__attribute__ ((__unused__))
static int _raid_reshape_add_images(struct logical_volume *lv,
const struct segment_type *new_segtype, int yes,
uint32_t old_image_count, uint32_t new_image_count,
const unsigned new_stripes, const unsigned new_stripe_size,
struct dm_list *allocate_pvs)
{
uint32_t grown_le_count, current_le_count, s;
struct volume_group *vg;
struct logical_volume *slv;
struct lv_segment *seg = first_seg(lv);
struct lvinfo info = { 0 };
if (new_image_count == old_image_count) {
log_error(INTERNAL_ERROR "No change of image count on LV %s.", display_lvname(lv));
return_0;
}
vg = lv->vg;
if (!lv_info(vg->cmd, lv, 0, &info, 1, 0) && driver_version(NULL, 0)) {
log_error("lv_info failed: aborting.");
return 0;
}
if (seg->segtype != new_segtype)
log_print_unless_silent("Ignoring layout change on device adding reshape.");
if (seg_is_any_raid10(seg) && (new_image_count % seg->data_copies)) {
log_error("Can't reshape %s LV %s to odd number of stripes.",
lvseg_name(seg), display_lvname(lv));
return 0;
}
if (!_lv_reshape_get_new_len(lv, old_image_count, new_image_count, &grown_le_count))
return 0;
current_le_count = lv->le_count - _reshape_len_per_lv(lv);
grown_le_count -= _reshape_len_per_dev(seg) * _data_rimages_count(seg, new_image_count);
log_warn("WARNING: Adding stripes to active%s logical volume %s "
"will grow it from %u to %u extents!",
info.open_count ? " and open" : "",
display_lvname(lv), current_le_count, grown_le_count);
log_print_unless_silent("Run \"lvresize -l%u %s\" to shrink it or use the additional capacity.",
current_le_count, display_lvname(lv));
if (!yes && yes_no_prompt("Are you sure you want to add %u images to %s LV %s? [y/n]: ",
new_image_count - old_image_count, lvseg_name(seg), display_lvname(lv)) == 'n') {
log_error("Logical volume %s NOT converted.", display_lvname(lv));
return 0;
}
/* Allocate new image component pairs for the additional stripes and grow LV size */
log_debug_metadata("Adding %u data and metadata image LV pair%s to %s.",
new_image_count - old_image_count, new_image_count - old_image_count > 1 ? "s" : "",
display_lvname(lv));
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 0))
return 0;
/* Reshape adding image component pairs -> change sizes/counters accordingly */
if (!_reshape_adjust_to_size(lv, old_image_count, new_image_count)) {
log_error("Failed to adjust LV %s to new size!", display_lvname(lv));
return 0;
}
/* Allocate forward out of place reshape space at the beginning of all data image LVs */
log_debug_metadata("(Re)allocating reshape space for %s.", display_lvname(lv));
if (!_lv_alloc_reshape_space(lv, alloc_begin, NULL, allocate_pvs))
return 0;
/*
* Reshape adding image component pairs:
*
* - reset rebuild flag on new image LVs
* - set delta disks plus flag on new image LVs
*/
if (old_image_count < seg->area_count) {
log_debug_metadata("Setting delta disk flag on new data LVs of %s.",
display_lvname(lv));
for (s = old_image_count; s < seg->area_count; s++) {
slv = seg_lv(seg, s);
slv->status &= ~LV_REBUILD;
slv->status |= LV_RESHAPE_DELTA_DISKS_PLUS;
}
}
seg->stripe_size = new_stripe_size;
return 1;
}
/*
* HM Helper:
*
* Reshape: remove images from existing raid lv
*
*/
__attribute__ ((__unused__))
static int _raid_reshape_remove_images(struct logical_volume *lv,
const struct segment_type *new_segtype,
int yes, int force,
uint32_t old_image_count, uint32_t new_image_count,
const unsigned new_stripes, const unsigned new_stripe_size,
struct dm_list *allocate_pvs, struct dm_list *removal_lvs)
{
uint32_t active_lvs, current_le_count, reduced_le_count, removed_lvs, s;
uint64_t extend_le_count;
unsigned devs_health, devs_in_sync;
struct lv_segment *seg = first_seg(lv);
struct lvinfo info = { 0 };
if (seg_is_any_raid6(seg) && new_stripes < 3) {
log_error("Minimum 3 stripes required for %s LV %s.",
lvseg_name(seg), display_lvname(lv));
return 0;
}
if (new_image_count == old_image_count) {
log_error(INTERNAL_ERROR "No change of image count on LV %s.", display_lvname(lv));
return_0;
}
switch (_reshaped_state(lv, new_image_count, &devs_health, &devs_in_sync)) {
case 3:
/*
* Disk removal reshape step 1:
*
* we got more disks active than requested via @new_stripes
*
* -> flag the ones to remove
*
*/
if (seg->segtype != new_segtype)
log_print_unless_silent("Ignoring layout change on device removing reshape.");
if (!lv_info(lv->vg->cmd, lv, 0, &info, 1, 0) && driver_version(NULL, 0)) {
log_error("lv_info failed: aborting.");
return 0;
}
if (!_lv_reshape_get_new_len(lv, old_image_count, new_image_count, &reduced_le_count))
return 0;
reduced_le_count -= seg->reshape_len * _data_rimages_count(seg, new_image_count);
current_le_count = lv->le_count - seg->reshape_len * _data_rimages_count(seg, old_image_count);
extend_le_count = current_le_count * current_le_count / reduced_le_count;
log_warn("WARNING: Removing stripes from active%s logical "
"volume %s will shrink it from %s to %s!",
info.open_count ? " and open" : "", display_lvname(lv),
display_size(lv->vg->cmd, (uint64_t) current_le_count * lv->vg->extent_size),
display_size(lv->vg->cmd, (uint64_t) reduced_le_count * lv->vg->extent_size));
log_warn("THIS MAY DESTROY (PARTS OF) YOUR DATA!");
if (!yes)
log_warn("Interrupt the conversion and run \"lvresize -y -l%u %s\" to "
"keep the current size if not done already!",
(uint32_t) extend_le_count, display_lvname(lv));
log_print_unless_silent("If that leaves the logical volume larger than %llu extents due to stripe rounding,",
(unsigned long long) extend_le_count);
log_print_unless_silent("you may want to grow the content afterwards (filesystem etc.)");
log_warn("WARNING: too remove freed stripes after the conversion has finished, you have to run \"lvconvert --stripes %u %s\"",
new_stripes, display_lvname(lv));
if (!force) {
log_warn("WARNING: Can't remove stripes without --force option.");
return 0;
}
if (!yes && yes_no_prompt("Are you sure you want to remove %u images from %s LV %s? [y/n]: ",
old_image_count - new_image_count, lvseg_name(seg), display_lvname(lv)) == 'n') {
log_error("Logical volume %s NOT converted.", display_lvname(lv));
return 0;
}
/*
* Allocate backward out of place reshape space at the
* _end_ of all data image LVs, because MD reshapes backwards
* to remove disks from a raid set
*/
if (!_lv_alloc_reshape_space(lv, alloc_end, NULL, allocate_pvs))
return 0;
/* Flag all disks past new images as delta disks minus to kernel */
for (s = new_image_count; s < old_image_count; s++)
seg_lv(seg, s)->status |= LV_RESHAPE_DELTA_DISKS_MINUS;
if (seg_is_any_raid5(seg) && new_image_count == 2)
seg->data_copies = 2;
break;
case 1:
/*
* Disk removal reshape step 2:
*
* we got the proper (smaller) amount of devices active
* for a previously finished disk removal reshape
*
* -> remove the freed up images and reduce LV size
*
*/
for (active_lvs = removed_lvs = s = 0; s < seg->area_count; s++) {
struct logical_volume *slv;
if (!seg_lv(seg, s) || !(slv = seg_lv(seg, s))) {
log_error("Missing image sub lv off LV %s.", display_lvname(lv));
return 0;
}
if (slv->status & LV_REMOVE_AFTER_RESHAPE)
removed_lvs++;
else
active_lvs++;
}
if (devs_in_sync != new_image_count) {
log_error("No correct kernel/lvm active LV count on %s.", display_lvname(lv));
return 0;
}
if (active_lvs + removed_lvs != old_image_count) {
log_error ("No correct kernel/lvm total LV count on %s.", display_lvname(lv));
return 0;
}
/* Reshape removing image component pairs -> change sizes accordingly */
if (!_reshape_adjust_to_size(lv, old_image_count, new_image_count)) {
log_error("Failed to adjust LV %s to new size!", display_lvname(lv));
return 0;
}
log_debug_metadata("Removing %u data and metadata image LV pair%s from %s.",
old_image_count - new_image_count, old_image_count - new_image_count > 1 ? "s" : "",
display_lvname(lv));
if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, removal_lvs, 0, 0))
return 0;
seg->area_count = new_image_count;
break;
default:
log_error(INTERNAL_ERROR "Bad return provided to %s.", __func__);
return 0;
}
seg->stripe_size = new_stripe_size;
return 1;
}
/*
* HM Helper:
*
* Reshape: keep images in RAID @lv but change stripe size or data copies
*
*/
__attribute__ ((__unused__))
static int _raid_reshape_keep_images(struct logical_volume *lv,
const struct segment_type *new_segtype,
int yes, int force, int *force_repair,
const int new_data_copies, const unsigned new_stripe_size,
struct dm_list *allocate_pvs)
{
int alloc_reshape_space = 1;
enum alloc_where where = alloc_anywhere;
struct lv_segment *seg = first_seg(lv);
if (seg->segtype != new_segtype)
log_print_unless_silent("Converting %s LV %s to %s.",
lvseg_name(seg), display_lvname(lv), new_segtype->name);
if (!yes && yes_no_prompt("Are you sure you want to convert %s LV %s? [y/n]: ",
lvseg_name(seg), display_lvname(lv)) == 'n') {
log_error("Logical volume %s NOT converted.", display_lvname(lv));
return 0;
}
seg->stripe_size = new_stripe_size;
/*
* Reshape layout alogorithm or chunksize:
*
* Allocate free out-of-place reshape space unless raid10_far.
*
* If other raid10, allocate it appropriatly.
*
* Allocate it anywhere for raid4/5 to avoid remapping
* it in case it is already allocated.
*
* The dm-raid target is able to use the space whereever it
* is found by appropriately selecting forward or backward reshape.
*/
if (seg->area_count != 2 &&
alloc_reshape_space &&
!_lv_alloc_reshape_space(lv, where, NULL, allocate_pvs))
return 0;
seg->segtype = new_segtype;
return 1;
}
/*
* _alloc_rmeta_for_lv
* @lv