/* * 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; } 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; }