From 46a68b7dd60c056955aa15906b575e5172ebb937 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 6 May 2003 12:22:24 +0000 Subject: [PATCH] move functions --- lib/metadata/mirror.c | 250 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 lib/metadata/mirror.c diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c new file mode 100644 index 000000000..e0c7ba225 --- /dev/null +++ b/lib/metadata/mirror.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2003 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#include "lib.h" +#include "metadata.h" +#include "toolcontext.h" + +/* + * Replace any LV segments on given PV with temporary mirror. + * Returns list of LVs changed. + */ +int insert_pvmove_mirrors(struct cmd_context *cmd, + struct logical_volume *lv_mirr, + struct physical_volume *pv, + struct logical_volume *lv, + struct list *allocatable_pvs, + struct list *lvs_changed) +{ + struct list *segh; + struct lv_segment *seg; + struct lv_list *lvl; + int lv_used = 0; + uint32_t s, start_le, extent_count = 0u; + + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct lv_segment); + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV || + seg->area[s].u.pv.pv->dev != pv->dev) + continue; + + if (!lv_used) { + if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) { + log_error("lv_list alloc failed"); + return 0; + } + lvl->lv = lv; + list_add(lvs_changed, &lvl->list); + lv_used = 1; + } + + start_le = lv_mirr->le_count; + if (!lv_extend_mirror(lv->vg->fid, lv_mirr, + seg->area[s].u.pv.pv, + seg->area[s].u.pv.pe, + seg->area_len, allocatable_pvs, + PVMOVE)) { + log_error("Allocation for temporary " + "pvmove LV failed"); + return 0; + } + seg->area[s].type = AREA_LV; + seg->area[s].u.lv.lv = lv_mirr; + seg->area[s].u.lv.le = start_le; + + extent_count += seg->area_len; + + lv->status |= LOCKED; + } + } + + log_verbose("Moving %u extents of logical volume %s/%s", extent_count, + lv->vg->name, lv->name); + + return 1; +} + +/* Remove a temporary mirror */ +int remove_pvmove_mirrors(struct volume_group *vg, + struct logical_volume *lv_mirr) +{ + struct list *lvh, *segh; + struct logical_volume *lv1; + struct lv_segment *seg, *mir_seg; + uint32_t s, c; + + list_iterate(lvh, &vg->lvs) { + lv1 = list_item(lvh, struct lv_list)->lv; + if (lv1 == lv_mirr) + continue; + + list_iterate(segh, &lv1->segments) { + seg = list_item(segh, struct lv_segment); + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_LV || + seg->area[s].u.lv.lv != lv_mirr) + continue; + + if (!(mir_seg = find_seg_by_le(lv_mirr, + seg->area[s].u. + lv.le))) { + log_error("No segment found with LE"); + return 0; + } + + if (mir_seg->type != SEG_MIRRORED || + !(mir_seg->status & PVMOVE) || + mir_seg->le != seg->area[s].u.lv.le || + mir_seg->area_count != 2 || + mir_seg->area_len != seg->area_len) { + log_error("Incompatible segments"); + return 0; + } + + if (mir_seg->extents_moved == mir_seg->area_len) + c = 1; + else + c = 0; + + seg->area[s].type = AREA_PV; + seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv; + seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe; + + mir_seg->type = SEG_STRIPED; + mir_seg->area_count = 1; + + lv1->status &= ~LOCKED; + } + } + } + + return 1; +} + +struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume + *lv_mirr) +{ + struct list *segh; + struct lv_segment *seg; + + list_iterate(segh, &lv_mirr->segments) { + seg = list_item(segh, struct lv_segment); + if (seg->type != SEG_MIRRORED) + continue; + if (seg->area[0].type != AREA_PV) + continue; + return seg->area[0].u.pv.pv; + } + + return NULL; +} + +struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv) +{ + struct list *segh; + struct lv_segment *seg; + uint32_t s; + + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct lv_segment); + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_LV) + continue; + return get_pvmove_pv_from_lv_mirr(seg->area[s].u.lv.lv); + } + } + + return NULL; +} + +struct logical_volume *find_pvmove_lv(struct volume_group *vg, + struct device *dev) +{ + struct list *lvh, *segh; + struct logical_volume *lv; + struct lv_segment *seg; + + /* Loop through all LVs */ + list_iterate(lvh, &vg->lvs) { + lv = list_item(lvh, struct lv_list)->lv; + + if (!(lv->status & PVMOVE)) + continue; + + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct lv_segment); + if (seg->area[0].type != AREA_PV) + continue; + if (seg->area[0].u.pv.pv->dev != dev) + continue; + return lv; + } + } + + return NULL; +} + +struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg, + struct logical_volume *lv) +{ + struct list *lvh, *segh, *lvs; + struct logical_volume *lv1; + struct lv_list *lvl; + struct lv_segment *seg; + uint32_t s; + + if (!(lvs = pool_alloc(cmd->mem, sizeof(*lvs)))) { + log_error("lvs list alloc failed"); + return NULL; + } + + list_init(lvs); + + /* Loop through all LVs except the one supplied */ + list_iterate(lvh, &vg->lvs) { + lv1 = list_item(lvh, struct lv_list)->lv; + if (lv1 == lv) + continue; + + list_iterate(segh, &lv1->segments) { + seg = list_item(segh, struct lv_segment); + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_LV || + seg->area[s].u.lv.lv != lv) + continue; + if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) { + log_error("lv_list alloc failed"); + return NULL; + } + lvl->lv = lv1; + list_add(lvs, &lvl->list); + goto next_lv; + } + } + next_lv: + } + + return lvs; +} + +float pvmove_percent(struct logical_volume *lv_mirr) +{ + uint32_t numerator = 0u, denominator = 0u; + struct list *segh; + struct lv_segment *seg; + + list_iterate(segh, &lv_mirr->segments) { + seg = list_item(segh, struct lv_segment); + if (!(seg->status & PVMOVE)) + continue; + + numerator += seg->extents_moved; + denominator += seg->area_len; + } + + return denominator ? (float) numerator *100 / denominator : 100.0; +}