Multiple fixes for 'vgreduce --removemissing' on stacked mirror * reconfigure_mirror_images() should call _remove_mirror_images() The existing user of reconfigure_mirror_images() (i.e. vgreduce) expects it to remove the specified number of mirror images from the given mirror segment. vgreduce is responsible to check LVs on missing PVs and sort the seg->areas so that the images being removed become last. It passes removable_pvs=NULL for reconfigure_mirror_images(). So, reconfigure_mirror_images() should just takes care of the given segment, not walking down the stack. * _remove_mirror_images() to handle '0 area' case Under the context of 'vgreduce --removemissing', it's possible that the mirrored LV no longer has valid mirror images. In this case, vgreduce should call reconfigure_mirror_images() and it calls _remove_mirror_images() to remove all mirror images. _remove_mirror_images() should empty the LV and add error segment. * _make_vg_consistent() for stacked mirror _make_vg_consistent() is a core function for 'vgreduce --removemissing'. For mirrored LV, the function is 2-pass. First, it goes through LVs and marks those which are on missing PVs. Second, for any mirrored LVs, reorder areas so that marked LVs become the last areas and call reconfigure_mirror_images() to remove them. As a result of the 2nd pass, 2 things could happen: - all images are removed from the mirrored LV -> the mirrored LV should be marked and restart the 2nd pass - a temporary layer below the mirrored LV is removed -> need to recheck the areas Index: LVM2.work/lib/metadata/mirror.c =================================================================== --- LVM2.work.orig/lib/metadata/mirror.c +++ LVM2.work/lib/metadata/mirror.c @@ -515,6 +515,15 @@ static int _remove_mirror_images(struct log_error("Failed to add mirror images"); return 0; } + } else if (new_area_count == 0) { + /* All mirror images are gone. + * It can happen for vgreduce --removemissing. */ + _remove_mirror_log(mirrored_seg); + lv->status &= ~MIRRORED; + lv->status &= ~MIRROR_NOTSYNCED; + if (!lv_remap_error(lv)) + return_0; + remove_log = 1; } else if (remove_log) _remove_mirror_log(mirrored_seg); @@ -795,8 +804,8 @@ int reconfigure_mirror_images(struct lv_ */ init_mirror_in_sync(in_sync); - r = remove_mirror_images(mirrored_seg->lv, num_mirrors, - removable_pvs, remove_log); + r = _remove_mirror_images(mirrored_seg->lv, old_num_mirrors - num_mirrors, + removable_pvs, remove_log, 0, NULL); if (!r) /* Unable to remove bad devices */ return 0; Index: LVM2.work/tools/vgreduce.c =================================================================== --- LVM2.work.orig/tools/vgreduce.c +++ LVM2.work/tools/vgreduce.c @@ -255,8 +255,10 @@ static int _make_vg_consistent(struct cm } } + lvs_changed_altered: /* Remove lost mirror images from mirrors */ list_iterate_items(lvl, &vg->lvs) { + mirrored_seg_altered: mirrored_seg = first_seg(lvl->lv); if (!seg_is_mirrored(mirrored_seg)) continue; @@ -315,6 +317,23 @@ static int _make_vg_consistent(struct cm vg_revert(vg); return 0; } + + /* mirrored LV no longer has valid mimages. + * So add it to lvs_changed for removal. + * For this LV may be an area of other mirror, + * restart the loop. */ + if (!mimages) { + if (!_remove_lv(cmd, lvl->lv, + &list_unsafe, &lvs_changed)) + return_0; + goto lvs_changed_altered; + } + + /* As a result of reconfigure_mirror_images(), + * first_seg(lv) may now be different seg. + * e.g. a temporary layer might be removed. + * So check the mirrored_seg again. */ + goto mirrored_seg_altered; } } Index: LVM2.work/lib/metadata/lv_manip.c =================================================================== --- LVM2.work.orig/lib/metadata/lv_manip.c +++ LVM2.work/lib/metadata/lv_manip.c @@ -459,6 +459,24 @@ int lv_empty(struct logical_volume *lv) } /* + * Empty an LV and add error segment. + */ +int lv_remap_error(struct logical_volume *lv) +{ + uint32_t len = lv->le_count; + + if (!lv_empty(lv)) + return_0; + + if (!lv_add_virtual_segment(lv, 0, len, + get_segtype_from_string(lv->vg->cmd, + "error"))) + return_0; + + return 1; +} + +/* * Remove given number of extents from LV. */ int lv_reduce(struct logical_volume *lv, uint32_t extents) Index: LVM2.work/lib/metadata/metadata-exported.h =================================================================== --- LVM2.work.orig/lib/metadata/metadata-exported.h +++ LVM2.work/lib/metadata/metadata-exported.h @@ -378,6 +378,9 @@ int lv_reduce(struct logical_volume *lv, /* Empty an LV prior to deleting it */ int lv_empty(struct logical_volume *lv); +/* Empty an LV and add error segment */ +int lv_remap_error(struct logical_volume *lv); + /* Entry point for all LV extent allocations */ int lv_extend(struct logical_volume *lv, const struct segment_type *segtype,