diff --git a/WHATS_NEW b/WHATS_NEW index 18ef848da..9bd257081 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,6 +1,7 @@ Version 2.02.02 - ==================================== Always print warning if activation is disabled. + vgreduce removes mirror images. Add --mirrorsonly to vgreduce. vgreduce replaces active LVs with error segment before removing them. Set block_on_error parameter if available. diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c index 2d74fd5ff..1e7ee09de 100644 --- a/lib/mirror/mirrored.c +++ b/lib/mirror/mirrored.c @@ -326,7 +326,7 @@ static int _target_present(void) static int checked = 0; static int present = 0; uint32_t maj, min, patchlevel; - unsigned maj2, min2; + unsigned maj2, min2, patchlevel2; char vsn[80]; if (!checked) { @@ -342,8 +342,8 @@ static int _target_present(void) maj == 1 && (min >= 1 || (min == 0 && driver_version(vsn, sizeof(vsn)) && - sscanf(vsn, "%u.%u", &maj2, &min2) == 2 && - maj2 >= 4 && min2 >= 5))) /* RHEL4U3 */ + sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 && + maj2 == 4 && min2 == 5 && patchlevel2 == 0))) /* RHEL4U3 */ _block_on_error_available = 1; } diff --git a/tools/vgreduce.c b/tools/vgreduce.c index 1954e553b..b6f46bad3 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -50,7 +50,7 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl) static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, int *list_unsafe, struct list *lvs_changed) { - struct lv_segment *snap_seg; + struct lv_segment *snap_seg, *mirror_seg; struct list *snh, *snht; struct logical_volume *cow; struct lv_list *lvl; @@ -113,6 +113,7 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, */ if (lv_info(cmd, lv, &info, 0) && info.exists) { extents = lv->le_count; + mirror_seg = first_seg(lv)->mirror_seg; if (!lv_empty(lv)) { stack; return 0; @@ -123,6 +124,10 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, stack; return 0; } + if (mirror_seg) { + first_seg(lv)->status |= MIRROR_IMAGE; + first_seg(lv)->mirror_seg = mirror_seg; + } if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) { log_error("lv_list alloc failed"); @@ -147,11 +152,13 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) struct list *pvh, *pvht; struct list *lvh, *lvht; struct pv_list *pvl; - struct lv_list *lvl; + struct lv_list *lvl, *lvl2, *lvlt; struct logical_volume *lv; struct physical_volume *pv; - struct lv_segment *seg; + struct lv_segment *seg, *mirrored_seg; + struct lv_segment_area area; unsigned int s; + uint32_t mimages; int list_unsafe, only_mirror_images_found; LIST_INIT(lvs_changed); only_mirror_images_found = 1; @@ -244,7 +251,44 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) } } -/* FIXME If any lvs_changed belong to mirrors, reduce those mirrors */ + /* Remove lost mirror images from mirrors */ + list_iterate_items(lvl, &vg->lvs) { + mirrored_seg = first_seg(lvl->lv); + if (!seg_is_mirrored(mirrored_seg)) + continue; + mimages = mirrored_seg->area_count; + for (s = 0; s < mirrored_seg->area_count; s++) { + list_iterate_items_safe(lvl2, lvlt, &lvs_changed) { + if (seg_type(mirrored_seg, s) != AREA_LV || + lvl2->lv != seg_lv(mirrored_seg, s)) + continue; + list_del(&lvl2->list); + area = mirrored_seg->areas[mimages - 1]; + mirrored_seg->areas[mimages - 1] = mirrored_seg->areas[s]; + mirrored_seg->areas[s] = area; + mimages--; /* FIXME Assumes uniqueness */ + } + } + if (mimages != mirrored_seg->area_count) { + if (!remove_mirror_images(mirrored_seg, mimages, NULL, 0)) { + stack; + return 0; + } + + if (!vg_write(vg)) { + log_error("Failed to write out updated " + "VG for %s", vg->name); + return 0; + } + + if (!vg_commit(vg)) { + log_error("Failed to commit updated VG " + "for %s", vg->name); + vg_revert(vg); + return 0; + } + } + } /* Deactivate error LVs */ if (!test_mode()) {