From 31e9db26907d830073e2cd4b7f9d0cfe1f1de5ae Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 20 Dec 2007 18:55:46 +0000 Subject: [PATCH] stacked mirror support (incomplete) --- WHATS_NEW | 1 + lib/metadata/lv_manip.c | 120 ++++++++++---- lib/metadata/metadata-exported.h | 14 +- lib/metadata/metadata.c | 6 +- lib/metadata/metadata.h | 4 +- lib/metadata/mirror.c | 266 +++++++++++++++++++++++++------ tools/lvconvert.c | 22 ++- tools/lvresize.c | 4 +- tools/toollib.c | 6 + 9 files changed, 343 insertions(+), 100 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index c56b209c0..29f7756a4 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.30 - =================================== + Add support for stacked mirrors. Major restructuring of pvmove and lvconvert layer manipulation code. Replace tools/fsadm with scripts/fsadm.sh. Append fields to report/pvsegs_cols_verbose. diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 926d071e3..7b9d067a5 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -1407,6 +1407,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv, for (m = old_area_count; m < new_area_count; m++) { set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count], 0, status); first_seg(sub_lvs[m - old_area_count])->mirror_seg = seg; + sub_lvs[m - old_area_count]->status &= ~VISIBLE_LV; } return 1; @@ -1451,6 +1452,39 @@ int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv) return 1; } +static int _lv_extend_mirror(struct alloc_handle *ah, + struct logical_volume *lv, + uint32_t extents, uint32_t first_area) +{ + struct lv_segment *seg; + uint32_t m, s; + + seg = first_seg(lv); + for (m = first_area, s = 0; s < seg->area_count; s++) { + if (is_temporary_mirror_layer(seg_lv(seg, s))) { + if (!_lv_extend_mirror(ah, seg_lv(seg, s), extents, m)) + return_0; + m += lv_mirror_count(seg_lv(seg, s)); + continue; + } + + if (!lv_add_segment(ah, m++, 1, seg_lv(seg, s), + get_segtype_from_string(lv->vg->cmd, + "striped"), + 0, 0, 0, NULL)) { + log_error("Aborting. Failed to extend %s.", + seg_lv(seg, s)->name); + return 0; + } + } + seg->area_len += extents; + seg->len += extents; + lv->le_count += extents; + lv->size += (uint64_t) extents *lv->vg->extent_size; + + return 1; +} + /* * Entry point for single-step LV allocation + extension. */ @@ -1464,9 +1498,7 @@ int lv_extend(struct logical_volume *lv, alloc_policy_t alloc) { int r = 1; - uint32_t m; struct alloc_handle *ah; - struct lv_segment *seg; if (segtype_is_virtual(segtype)) return lv_add_virtual_segment(lv, status, extents, segtype); @@ -1482,21 +1514,8 @@ int lv_extend(struct logical_volume *lv, goto out; } } else { - seg = first_seg(lv); - for (m = 0; m < mirrors; m++) { - if (!lv_add_segment(ah, m, 1, seg_lv(seg, m), - get_segtype_from_string(lv->vg->cmd, - "striped"), - 0, 0, 0, NULL)) { - log_error("Aborting. Failed to extend %s.", - seg_lv(seg, m)->name); - return 0; - } - } - seg->area_len += extents; - seg->len += extents; - lv->le_count += extents; - lv->size += (uint64_t) extents *lv->vg->extent_size; + if (!_lv_extend_mirror(ah, lv, extents, 0)) + return_0; } out: @@ -1599,10 +1618,14 @@ static int _for_each_sub_lv(struct cmd_context *cmd, struct logical_volume *lv, list_iterate_items(seg, &lv->segments) { if (seg->log_lv && !func(cmd, seg->log_lv, data)) return 0; - for (s = 0; s < seg->area_count; s++) - if (seg_type(seg, s) == AREA_LV && - !func(cmd, seg_lv(seg, s), data)) + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) != AREA_LV) + continue; + if (!func(cmd, seg_lv(seg, s), data)) return 0; + if (!_for_each_sub_lv(cmd, seg_lv(seg, s), func, data)) + return 0; + } } return 1; @@ -2180,23 +2203,62 @@ static void _move_lv_segments(struct logical_volume *lv_to, lv_from->size = 0; } +/* + * Find a parent LV for the layer_lv in the lv + */ +struct logical_volume *find_parent_for_layer(struct logical_volume *lv, + struct logical_volume *layer_lv) +{ + struct logical_volume *parent; + struct lv_segment *seg; + uint32_t s; + + list_iterate_items(seg, &lv->segments) { + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) != AREA_LV) + continue; + if (seg_lv(seg, s) == layer_lv) + return lv; + parent = find_parent_for_layer(seg_lv(seg, s), + layer_lv); + if (parent) + return parent; + } + } + return NULL; +} + /* Remove a layer from the LV */ -/* FIXME: how to specify what should be removed if multiple layers stacked? */ -int remove_layer_from_lv(struct logical_volume *lv) +int remove_layer_from_lv(struct logical_volume *lv, + struct logical_volume *layer_lv) { - struct logical_volume *orig_lv; + struct logical_volume *parent; + struct segment_type *segtype; + + parent = find_parent_for_layer(lv, layer_lv); + if (!parent) { + log_error("Failed to find layer %s in %s", + layer_lv->name, lv->name); + return 0; + } /* * Before removal, the layer should be cleaned up, * i.e. additional segments and areas should have been removed. */ - if (list_size(&lv->segments) != 1 || - first_seg(lv)->area_count != 1 || - seg_type(first_seg(lv), 0) != AREA_LV) - return 0; + if (list_size(&parent->segments) != 1 || + first_seg(parent)->area_count != 1 || + seg_type(first_seg(parent), 0) != AREA_LV || + layer_lv != seg_lv(first_seg(parent), 0) || + parent->le_count != layer_lv->le_count) + return_0; + + _move_lv_segments(parent, layer_lv, 0, 0); - orig_lv = seg_lv(first_seg(lv), 0); - _move_lv_segments(lv, orig_lv, 0, 0); + /* Replace the empty layer with error segment */ + segtype = get_segtype_from_string(lv->vg->cmd, "error"); + if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype)) + return_0; return 1; } diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index f8b870403..4489a13c6 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -398,7 +398,10 @@ int remove_layers_for_segments_all(struct cmd_context *cmd, struct list *lvs_changed); int split_parent_segments_for_layer(struct cmd_context *cmd, struct logical_volume *layer_lv); -int remove_layer_from_lv(struct logical_volume *lv); +struct logical_volume *find_parent_for_layer(struct logical_volume *lv, + struct logical_volume *layer_lv); +int remove_layer_from_lv(struct logical_volume *lv, + struct logical_volume *layer_lv); struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd, struct logical_volume *lv_where, uint32_t status, @@ -417,7 +420,7 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd, const char *pv_name); /* Find LV segment containing given LE */ -struct lv_segment *first_seg(struct logical_volume *lv); +struct lv_segment *first_seg(const struct logical_volume *lv); /* @@ -458,8 +461,8 @@ int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv, #define MIRROR_BY_SEG 0x00000001U /* segment-by-segment mirror */ #define MIRROR_BY_LV 0x00000002U /* mirror by mimage LVs */ -uint32_t lv_mirror_count(struct logical_volume *lv); -struct alloc_handle; +int is_temporary_mirror_layer(const struct logical_volume *lv); +uint32_t lv_mirror_count(const struct logical_volume *lv); uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents, uint32_t region_size); int remove_mirrors_from_segments(struct logical_volume *lv, @@ -468,7 +471,7 @@ int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t region_size, struct list *allocatable_pvs, alloc_policy_t alloc); -int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, +int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors, struct list *removable_pvs, unsigned remove_log); int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv, uint32_t mirrors, uint32_t stripes, uint32_t region_size, @@ -482,6 +485,7 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, struct list *removable_pvs, unsigned remove_log); +int collapse_mirrored_lv(struct logical_volume *lv); struct logical_volume *find_pvmove_lv(struct volume_group *vg, struct device *dev, uint32_t lv_type); diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index fbfffdffa..f79a763da 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -937,7 +937,7 @@ static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd, } /* Find segment at a given logical extent in an LV */ -struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le) +struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le) { struct lv_segment *seg; @@ -948,7 +948,7 @@ struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le) return NULL; } -struct lv_segment *first_seg(struct logical_volume *lv) +struct lv_segment *first_seg(const struct logical_volume *lv) { struct lv_segment *seg = NULL; @@ -959,7 +959,7 @@ struct lv_segment *first_seg(struct logical_volume *lv) } /* Find segment at a given physical extent in a PV */ -struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe) +struct pv_segment *find_peg_by_pe(const struct physical_volume *pv, uint32_t pe) { struct pv_segment *peg; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index e3a5e6872..e95d3cad7 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -264,10 +264,10 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, struct physical_volume *find_pv(struct volume_group *vg, struct device *dev); /* Find LV segment containing given LE */ -struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le); +struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le); /* Find PV segment containing given LE */ -struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe); +struct pv_segment *find_peg_by_pe(const struct physical_volume *pv, uint32_t pe); /* * Remove a dev_dir if present. diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index 5ea7564ca..0eca87964 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -32,12 +32,41 @@ #define MIRROR_ALLOCATE 1 #define MIRROR_ALLOCATE_ANYWHERE 2 +/* + * Returns true if the lv is temporary mirror layer for resync + */ +int is_temporary_mirror_layer(const struct logical_volume *lv) +{ + if (lv->status & MIRROR_IMAGE + && lv->status & MIRRORED + && !(lv->status & LOCKED)) + return 1; + + return 0; +} + /* * Returns the number of mirrors of the LV */ -uint32_t lv_mirror_count(struct logical_volume *lv) +uint32_t lv_mirror_count(const struct logical_volume *lv) { - return (lv->status & MIRRORED) ? first_seg(lv)->area_count : 1; + struct lv_segment *seg; + uint32_t s, mirrors; + + if (!(lv->status & MIRRORED)) + return 1; + + seg = first_seg(lv); + mirrors = seg->area_count; + + for (s = 0; s < seg->area_count; s++) { + if (seg_type(seg, s) != AREA_LV) + continue; + if (is_temporary_mirror_layer(seg_lv(seg, s))) + mirrors += lv_mirror_count(seg_lv(seg, s)) - 1; + } + + return mirrors; } struct lv_segment *find_mirror_seg(struct lv_segment *seg) @@ -68,21 +97,21 @@ uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents, /* * Delete independent/orphan LV, it must acquire lock. */ -static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv) +static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv) { - struct cmd_context *cmd = mirrored_seg->lv->vg->cmd; + struct cmd_context *cmd = mirror_lv->vg->cmd; struct str_list *sl; /* Inherit tags - maybe needed for activation */ - if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) { - list_iterate_items(sl, &mirrored_seg->lv->tags) + if (!str_list_match_list(&mirror_lv->tags, &lv->tags)) { + list_iterate_items(sl, &mirror_lv->tags) if (!str_list_add(cmd->mem, &lv->tags, sl->str)) { log_error("Aborting. Unable to tag."); return 0; } - if (!vg_write(mirrored_seg->lv->vg) || - !vg_commit(mirrored_seg->lv->vg)) { + if (!vg_write(mirror_lv->vg) || + !vg_commit(mirror_lv->vg)) { log_error("Intermediate VG commit for orphan volume failed."); return 0; } @@ -101,29 +130,31 @@ static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv } /* - * Reduce mirrored_seg to num_mirrors images. + * Remove num_removed images from mirrored_seg */ -int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, - struct list *removable_pvs, unsigned remove_log) +static int _remove_mirror_images(struct logical_volume *lv, + uint32_t num_removed, + struct list *removable_pvs, + unsigned remove_log, struct list *orphan_lvs) { uint32_t m; - uint32_t extents; uint32_t s, s1; struct logical_volume *sub_lv; struct logical_volume *log_lv = NULL; struct logical_volume *lv1 = NULL; struct physical_volume *pv; - struct lv_segment *seg; + struct lv_segment *seg, *mirrored_seg = first_seg(lv); struct lv_segment_area area; int all_pvs_removable, pv_found; struct pv_list *pvl; uint32_t old_area_count = mirrored_seg->area_count; uint32_t new_area_count = mirrored_seg->area_count; - struct segment_type *segtype; + struct lv_list *lvl; + struct list tmp_orphan_lvs; log_very_verbose("Reducing mirror set from %" PRIu32 " to %" PRIu32 " image(s)%s.", - old_area_count, num_mirrors, + old_area_count, old_area_count - num_removed, remove_log ? " and no log volume" : ""); /* Move removable_pvs to end of array */ @@ -162,39 +193,46 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, mirrored_seg->areas[s] = area; } /* Found enough matches? */ - if (new_area_count == num_mirrors) + if (old_area_count - new_area_count == num_removed) break; } - if (new_area_count == mirrored_seg->area_count) { + if (old_area_count == new_area_count) { log_error("No mirror images found using specified PVs."); return 0; } - } + } else + new_area_count = old_area_count - num_removed; - for (m = num_mirrors; m < mirrored_seg->area_count; m++) { + /* Remove mimage LVs from the segment */ + list_init(&tmp_orphan_lvs); + for (m = new_area_count; m < mirrored_seg->area_count; m++) { seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE; seg_lv(mirrored_seg, m)->status |= VISIBLE_LV; + if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl)))) { + log_error("lv_list alloc failed"); + return 0; + } + lvl->lv = seg_lv(mirrored_seg, m); + list_add(&tmp_orphan_lvs, &lvl->list); } + mirrored_seg->area_count = new_area_count; - mirrored_seg->area_count = num_mirrors; + /* Save log_lv as mirrored_seg may not be available after + * remove_layer_from_lv(), */ + log_lv = mirrored_seg->log_lv; /* If no more mirrors, remove mirror layer */ - if (num_mirrors == 1) { + if (new_area_count == 1) { lv1 = seg_lv(mirrored_seg, 0); - extents = lv1->le_count; - remove_layer_from_lv(mirrored_seg->lv); - mirrored_seg->lv->status &= ~MIRRORED; - mirrored_seg->lv->status &= ~MIRROR_NOTSYNCED; - remove_log = 1; - /* Replace mirror with error segment */ - segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error"); - if (!lv_add_virtual_segment(lv1, 0, extents, segtype)) + mirrored_seg->log_lv = NULL; + if (!remove_layer_from_lv(lv, lv1)) return_0; + lv->status &= ~MIRRORED; + lv->status &= ~MIRROR_NOTSYNCED; + remove_log = 1; } - if (remove_log && mirrored_seg->log_lv) { - log_lv = mirrored_seg->log_lv; - mirrored_seg->log_lv = NULL; + if (remove_log && log_lv) { log_lv->status &= ~MIRROR_LOG; log_lv->status |= VISIBLE_LV; } @@ -228,20 +266,152 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors, return 0; } - /* Delete the 'orphan' LVs */ - for (m = num_mirrors; m < old_area_count; m++) - if (!_delete_lv(mirrored_seg, seg_lv(mirrored_seg, m))) - return 0; + /* Save or delete the 'orphan' LVs */ + if (orphan_lvs) { + *orphan_lvs = tmp_orphan_lvs; + orphan_lvs->n->p = orphan_lvs; + orphan_lvs->p->n = orphan_lvs; + } else { + list_iterate_items(lvl, &tmp_orphan_lvs) + if (!_delete_lv(lv, lvl->lv)) + return 0; + } - if (lv1 && !_delete_lv(mirrored_seg, lv1)) + if (lv1 && !_delete_lv(lv, lv1)) return 0; - if (log_lv && !_delete_lv(mirrored_seg, log_lv)) + if (remove_log && log_lv && !_delete_lv(lv, log_lv)) return 0; return 1; } +/* + * Remove the number of mirror images from the LV + */ +int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors, + struct list *removable_pvs, unsigned remove_log) +{ + uint32_t num_removed, removed_once; + uint32_t existing_mirrors = lv_mirror_count(lv); + + num_removed = existing_mirrors - num_mirrors; + + while (num_removed) { + if (num_removed < first_seg(lv)->area_count) + removed_once = num_removed; + else + removed_once = first_seg(lv)->area_count - 1; + + if (!_remove_mirror_images(lv, removed_once, + removable_pvs, remove_log, NULL)) + return_0; + + num_removed -= removed_once; + } + + return 1; +} + +static int _mirrored_lv_in_sync(struct logical_volume *lv) +{ + float sync_percent; + + if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent, NULL)) { + log_error("Unable to determine mirror sync status of %s/%s.", + lv->vg->name, lv->name); + return 0; + } + + if (sync_percent >= 100.0) + return 1; + + return 0; +} + +static int _merge_mirror_images(struct logical_volume *lv, + const struct list *mimages) +{ + int addition = list_size(mimages); + struct logical_volume **img_lvs; + struct lv_list *lvl; + int i = 0; + + if (!addition) + return 1; + + if (!(img_lvs = alloca(sizeof(*img_lvs) * addition))) + return_0; + + list_iterate_items(lvl, mimages) + img_lvs[i++] = lvl->lv; + + return lv_add_mirror_lvs(lv, img_lvs, addition, + MIRROR_IMAGE, first_seg(lv)->region_size); +} + +/* + * Return a temporary LV for resyncing added mirror image. + * Add other mirror legs to lvs list. + */ +static struct logical_volume *_find_tmp_mirror(struct logical_volume *lv) +{ + struct lv_segment *seg; + + if (!(lv->status & MIRRORED)) + return NULL; + + seg = first_seg(lv); + + /* Temporary mirror is always area_num == 0 */ + if (seg_type(seg, 0) == AREA_LV && + is_temporary_mirror_layer(seg_lv(seg, 0))) + return seg_lv(seg, 0); + + return NULL; +} + +/* + * Collapsing temporary mirror layers. + * + * When mirrors are added to already-mirrored LV, a temporary mirror layer + * is inserted at the top of the stack to reduce resync work. + * The function will remove the intermediate layer and collapse the stack + * as far as mirrors are in-sync. + * + * The function is destructive: to remove intermediate mirror layers, + * VG metadata commits and suspend/resume are necessary. + */ +int collapse_mirrored_lv(struct logical_volume *lv) +{ + struct logical_volume *tmp_lv, *parent_lv; + struct list lvlist; + + while ((tmp_lv = _find_tmp_mirror(lv))) { + parent_lv = find_parent_for_layer(lv, tmp_lv); + if (!_mirrored_lv_in_sync(parent_lv)) { + log_verbose("Not collapsing %s: out-of-sync", + parent_lv->name); + return 1; + } + + list_init(&lvlist); + if (!_remove_mirror_images(parent_lv, + first_seg(parent_lv)->area_count - 1, + NULL, 1, &lvlist)) { + log_error("Failed to release mirror images"); + return 0; + } + + if (!_merge_mirror_images(parent_lv, &lvlist)) { + log_error("Failed to add mirror images"); + return 0; + } + } + + return 1; +} + static int get_mirror_fault_policy(struct cmd_context *cmd __attribute((unused)), int log_policy) { @@ -338,19 +508,13 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr struct list *removable_pvs, unsigned remove_log) { int r; - int in_sync = 0; + int in_sync; int log_policy, dev_policy; uint32_t old_num_mirrors = mirrored_seg->area_count; int had_log = (mirrored_seg->log_lv) ? 1 : 0; - float sync_percent = 0; /* was the mirror in-sync before problems? */ - if (!lv_mirror_percent(mirrored_seg->lv->vg->cmd, - mirrored_seg->lv, 0, &sync_percent, NULL)) - log_error("WARNING: Unable to determine mirror sync status of %s/%s.", - mirrored_seg->lv->vg->name, mirrored_seg->lv->name); - else if (sync_percent >= 100.0) - in_sync = 1; + in_sync = _mirrored_lv_in_sync(mirrored_seg->lv); /* * While we are only removing devices, we can have sync set. @@ -359,7 +523,7 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr */ init_mirror_in_sync(in_sync); - r = remove_mirror_images(mirrored_seg, num_mirrors, + r = remove_mirror_images(mirrored_seg->lv, num_mirrors, removable_pvs, remove_log); if (!r) /* Unable to remove bad devices */ @@ -721,7 +885,7 @@ int remove_mirror_log(struct cmd_context *cmd, init_mirror_in_sync(0); } - if (!remove_mirror_images(first_seg(lv), lv_mirror_count(lv), + if (!remove_mirror_images(lv, lv_mirror_count(lv), removable_pvs, 1U)) return_0; @@ -1195,17 +1359,17 @@ int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv, return 0; } - if (seg->area_count <= mirrors) { + if (lv_mirror_count(lv) <= mirrors) { log_error("Removing more than existing: %d <= %d", seg->area_count, mirrors); return 0; } - new_mirrors = seg->area_count - mirrors - 1; + new_mirrors = lv_mirror_count(lv) - mirrors - 1; /* MIRROR_BY_LV */ if (seg_type(seg, 0) == AREA_LV && seg_lv(seg, 0)->status & MIRROR_IMAGE) { - return remove_mirror_images(first_seg(lv), new_mirrors + 1, + return remove_mirror_images(lv, new_mirrors + 1, pvs, log_count ? 1U : 0); } diff --git a/tools/lvconvert.c b/tools/lvconvert.c index 0f2a254fc..f77e7733f 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -369,14 +369,20 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l return 1; } } else if (lp->mirrors > existing_mirrors) { - /* FIXME Unless anywhere, remove PV of log_lv - * from allocatable_pvs & allocate - * (mirrors - existing_mirrors) new areas - */ - /* FIXME Create mirror hierarchy to sync */ - log_error("Adding mirror images is not " - "supported yet."); - return 0; + /* FIXME: can't have multiple mlogs. force corelog. */ + corelog = 1; + if (!insert_layer_for_lv(cmd, lv, 0, "_resync%d")) { + log_error("Failed to insert resync layer"); + return 0; + } + if (!lv_add_mirrors(cmd, lv, lp->mirrors - existing_mirrors, 1, + adjusted_mirror_region_size( + lv->vg->extent_size, + lv->le_count, + lp->region_size), + corelog ? 0U : 1U, lp->pvh, lp->alloc, + MIRROR_BY_LV)) + return_0; } else { /* Reduce number of mirrors */ if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors, diff --git a/tools/lvresize.c b/tools/lvresize.c index b083e3426..f67e928da 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -435,7 +435,7 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg, if ((lp->extents > lv->le_count)) { list_iterate_back_items(seg, &lv->segments) { if (seg_is_mirrored(seg)) - seg_mirrors = seg->area_count; + seg_mirrors = lv_mirror_count(seg->lv); else seg_mirrors = 0; break; @@ -469,7 +469,7 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg, } if (seg_is_mirrored(seg)) - seg_mirrors = seg->area_count; + seg_mirrors = lv_mirror_count(seg->lv); else seg_mirrors = 0; diff --git a/tools/toollib.c b/tools/toollib.c index 32e99bda8..f608efc21 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -1222,6 +1222,12 @@ int apply_lvname_restrictions(const char *name) return 0; } + if (strstr(name, "_resync")) { + log_error("Names including \"_resync\" are reserved. " + "Please choose a different LV name."); + return 0; + } + return 1; } -- 2.43.5