uint32_t status,
uint32_t region_size,
struct logical_volume *log_lv);
+int lv_add_more_mirrored_areas(struct logical_volume *lv,
+ struct logical_volume **sub_lvs,
+ uint32_t new_area_count,
+ uint32_t status);
void alloc_destroy(struct alloc_handle *ah);
if (log_lv) {
log_lv->status |= MIRROR_LOG;
- find_seg_by_le(log_lv, 0)->mirror_seg = seg;
+ first_seg(log_lv)->mirror_seg = seg;
}
return seg;
lv->status |= flags;
}
-static int _lv_segment_add_areas(struct logical_volume *lv,
- struct lv_segment *seg,
- uint32_t new_area_count) __attribute__ ((unused));
/*
* Prepare for adding parallel areas to an existing segment.
*/
for (m = 0; m < mirrors; m++) {
set_lv_segment_area_lv(seg, m, sub_lvs[m], 0, MIRROR_IMAGE);
- find_seg_by_le(sub_lvs[m], 0)->mirror_seg = seg;
+ first_seg(sub_lvs[m])->mirror_seg = seg;
}
list_add(&lv->segments, &seg->list);
return 1;
}
+/*
+ * Add parallel areas to an existing mirror
+ */
+int lv_add_more_mirrored_areas(struct logical_volume *lv,
+ struct logical_volume **sub_lvs,
+ uint32_t num_extra_areas,
+ uint32_t status)
+{
+ struct lv_segment *seg;
+ uint32_t old_area_count, new_area_count;
+ uint32_t m;
+
+ if (list_size(&lv->segments) != 1) {
+ log_error("Mirrored LV must only have one segment.");
+ return 0;
+ }
+
+ list_iterate_items(seg, &lv->segments)
+ break;
+
+ old_area_count = seg->area_count;
+ new_area_count = old_area_count + num_extra_areas;
+
+ if (!_lv_segment_add_areas(lv, seg, new_area_count)) {
+ log_error("Failed to allocate widened LV segment for %s.",
+ lv->name);
+ return 0;
+ }
+
+ 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;
+ }
+
+ return 1;
+}
/*
* Entry point for single-step LV allocation + extension.
int r = 1;
uint32_t m;
struct alloc_handle *ah;
- struct lv_segment *first_seg;
+ struct lv_segment *seg;
if (segtype_is_virtual(segtype))
return lv_add_virtual_segment(lv, status, extents, segtype);
goto out;
}
} else {
- list_iterate_items(first_seg, &lv->segments)
- break;
+ seg = first_seg(lv);
for (m = 0; m < mirrors; m++) {
- if (!lv_add_segment(ah, m, 1, seg_lv(first_seg, m),
+ if (!lv_add_segment(ah, m, 1, seg_lv(seg, m),
get_segtype_from_string(lv->vg->cmd,
"striped"),
0, NULL, 0, 0, 0, NULL)) {
log_error("Aborting. Failed to extend %s.",
- seg_lv(first_seg, m)->name);
+ seg_lv(seg, m)->name);
return 0;
}
}
- first_seg->area_len += extents;
- first_seg->len += extents;
+ seg->area_len += extents;
+ seg->len += extents;
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
}
r = 0;
}
- if (!(seg2 = find_seg_by_le(seg->log_lv, 0)) ||
+ if (!(seg2 = first_seg(seg->log_lv)) ||
seg2->mirror_seg != seg) {
log_error("LV %s: segment %u log LV does not "
"point back to mirror segment",
return NULL;
}
+struct lv_segment *first_seg(struct logical_volume *lv)
+{
+ struct lv_segment *seg = NULL;
+
+ list_iterate_items(seg, &lv->segments)
+ break;
+
+ return seg;
+}
+
/* Find segment at a given physical extent in a PV */
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
{
/* Find LV segment containing given LE */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
+struct lv_segment *first_seg(struct logical_volume *lv);
/* Find PV segment containing given LE */
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
return region_size;
}
+static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volume *lv_from)
+{
+ struct lv_segment *seg;
+
+ lv_to->segments = lv_from->segments;
+ lv_to->segments.n->p = &lv_to->segments;
+ lv_to->segments.p->n = &lv_to->segments;
+
+ list_iterate_items(seg, &lv_to->segments)
+ seg->lv = lv_to;
+
+/* FIXME set or reset seg->mirror_seg (according to status)? */
+
+ list_init(&lv_from->segments);
+
+ lv_from->le_count = 0;
+ lv_from->size = 0;
+}
+
/*
* Reduce mirrored_seg to num_mirrors images.
*/
int remove_all_mirror_images(struct logical_volume *lv)
{
- struct lv_segment *first_seg, *seg;
+ struct lv_segment *seg;
struct logical_volume *lv1;
- list_iterate_items(first_seg, &lv->segments)
- break;
+ seg = first_seg(lv);
- if (!remove_mirror_images(first_seg, 1)) {
+ if (!remove_mirror_images(seg, 1)) {
stack;
return 0;
}
- if (!lv_remove(first_seg->log_lv)) {
+ if (seg->log_lv && !lv_remove(seg->log_lv)) {
stack;
return 0;
}
- lv1 = seg_lv(first_seg, 0);
+ lv1 = seg_lv(seg, 0);
- lv->segments = lv1->segments;
- lv->segments.n->p = &lv->segments;
- lv->segments.p->n = &lv->segments;
+ _move_lv_segments(lv, lv1);
- list_init(&lv1->segments);
- lv1->le_count = 0;
- lv1->size = 0;
if (!lv_remove(lv1)) {
stack;
return 0;
lv->status &= ~MIRRORED;
- list_iterate_items(seg, &lv->segments)
- seg->lv = lv;
-
return 1;
}
}
*/
-int create_mirror_layers(struct alloc_handle *ah,
- uint32_t first_area,
- uint32_t num_mirrors,
- struct logical_volume *lv,
- struct segment_type *segtype,
- uint32_t status,
- uint32_t region_size,
- struct logical_volume *log_lv)
+static int _create_layers_for_mirror(struct alloc_handle *ah,
+ uint32_t first_area,
+ uint32_t num_mirrors,
+ struct logical_volume *lv,
+ struct segment_type *segtype,
+ struct logical_volume **img_lvs)
{
uint32_t m;
- struct logical_volume **img_lvs;
char *img_name;
size_t len;
- if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
- log_error("img_lvs allocation failed. "
- "Remove new LV and retry.");
- return 0;
- }
-
len = strlen(lv->name) + 32;
if (!(img_name = alloca(len))) {
log_error("img_name allocation failed. "
}
}
+ return 1;
+}
+
+int create_mirror_layers(struct alloc_handle *ah,
+ uint32_t first_area,
+ uint32_t num_mirrors,
+ struct logical_volume *lv,
+ struct segment_type *segtype,
+ uint32_t status,
+ uint32_t region_size,
+ struct logical_volume *log_lv)
+{
+ struct logical_volume **img_lvs;
+
+ if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
+ log_error("img_lvs allocation failed. "
+ "Remove new LV and retry.");
+ return 0;
+ }
+
+ if (!_create_layers_for_mirror(ah, first_area, num_mirrors, lv,
+ segtype, img_lvs)) {
+ stack;
+ return 0;
+ }
+
+ /* Already got the parent mirror segment? */
+ if (lv->status & MIRRORED)
+ return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors,
+ MIRROR_IMAGE);
+
+ /* Already got a non-mirrored area to be converted? */
+ if (!first_area) {
+ _move_lv_segments(img_lvs[0], lv);
+ lv->status |= MIRRORED;
+ }
+
if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
0, region_size, log_lv)) {
log_error("Aborting. Failed to add mirror segment. "
continue;
if (seg->log_lv)
- find_seg_by_le(seg->log_lv, 0)->mirror_seg = seg;
+ first_seg(seg->log_lv)->mirror_seg = seg;
for (s = 0; s < seg->area_count; s++)
if (seg_type(seg, s) == AREA_LV)
- find_seg_by_le(seg_lv(seg, s), 0)->
- mirror_seg = seg;
+ first_seg(seg_lv(seg, s))->mirror_seg
+ = seg;
}
}
+
+ return 1;
}
static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * lv,
struct lvconvert_params *lp)
{
- struct lv_segment *first_seg;
+ struct lv_segment *seg;
uint32_t existing_mirrors;
// struct alloc_handle *ah = NULL;
// struct logical_volume *log_lv;
"mirror segments.", lv->name);
return 0;
}
- list_iterate_items(first_seg, &lv->segments)
- break;
- existing_mirrors = first_seg->area_count;
+ seg = first_seg(lv);
+ existing_mirrors = seg->area_count;
if (lp->mirrors == existing_mirrors) {
log_error("Logical volume %s already has %"
PRIu32 " mirror(s).", lv->name,
"supported yet.");
return 0;
} else {
- if (!remove_mirror_images(first_seg, lp->mirrors)) {
+ if (!remove_mirror_images(seg, lp->mirrors)) {
stack;
return 0;
}