mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
stacked mirror support (incomplete)
This commit is contained in:
parent
ac089d9015
commit
31e9db2690
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
/*
|
||||
* 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 *orig_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 */
|
||||
int remove_layer_from_lv(struct logical_volume *lv,
|
||||
struct logical_volume *layer_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;
|
||||
|
||||
orig_lv = seg_lv(first_seg(lv), 0);
|
||||
_move_lv_segments(lv, orig_lv, 0, 0);
|
||||
_move_lv_segments(parent, layer_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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,16 +266,148 @@ 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)))
|
||||
/* 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(lv, lv1))
|
||||
return 0;
|
||||
|
||||
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 (lv1 && !_delete_lv(mirrored_seg, lv1))
|
||||
return 0;
|
||||
|
||||
if (log_lv && !_delete_lv(mirrored_seg, log_lv))
|
||||
return 0;
|
||||
if (!_merge_mirror_images(parent_lv, &lvlist)) {
|
||||
log_error("Failed to add mirror images");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user