1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-21 22:04:19 +03:00

raid_manip: add support to split off a raid1 mirror from duplicating LVs

This commit is contained in:
Heinz Mauelshagen 2015-10-06 18:25:44 +02:00
parent da14cdf468
commit 1a1fc812ae
4 changed files with 186 additions and 21 deletions

View File

@ -152,8 +152,8 @@ static int _lv_is_duplicating(const struct logical_volume *lv)
/* Needs to be raid1 with 2 legs and the legs must have the proper names suffixes */
if (!seg ||
seg->area_count < 2 ||
!seg_is_raid1(seg))
!seg_is_raid1(seg) ||
seg->area_count < 2)
return 0;
for (s = 0; s < seg->area_count; s++)
@ -962,7 +962,7 @@ static int _extract_image_component_error_seg(struct lv_segment *seg,
lv->status &= ~(type | RAID);
lv_set_visible(lv);
/* release lv areas */
/* remove reference from @seg to @lv */
if (!remove_seg_from_segs_using_this_lv(lv, seg))
return_0;
@ -2298,11 +2298,13 @@ PFLA("lv=%s", display_lvname(lvl->lv));
}
/*
* Split off raid1 images of @lv, prefix with @split_name,
* Split off raid1 images of @lv, prefix with @split_name or selecet duplicated LV by @split_name,
* leave @new_image_count in the raid1 set and find them on @splittable_pvs
*/
static int _lv_update_and_reload_origin_eliminate_lvs(struct logical_volume *lv,
struct dm_list *removal_lvs);
static int _raid_split_duplicate(struct logical_volume *lv, const char *split_name,
uint32_t new_image_count);
int lv_raid_split(struct logical_volume *lv, const char *split_name,
uint32_t new_image_count, struct dm_list *splittable_pvs)
{
@ -2335,6 +2337,10 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
return 0;
}
/* Special case for splitting off image of a duplicating lv */
if (_lv_is_duplicating(lv))
return _raid_split_duplicate(lv, split_name, new_image_count);
if (find_lv_in_vg(lv->vg, split_name)) {
log_error("Logical Volume \"%s\" already exists in %s",
split_name, lv->vg->name);
@ -2430,12 +2436,13 @@ PFLA("split_lv->le_count=%u", split_lv->le_count);
dm_list_iterate_items(lvl, &data_lvs)
if (!activate_lv_excl_local(cmd, lvl->lv))
return_0;
dm_list_iterate_items(lvl, &meta_lvs)
if (!activate_lv_excl_local(cmd, lvl->lv))
return_0;
if (!resume_lv(lv->vg->cmd, lv_lock_holder(lv))) {
if (!resume_lv(cmd, lv_lock_holder(lv))) {
log_error("Failed to resume %s after committing changes",
display_lvname(lv));
return 0;
@ -4030,13 +4037,166 @@ static int _rename_metasub_lvs(struct logical_volume *lv, enum rename_dir dir)
return __rename_sub_lvs(lv, dir, RAID_META);
}
/*
* HM Helper:
*
* split off a sub-lv of a duplicatting @lv
*/
#define CONVERSION_HELPER_FN(function_name) TAKEOVER_FN(function_name)
static int _raid_split_duplicate(struct logical_volume *lv, const char *split_name, uint32_t new_image_count)
{
uint32_t s;
struct dm_list removal_lvs;
struct lv_list *lvl;
struct lv_segment *seg = first_seg(lv);
struct logical_volume *split_lv;
dm_list_init(&removal_lvs);
if (!lv_is_active(lv)) {
log_error("%s must be active to perform this operation.",
display_lvname(lv));
return 0;
}
if (!_lv_is_duplicating(lv)) {
log_error(INTERNAL_ERROR "Called with non-duplicating lv %s",
display_lvname(lv));
return 0;
}
if (new_image_count != 1) {
log_error("Only suitable on duplicating LV %s with \"lvconvert --splitmirrors 1\"",
display_lvname(lv));
return 0;
}
if (!split_name || *split_name == '\0') {
log_error("Need \"--name ...\" to select the LV to split out");
return 0;
}
if (!(lvl = find_lv_in_vg(lv->vg, split_name))) {
log_error("Unable to find %s", split_name);
return 0;
}
/* Try to find s@split_name in sub lvs */
for (s = 0; s < seg->area_count; s++)
if (!strcmp(seg_lv(seg, s)->name, split_name))
break;
if (s == seg->area_count) {
log_error("No sub lv %s to split out in %s", split_name, display_lvname(lv));
return 0;
}
split_lv = seg_lv(seg, s);
if (!_raid_in_sync(lv)) {
log_error("Can't split off %s when LV %s is not in sync",
split_name, display_lvname(lv));
return 0;
}
log_debug_metadata("Extract metadata image for split LV %s", split_name);
if (!_extract_image_component_sublist(seg, RAID_META, s, s + 1, &removal_lvs, 1))
return 0;
/* remove reference from @seg to @split_lv */
if (!remove_seg_from_segs_using_this_lv(split_lv, seg))
return 0;
/* Shift areas down */
for ( ; s < seg->area_count - 1; s++) {
seg->areas[s] = seg->areas[s + 1];
if (seg->meta_areas)
seg->meta_areas[s] = seg->meta_areas[s + 1];
}
seg->area_count--;
seg->data_copies--;
lv_set_visible(split_lv);
split_lv->status &= ~LV_NOTSYNCED;
log_debug_metadata("Rename sub LVs of %s", display_lvname(split_lv));
if (!_rename_sub_lvs(split_lv, from_dup)) {
log_error(INTERNAL_ERROR "Failed to rename %s sub LVs", display_lvname(split_lv));
return 0;
}
PFL();
log_debug_metadata("Updating VG metadata and reactivating %s and %s",
display_lvname(lv), display_lvname(split_lv));
if (!_lv_update_and_reload_origin_eliminate_lvs(lv, &removal_lvs) ||
!lv_update_and_reload_origin(split_lv))
return 0;
PFL();
#if 1
/* We are down to the last sub lv -> remove the top-level raid1 mapping */
if (seg->area_count == 1) {
struct logical_volume *slv = seg_lv(seg, 0);
dm_list_init(&removal_lvs);
log_debug_metadata("Removing last metadata image of top-level raid1 lv %s", display_lvname(lv));
if (!_extract_image_component_sublist(seg, RAID_META, 0, 1, &removal_lvs, 1))
return 0;
if (!_rename_sub_lvs(slv, from_dup)) {
log_error(INTERNAL_ERROR "Failed to rename %s sub LVs", display_lvname(lv));
return 0;
}
if (!remove_seg_from_segs_using_this_lv(slv, seg))
return 0;
dm_list_init(&lv->segments);
if (!move_lv_segments(lv, slv, 0, 0))
return_0;
/* seg has changed... */
seg = first_seg(lv);
slv->le_count = 0;
if (!replace_lv_with_error_segment(slv))
return_0;
if (!_lv_reset_raid_add_to_list(slv, &removal_lvs))
return 0;
for (s = 0; s < seg->area_count; s++)
if (seg_type(seg, s) == AREA_LV) {
char *suffix, *p;
p = (char *) seg_lv(seg, s)->name;
if ((suffix = strstr(p, "_rimage"))) {
strcpy(p, lv->name);
strcat(p, suffix);
}
if (seg->meta_areas) {
p = (char *) seg_metalv(seg, s)->name;
if ((suffix = strstr(p, "_rmeta"))) {
strcpy(p, lv->name);
strcat(p, suffix);
}
}
}
if (!_lv_update_and_reload_origin_eliminate_lvs(lv, &removal_lvs))
return_0;
}
#endif
PFL();
return 1;
}
/*
* HM Helper:
*
* remove top-level raid1 lv with either source/destination
* legs selected by --type/--stripes/--mirrors arguments option
*/
#define CONVERSION_HELPER_FN(function_name) TAKEOVER_FN(function_name)
static int _raid_conv_unduplicate(struct logical_volume *lv,
const struct segment_type *new_segtype,
unsigned new_image_count,
@ -4056,19 +4216,11 @@ static int _raid_conv_unduplicate(struct logical_volume *lv,
struct lv_segment *seg = first_seg(lv), *seg0;
PFL();
/* Check, if lv passed in is in order for unduplication */
if (!seg_is_raid1(seg) ||
!_lv_is_duplicating(lv))
goto err;
for (s = 0; s < seg->area_count; s++)
if (seg_type(seg, s) != AREA_LV) {
err:
log_error(INTERNAL_ERROR "Called with non-duplicating lv %s",
display_lvname(lv));
return 0;
}
/* END check */
if (!_lv_is_duplicating(lv)) {
log_error(INTERNAL_ERROR "Called with non-duplicating lv %s",
display_lvname(lv));
return 0;
}
PFLA("new_segtype=%s new_image_count=%u new_datacopes=%u", new_segtype->name, new_image_count, new_data_copies);
/* Find sublv to keep based on passed in properties */

View File

@ -162,7 +162,6 @@ static const char *_lvname_has_reserved_string(const char *lvname)
"_rmeta",
"_rdimage",
"_rdmeta",
"_dup",
"_tdata",
"_tmeta",
"_vorigin"

View File

@ -164,7 +164,7 @@ FIELD(VGS, vg, SIZ, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smalles
FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 8, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1)
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, segtype, "Type of LV segment.", 0)
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, stripes, "Number of stripes or mirror legs.", 0)
FIELD(SEGS, seg, NUM, "#Str", list, 4, segstripes, stripes, "Number of stripes or mirror legs.", 0)
FIELD(SEGS, seg, NUM, "SReshape", list, 4, segreshape_len, reshape_len, "Number of reshape extents.", 0)
FIELD(SEGS, seg, NUM, "SReshape", list, 4, segreshape_len, reshapelen, "Number of reshape extents.", 0)
FIELD(SEGS, seg, NUM, "#Cpy", list, 4, segdata_copies, datacopies, "Number of data copies.", 0)

View File

@ -1984,6 +1984,20 @@ static int _segmonitor_disp(struct dm_report *rh, struct dm_pool *mem,
GET_FIELD_RESERVED_VALUE(seg_monitor_undef));
}
static int _segstripes_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
uint32_t stripes = seg->area_count;
if (seg_is_striped_raid(seg) &&
seg->segtype)
stripes -= seg->segtype->parity_devs;
return dm_report_field_uint32(rh, field, &stripes);
}
static int _segreshape_len_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)