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

raid_manip: enhance replacement/repair with duplicated LVs

lv_manip: enhance check for duplicating LV
This commit is contained in:
Heinz Mauelshagen 2015-10-22 17:39:51 +02:00
parent 729088c96e
commit c787ae54a5
4 changed files with 263 additions and 177 deletions

View File

@ -1427,7 +1427,7 @@ PFL();
return 1;
}
/* Return 1 in case any last segmenbt of @lv, area @s contains another layered LV */
/* Return 1 in case any last segment of @lv, area @s contains another layered LV */
/* HM FIXME: correct? */
static int _is_multilayered_lv(struct logical_volume *lv, uint32_t s)
{
@ -1436,7 +1436,8 @@ static int _is_multilayered_lv(struct logical_volume *lv, uint32_t s)
return seg &&
seg_is_raid1(seg) &&
seg_type(seg, s) == AREA_LV &&
(seg1 = last_seg(seg_lv(seg, s)));
(seg1 = last_seg(seg_lv(seg, s))) &&
!seg_is_striped(seg1);
#if 0
&& /* <- segment of #s LV underneath top-level */
seg_type(seg1, 0) == AREA_LV &&
@ -4414,12 +4415,11 @@ PFLA("mirrors=%u stripes=%u", mirrors, stripes);
/* HM FIXME: caller should ensure... */
if (seg) {
mirrors = seg->data_copies;
stripes = 1;
if (seg_is_raid(seg))
stripes = seg->area_count - seg->segtype->parity_devs;
else if (seg_is_raid01(seg))
stripes = first_seg(seg_lv(seg, 0))->area_count;
else
stripes = 1;
PFLA("mirrors=%u stripes=%u", mirrors, stripes);
}
PFLA("mirrors=%u stripes=%u", mirrors, stripes);
@ -4522,7 +4522,12 @@ PFLA("extents=%u ah->new_extents=%u lv->le_count=%u stripes=%u sub_lv_count=%u",
* and the LV has the LV_NOTSYNCED flag set.
*/
if (old_extents &&
#if 1
(segtype_is_mirror(segtype) || segtype_is_raid1(segtype)) &&
#else
segtype_is_mirrored(segtype) &&
#endif
(lv->status & LV_NOTSYNCED)) {
dm_percent_t sync_percent = DM_PERCENT_INVALID;

View File

@ -1144,6 +1144,7 @@ uint32_t lv_raid_image_count(const struct logical_volume *lv);
int lv_raid_split(struct logical_volume *lv, const char *split_name,
uint32_t new_count, struct dm_list *splittable_pvs);
int lv_raid_split_and_track(struct logical_volume *lv,
const char *sub_lv_name,
struct dm_list *splittable_pvs);
int lv_raid_merge(struct logical_volume *lv);
int lv_raid_convert(struct logical_volume *lv,
@ -1156,7 +1157,8 @@ int lv_raid_convert(struct logical_volume *lv,
const unsigned new_stripe_size,
const char *pool_data_name,
struct dm_list *allocate_pvs);
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
int lv_raid_replace(struct logical_volume *lv, int yes,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);

View File

@ -78,9 +78,9 @@ static uint32_t _data_rimages_count(const struct lv_segment *seg, const uint32_t
*/
static int _cmp_level(const struct segment_type *t1, const struct segment_type *t2)
{
/* raid10 */
if (!strncmp(t1->name, t2->name, 6))
return 1;
if ((segtype_is_any_raid10(t1) && !segtype_is_any_raid10(t2)) ||
(!segtype_is_any_raid10(t1) && segtype_is_any_raid10(t2)))
return 0;
return !strncmp(t1->name, t2->name, 5);
}
@ -1529,7 +1529,7 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_image_co
struct dm_list *extracted_meta_lvs,
struct dm_list *extracted_data_lvs)
{
int check_partial, inc;
int inc;
unsigned s, extract;
struct lv_list *lvl_pairs;
struct lv_segment *seg = first_seg(lv);
@ -1593,12 +1593,8 @@ PFL();
}
/* Second pass */
check_partial = (target_pvs == &lv->vg->pvs) ? 1 : 0;
for (s = seg->area_count; s-- && extract; ) {
for (s = seg->area_count; target_pvs && s-- && extract; ) {
/* Conditions for second pass */
if (!target_pvs)
break;
if (!_raid_in_sync(lv) &&
(!seg_is_mirrored(seg) || !s)) {
log_error("Unable to extract %sRAID image"
@ -1609,23 +1605,34 @@ PFL();
inc = 0;
#if 1
if (seg->meta_areas &&
(!check_partial || (seg_metalv(seg, s)->status & PARTIAL_LV)) &&
lv_is_on_pvs(seg_metalv(seg, s), target_pvs)) {
#else
/* HM FIXME: PARTIAL_LV not set for LVs on replacement PVs ("lvconvert --replace $PV $LV") */
if (seg->meta_areas &&
(seg_metalv(seg, s)->status & PARTIAL_LV) &&
lv_is_on_pvs(seg_metalv(seg, s), target_pvs)) {
#endif
if (!_extract_image_component(seg, RAID_META, s, &lvl_pairs[0].lv, 0))
return_0;
dm_list_add(extracted_meta_lvs, &lvl_pairs[0].list);
inc = 1;
inc++;
}
if ((!check_partial || (seg_lv(seg, s)->status & PARTIAL_LV)) &&
#if 1
if (lv_is_on_pvs(seg_lv(seg, s), target_pvs)) {
#else
/* HM FIXME: PARTIAL_LV not set for LVs on replacement PVs ("lvconvert --replace $PV $LV") */
if ((seg_lv(seg, s)->status & PARTIAL_LV) &&
lv_is_on_pvs(seg_lv(seg, s), target_pvs)) {
#endif
if (!_extract_image_component(seg, RAID_IMAGE, s, &lvl_pairs[1].lv, 0))
return_0;
dm_list_add(extracted_data_lvs, &lvl_pairs[1].list);
inc = 1;
inc++;
}
if (inc) {
@ -2602,6 +2609,7 @@ PFLA("split_lv->le_count=%u", split_lv->le_count);
* Returns: 1 on success, 0 on error
*/
int lv_raid_split_and_track(struct logical_volume *lv,
const char *sub_lv_name,
struct dm_list *splittable_pvs)
{
int s;
@ -2625,19 +2633,28 @@ int lv_raid_split_and_track(struct logical_volume *lv,
}
if (seg->area_count < 3) {
log_error("Tracking an image in 2-way raid1 LV %s would cause loosing redundancy!",
display_lvname(lv));
log_error("Run \"lvconvert -m2 %s\" to have 3 legs and redo",
log_error("Tracking an image in 2-way raid1 LV %s would cause loss of redundancy!",
display_lvname(lv));
if (_lv_is_duplicating(lv))
log_error("Run \"lvconvert --dup ... %s\" to have 3 legs and redo",
display_lvname(lv));
else
log_error("Run \"lvconvert -m2 %s\" to have 3 legs and redo",
display_lvname(lv));
return 0;
}
for (s = seg->area_count - 1; s >= 0; --s)
for (s = seg->area_count - 1; s >= 0; --s) {
if (sub_lv_name &&
!strstr(sub_lv_name, seg_lv(seg, s)->name))
continue;
if (lv_is_on_pvs(seg_lv(seg, s), splittable_pvs)) {
lv_set_visible(seg_lv(seg, s));
seg_lv(seg, s)->status &= ~LVM_WRITE;
break;
}
}
if (s < 0) {
log_error("Unable to find image to satisfy request");
@ -2676,7 +2693,8 @@ int lv_raid_merge(struct logical_volume *image_lv)
if (!(lv_name = dm_pool_strdup(vg->vgmem, image_lv->name)))
return_0;
if (!(p = strstr(lv_name, "_rimage_"))) {
if (!(p = strstr(lv_name, "_rimage_")) &&
!(p = strstr(lv_name, "_dup_"))) {
log_error("Unable to merge non-mirror image %s.",
display_lvname(image_lv));
return 0;
@ -2711,6 +2729,7 @@ int lv_raid_merge(struct logical_volume *image_lv)
}
/* Image LVs should not be resizable directly, but... */
/* HM FIXME: duplictaing sub lvs can have different size! */
if (seg->len != image_lv->le_count) {
log_error(INTERNAL_ERROR "The image LV %s of %s has different size!",
display_lvname(image_lv), display_lvname(lv));
@ -5372,6 +5391,29 @@ TAKEOVER_HELPER_FN(_raid145_raid1_raid6)
return _lv_update_and_reload_origin_eliminate_lvs(lv, &removal_lvs);
}
/* HM Helper: sdjust size of raid10_far @lv from @le_count depending on @data_copes, so that lv_reduce() can shrink it */
static int _adjust_raid10_far_lv_size(struct logical_volume *lv,
uint32_t le_count, uint32_t data_copies)
{
struct lv_segment *seg = first_seg(lv);
if (!seg_is_raid10_far(seg)) {
log_error(INTERNAL_ERROR "iLV %s is not raid10_far!", display_lvname(lv));
return 0;
}
lv->le_count = le_count * data_copies;
lv->size = lv->le_count * lv->vg->extent_size;
seg->len = lv->le_count;
if (lv->le_count % seg->area_count) {
log_error(INTERNAL_ERROR "LV %s le_count not divisable by #stripes", display_lvname(lv));
return 0;
}
seg->area_len = lv->le_count / seg->area_count;
return 1;
}
/* Helper: raid1/5 with 2 images <-> raid4/5/10 or raid4 <-> raid5_n with any image count (no change to count!) */
TAKEOVER_HELPER_FN(_raid145_raid4510)
{
@ -5380,16 +5422,19 @@ TAKEOVER_HELPER_FN(_raid145_raid4510)
if (!seg_is_raid1(seg) &&
!seg_is_raid4(seg) &&
!seg_is_any_raid5(seg)) {
log_error(INTERNAL_ERROR "Called with wrong segment type %s",
lvseg_name(seg));
log_error(INTERNAL_ERROR "Called on LV %s with wrong segment type %s",
display_lvname(lv), lvseg_name(seg));
return 0;
}
if (segtype_is_any_raid10(new_segtype) &&
!segtype_is_raid10_near(new_segtype)) {
log_error("Conversion of LV %s to raid10 has to be to raid10_near",
display_lvname(lv));
return 0;
if (segtype_is_any_raid10(new_segtype)) {
if (!segtype_is_raid10_near(new_segtype)) {
log_error("Conversion of LV %s to raid10 has to be to raid10_near",
display_lvname(lv));
return 0;
}
seg->data_copies = seg->area_count;
}
if (!_raid_in_sync(lv))
@ -5424,6 +5469,8 @@ TAKEOVER_HELPER_FN(_raid145_raid4510)
} else
seg->segtype = new_segtype;
seg->stripe_size = new_stripe_size ?: DEFAULT_STRIPESIZE;
return _lv_update_and_reload_origin_eliminate_lvs(lv, NULL);
}
@ -5486,16 +5533,9 @@ TAKEOVER_HELPER_FN_REMOVAL_LVS(_raid10_striped_r0)
return 0;
/* raid10_far: prepare properties to shrink lv size to striped/raid0* */
} else if (raid10_far) {
lv->le_count = le_count * data_copies;
lv->size = lv->le_count * lv->vg->extent_size;
seg->len = lv->le_count;
if (lv->le_count % seg->area_count) {
log_error(INTERNAL_ERROR "LV %s le_count not divisable by #stripes", display_lvname(lv));
} else if (raid10_far &&
!_adjust_raid10_far_lv_size(lv, le_count, data_copies))
return 0;
}
seg->area_len = lv->le_count / seg->area_count;
}
if (!segtype_is_any_raid0(new_segtype)) {
/* -> striped */
@ -5530,7 +5570,7 @@ PFLA("seg->chunk_size=%u", seg->chunk_size);
return force ? 1 : _lv_update_and_reload_origin_eliminate_lvs(lv, removal_lvs);
}
/* Helper: raid10 with 2 images <-> raid1/raid4/raid5* */
/* Helper: raid10 with 2/N (if appropriate) images <-> raid1/raid4/raid5* */
TAKEOVER_HELPER_FN(_raid10_r1456)
{
struct lv_segment *seg = first_seg(lv);
@ -5538,12 +5578,26 @@ TAKEOVER_HELPER_FN(_raid10_r1456)
dm_list_init(&removal_lvs);
if (seg->area_count != 2 && seg_is_raid1(seg)) {
if (seg_is_any_raid10(seg)) {
if (!seg_is_raid10_near(seg)) {
log_error(INTERNAL_ERROR "Can't takeover %s LV %s",
lvseg_name(seg), display_lvname(lv));
return 0;
}
if (seg->data_copies != seg->area_count) {
log_error(INTERNAL_ERROR "Can't takeover %s LV %s with data copies != areas!",
lvseg_name(seg), display_lvname(lv));
return 0;
}
} else if (seg->area_count != 2 ) {
log_error("Can't convert %s from %s to %s with != 2 images",
display_lvname(lv), lvseg_name(seg), new_segtype->name);
return 0;
}
if (!_raid_in_sync(lv))
return 0;
@ -5554,7 +5608,13 @@ TAKEOVER_HELPER_FN(_raid10_r1456)
if (!archive(lv->vg))
return_0;
first_seg(lv)->segtype = new_segtype;
/* Free any reshape space */
if (!_lv_free_reshape_space(lv)) {
log_error(INTERNAL_ERROR "Failed to free reshape space of %s", display_lvname(lv));
return 0;
}
seg->segtype = new_segtype;
return _lv_update_and_reload_origin_eliminate_lvs(lv, &removal_lvs);
}
@ -5894,7 +5954,7 @@ TAKEOVER_FN(_r1_r1)
return _raid145_raid1_raid6(lv, new_segtype, yes, force, new_image_count, 0 /* data_copies */, 0, 0, allocate_pvs);
}
/* raid1 with 2 legs -> raid10 */
/* raid1 with 2 legs -> raid4/5 */
TAKEOVER_FN(_r1_r45)
{
if (first_seg(lv)->area_count != 2) {
@ -5908,24 +5968,17 @@ TAKEOVER_FN(_r1_r45)
}
/****************************************************************************/
/* raid1 with 2 legs or duplicating one -> raid10 */
/* raid1 with N legs or duplicating one -> raid10_near */
TAKEOVER_FN(_r1_r10)
{
if (first_seg(lv)->area_count != 2) {
log_error("Can't convert %s from %s to %s with != 2 images",
display_lvname(lv),
SEG_TYPE_NAME_RAID1, new_segtype->name);
return 0;
}
if (segtype_is_raid10_far(new_segtype)) {
log_error("Conversion of %s to raid10_far prohibited",
display_lvname(lv));
if (!segtype_is_raid10_near(new_segtype)) {
log_error("Conversion of %s to %s prohibited",
display_lvname(lv), new_segtype->name);
log_error("Please use \"lvconvert --duplicate ...\"");
return 1;
}
return _raid145_raid4510(lv, new_segtype, yes, force, new_image_count, 0 /* data_copies */, 0, 0, allocate_pvs);
return _raid145_raid4510(lv, new_segtype, yes, force, new_image_count, 0 /* data_copies */, 0 /* stripes */, new_stripe_size, allocate_pvs);
}
/* raid45 with 2 images -> linear */
@ -6212,8 +6265,12 @@ TAKEOVER_FN(_r10_r0m)
/* raid10 with 2 images -> raid1 */
TAKEOVER_FN(_r10_r1)
{
return _lv_has_segments_with_n_areas(lv, 2) &&
_raid10_r1456(lv, new_segtype, yes, force, 2, 2, 0, 0, allocate_pvs);
struct lv_segment *seg = first_seg(lv);
return ((seg_is_raid10_near(seg) && seg->data_copies == seg->area_count) ||
_lv_has_segments_with_n_areas(lv, 2)) &&
_raid10_r1456(lv, new_segtype, yes, force, new_image_count, seg->data_copies,
seg->area_count, 0, allocate_pvs);
}
/*
@ -6521,10 +6578,7 @@ int lv_raid_convert(struct logical_volume *lv,
new_image_count = new_image_count ?: seg->area_count;
if (!unduplicate) {
if (!new_segtype) {
log_error(INTERNAL_ERROR "New segtype not specified");
return 0;
}
new_segtype = new_segtype ?: seg->segtype;
if (!(striped_segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
return_0;
@ -6617,7 +6671,9 @@ PFLA("new_segtype=%s new_image_count=%u new_stripes=%u stripes=%u", new_segtype
*
* reshape of capable raid type requested
*/
switch (_reshape_requested(lv, new_segtype_tmp, stripes, stripe_size)) {
new_segtype = new_segtype ?: seg->segtype;
switch (_reshape_requested(lv, new_segtype_tmp ?: seg->segtype, stripes, stripe_size)) {
case 0:
break;
case 1:
@ -6627,15 +6683,12 @@ PFLA("new_segtype=%s new_image_count=%u new_stripes=%u stripes=%u", new_segtype
return 0;
}
#if 0
if (!(seg_is_raid10_near(seg) || seg_is_raid10_offset(seg)) &&
new_stripes &&
if ((new_stripes || stripe_size != seg->stripe_size) &&
seg->segtype != new_segtype) {
log_error("Can't reshape and takeover %s at the same time",
display_lvname(lv));
return 0;
}
#endif
return _raid_reshape(lv, new_segtype, yes, force, stripes, stripe_size, allocate_pvs);
case 2:
@ -6776,6 +6829,7 @@ has_enough_space:
/* HM Helper fn to generate LV names and set segment area lv */
static int _generate_name_and_set_segment(struct logical_volume *lv,
int duplicating,
uint32_t s, uint32_t sd,
struct dm_list *lvs, char **tmp_names)
{
@ -6796,12 +6850,11 @@ static int _generate_name_and_set_segment(struct logical_volume *lv,
lvl = dm_list_item(dm_list_first(lvs), struct lv_list);
dm_list_del(&lvl->list);
if (strstr(lv->name, "_dup"))
if (strstr(lv->name, "_dup_") || duplicating)
suffix = (s == sd) ? "rdmeta" : "rdimage";
else
suffix = (s == sd) ? "rmeta" : "rimage";
PFLA("suffix=%s", suffix);
if (!(tmp_names[sd] = _generate_raid_name(lv, suffix, s)))
return_0;
@ -6810,23 +6863,37 @@ PFLA("suffix=%s", suffix);
return 0;
}
PFLA("lvl->lv->name=%s", lvl->lv->name);
lv_set_hidden(lvl->lv);
return 1;
}
/* Retturn 1 in case @sub_lv has to be replaced, because it has any allocation on list @removal_pvs */
static int _sub_lv_needs_rebuilding(struct lv_segment *seg, uint32_t s,
struct dm_list *remove_pvs)
/* Return 1 in case @slv has to be replaced, because it has any allocation on list @removal_pvs */
static int __sub_lv_needs_rebuilding(struct logical_volume *slv,
struct dm_list *remove_pvs, uint32_t *partial_lvs)
{
if (lv_is_on_pvs(seg_lv(seg, s), remove_pvs) ||
(lv_is_virtual(seg_lv(seg, s))))
return 1;
int r = 0;
return (seg->meta_areas &&
(lv_is_on_pvs(seg_metalv(seg, s), remove_pvs) ||
lv_is_virtual(seg_metalv(seg, s))));
if (lv_is_on_pvs(slv, remove_pvs) ||
lv_is_virtual(slv)) {
r = 1;
if (slv->status & PARTIAL_LV)
(*partial_lvs)++;
}
return r;
}
/* Return 1 in case seg_lv(@seg, @s) has to be replaced, because it has any allocation on list @removal_pvs */
static int _sub_lv_needs_rebuilding(struct lv_segment *seg, uint32_t s,
struct dm_list *remove_pvs, uint32_t *partial_lvs)
{
int r = __sub_lv_needs_rebuilding(seg_lv(seg, s), remove_pvs, partial_lvs);
if (seg->meta_areas)
r += __sub_lv_needs_rebuilding(seg_metalv(seg, s), remove_pvs, partial_lvs);
return !!r;
}
/*
@ -6838,14 +6905,16 @@ static int _sub_lv_needs_rebuilding(struct lv_segment *seg, uint32_t s,
* Replace the specified PVs.
*/
int lv_raid_replace(struct logical_volume *lv,
int yes,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs)
{
int duplicating = 0, partial_segment_removed = 0;
uint32_t s, sd, match_count = 0;
uint32_t match_count = 0, partial_lvs = 0, s, sd;
char **tmp_names;
struct dm_list old_lvs;
struct dm_list new_meta_lvs, new_data_lvs;
struct logical_volume *slv;
struct lv_segment *raid_seg = first_seg(lv);
struct lv_list *lvl;
@ -6853,15 +6922,30 @@ int lv_raid_replace(struct logical_volume *lv,
dm_list_init(&new_meta_lvs);
dm_list_init(&new_data_lvs);
/* HM FIXME: handle mirror at all or require user to remove it? */
/* Recurse into sub lvs in case of a duplicating one */
if (_lv_is_duplicating(lv)) {
/* HM FIXME: first pass: handle mirror at all or require user to remove it? */
for (s = 0; s < raid_seg->area_count; s++) {
struct logical_volume *slv = seg_lv(raid_seg, s);
slv = seg_lv(raid_seg, s);
if (seg_type(raid_seg, s) == AREA_LV &&
seg_is_mirror(first_seg(slv)) &&
(slv->status & PARTIAL_LV)) {
log_error("LV %s is mirror and can't have its missing sub lvs replaced (yet)",
display_lvname(slv));
log_error("Yu have to split it off for the time being");
return 0;
}
}
/* 2nd pass: recurse into sub lvs */
for (s = 0; s < raid_seg->area_count; s++) {
slv = seg_lv(raid_seg, s);
if (seg_type(raid_seg, s) == AREA_LV &&
seg_is_raid(first_seg(slv)) && /* Prevent from processing unless raid sub lv */
!seg_is_any_raid0(first_seg(slv)) &&
!lv_raid_replace(slv, remove_pvs, allocate_pvs))
!lv_raid_replace(slv, yes, remove_pvs, allocate_pvs))
return 0;
}
@ -6908,7 +6992,7 @@ int lv_raid_replace(struct logical_volume *lv,
return 0;
}
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs))
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs, &partial_lvs))
match_count++;
}
@ -6923,13 +7007,27 @@ PFLA("match_count=%u", match_count);
display_lvname(lv));
return 0;
} else if (raid_seg->segtype->parity_devs &&
(match_count > raid_seg->segtype->parity_devs)) {
log_error("Unable to replace more than %u PVs from (%s) %s",
raid_seg->segtype->parity_devs,
lvseg_name(raid_seg),
display_lvname(lv));
return 0;
} else if (raid_seg->segtype->parity_devs) {
if (match_count > raid_seg->segtype->parity_devs) {
log_error("Unable to replace more than %u PVs from (%s) %s",
raid_seg->segtype->parity_devs,
lvseg_name(raid_seg), display_lvname(lv));
return 0;
} else if (match_count == raid_seg->segtype->parity_devs &&
match_count > partial_lvs / 2) {
log_warn("You'll loose all resilience on %s LV %s during replacement"
" until resynchronization has finished!",
lvseg_name(raid_seg), display_lvname(lv));
if (!yes && yes_no_prompt("WARNING: Do you really want to replace"
" PVs in %s LV %s?? [y/n]: ",
lvseg_name(raid_seg), display_lvname(lv))) {
log_warn("PVs in LV %s NOT replaced!", display_lvname(lv));
return 0;
}
if (sigint_caught())
return_0;
}
} else if (seg_is_any_raid10(raid_seg)) {
uint32_t copies = raid_seg->data_copies, i;
@ -6949,7 +7047,7 @@ PFLA("match_count=%u", match_count);
if (!(i % copies))
rebuilds_per_group = 0;
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs))
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs, &partial_lvs))
rebuilds_per_group++;
if (rebuilds_per_group >= copies) {
@ -6967,7 +7065,7 @@ PFLA("match_count=%u", match_count);
uint32_t rebuilds = 0;
for (i = 0; i < raid_seg->area_count; i++)
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs))
if (_sub_lv_needs_rebuilding(raid_seg, s, remove_pvs, &partial_lvs))
rebuilds++;
if (rebuilds >= copies) {
@ -6985,67 +7083,60 @@ PFLA("match_count=%u", match_count);
return 0;
}
#if 1
if (duplicating)
{
PFLA("%s", "DUPLICATING");
goto extract;
}
#endif
/*
* Allocate the new image components first
* - This makes it easy to avoid all currently used devs
* - We can immediately tell if there is enough space
*
* - We need to change the LV names when we insert them.
*/
while (!_alloc_image_components(lv, allocate_pvs, match_count,
&new_meta_lvs,
&new_data_lvs)) {
if (!(lv->status & PARTIAL_LV)) {
log_error("LV %s in not partial.", display_lvname(lv));
return 0;
}
/* If this is not the top-level duplicating raid1 LV -> allocate image component pairs */
if (!duplicating) {
/*
* We failed allocating all required devices so
* we'll try less devices; we must set partial_activation
* Allocate the new image components first
* - This makes it easy to avoid all currently used devs
* - We can immediately tell if there is enough space
*
* - We need to change the LV names when we insert them.
*/
lv->vg->cmd->partial_activation = 1;
while (!_alloc_image_components(lv, allocate_pvs, match_count,
&new_meta_lvs,
&new_data_lvs)) {
if (!(lv->status & PARTIAL_LV)) {
log_error("LV %s in not partial.", display_lvname(lv));
return 0;
}
/* This is a repair, so try to do better than all-or-nothing */
if (match_count > 0 && !partial_segment_removed) {
log_error("Failed to replace %u devices.", match_count);
match_count--;
log_error("Attempting to replace %u instead.", match_count);
} else if (!partial_segment_removed) {
/*
* match_count = 0
*
* We are down to the last straw. We can only hope
* that a failed PV is just one of several PVs in
* the image; and if we extract the image, there may
* be enough room on the image's other PVs for a
* reallocation of the image.
* We failed allocating all required devices so
* we'll try less devices; we must set partial_activation
*/
if (!_remove_partial_multi_segment_image(lv, remove_pvs))
return_0;
lv->vg->cmd->partial_activation = 1;
/* This is a repair, so try to do better than all-or-nothing */
if (match_count > 0 && !partial_segment_removed) {
log_error("Failed to replace %u devices.", match_count);
match_count--;
log_error("Attempting to replace %u instead.", match_count);
} else if (!partial_segment_removed) {
/*
* match_count = 0
*
* We are down to the last straw. We can only hope
* that a failed PV is just one of several PVs in
* the image; and if we extract the image, there may
* be enough room on the image's other PVs for a
* reallocation of the image.
*/
if (!_remove_partial_multi_segment_image(lv, remove_pvs))
return_0;
match_count = 1;
partial_segment_removed = 1;
match_count = 1;
partial_segment_removed = 1;
} else {
log_error("Failed to allocate replacement images for %s",
display_lvname(lv));
return 0;
} else {
log_error("Failed to allocate replacement images for %s",
display_lvname(lv));
return 0;
}
}
}
#if 1
extract:
#endif
/*
* Remove the old images
* - If we did this before the allocate, we wouldn't have to rename
@ -7058,9 +7149,12 @@ extract:
* the image with the error target. Thus, the full set of PVs is
* supplied - knowing that only the image with the error target
* will be affected.
*
* - If this is the duplicating top-level LV, only extract
* any failed metadata devices.
*/
/* HM FIXME: top-level raid1 in case of duplication may have rmeta devs failed but not the rimage ones */
/* never extract top-level raid1 images, because they are stacked LVs (e.g. raid5) */
if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
(partial_segment_removed || dm_list_empty(remove_pvs)) ?
&lv->vg->pvs : remove_pvs, 0 /* Don't shift */,
@ -7069,24 +7163,21 @@ extract:
display_lvname(lv));
return 0;
}
PFLA("dm_list_size(&old_lvs)=%u", dm_list_size(&old_lvs));
/*
* Now that they are extracted and visible, make the system aware
* of their new names.
*/
dm_list_iterate_items(lvl, &old_lvs)
{
PFLA("old_lv=%s", display_lvname(lvl->lv));
if (!activate_lv_excl_local(lv->vg->cmd, lvl->lv))
return_0;
}
#if 1
/* Top-level LV needs special treatment of its metadata LVs */
if (duplicating) {
struct lv_list *lvlist;
/* HM FIXME: if we don't need to clear the new metadata LVs, avoid lvlist altogether */
if (!(lvlist = dm_pool_alloc(lv->vg->vgmem, dm_list_size(&old_lvs) * sizeof(*lvlist))))
return 0;
@ -7101,19 +7192,9 @@ PFLA("old_lv=%s", display_lvname(lvl->lv));
if (!__alloc_rmeta_for_lv(seg_lv(raid_seg, s), &lvlist[sd].lv, allocate_pvs))
return 0;
if (!(lvlist[sd].lv->name = _generate_raid_name(lv, "_rdmeta", s)))
return_0;
dm_list_add(&new_meta_lvs, &lvlist[sd].list);
sd++;
}
#if 0
log_debug_metadata("Clearing newly allocated metadata LVs of %s", display_lvname(lv));
if (!_clear_lvs(&new_meta_lvs)) {
log_error("Failed to clear newly allocated metadata LVs of %s", display_lvname(lv));
return_0;
}
#endif
}
#endif
@ -7125,29 +7206,24 @@ PFLA("old_lv=%s", display_lvname(lvl->lv));
*
* Insert new allocated image component pairs into now empty area slots.
*/
PFLA("duplicating=%d", duplicating);
for (s = 0, sd = raid_seg->area_count; s < raid_seg->area_count; s++, sd++) {
PFL();
if (seg_type(raid_seg, s) == AREA_UNASSIGNED)
PFLA("%s image area %u UNASSIGNED", display_lvname(lv), s);
if (seg_type(raid_seg, s) == AREA_UNASSIGNED) {
if (!_generate_name_and_set_segment(lv, s, sd, &new_data_lvs, tmp_names))
return 0;
PFLA("lv %s -> %s", display_lvname(lv), display_lvname(seg_lv(raid_seg, s)));
}
if (seg_type(raid_seg, s) == AREA_UNASSIGNED &&
!_generate_name_and_set_segment(lv, duplicating, s, sd, &new_data_lvs, tmp_names))
return 0;
PFL();
if (raid_seg->meta_areas && seg_metatype(raid_seg, s) == AREA_UNASSIGNED)
PFLA("%s meta area %u UNASSIGNED", display_lvname(lv), s);
if (raid_seg->meta_areas &&
seg_metatype(raid_seg, s) == AREA_UNASSIGNED) {
if (!_generate_name_and_set_segment(lv, s, s, &new_meta_lvs, tmp_names))
if (!_generate_name_and_set_segment(lv, duplicating, s, s, &new_meta_lvs, tmp_names))
return 0;
/* HM FIXME: can I do a partial rebuild (kernel rejects w/o LV_REBUILD) */
seg_lv(raid_seg, s)->status |= LV_REBUILD;
PFLA("lv %s -> %s", display_lvname(lv), display_lvname(seg_metalv(raid_seg, s)));
}
}
@ -7537,7 +7613,7 @@ int partial_raid_lv_supports_degraded_activation(const struct logical_volume *cl
return !not_capable;
}
/* raid10_far helper: ensure consistent image LVs have been passed in for @seg */
/* HM raid10_far helper: ensure consistent image LVs have been passed in for @seg */
static int _raid10_seg_images_sane(struct lv_segment *seg)
{
uint32_t len = 0, s;
@ -7576,7 +7652,7 @@ static int _raid10_seg_images_sane(struct lv_segment *seg)
return 1;
}
/* raid10_far helper: split up all data image sub LVs of @lv from @start LE to @end LE in @split_len increments */
/* HM raid10_far helper: split up all data image sub LVs of @lv from @start LE to @end LE in @split_len increments */
static int _split_lv_data_images(struct logical_volume *lv,
uint32_t start, uint32_t end,
uint32_t split_len)
@ -7598,6 +7674,8 @@ static int _split_lv_data_images(struct logical_volume *lv,
}
/*
* HM
*
* Reorder segments for @extents length in @lv;
* @extend flag indicates extension/reduction request.
*
@ -7715,7 +7793,7 @@ PFL();
}
/*
* Helper: create a raid01 (mirrors on top of stripes) LV
* HM Helper: create a raid01 (mirrors on top of stripes) LV
*/
int lv_create_raid01(struct logical_volume *lv, const struct segment_type *segtype,
unsigned data_copies, unsigned stripes,

View File

@ -530,7 +530,8 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
}
if (arg_count(cmd, merge_ARG)) {
if ((argc == 1) && strstr(argv[0], "_rimage_"))
if ((argc == 1) &&
(strstr(argv[0], "_rimage_") || strstr(argv[0], "_dup_")))
lp->merge_mirror = 1;
else
lp->merge = 1;
@ -1756,7 +1757,7 @@ PFLA("image_count=%u\n", image_count);
return lv_raid_merge(lv);
if (arg_count(cmd, trackchanges_ARG))
return lv_raid_split_and_track(lv, lp->pvh);
return lv_raid_split_and_track(lv, lp->lv_split_name, lp->pvh);
if (arg_count(cmd, splitmirrors_ARG))
return lv_raid_split(lv, lp->lv_split_name, image_count, lp->pvh);
@ -1826,7 +1827,7 @@ PFLA("image_count=%u\n", image_count);
}
if (arg_count(cmd, replace_ARG))
return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
return lv_raid_replace(lv, lp->yes, lp->replace_pvh, lp->pvh);
if (arg_count(cmd, repair_ARG)) {
if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
@ -1868,7 +1869,7 @@ PFLA("replace=%d", replace);
PFLA("dm_list_size(failed_pvs)=%u", dm_list_size(failed_pvs));
if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
if (!lv_raid_replace(lv, lp->yes, failed_pvs, lp->pvh)) {
log_error("Failed to replace faulty devices in"
" %s/%s.", lv->vg->name, lv->name);
return 0;