1
0
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:
Alasdair Kergon 2007-12-20 15:42:55 +00:00
parent 72199adfc3
commit a69ab65278
12 changed files with 1467 additions and 815 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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\""

View File

@ -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;
}

View File

@ -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:

View File

@ -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];

View File

@ -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;
}

View File

@ -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);