mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Major restructuring of pvmove and lvconvert layer manipulation code
This commit is contained in:
parent
72199adfc3
commit
a69ab65278
@ -1,5 +1,6 @@
|
||||
Version 2.02.30 -
|
||||
===================================
|
||||
Major restructuring of pvmove and lvconvert layer manipulation code.
|
||||
Replace tools/fsadm with scripts/fsadm.sh.
|
||||
Append fields to report/pvsegs_cols_verbose.
|
||||
Permit LV segment fields with PV segment reports.
|
||||
|
@ -50,7 +50,6 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t extents,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
unsigned can_split,
|
||||
struct list *parallel_areas);
|
||||
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
@ -58,27 +57,21 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t stripe_size,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
int lv_add_mirror_areas(struct alloc_handle *ah,
|
||||
struct logical_volume *lv, uint32_t le,
|
||||
uint32_t region_size);
|
||||
int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t num_extra_areas,
|
||||
uint32_t status, uint32_t region_size);
|
||||
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
|
||||
int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
|
||||
uint32_t extents, const struct segment_type *segtype);
|
||||
int lv_add_mirror_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t mirrors,
|
||||
const struct segment_type *segtype,
|
||||
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);
|
||||
|
||||
|
@ -43,6 +43,17 @@ struct seg_pvs {
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
static struct seg_pvs *_find_seg_pvs_by_le(struct list *list, uint32_t le)
|
||||
{
|
||||
struct seg_pvs *spvs;
|
||||
|
||||
list_iterate_items(spvs, list)
|
||||
if (le >= spvs->le && le < spvs->le + spvs->len)
|
||||
return spvs;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find first unused LV number.
|
||||
*/
|
||||
@ -160,7 +171,9 @@ void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
|
||||
return;
|
||||
|
||||
if (seg_type(seg, s) == AREA_PV) {
|
||||
release_pv_segment(seg_pvseg(seg, s), area_reduction);
|
||||
if (release_pv_segment(seg_pvseg(seg, s), area_reduction) &&
|
||||
seg->area_len == area_reduction)
|
||||
seg_type(seg, s) = AREA_UNASSIGNED;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -543,17 +556,12 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
const struct segment_type *segtype,
|
||||
struct alloced_area *aa,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv __attribute((unused)))
|
||||
{
|
||||
uint32_t s, extents, area_multiple, extra_areas = 0;
|
||||
uint32_t s, extents, area_multiple;
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (mirrored_pv)
|
||||
extra_areas = 1;
|
||||
|
||||
area_multiple = calc_area_multiple(segtype, area_count);
|
||||
|
||||
/* log_lv gets set up elsehere */
|
||||
@ -561,22 +569,14 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
|
||||
lv->le_count,
|
||||
aa[0].len * area_multiple,
|
||||
status, stripe_size, NULL,
|
||||
area_count + extra_areas,
|
||||
area_count,
|
||||
aa[0].len, 0u, region_size, 0u))) {
|
||||
log_error("Couldn't allocate new LV segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (extra_areas) {
|
||||
if (!set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
if (!set_lv_segment_area_pv(seg, s + extra_areas, aa[s].pv,
|
||||
aa[s].pe)) {
|
||||
if (!set_lv_segment_area_pv(seg, s, aa[s].pv, aa[s].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@ -600,8 +600,6 @@ static int _setup_alloced_segments(struct logical_volume *lv,
|
||||
uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
const struct segment_type *segtype,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
{
|
||||
@ -610,7 +608,6 @@ static int _setup_alloced_segments(struct logical_volume *lv,
|
||||
list_iterate_items(aa, &alloced_areas[0]) {
|
||||
if (!_setup_alloced_segment(lv, status, area_count,
|
||||
stripe_size, segtype, aa,
|
||||
mirrored_pv, mirrored_pe,
|
||||
region_size, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
@ -1180,7 +1177,6 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
uint32_t extents,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
unsigned can_split,
|
||||
struct list *parallel_areas)
|
||||
{
|
||||
struct alloc_handle *ah;
|
||||
@ -1209,7 +1205,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
|
||||
if (!segtype_is_virtual(segtype) &&
|
||||
!_allocate(ah, vg, lv, (lv ? lv->le_count : 0) + extents,
|
||||
can_split, allocatable_pvs)) {
|
||||
1, allocatable_pvs)) {
|
||||
stack;
|
||||
alloc_destroy(ah);
|
||||
return NULL;
|
||||
@ -1226,8 +1222,6 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t stripe_size,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
@ -1245,7 +1239,6 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
|
||||
num_areas, status,
|
||||
stripe_size, segtype,
|
||||
mirrored_pv, mirrored_pe,
|
||||
region_size, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
@ -1266,6 +1259,159 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* "mirror" segment type doesn't support split.
|
||||
* So, when adding mirrors to linear LV segment, first split it,
|
||||
* then convert it to "mirror" and add areas.
|
||||
*/
|
||||
static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
{
|
||||
struct lv_segment *newseg;
|
||||
uint32_t s;
|
||||
|
||||
if (!seg_is_striped(seg)) {
|
||||
log_error("Can't convert non-striped segment to mirrored.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (seg->area_count > 1) {
|
||||
log_error("Can't convert striped segment with multiple areas "
|
||||
"to mirrored.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(newseg = alloc_lv_segment(seg->lv->vg->cmd->mem,
|
||||
get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
log_lv,
|
||||
seg->area_count, seg->area_len,
|
||||
seg->chunk_size, region_size,
|
||||
seg->extents_copied))) {
|
||||
log_error("Couldn't allocate converted LV segment");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++)
|
||||
if (!move_lv_segment_area(newseg, s, seg, s))
|
||||
return_NULL;
|
||||
|
||||
list_add(&seg->list, &newseg->list);
|
||||
list_del(&seg->list);
|
||||
|
||||
return newseg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add new areas to mirrored segments
|
||||
*/
|
||||
int lv_add_mirror_areas(struct alloc_handle *ah,
|
||||
struct logical_volume *lv, uint32_t le,
|
||||
uint32_t region_size)
|
||||
{
|
||||
struct alloced_area *aa;
|
||||
struct lv_segment *seg;
|
||||
uint32_t current_le = le;
|
||||
uint32_t s, old_area_count, new_area_count;
|
||||
|
||||
list_iterate_items(aa, &ah->alloced_areas[0]) {
|
||||
if (!(seg = find_seg_by_le(lv, current_le))) {
|
||||
log_error("Failed to find segment for %s extent %"
|
||||
PRIu32, lv->name, current_le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocator assures aa[0].len <= seg->area_len */
|
||||
if (aa[0].len < seg->area_len) {
|
||||
if (!lv_split_segment(lv, seg->le + aa[0].len)) {
|
||||
log_error("Failed to split segment at %s "
|
||||
"extent %" PRIu32, lv->name, le);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!seg_is_mirrored(seg) &&
|
||||
(!(seg = _convert_seg_to_mirror(seg, region_size, NULL))))
|
||||
return_0;
|
||||
|
||||
old_area_count = seg->area_count;
|
||||
new_area_count = old_area_count + ah->area_count;
|
||||
|
||||
if (!_lv_segment_add_areas(lv, seg, new_area_count))
|
||||
return_0;
|
||||
|
||||
for (s = 0; s < ah->area_count; s++) {
|
||||
if (!set_lv_segment_area_pv(seg, s + old_area_count,
|
||||
aa[s].pv, aa[s].pe))
|
||||
return_0;
|
||||
}
|
||||
|
||||
current_le += seg->area_len;
|
||||
}
|
||||
|
||||
lv->status |= MIRRORED;
|
||||
|
||||
if (lv->vg->fid->fmt->ops->lv_setup &&
|
||||
!lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add mirror image LVs to mirrored segments
|
||||
*/
|
||||
int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t num_extra_areas,
|
||||
uint32_t status, uint32_t region_size)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t old_area_count, new_area_count;
|
||||
uint32_t m;
|
||||
struct segment_type *mirror_segtype;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
if (list_size(&lv->segments) != 1 || seg_type(seg, 0) != AREA_LV) {
|
||||
log_error("Mirror layer must be inserted before adding mirrors");
|
||||
return_0;
|
||||
}
|
||||
|
||||
mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
|
||||
if (seg->segtype != mirror_segtype)
|
||||
if (!(seg = _convert_seg_to_mirror(seg, region_size, NULL)))
|
||||
return_0;
|
||||
|
||||
if (region_size && region_size != seg->region_size) {
|
||||
log_error("Conflicting region_size");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = 0; m < old_area_count; m++) {
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn an empty LV into a mirror log.
|
||||
*/
|
||||
@ -1305,90 +1451,6 @@ int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a mirror segment
|
||||
*/
|
||||
int lv_add_mirror_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t mirrors,
|
||||
const struct segment_type *segtype __attribute((unused)),
|
||||
uint32_t status __attribute((unused)),
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t m;
|
||||
|
||||
if (log_lv && list_empty(&log_lv->segments)) {
|
||||
log_error("Log LV %s is empty.", log_lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem,
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"mirror"),
|
||||
lv, lv->le_count, ah->total_area_len, 0,
|
||||
0, log_lv, mirrors, ah->total_area_len, 0,
|
||||
region_size, 0))) {
|
||||
log_error("Couldn't allocate new mirror segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (m = 0; m < mirrors; m++) {
|
||||
set_lv_segment_area_lv(seg, m, sub_lvs[m], 0, MIRROR_IMAGE);
|
||||
first_seg(sub_lvs[m])->mirror_seg = seg;
|
||||
}
|
||||
|
||||
list_add(&lv->segments, &seg->list);
|
||||
lv->le_count += ah->total_area_len;
|
||||
lv->size += (uint64_t) lv->le_count *lv->vg->extent_size;
|
||||
|
||||
if (lv->vg->fid->fmt->ops->lv_setup &&
|
||||
!lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -1396,7 +1458,8 @@ int lv_extend(struct logical_volume *lv,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t stripes, uint32_t stripe_size,
|
||||
uint32_t mirrors, uint32_t extents,
|
||||
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
|
||||
struct physical_volume *mirrored_pv __attribute((unused)),
|
||||
uint32_t mirrored_pe __attribute((unused)),
|
||||
uint32_t status, struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc)
|
||||
{
|
||||
@ -1404,23 +1467,17 @@ int lv_extend(struct logical_volume *lv,
|
||||
uint32_t m;
|
||||
struct alloc_handle *ah;
|
||||
struct lv_segment *seg;
|
||||
unsigned can_split = 1;
|
||||
|
||||
if (segtype_is_virtual(segtype))
|
||||
return lv_add_virtual_segment(lv, status, extents, segtype);
|
||||
|
||||
/* FIXME Temporary restriction during code reorganisation */
|
||||
if (mirrored_pv)
|
||||
can_split = 0;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
|
||||
extents, allocatable_pvs, alloc, can_split,
|
||||
NULL)))
|
||||
extents, allocatable_pvs, alloc, NULL)))
|
||||
return_0;
|
||||
|
||||
if (mirrors < 2) {
|
||||
if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
|
||||
mirrored_pv, mirrored_pe, status, 0, NULL)) {
|
||||
status, 0, NULL)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@ -1430,7 +1487,7 @@ int lv_extend(struct logical_volume *lv,
|
||||
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)) {
|
||||
0, 0, 0, NULL)) {
|
||||
log_error("Aborting. Failed to extend %s.",
|
||||
seg_lv(seg, m)->name);
|
||||
return 0;
|
||||
@ -1900,3 +1957,504 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
log_print("Logical volume \"%s\" successfully removed", lv->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* insert_layer_for_segments_on_pv() inserts a layer segment for a segment area.
|
||||
* However, layer modification could split the underlying layer segment.
|
||||
* This function splits the parent area according to keep the 1:1 relationship
|
||||
* between the parent area and the underlying layer segment.
|
||||
* Since the layer LV might have other layers below, build_parallel_areas()
|
||||
* is used to find the lowest-level segment boundaries.
|
||||
*/
|
||||
static int _split_parent_area(struct lv_segment *seg, uint32_t s,
|
||||
struct list *layer_seg_pvs)
|
||||
{
|
||||
uint32_t parent_area_len, parent_le, layer_le;
|
||||
uint32_t area_multiple;
|
||||
struct seg_pvs *spvs;
|
||||
|
||||
if (seg_is_striped(seg))
|
||||
area_multiple = seg->area_count;
|
||||
else
|
||||
area_multiple = 1;
|
||||
|
||||
parent_area_len = seg->area_len;
|
||||
parent_le = seg->le;
|
||||
layer_le = seg_le(seg, s);
|
||||
|
||||
while (parent_area_len > 0) {
|
||||
/* Find the layer segment pointed at */
|
||||
if (!(spvs = _find_seg_pvs_by_le(layer_seg_pvs, layer_le))) {
|
||||
log_error("layer segment for %s:%" PRIu32 " not found",
|
||||
seg->lv->name, parent_le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (spvs->le != layer_le) {
|
||||
log_error("Incompatible layer boundary: "
|
||||
"%s:%" PRIu32 "[%" PRIu32 "] on %s:%" PRIu32,
|
||||
seg->lv->name, parent_le, s,
|
||||
seg_lv(seg, s)->name, layer_le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (spvs->len < parent_area_len) {
|
||||
parent_le += spvs->len * area_multiple;
|
||||
if (!lv_split_segment(seg->lv, parent_le))
|
||||
return_0;
|
||||
}
|
||||
|
||||
parent_area_len -= spvs->len;
|
||||
layer_le += spvs->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split the parent LV segments if the layer LV below it is splitted.
|
||||
*/
|
||||
int split_parent_segments_for_layer(struct cmd_context *cmd,
|
||||
struct logical_volume *layer_lv)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *parent_lv;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
struct list *parallel_areas;
|
||||
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, layer_lv)))
|
||||
return_0;
|
||||
|
||||
/* Loop through all LVs except itself */
|
||||
list_iterate_items(lvl, &layer_lv->vg->lvs) {
|
||||
parent_lv = lvl->lv;
|
||||
if (parent_lv == layer_lv)
|
||||
continue;
|
||||
|
||||
/* Find all segments that point at the layer LV */
|
||||
list_iterate_items(seg, &parent_lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != layer_lv)
|
||||
continue;
|
||||
|
||||
if (!_split_parent_area(seg, s, parallel_areas))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove a layer from the LV */
|
||||
int remove_layers_for_segments(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status_mask, struct list *lvs_changed)
|
||||
{
|
||||
struct lv_segment *seg, *lseg;
|
||||
uint32_t s;
|
||||
int lv_changed = 0;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/* Find all segments that point at the temporary mirror */
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != layer_lv)
|
||||
continue;
|
||||
|
||||
/* Find the layer segment pointed at */
|
||||
if (!(lseg = find_seg_by_le(layer_lv, seg_le(seg, s)))) {
|
||||
log_error("Layer segment found: %s:%" PRIu32,
|
||||
layer_lv->name, seg_le(seg, s));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the segment params are compatible */
|
||||
if (!seg_is_striped(lseg) || lseg->area_count != 1) {
|
||||
log_error("Layer is not linear: %s:%" PRIu32,
|
||||
layer_lv->name, lseg->le);
|
||||
return 0;
|
||||
}
|
||||
if ((lseg->status & status_mask) != status_mask) {
|
||||
log_error("Layer status does not match: "
|
||||
"%s:%" PRIu32 " status: 0x%x/0x%x",
|
||||
layer_lv->name, lseg->le,
|
||||
lseg->status, status_mask);
|
||||
return 0;
|
||||
}
|
||||
if (lseg->le != seg_le(seg, s) ||
|
||||
lseg->area_len != seg->area_len) {
|
||||
log_error("Layer boundary mismatch: "
|
||||
"%s:%" PRIu32 "-%" PRIu32 " on "
|
||||
"%s:%" PRIu32 " / "
|
||||
"%" PRIu32 "-%" PRIu32 " / ",
|
||||
lv->name, seg->le, seg->area_len,
|
||||
layer_lv->name, seg_le(seg, s),
|
||||
lseg->le, lseg->area_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!move_lv_segment_area(seg, s, lseg, 0))
|
||||
return_0;
|
||||
|
||||
/* Replace mirror with error segment */
|
||||
if (!(lseg->segtype =
|
||||
get_segtype_from_string(lv->vg->cmd, "error"))) {
|
||||
log_error("Missing error segtype");
|
||||
return 0;
|
||||
}
|
||||
lseg->area_count = 0;
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
if (!lv_changed && lvs_changed) {
|
||||
if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
return 0;
|
||||
}
|
||||
lvl->lv = lv;
|
||||
list_add(lvs_changed, &lvl->list);
|
||||
lv_changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lv_changed && !lv_merge_segments(lv))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove a layer */
|
||||
int remove_layers_for_segments_all(struct cmd_context *cmd,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status_mask,
|
||||
struct list *lvs_changed)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv1;
|
||||
|
||||
/* Loop through all LVs except the temporary mirror */
|
||||
list_iterate_items(lvl, &layer_lv->vg->lvs) {
|
||||
lv1 = lvl->lv;
|
||||
if (lv1 == layer_lv)
|
||||
continue;
|
||||
|
||||
if (!remove_layers_for_segments(cmd, lv1, layer_lv,
|
||||
status_mask, lvs_changed))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_empty(layer_lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _move_lv_segments(struct logical_volume *lv_to,
|
||||
struct logical_volume *lv_from,
|
||||
uint32_t set_status, uint32_t reset_status)
|
||||
{
|
||||
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;
|
||||
seg->status &= ~reset_status;
|
||||
seg->status |= set_status;
|
||||
}
|
||||
|
||||
/* FIXME: how to handle snapshot segments? */
|
||||
|
||||
list_init(&lv_from->segments);
|
||||
|
||||
lv_to->le_count = lv_from->le_count;
|
||||
lv_to->size = lv_from->size;
|
||||
|
||||
lv_from->le_count = 0;
|
||||
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)
|
||||
{
|
||||
struct logical_volume *orig_lv;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
orig_lv = seg_lv(first_seg(lv), 0);
|
||||
_move_lv_segments(lv, orig_lv, 0, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and insert a linear LV "above" lv_where.
|
||||
* After the insertion, a new LV named lv_where->name + suffix is created
|
||||
* and all segments of lv_where is moved to the new LV.
|
||||
* lv_where will have a single segment which maps linearly to the new LV.
|
||||
*/
|
||||
struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_where,
|
||||
uint32_t status,
|
||||
const char *layer_suffix)
|
||||
{
|
||||
struct logical_volume *layer_lv;
|
||||
char *name;
|
||||
size_t len;
|
||||
struct segment_type *segtype;
|
||||
struct lv_segment *mapseg;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv_where->vg->cmd, "striped")))
|
||||
return_NULL;
|
||||
|
||||
/* create an empty layer LV */
|
||||
|
||||
len = strlen(lv_where->name) + 32;
|
||||
if (!(name = alloca(len))) {
|
||||
log_error("layer name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dm_snprintf(name, len, "%s%s", lv_where->name, layer_suffix) < 0) {
|
||||
log_error("layer name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(layer_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE,
|
||||
ALLOC_INHERIT, 0, lv_where->vg))) {
|
||||
log_error("Creation of layer LV failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_very_verbose("Inserting layer %s for %s",
|
||||
layer_lv->name, lv_where->name);
|
||||
|
||||
_move_lv_segments(layer_lv, lv_where, 0, 0);
|
||||
|
||||
/* allocate a new linear segment */
|
||||
if (!(mapseg = alloc_lv_segment(lv_where->vg->cmd->mem, segtype,
|
||||
lv_where, 0, layer_lv->le_count,
|
||||
status, 0, NULL, 1, layer_lv->le_count,
|
||||
0, 0, 0)))
|
||||
return_NULL;
|
||||
|
||||
/* map the new segment to the original underlying are */
|
||||
set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0);
|
||||
|
||||
/* add the new segment to the layer LV */
|
||||
list_add(&lv_where->segments, &mapseg->list);
|
||||
lv_where->le_count = layer_lv->le_count;
|
||||
lv_where->size = lv_where->le_count * lv_where->vg->extent_size;
|
||||
|
||||
return layer_lv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend and insert a linear layer LV beneath the source segment area.
|
||||
*/
|
||||
static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
|
||||
struct lv_segment *seg, uint32_t s,
|
||||
uint32_t status)
|
||||
{
|
||||
struct lv_segment *mapseg;
|
||||
struct segment_type *segtype;
|
||||
struct physical_volume *src_pv = seg_pv(seg, s);
|
||||
uint32_t src_pe = seg_pe(seg, s);
|
||||
|
||||
if (seg_type(seg, s) != AREA_PV && seg_type(seg, s) != AREA_LV)
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, "striped")))
|
||||
return_0;
|
||||
|
||||
/* FIXME Incomplete message? Needs more context */
|
||||
log_very_verbose("Inserting %s:%" PRIu32 "-%" PRIu32 " of %s/%s",
|
||||
pv_dev_name(src_pv),
|
||||
src_pe, src_pe + seg->area_len - 1,
|
||||
seg->lv->vg->name, seg->lv->name);
|
||||
|
||||
/* allocate a new segment */
|
||||
if (!(mapseg = alloc_lv_segment(layer_lv->vg->cmd->mem, segtype,
|
||||
layer_lv, layer_lv->le_count,
|
||||
seg->area_len, status, 0,
|
||||
NULL, 1, seg->area_len, 0, 0, 0)))
|
||||
return_0;
|
||||
|
||||
/* map the new segment to the original underlying are */
|
||||
if (!move_lv_segment_area(mapseg, 0, seg, s))
|
||||
return_0;
|
||||
|
||||
/* add the new segment to the layer LV */
|
||||
list_add(&layer_lv->segments, &mapseg->list);
|
||||
layer_lv->le_count += seg->area_len;
|
||||
layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
|
||||
|
||||
/* map the original area to the new segment */
|
||||
set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match the segment area to PEs in the pvl
|
||||
* (the segment area boundary should be aligned to PE ranges by
|
||||
* _adjust_layer_segments() so that there is no partial overlap.)
|
||||
*/
|
||||
static int _match_seg_area_to_pe_range(struct lv_segment *seg, uint32_t s,
|
||||
struct pv_list *pvl)
|
||||
{
|
||||
struct pe_range *per;
|
||||
uint32_t pe_start, per_end;
|
||||
|
||||
if (!pvl)
|
||||
return 1;
|
||||
|
||||
if (seg_type(seg, s) != AREA_PV || seg_dev(seg, s) != pvl->pv->dev)
|
||||
return 0;
|
||||
|
||||
pe_start = seg_pe(seg, s);
|
||||
|
||||
/* Do these PEs match to any of the PEs in pvl? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
if ((pe_start < per->start) || (pe_start > per_end))
|
||||
continue;
|
||||
|
||||
/* FIXME Missing context in this message - add LV/seg details */
|
||||
log_debug("Matched PE range %s:%" PRIu32 "-%" PRIu32 " against "
|
||||
"%s %" PRIu32 " len %" PRIu32, dev_name(pvl->pv->dev),
|
||||
per->start, per_end, dev_name(seg_dev(seg, s)),
|
||||
seg_pe(seg, s), seg->area_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each segment in lv_where that uses a PV in pvl directly,
|
||||
* split the segment if it spans more than one underlying PV.
|
||||
*/
|
||||
static int _align_segment_boundary_to_pe_range(struct logical_volume *lv_where,
|
||||
struct pv_list *pvl)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct pe_range *per;
|
||||
uint32_t pe_start, pe_end, per_end, stripe_multiplier, s;
|
||||
|
||||
if (!pvl)
|
||||
return 1;
|
||||
|
||||
/* Split LV segments to match PE ranges */
|
||||
list_iterate_items(seg, &lv_where->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) != AREA_PV ||
|
||||
seg_dev(seg, s) != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
/* Do these PEs match with the condition? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
pe_start = seg_pe(seg, s);
|
||||
pe_end = pe_start + seg->area_len - 1;
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
/* No overlap? */
|
||||
if ((pe_end < per->start) ||
|
||||
(pe_start > per_end))
|
||||
continue;
|
||||
|
||||
if (seg_is_striped(seg))
|
||||
stripe_multiplier = seg->area_count;
|
||||
else
|
||||
stripe_multiplier = 1;
|
||||
|
||||
if ((per->start != pe_start &&
|
||||
per->start > pe_start) &&
|
||||
!lv_split_segment(lv_where, seg->le +
|
||||
(per->start - pe_start) *
|
||||
stripe_multiplier))
|
||||
return_0;
|
||||
|
||||
if ((per_end != pe_end &&
|
||||
per_end < pe_end) &&
|
||||
!lv_split_segment(lv_where, seg->le +
|
||||
(per_end - pe_start + 1) *
|
||||
stripe_multiplier))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan lv_where for segments on a PV in pvl, and for each one found
|
||||
* append a linear segment to lv_layer and insert it between the two.
|
||||
*
|
||||
* If pvl is empty, a layer is placed under the whole of lv_where.
|
||||
* If the layer is inserted, lv_where is added to lvs_changed.
|
||||
*/
|
||||
int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_where,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status,
|
||||
struct pv_list *pvl,
|
||||
struct list *lvs_changed)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct lv_list *lvl;
|
||||
int lv_used = 0;
|
||||
uint32_t s;
|
||||
|
||||
if (!_align_segment_boundary_to_pe_range(lv_where, pvl))
|
||||
return_0;
|
||||
|
||||
/* Work through all segments on the supplied PV */
|
||||
list_iterate_items(seg, &lv_where->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (!_match_seg_area_to_pe_range(seg, s, pvl))
|
||||
continue;
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
if (!lv_used && lvs_changed) {
|
||||
if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
return 0;
|
||||
}
|
||||
lvl->lv = lv_where;
|
||||
list_add(lvs_changed, &lvl->list);
|
||||
lv_used = 1;
|
||||
}
|
||||
|
||||
if (!_extend_layer_lv_for_segment(layer_lv, seg, s,
|
||||
status)) {
|
||||
log_error("Failed to insert segment in layer "
|
||||
"LV %s under %s:%" PRIu32 "-%" PRIu32,
|
||||
layer_lv->name, lv_where->name,
|
||||
seg->le, seg->le + seg->len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -379,6 +379,31 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
const char *new_name);
|
||||
|
||||
/*
|
||||
* Functions for layer manipulation
|
||||
*/
|
||||
int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_where,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status,
|
||||
struct pv_list *pv,
|
||||
struct list *lvs_changed);
|
||||
int remove_layers_for_segments(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status_mask, struct list *lvs_changed);
|
||||
int remove_layers_for_segments_all(struct cmd_context *cmd,
|
||||
struct logical_volume *layer_lv,
|
||||
uint32_t status_mask,
|
||||
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 *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_where,
|
||||
uint32_t status,
|
||||
const char *layer_suffix);
|
||||
|
||||
/* Find a PV within a given VG */
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id);
|
||||
@ -422,32 +447,42 @@ int vg_check_status(const struct volume_group *vg, uint32_t status);
|
||||
/*
|
||||
* Mirroring functions
|
||||
*/
|
||||
int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t stripes,
|
||||
uint32_t region_size, uint32_t log_count,
|
||||
struct list *pvs, alloc_policy_t alloc, uint32_t flags);
|
||||
int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
struct list *pvs, uint32_t status_mask);
|
||||
/* conversion flags */
|
||||
#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;
|
||||
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
uint32_t region_size);
|
||||
int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
int remove_mirrors_from_segments(struct logical_volume *lv,
|
||||
uint32_t new_mirrors, uint32_t status_mask);
|
||||
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,
|
||||
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,
|
||||
struct list *allocatable_pvs, alloc_policy_t alloc,
|
||||
uint32_t log_count);
|
||||
int remove_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct list *removable_pvs);
|
||||
int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t log_count, uint32_t region_size,
|
||||
struct list *allocatable_pvs, alloc_policy_t alloc);
|
||||
|
||||
int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct list *removable_pvs, unsigned remove_log);
|
||||
|
||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
struct list *lvs_changed);
|
||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
struct logical_volume *lv_mirr);
|
||||
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||
struct device *dev, uint32_t lv_type);
|
||||
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||
|
@ -295,11 +295,6 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le);
|
||||
/*
|
||||
* Mirroring functions
|
||||
*/
|
||||
int add_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t num_mirrors,
|
||||
uint32_t existing_mirrors,
|
||||
struct logical_volume *lv,
|
||||
const struct segment_type *segtype);
|
||||
|
||||
/*
|
||||
* Given mirror image or mirror log segment, find corresponding mirror segment
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -40,8 +40,8 @@ MOUNT=mount
|
||||
UMOUNT=umount
|
||||
MKDIR=mkdir
|
||||
RM=rm
|
||||
BLOCKDEV=blockdev
|
||||
BLKID=blkid
|
||||
BLOCKDEV=echo
|
||||
BLKID=echo
|
||||
GREP=grep
|
||||
READLINK=readlink
|
||||
FSCK=fsck
|
||||
@ -133,7 +133,7 @@ decode_size() {
|
||||
# detect filesystem on the given device
|
||||
# dereference device name if it is symbolic link
|
||||
detect_fs() {
|
||||
VOLUME=$($READLINK -e -n "$1")
|
||||
VOLUME=$($READLINK -n "$1")
|
||||
# use /dev/null as cache file to be sure about the result
|
||||
FSTYPE=$($BLKID -c /dev/null -o value -s TYPE "$VOLUME" || error "Cannot get FSTYPE of \"$VOLUME\"")
|
||||
verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
|
||||
|
@ -232,10 +232,6 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t existing_mirrors;
|
||||
struct alloc_handle *ah = NULL;
|
||||
struct logical_volume *log_lv;
|
||||
struct list *parallel_areas;
|
||||
float sync_percent;
|
||||
const char *mirrorlog;
|
||||
unsigned corelog = 0;
|
||||
|
||||
@ -312,8 +308,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!remove_mirror_images(seg, 1,
|
||||
lp->pv_count ? lp->pvh : NULL, 1))
|
||||
if (!lv_remove_mirrors(cmd, lv, existing_mirrors - 1, 1,
|
||||
lp->pv_count ? lp->pvh : NULL, 0))
|
||||
return_0;
|
||||
goto commit_changes;
|
||||
}
|
||||
@ -332,33 +328,13 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
}
|
||||
}
|
||||
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
|
||||
return_0;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype,
|
||||
1, lp->mirrors - 1,
|
||||
corelog ? 0U : 1U,
|
||||
lv->le_count, lp->pvh, lp->alloc,
|
||||
1, parallel_areas)))
|
||||
return_0;
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size);
|
||||
|
||||
log_lv = NULL;
|
||||
if (!corelog &&
|
||||
!(log_lv = create_mirror_log(cmd, lv->vg, ah,
|
||||
lp->alloc,
|
||||
lv->name, 0, &lv->tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
|
||||
lp->segtype, 0,
|
||||
lp->region_size,
|
||||
log_lv))
|
||||
if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, 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;
|
||||
goto commit_changes;
|
||||
}
|
||||
@ -375,54 +351,15 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
|
||||
if (lp->mirrors == existing_mirrors) {
|
||||
if (!seg->log_lv && !corelog) {
|
||||
/* No disk log present, add one. */
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
|
||||
if (!add_mirror_log(cmd, lv, 1,
|
||||
adjusted_mirror_region_size(
|
||||
lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
lp->pvh, lp->alloc))
|
||||
return_0;
|
||||
if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
|
||||
log_error("Unable to determine mirror sync status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype, 0,
|
||||
0, 1, 0, lp->pvh, lp->alloc,
|
||||
1, parallel_areas))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sync_percent >= 100.0)
|
||||
init_mirror_in_sync(1);
|
||||
else
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
|
||||
lp->alloc, lv->name,
|
||||
(sync_percent >= 100.0) ?
|
||||
1 : 0, &lv->tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
seg->log_lv = log_lv;
|
||||
log_lv->status |= MIRROR_LOG;
|
||||
first_seg(log_lv)->mirror_seg = seg;
|
||||
} else if (seg->log_lv && corelog) {
|
||||
/* Had disk log, switch to core. */
|
||||
if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
|
||||
log_error("Unable to determine mirror sync status.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sync_percent >= 100.0)
|
||||
init_mirror_in_sync(1);
|
||||
else {
|
||||
/* A full resync will take place */
|
||||
lv->status &= ~MIRROR_NOTSYNCED;
|
||||
init_mirror_in_sync(0);
|
||||
}
|
||||
|
||||
if (!remove_mirror_images(seg, lp->mirrors,
|
||||
lp->pv_count ?
|
||||
lp->pvh : NULL, 1))
|
||||
if (!remove_mirror_log(cmd, lv, lp->pvh))
|
||||
return_0;
|
||||
} else {
|
||||
/* No change */
|
||||
@ -442,9 +379,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
return 0;
|
||||
} else {
|
||||
/* Reduce number of mirrors */
|
||||
if (!remove_mirror_images(seg, lp->mirrors,
|
||||
lp->pv_count ?
|
||||
lp->pvh : NULL, 0))
|
||||
if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
|
||||
0, lp->pv_count ? lp->pvh : NULL, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,7 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "mirror"))) {
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@ -524,11 +524,10 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t size_rest;
|
||||
uint32_t status = 0;
|
||||
uint64_t tmp_size;
|
||||
struct logical_volume *lv, *org = NULL, *log_lv = NULL;
|
||||
struct logical_volume *lv, *org = NULL;
|
||||
struct list *pvh, tags;
|
||||
const char *tag = NULL;
|
||||
int origin_active = 0;
|
||||
struct alloc_handle *ah = NULL;
|
||||
char lv_name_buf[128];
|
||||
const char *lv_name;
|
||||
struct lvinfo info;
|
||||
@ -745,38 +744,6 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
/* FIXME Calculate how many extents needed for the log */
|
||||
|
||||
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
|
||||
lp->mirrors, lp->corelog ? 0U : 1U,
|
||||
lp->extents, pvh, lp->alloc, 1, NULL)))
|
||||
return_0;
|
||||
|
||||
lp->region_size = adjusted_mirror_region_size(vg->extent_size,
|
||||
lp->extents,
|
||||
lp->region_size);
|
||||
|
||||
init_mirror_in_sync(lp->nosync);
|
||||
|
||||
if (lp->nosync) {
|
||||
log_warn("WARNING: New mirror won't be synchronised. "
|
||||
"Don't read what you didn't write!");
|
||||
status |= MIRROR_NOTSYNCED;
|
||||
}
|
||||
|
||||
list_init(&tags);
|
||||
if (tag)
|
||||
str_list_add(cmd->mem, &tags, tag);
|
||||
|
||||
if (!lp->corelog &&
|
||||
!(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc,
|
||||
lv_name, lp->nosync, &tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lv = lv_create_empty(lv_name ? lv_name : "lvol%d", NULL,
|
||||
status, lp->alloc, 0, vg))) {
|
||||
stack;
|
||||
@ -802,19 +769,34 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
|
||||
1, lp->extents, NULL, 0u, 0u, pvh, lp->alloc))
|
||||
return_0;
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
if (!create_mirror_layers(ah, 0, lp->mirrors, lv,
|
||||
lp->segtype, 0,
|
||||
lp->region_size, log_lv)) {
|
||||
stack;
|
||||
goto error;
|
||||
init_mirror_in_sync(lp->nosync);
|
||||
|
||||
if (lp->nosync) {
|
||||
log_warn("WARNING: New mirror won't be synchronised. "
|
||||
"Don't read what you didn't write!");
|
||||
status |= MIRROR_NOTSYNCED;
|
||||
}
|
||||
|
||||
alloc_destroy(ah);
|
||||
ah = NULL;
|
||||
} else if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
|
||||
lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc))
|
||||
return_0;
|
||||
list_init(&tags);
|
||||
if (tag)
|
||||
str_list_add(cmd->mem, &tags, tag);
|
||||
|
||||
if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, lp->stripes,
|
||||
adjusted_mirror_region_size(
|
||||
vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size),
|
||||
lp->corelog ? 0U : 1U, pvh, lp->alloc,
|
||||
MIRROR_BY_LV)) {
|
||||
stack;
|
||||
goto revert_new_lv;
|
||||
}
|
||||
}
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!vg_write(vg))
|
||||
@ -901,8 +883,6 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 1;
|
||||
|
||||
error:
|
||||
if (ah)
|
||||
alloc_destroy(ah);
|
||||
return 0;
|
||||
|
||||
deactivate_and_revert_new_lv:
|
||||
|
@ -106,6 +106,40 @@ static struct list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
|
||||
return allocatable_pvs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace any LV segments on given PV with temporary mirror.
|
||||
* Returns list of LVs changed.
|
||||
*/
|
||||
static int _insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *lvs_changed)
|
||||
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
uint32_t prev_le_count;
|
||||
|
||||
/* Only 1 PV may feature in source_pvl */
|
||||
pvl = list_item(source_pvl->n, struct pv_list);
|
||||
|
||||
prev_le_count = lv_mirr->le_count;
|
||||
if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE,
|
||||
pvl, lvs_changed))
|
||||
return_0;
|
||||
|
||||
/* check if layer was inserted */
|
||||
if (lv_mirr->le_count - prev_le_count) {
|
||||
lv->status |= LOCKED;
|
||||
|
||||
log_verbose("Moving %u extents of logical volume %s/%s",
|
||||
lv_mirr->le_count - prev_le_count,
|
||||
lv->vg->name, lv->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create new LV with mirror segments for the required copies */
|
||||
static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
@ -117,6 +151,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
{
|
||||
struct logical_volume *lv_mirr, *lv;
|
||||
struct lv_list *lvl;
|
||||
uint32_t log_count = 0;
|
||||
|
||||
/* FIXME Cope with non-contiguous => splitting existing segments */
|
||||
if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
|
||||
@ -161,14 +196,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
log_print("Skipping locked LV %s", lv->name);
|
||||
continue;
|
||||
}
|
||||
/* FIXME Just insert the layer below - no allocation */
|
||||
// This knows nothing about pvmove
|
||||
// insert_layer_for_segments_on_pv(cmd, lv, source_pvl, lv_mirr, *lvs_changed)
|
||||
// - for each lv segment using that pv
|
||||
// - call new fn insert_internal_layer()
|
||||
if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
|
||||
allocatable_pvs, alloc,
|
||||
*lvs_changed)) {
|
||||
if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
|
||||
*lvs_changed)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@ -180,9 +209,16 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME Do allocation and convert to mirror */
|
||||
// again, this knows nothing about pvmove: it's a normal lvconvert lv_mirr to mirror with in-core log
|
||||
// - a flag passed in requires that parent segs get split after the allocation (with failure if not possible)
|
||||
if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count,
|
||||
allocatable_pvs, alloc, MIRROR_BY_SEG)) {
|
||||
log_error("Failed to convert pvmove LV to mirrored");
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
if (!split_parent_segments_for_layer(cmd, lv_mirr)) {
|
||||
log_error("Failed to split segments being moved");
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
return lv_mirr;
|
||||
}
|
||||
@ -381,13 +417,22 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct list *lvs_changed)
|
||||
{
|
||||
int r = 1;
|
||||
struct list lvs_completed;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/* Update metadata to remove mirror segments and break dependencies */
|
||||
if (!remove_pvmove_mirrors(vg, lv_mirr)) {
|
||||
list_init(&lvs_completed);
|
||||
if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
|
||||
!remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
|
||||
&lvs_completed)) {
|
||||
log_error("ABORTING: Removal of temporary mirror failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(lvl, &lvs_completed)
|
||||
/* FIXME Assumes only one pvmove at a time! */
|
||||
lvl->lv->status &= ~LOCKED;
|
||||
|
||||
/* Store metadata without dependencies on mirror segments */
|
||||
if (!vg_write(vg)) {
|
||||
log_error("ABORTING: Failed to write new data locations "
|
||||
@ -488,6 +533,17 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
|
||||
char *pv_name = NULL;
|
||||
char *colon;
|
||||
int ret;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
return_0;
|
||||
|
||||
if (activation() && segtype->ops->target_present &&
|
||||
!segtype->ops->target_present(NULL)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
pv_name = argv[0];
|
||||
|
166
tools/toollib.c
166
tools/toollib.c
@ -1241,26 +1241,6 @@ int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int generate_log_name_format(struct volume_group *vg __attribute((unused)),
|
||||
const char *lv_name, char *buffer, size_t size)
|
||||
{
|
||||
if (dm_snprintf(buffer, size, "%s_mlog", lv_name) < 0) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME I think we can cope without this. Cf. _add_lv_to_dtree()
|
||||
if (find_lv_in_vg(vg, buffer) &&
|
||||
dm_snprintf(buffer, size, "%s_mlog_%%d",
|
||||
lv_name) < 0) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*******/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the LV with 'value'.
|
||||
*/
|
||||
@ -1307,149 +1287,3 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes a new header to the mirror log header to the lv
|
||||
*
|
||||
* Returns: 1 on success, 0 on failure
|
||||
*/
|
||||
static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
struct device *dev;
|
||||
char *name;
|
||||
struct { /* The mirror log header */
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint64_t nr_regions;
|
||||
} log_header;
|
||||
|
||||
log_header.magic = xlate32(MIRROR_MAGIC);
|
||||
log_header.version = xlate32(MIRROR_DISK_VERSION);
|
||||
log_header.nr_regions = xlate64((uint64_t)-1);
|
||||
|
||||
if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Name allocation failed - log header not written (%s)",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
|
||||
lv->vg->name, lv->name) < 0) {
|
||||
log_error("Name too long - log header not written (%s)", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Writing log header to device, %s", lv->name);
|
||||
|
||||
if (!(dev = dev_cache_get(name, NULL))) {
|
||||
log_error("%s: not found: log header not written", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_open_quiet(dev))
|
||||
return 0;
|
||||
|
||||
if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
|
||||
log_error("Failed to write log header to %s", name);
|
||||
dev_close_immediate(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_close_immediate(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name,
|
||||
int in_sync,
|
||||
struct list *tags)
|
||||
{
|
||||
struct logical_volume *log_lv;
|
||||
char *log_name;
|
||||
size_t len;
|
||||
struct str_list *sl;
|
||||
|
||||
if (!activation() && in_sync) {
|
||||
log_error("Aborting. Unable to create in-sync mirror log "
|
||||
"while activation is disabled.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen(lv_name) + 32;
|
||||
if (!(log_name = alloca(len)) ||
|
||||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
|
||||
log_error("log_name allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(log_lv = lv_create_empty(log_name, NULL,
|
||||
VISIBLE_LV | LVM_READ | LVM_WRITE,
|
||||
alloc, 0, vg)))
|
||||
return_NULL;
|
||||
|
||||
if (!lv_add_log_segment(ah, log_lv))
|
||||
return_NULL;
|
||||
|
||||
/* Temporary tag mirror log */
|
||||
list_iterate_items(sl, tags)
|
||||
if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
|
||||
log_error("Aborting. Unable to tag mirror log.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* store mirror log on disk(s) */
|
||||
if (!vg_write(vg))
|
||||
return_NULL;
|
||||
|
||||
backup(vg);
|
||||
|
||||
if (!vg_commit(vg))
|
||||
return_NULL;
|
||||
|
||||
if (!activate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to activate mirror log.");
|
||||
goto revert_new_lv;
|
||||
}
|
||||
|
||||
list_iterate_items(sl, tags)
|
||||
if (!str_list_del(&log_lv->tags, sl->str))
|
||||
log_error("Failed to remove tag %s from mirror log.",
|
||||
sl->str);
|
||||
|
||||
if (activation() && !set_lv(cmd, log_lv, log_lv->size,
|
||||
in_sync ? -1 : 0)) {
|
||||
log_error("Aborting. Failed to wipe mirror log.");
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
if (activation() && !_write_log_header(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to write mirror log header.");
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to deactivate mirror log. "
|
||||
"Manual intervention required.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
|
||||
return log_lv;
|
||||
|
||||
deactivate_and_revert_new_lv:
|
||||
if (!deactivate_lv(cmd, log_lv)) {
|
||||
log_error("Unable to deactivate mirror log LV. "
|
||||
"Manual intervention required.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
revert_new_lv:
|
||||
if (!lv_remove(log_lv) || !vg_write(vg) || (backup(vg), !vg_commit(vg)))
|
||||
log_error("Manual intervention may be required to remove "
|
||||
"abandoned log LV before retrying.");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -98,17 +98,6 @@ int apply_lvname_restrictions(const char *name);
|
||||
|
||||
int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int generate_log_name_format(struct volume_group *vg, const char *lv_name,
|
||||
char *buffer, size_t size);
|
||||
|
||||
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name,
|
||||
int in_sync,
|
||||
struct list *tags);
|
||||
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint64_t sectors, int value);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user