mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Maintain lists of stacked LV segments using each LV.
This commit is contained in:
parent
fb3226a3ed
commit
72baf0c345
@ -1,5 +1,7 @@
|
|||||||
Version 2.02.30 -
|
Version 2.02.30 -
|
||||||
===================================
|
===================================
|
||||||
|
Maintain lists of stacked LV segments using each LV.
|
||||||
|
Change vgsplit -l (for unimplemented --list) into --maxlogicalvolumes.
|
||||||
Fix process_all_pvs to detect non-orphans with no MDAs correctly.
|
Fix process_all_pvs to detect non-orphans with no MDAs correctly.
|
||||||
Don't use block_on_error with mirror targets version 1.12 and above.
|
Don't use block_on_error with mirror targets version 1.12 and above.
|
||||||
Update vgsplit to include vgcreate-style options when new VG is destination.
|
Update vgsplit to include vgcreate-style options when new VG is destination.
|
||||||
|
@ -361,6 +361,7 @@ int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lv
|
|||||||
list_init(&lv->snapshot_segs);
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
list_init(&lv->segs_using_this_lv);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct list *p
|
|||||||
list_init(&lv->snapshot_segs);
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
list_init(&lv->segs_using_this_lv);
|
||||||
|
|
||||||
list_iterate_items(pl, pls) {
|
list_iterate_items(pl, pls) {
|
||||||
lv->size += pl->pd.pl_blocks;
|
lv->size += pl->pd.pl_blocks;
|
||||||
|
@ -408,8 +408,10 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||||
set_lv_segment_area_lv(seg, s, lv1, (uint32_t) cv->next->v.i,
|
if (!set_lv_segment_area_lv(seg, s, lv1,
|
||||||
flags);
|
(uint32_t) cv->next->v.i,
|
||||||
|
flags))
|
||||||
|
return_0;
|
||||||
} else {
|
} else {
|
||||||
log_error("Couldn't find volume '%s' "
|
log_error("Couldn't find volume '%s' "
|
||||||
"for segment '%s'.",
|
"for segment '%s'.",
|
||||||
@ -562,6 +564,7 @@ static int _read_lvnames(struct format_instance *fid __attribute((unused)),
|
|||||||
list_init(&lv->snapshot_segs);
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
list_init(&lv->segs_using_this_lv);
|
||||||
|
|
||||||
/* Optional tags */
|
/* Optional tags */
|
||||||
if ((cn = find_config_node(lvn, "tags")) &&
|
if ((cn = find_config_node(lvn, "tags")) &&
|
||||||
|
@ -33,9 +33,9 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
|||||||
|
|
||||||
int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
||||||
struct physical_volume *pv, uint32_t pe);
|
struct physical_volume *pv, uint32_t pe);
|
||||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||||
struct logical_volume *lv, uint32_t le,
|
struct logical_volume *lv, uint32_t le,
|
||||||
uint32_t flags);
|
uint32_t flags);
|
||||||
int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
|
int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
|
||||||
struct lv_segment *seg_from, uint32_t area_from);
|
struct lv_segment *seg_from, uint32_t area_from);
|
||||||
void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
|
void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
|
||||||
|
@ -31,6 +31,69 @@ struct lv_names {
|
|||||||
const char *new;
|
const char *new;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg)
|
||||||
|
{
|
||||||
|
struct seg_list *sl;
|
||||||
|
|
||||||
|
list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||||
|
if (sl->seg == seg) {
|
||||||
|
sl->count++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sl = dm_pool_zalloc(lv->vg->cmd->mem, sizeof(*sl)))) {
|
||||||
|
log_error("Failed to allocate segment list");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sl->count = 1;
|
||||||
|
sl->seg = seg;
|
||||||
|
list_add(&lv->segs_using_this_lv, &sl->list);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg)
|
||||||
|
{
|
||||||
|
struct seg_list *sl;
|
||||||
|
|
||||||
|
list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||||
|
if (sl->seg != seg)
|
||||||
|
continue;
|
||||||
|
if (sl->count > 1)
|
||||||
|
sl->count--;
|
||||||
|
else
|
||||||
|
list_del(&sl->list);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a function specialized for the common case where there is
|
||||||
|
* only one segment which uses the LV.
|
||||||
|
* e.g. the LV is a layer inserted by insert_layer_for_lv().
|
||||||
|
*
|
||||||
|
* In general, walk through lv->segs_using_this_lv.
|
||||||
|
*/
|
||||||
|
struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
struct seg_list *sl;
|
||||||
|
|
||||||
|
if (list_size(&lv->segs_using_this_lv) != 1) {
|
||||||
|
log_error("%s is expected to have only one segment using it, "
|
||||||
|
"while it has %d", lv->name,
|
||||||
|
list_size(&lv->segs_using_this_lv));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sl = list_item(list_first(&lv->segs_using_this_lv), struct seg_list);
|
||||||
|
|
||||||
|
return sl->seg;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PVs used by a segment of an LV
|
* PVs used by a segment of an LV
|
||||||
*/
|
*/
|
||||||
@ -127,12 +190,12 @@ struct lv_segment *alloc_lv_segment(struct dm_pool *mem,
|
|||||||
seg->region_size = region_size;
|
seg->region_size = region_size;
|
||||||
seg->extents_copied = extents_copied;
|
seg->extents_copied = extents_copied;
|
||||||
seg->log_lv = log_lv;
|
seg->log_lv = log_lv;
|
||||||
seg->mirror_seg = NULL;
|
|
||||||
list_init(&seg->tags);
|
list_init(&seg->tags);
|
||||||
|
|
||||||
if (log_lv) {
|
if (log_lv) {
|
||||||
log_lv->status |= MIRROR_LOG;
|
log_lv->status |= MIRROR_LOG;
|
||||||
first_seg(log_lv)->mirror_seg = seg;
|
if (!add_seg_to_segs_using_this_lv(log_lv, seg))
|
||||||
|
return_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return seg;
|
return seg;
|
||||||
@ -183,6 +246,7 @@ void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (area_reduction == seg->area_len) {
|
if (area_reduction == seg->area_len) {
|
||||||
|
remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg);
|
||||||
seg_lv(seg, s) = NULL;
|
seg_lv(seg, s) = NULL;
|
||||||
seg_le(seg, s) = 0;
|
seg_le(seg, s) = 0;
|
||||||
seg_type(seg, s) = AREA_UNASSIGNED;
|
seg_type(seg, s) = AREA_UNASSIGNED;
|
||||||
@ -223,7 +287,8 @@ int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
|
|||||||
seg_from->area_len);
|
seg_from->area_len);
|
||||||
release_lv_segment_area(seg_to, area_to, seg_to->area_len);
|
release_lv_segment_area(seg_to, area_to, seg_to->area_len);
|
||||||
|
|
||||||
set_lv_segment_area_lv(seg_to, area_to, lv, le, 0);
|
if (!set_lv_segment_area_lv(seg_to, area_to, lv, le, 0))
|
||||||
|
return_0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -254,14 +319,19 @@ int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
|||||||
/*
|
/*
|
||||||
* Link one LV segment to another. Assumes sizes already match.
|
* Link one LV segment to another. Assumes sizes already match.
|
||||||
*/
|
*/
|
||||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
int set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||||
struct logical_volume *lv, uint32_t le,
|
struct logical_volume *lv, uint32_t le,
|
||||||
uint32_t flags)
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
seg->areas[area_num].type = AREA_LV;
|
seg->areas[area_num].type = AREA_LV;
|
||||||
seg_lv(seg, area_num) = lv;
|
seg_lv(seg, area_num) = lv;
|
||||||
seg_le(seg, area_num) = le;
|
seg_le(seg, area_num) = le;
|
||||||
lv->status |= flags;
|
lv->status |= flags;
|
||||||
|
|
||||||
|
if (!add_seg_to_segs_using_this_lv(lv, seg))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1399,14 +1469,13 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (m = 0; m < old_area_count; m++) {
|
for (m = 0; m < old_area_count; m++)
|
||||||
seg_lv(seg, m)->status |= status;
|
seg_lv(seg, m)->status |= status;
|
||||||
first_seg(seg_lv(seg, m))->mirror_seg = seg;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (m = old_area_count; m < new_area_count; m++) {
|
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);
|
if (!set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count],
|
||||||
first_seg(sub_lvs[m - old_area_count])->mirror_seg = seg;
|
0, status))
|
||||||
|
return_0;
|
||||||
sub_lvs[m - old_area_count]->status &= ~VISIBLE_LV;
|
sub_lvs[m - old_area_count]->status &= ~VISIBLE_LV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1780,6 +1849,7 @@ struct logical_volume *lv_create_empty(const char *name,
|
|||||||
list_init(&lv->snapshot_segs);
|
list_init(&lv->snapshot_segs);
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
list_init(&lv->tags);
|
list_init(&lv->tags);
|
||||||
|
list_init(&lv->segs_using_this_lv);
|
||||||
|
|
||||||
if (lvid)
|
if (lvid)
|
||||||
lv->lvid = *lvid;
|
lv->lvid = *lvid;
|
||||||
@ -2212,53 +2282,29 @@ static int _move_lv_segments(struct logical_volume *lv_to,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
/* Remove a layer from the LV */
|
||||||
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 *layer_lv)
|
||||||
{
|
{
|
||||||
struct logical_volume *parent;
|
struct logical_volume *parent;
|
||||||
|
struct lv_segment *parent_seg;
|
||||||
struct segment_type *segtype;
|
struct segment_type *segtype;
|
||||||
|
|
||||||
parent = find_parent_for_layer(lv, layer_lv);
|
if (!(parent_seg = get_only_segment_using_this_lv(layer_lv))) {
|
||||||
if (!parent) {
|
|
||||||
log_error("Failed to find layer %s in %s",
|
log_error("Failed to find layer %s in %s",
|
||||||
layer_lv->name, lv->name);
|
layer_lv->name, lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
parent = parent_seg->lv;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before removal, the layer should be cleaned up,
|
* Before removal, the layer should be cleaned up,
|
||||||
* i.e. additional segments and areas should have been removed.
|
* i.e. additional segments and areas should have been removed.
|
||||||
*/
|
*/
|
||||||
if (list_size(&parent->segments) != 1 ||
|
if (list_size(&parent->segments) != 1 ||
|
||||||
first_seg(parent)->area_count != 1 ||
|
parent_seg->area_count != 1 ||
|
||||||
seg_type(first_seg(parent), 0) != AREA_LV ||
|
seg_type(parent_seg, 0) != AREA_LV ||
|
||||||
layer_lv != seg_lv(first_seg(parent), 0) ||
|
layer_lv != seg_lv(parent_seg, 0) ||
|
||||||
parent->le_count != layer_lv->le_count)
|
parent->le_count != layer_lv->le_count)
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
@ -2328,7 +2374,8 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
|||||||
return_NULL;
|
return_NULL;
|
||||||
|
|
||||||
/* map the new segment to the original underlying are */
|
/* map the new segment to the original underlying are */
|
||||||
set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0);
|
if (!set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0))
|
||||||
|
return_NULL;
|
||||||
|
|
||||||
/* add the new segment to the layer LV */
|
/* add the new segment to the layer LV */
|
||||||
list_add(&lv_where->segments, &mapseg->list);
|
list_add(&lv_where->segments, &mapseg->list);
|
||||||
@ -2379,7 +2426,8 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
|
|||||||
layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
|
layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
|
||||||
|
|
||||||
/* map the original area to the new segment */
|
/* map the original area to the new segment */
|
||||||
set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0);
|
if (!set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0))
|
||||||
|
return_0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,10 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
{
|
{
|
||||||
struct lv_segment *seg, *seg2;
|
struct lv_segment *seg, *seg2;
|
||||||
uint32_t le = 0;
|
uint32_t le = 0;
|
||||||
unsigned seg_count = 0;
|
unsigned seg_count = 0, seg_found;
|
||||||
int r = 1;
|
int r = 1;
|
||||||
uint32_t area_multiplier, s;
|
uint32_t area_multiplier, s;
|
||||||
|
struct seg_list *sl;
|
||||||
|
|
||||||
list_iterate_items(seg, &lv->segments) {
|
list_iterate_items(seg, &lv->segments) {
|
||||||
seg_count++;
|
seg_count++;
|
||||||
@ -101,7 +102,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(seg2 = first_seg(seg->log_lv)) ||
|
if (!(seg2 = first_seg(seg->log_lv)) ||
|
||||||
seg2->mirror_seg != seg) {
|
find_mirror_seg(seg2) != seg) {
|
||||||
log_error("LV %s: segment %u log LV does not "
|
log_error("LV %s: segment %u log LV does not "
|
||||||
"point back to mirror segment",
|
"point back to mirror segment",
|
||||||
lv->name, seg_count);
|
lv->name, seg_count);
|
||||||
@ -110,8 +111,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (complete_vg && seg->status & MIRROR_IMAGE) {
|
if (complete_vg && seg->status & MIRROR_IMAGE) {
|
||||||
if (!seg->mirror_seg ||
|
if (!find_mirror_seg(seg) ||
|
||||||
!seg_is_mirrored(seg->mirror_seg)) {
|
!seg_is_mirrored(find_mirror_seg(seg))) {
|
||||||
log_error("LV %s: segment %u mirror image "
|
log_error("LV %s: segment %u mirror image "
|
||||||
"is not mirrored",
|
"is not mirrored",
|
||||||
lv->name, seg_count);
|
lv->name, seg_count);
|
||||||
@ -157,7 +158,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
(seg_lv(seg, s)->status & MIRROR_IMAGE) &&
|
(seg_lv(seg, s)->status & MIRROR_IMAGE) &&
|
||||||
(!(seg2 = find_seg_by_le(seg_lv(seg, s),
|
(!(seg2 = find_seg_by_le(seg_lv(seg, s),
|
||||||
seg_le(seg, s))) ||
|
seg_le(seg, s))) ||
|
||||||
seg2->mirror_seg != seg)) {
|
find_mirror_seg(seg2) != seg)) {
|
||||||
log_error("LV %s: segment %u mirror "
|
log_error("LV %s: segment %u mirror "
|
||||||
"image %u missing mirror ptr",
|
"image %u missing mirror ptr",
|
||||||
lv->name, seg_count, s);
|
lv->name, seg_count, s);
|
||||||
@ -173,12 +174,57 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
seg_found = 0;
|
||||||
|
list_iterate_items(sl, &seg_lv(seg, s)->segs_using_this_lv)
|
||||||
|
if (sl->seg == seg)
|
||||||
|
seg_found++;
|
||||||
|
if (!seg_found) {
|
||||||
|
log_error("LV %s segment %d uses LV %s,"
|
||||||
|
" but missing ptr from %s to %s",
|
||||||
|
lv->name, seg_count,
|
||||||
|
seg_lv(seg, s)->name,
|
||||||
|
seg_lv(seg, s)->name, lv->name);
|
||||||
|
r = 0;
|
||||||
|
} else if (seg_found > 1) {
|
||||||
|
log_error("LV %s has duplicated links "
|
||||||
|
"to LV %s segment %d",
|
||||||
|
seg_lv(seg, s)->name,
|
||||||
|
lv->name, seg_count);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
le += seg->len;
|
le += seg->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||||
|
seg = sl->seg;
|
||||||
|
seg_found = 0;
|
||||||
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
|
if (seg_type(seg, s) != AREA_LV)
|
||||||
|
continue;
|
||||||
|
if (lv == seg_lv(seg, s))
|
||||||
|
seg_found++;
|
||||||
|
}
|
||||||
|
if (seg->log_lv == lv)
|
||||||
|
seg_found++;
|
||||||
|
if (!seg_found) {
|
||||||
|
log_error("LV %s is used by LV %s:%" PRIu32 ", "
|
||||||
|
"but missing ptr from %s to %s",
|
||||||
|
lv->name, seg->lv->name, seg->le,
|
||||||
|
seg->lv->name, lv->name);
|
||||||
|
r = 0;
|
||||||
|
} else if (seg_found != sl->count) {
|
||||||
|
log_error("Reference count mismatch: LV %s has %d "
|
||||||
|
"links to LV %s:%" PRIu32
|
||||||
|
", which has %d links",
|
||||||
|
lv->name, sl->count,
|
||||||
|
seg->lv->name, seg->le, seg_found);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (le != lv->le_count) {
|
if (le != lv->le_count) {
|
||||||
log_error("LV %s: inconsistent LE count %u != %u",
|
log_error("LV %s: inconsistent LE count %u != %u",
|
||||||
lv->name, le, lv->le_count);
|
lv->name, le, lv->le_count);
|
||||||
@ -243,9 +289,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
|||||||
/* Split area at the offset */
|
/* Split area at the offset */
|
||||||
switch (seg_type(seg, s)) {
|
switch (seg_type(seg, s)) {
|
||||||
case AREA_LV:
|
case AREA_LV:
|
||||||
seg_lv(split_seg, s) = seg_lv(seg, s);
|
if (!set_lv_segment_area_lv(split_seg, s, seg_lv(seg, s),
|
||||||
seg_le(split_seg, s) =
|
seg_le(seg, s) + seg->area_len, 0))
|
||||||
seg_le(seg, s) + seg->area_len;
|
return_0;
|
||||||
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
||||||
seg->le, s, le, seg_lv(seg, s)->name,
|
seg->le, s, le, seg_lv(seg, s)->name,
|
||||||
seg_le(split_seg, s));
|
seg_le(split_seg, s));
|
||||||
|
@ -242,7 +242,6 @@ struct lv_segment {
|
|||||||
uint32_t region_size; /* For mirrors - in sectors */
|
uint32_t region_size; /* For mirrors - in sectors */
|
||||||
uint32_t extents_copied;
|
uint32_t extents_copied;
|
||||||
struct logical_volume *log_lv;
|
struct logical_volume *log_lv;
|
||||||
struct lv_segment *mirror_seg;
|
|
||||||
|
|
||||||
struct list tags;
|
struct list tags;
|
||||||
|
|
||||||
@ -274,6 +273,7 @@ struct logical_volume {
|
|||||||
|
|
||||||
struct list segments;
|
struct list segments;
|
||||||
struct list tags;
|
struct list tags;
|
||||||
|
struct list segs_using_this_lv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pe_range {
|
struct pe_range {
|
||||||
@ -412,8 +412,6 @@ int remove_layers_for_segments_all(struct cmd_context *cmd,
|
|||||||
struct list *lvs_changed);
|
struct list *lvs_changed);
|
||||||
int split_parent_segments_for_layer(struct cmd_context *cmd,
|
int split_parent_segments_for_layer(struct cmd_context *cmd,
|
||||||
struct logical_volume *layer_lv);
|
struct logical_volume *layer_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,
|
int remove_layer_from_lv(struct logical_volume *lv,
|
||||||
struct logical_volume *layer_lv);
|
struct logical_volume *layer_lv);
|
||||||
struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||||
@ -464,6 +462,7 @@ int vg_check_status(const struct volume_group *vg, uint32_t status);
|
|||||||
/*
|
/*
|
||||||
* Mirroring functions
|
* Mirroring functions
|
||||||
*/
|
*/
|
||||||
|
struct lv_segment *find_mirror_seg(struct lv_segment *seg);
|
||||||
int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
uint32_t mirrors, uint32_t stripes,
|
uint32_t mirrors, uint32_t stripes,
|
||||||
uint32_t region_size, uint32_t log_count,
|
uint32_t region_size, uint32_t log_count,
|
||||||
|
@ -158,6 +158,12 @@ struct peg_list {
|
|||||||
struct pv_segment *peg;
|
struct pv_segment *peg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct seg_list {
|
||||||
|
struct list list;
|
||||||
|
unsigned count;
|
||||||
|
struct lv_segment *seg;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ownership of objects passes to caller.
|
* Ownership of objects passes to caller.
|
||||||
*/
|
*/
|
||||||
@ -292,6 +298,14 @@ int lv_merge_segments(struct logical_volume *lv);
|
|||||||
*/
|
*/
|
||||||
int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add/remove upward link from underlying LV to the segment using it
|
||||||
|
* FIXME: ridiculously long name
|
||||||
|
*/
|
||||||
|
int add_seg_to_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
|
||||||
|
int remove_seg_from_segs_using_this_lv(struct logical_volume *lv, struct lv_segment *seg);
|
||||||
|
struct lv_segment *get_only_segment_using_this_lv(struct logical_volume *lv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mirroring functions
|
* Mirroring functions
|
||||||
*/
|
*/
|
||||||
@ -299,7 +313,6 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
|||||||
/*
|
/*
|
||||||
* Given mirror image or mirror log segment, find corresponding mirror segment
|
* Given mirror image or mirror log segment, find corresponding mirror segment
|
||||||
*/
|
*/
|
||||||
struct lv_segment *find_mirror_seg(struct lv_segment *seg);
|
|
||||||
int fixup_imported_mirrors(struct volume_group *vg);
|
int fixup_imported_mirrors(struct volume_group *vg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -76,7 +76,22 @@ uint32_t lv_mirror_count(const struct logical_volume *lv)
|
|||||||
|
|
||||||
struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
||||||
{
|
{
|
||||||
return seg->mirror_seg;
|
struct lv_segment *mirror_seg;
|
||||||
|
|
||||||
|
mirror_seg = get_only_segment_using_this_lv(seg->lv);
|
||||||
|
|
||||||
|
if (!mirror_seg) {
|
||||||
|
log_error("Failed to find mirror_seg for %s", seg->lv->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seg_is_mirrored(mirror_seg)) {
|
||||||
|
log_error("%s on %s is not a mirror segments",
|
||||||
|
mirror_seg->lv->name, seg->lv->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mirror_seg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -155,6 +170,20 @@ static int _merge_mirror_images(struct logical_volume *lv,
|
|||||||
MIRROR_IMAGE, first_seg(lv)->region_size);
|
MIRROR_IMAGE, first_seg(lv)->region_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unlink the relationship between the segment and its log_lv */
|
||||||
|
static void _remove_mirror_log(struct lv_segment *mirrored_seg)
|
||||||
|
{
|
||||||
|
struct logical_volume *log_lv;
|
||||||
|
|
||||||
|
if (!mirrored_seg->log_lv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_lv = mirrored_seg->log_lv;
|
||||||
|
mirrored_seg->log_lv = NULL;
|
||||||
|
log_lv->status &= ~MIRROR_LOG;
|
||||||
|
remove_seg_from_segs_using_this_lv(log_lv, mirrored_seg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove num_removed images from mirrored_seg
|
* Remove num_removed images from mirrored_seg
|
||||||
*/
|
*/
|
||||||
@ -244,6 +273,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
|||||||
}
|
}
|
||||||
lvl->lv = seg_lv(mirrored_seg, m);
|
lvl->lv = seg_lv(mirrored_seg, m);
|
||||||
list_add(&tmp_orphan_lvs, &lvl->list);
|
list_add(&tmp_orphan_lvs, &lvl->list);
|
||||||
|
release_lv_segment_area(mirrored_seg, m, mirrored_seg->area_len);
|
||||||
}
|
}
|
||||||
mirrored_seg->area_count = new_area_count;
|
mirrored_seg->area_count = new_area_count;
|
||||||
|
|
||||||
@ -254,7 +284,7 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
|||||||
/* If no more mirrors, remove mirror layer */
|
/* If no more mirrors, remove mirror layer */
|
||||||
if (new_area_count == 1) {
|
if (new_area_count == 1) {
|
||||||
lv1 = seg_lv(mirrored_seg, 0);
|
lv1 = seg_lv(mirrored_seg, 0);
|
||||||
mirrored_seg->log_lv = NULL;
|
_remove_mirror_log(mirrored_seg);
|
||||||
if (!remove_layer_from_lv(lv, lv1))
|
if (!remove_layer_from_lv(lv, lv1))
|
||||||
return_0;
|
return_0;
|
||||||
lv->status &= ~MIRRORED;
|
lv->status &= ~MIRRORED;
|
||||||
@ -265,12 +295,10 @@ static int _remove_mirror_images(struct logical_volume *lv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (remove_log)
|
} else if (remove_log)
|
||||||
mirrored_seg->log_lv = NULL;
|
_remove_mirror_log(mirrored_seg);
|
||||||
|
|
||||||
if (remove_log && log_lv) {
|
if (remove_log && log_lv)
|
||||||
log_lv->status &= ~MIRROR_LOG;
|
|
||||||
log_lv->status |= VISIBLE_LV;
|
log_lv->status |= VISIBLE_LV;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To successfully remove these unwanted LVs we need to
|
* To successfully remove these unwanted LVs we need to
|
||||||
@ -395,18 +423,25 @@ static struct logical_volume *_find_tmp_mirror(struct logical_volume *lv)
|
|||||||
*/
|
*/
|
||||||
int collapse_mirrored_lv(struct logical_volume *lv)
|
int collapse_mirrored_lv(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct logical_volume *tmp_lv, *parent_lv;
|
struct logical_volume *tmp_lv;
|
||||||
|
struct lv_segment *mirror_seg;
|
||||||
|
|
||||||
while ((tmp_lv = _find_tmp_mirror(lv))) {
|
while ((tmp_lv = _find_tmp_mirror(lv))) {
|
||||||
parent_lv = find_parent_for_layer(lv, tmp_lv);
|
mirror_seg = find_mirror_seg(first_seg(tmp_lv));
|
||||||
if (!_mirrored_lv_in_sync(parent_lv)) {
|
if (!mirror_seg) {
|
||||||
|
log_error("Failed to find mirrored LV for %s",
|
||||||
|
tmp_lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_mirrored_lv_in_sync(mirror_seg->lv)) {
|
||||||
log_verbose("Not collapsing %s: out-of-sync",
|
log_verbose("Not collapsing %s: out-of-sync",
|
||||||
parent_lv->name);
|
mirror_seg->lv->name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_remove_mirror_images(parent_lv,
|
if (!_remove_mirror_images(mirror_seg->lv,
|
||||||
first_seg(parent_lv)->area_count - 1,
|
mirror_seg->area_count - 1,
|
||||||
NULL, 1, 1)) {
|
NULL, 1, 1)) {
|
||||||
log_error("Failed to release mirror images");
|
log_error("Failed to release mirror images");
|
||||||
return 0;
|
return 0;
|
||||||
@ -801,7 +836,6 @@ int fixup_imported_mirrors(struct volume_group *vg)
|
|||||||
{
|
{
|
||||||
struct lv_list *lvl;
|
struct lv_list *lvl;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
uint32_t s;
|
|
||||||
|
|
||||||
list_iterate_items(lvl, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
list_iterate_items(seg, &lvl->lv->segments) {
|
list_iterate_items(seg, &lvl->lv->segments) {
|
||||||
@ -809,12 +843,8 @@ int fixup_imported_mirrors(struct volume_group *vg)
|
|||||||
get_segtype_from_string(vg->cmd, "mirror"))
|
get_segtype_from_string(vg->cmd, "mirror"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (seg->log_lv)
|
if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg))
|
||||||
first_seg(seg->log_lv)->mirror_seg = seg;
|
return_0;
|
||||||
for (s = 0; s < seg->area_count; s++)
|
|
||||||
if (seg_type(seg, s) == AREA_LV)
|
|
||||||
first_seg(seg_lv(seg, s))->mirror_seg
|
|
||||||
= seg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1103,7 +1133,7 @@ static void _add_mirror_log(struct logical_volume *lv,
|
|||||||
{
|
{
|
||||||
first_seg(lv)->log_lv = log_lv;
|
first_seg(lv)->log_lv = log_lv;
|
||||||
log_lv->status |= MIRROR_LOG;
|
log_lv->status |= MIRROR_LOG;
|
||||||
first_seg(log_lv)->mirror_seg = first_seg(lv);
|
add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
|
||||||
}
|
}
|
||||||
|
|
||||||
int add_mirror_log(struct cmd_context *cmd,
|
int add_mirror_log(struct cmd_context *cmd,
|
||||||
|
@ -275,13 +275,12 @@ static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((u
|
|||||||
static int _lv_mimage_in_sync(const struct logical_volume *lv)
|
static int _lv_mimage_in_sync(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
float percent;
|
float percent;
|
||||||
struct lv_segment *seg = first_seg(lv);
|
struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv));
|
||||||
|
|
||||||
if (!(lv->status & MIRROR_IMAGE) || !seg->mirror_seg)
|
if (!(lv->status & MIRROR_IMAGE) || !mirror_seg)
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!lv_mirror_percent(lv->vg->cmd, seg->mirror_seg->lv, 0,
|
if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, NULL))
|
||||||
&percent, NULL))
|
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (percent >= 100.0)
|
if (percent >= 100.0)
|
||||||
|
@ -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,
|
static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
int *list_unsafe, struct list *lvs_changed)
|
int *list_unsafe, struct list *lvs_changed)
|
||||||
{
|
{
|
||||||
struct lv_segment *snap_seg, *mirror_seg;
|
struct lv_segment *snap_seg;
|
||||||
struct list *snh, *snht;
|
struct list *snh, *snht;
|
||||||
struct logical_volume *cow;
|
struct logical_volume *cow;
|
||||||
struct lv_list *lvl;
|
struct lv_list *lvl;
|
||||||
@ -117,9 +117,8 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
* Clean-up is currently done by caller (_make_vg_consistent()).
|
* Clean-up is currently done by caller (_make_vg_consistent()).
|
||||||
*/
|
*/
|
||||||
if ((lv_info(cmd, lv, &info, 0, 0) && info.exists)
|
if ((lv_info(cmd, lv, &info, 0, 0) && info.exists)
|
||||||
|| first_seg(lv)->mirror_seg) {
|
|| find_mirror_seg(first_seg(lv))) {
|
||||||
extents = lv->le_count;
|
extents = lv->le_count;
|
||||||
mirror_seg = first_seg(lv)->mirror_seg;
|
|
||||||
if (!lv_empty(lv)) {
|
if (!lv_empty(lv)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@ -130,10 +129,6 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
stack;
|
stack;
|
||||||
return 0;
|
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)))) {
|
if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||||
log_error("lv_list alloc failed");
|
log_error("lv_list alloc failed");
|
||||||
|
Loading…
Reference in New Issue
Block a user