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:
parent
7d39b4d5e7
commit
4de0e692db
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user