1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-28 11:55:55 +03:00
lvm2/lib/metadata/mirror.c

749 lines
18 KiB
C
Raw Normal View History

2003-05-06 16:22:24 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
2005-11-29 21:20:23 +03:00
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
2003-05-06 16:22:24 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2003-05-06 16:22:24 +04:00
*/
#include "lib.h"
#include "metadata.h"
#include "toolcontext.h"
2004-09-16 22:40:56 +04:00
#include "segtype.h"
2004-05-05 01:25:57 +04:00
#include "display.h"
#include "activate.h"
2005-04-22 19:43:02 +04:00
#include "lv_alloc.h"
#include "lvm-string.h"
2005-11-29 21:20:23 +03:00
#include "locking.h" /* FIXME Should not be used in this file */
struct lv_segment *find_mirror_seg(struct lv_segment *seg)
{
return seg->mirror_seg;
}
/*
* Ensure region size is compatible with volume size.
*/
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
uint32_t region_size)
{
uint32_t region_max;
region_max = (1 << (ffs(extents) - 1)) * extent_size;
if (region_max < region_size) {
region_size = region_max;
log_print("Using reduced mirror region size of %" PRIu32
" sectors", region_max);
return region_max;
}
return region_size;
}
2005-10-28 16:48:50 +04:00
static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volume *lv_from)
{
struct lv_segment *seg;
lv_to->segments = lv_from->segments;
lv_to->segments.n->p = &lv_to->segments;
lv_to->segments.p->n = &lv_to->segments;
list_iterate_items(seg, &lv_to->segments)
seg->lv = lv_to;
/* FIXME set or reset seg->mirror_seg (according to status)? */
list_init(&lv_from->segments);
2005-11-29 21:20:23 +03:00
lv_to->le_count = lv_from->le_count;
lv_to->size = lv_from->size;
2005-10-28 16:48:50 +04:00
lv_from->le_count = 0;
lv_from->size = 0;
}
/*
* Reduce mirrored_seg to num_mirrors images.
*/
2005-11-29 21:20:23 +03:00
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
struct list *removable_pvs, int remove_log)
{
uint32_t m;
2005-11-29 21:20:23 +03:00
uint32_t s, s1;
struct logical_volume *sub_lv;
struct logical_volume *log_lv = NULL;
struct logical_volume *lv1 = NULL;
struct physical_volume *pv;
struct lv_segment *seg;
struct lv_segment_area area;
int all_pvs_removable, pv_found;
struct pv_list *pvl;
uint32_t old_area_count = mirrored_seg->area_count;
uint32_t new_area_count = mirrored_seg->area_count;
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
PRIu32 " image(s)%s.",
old_area_count, num_mirrors,
remove_log ? " and no log volume" : "");
/* Move removable_pvs to end of array */
if (removable_pvs) {
for (s = 0; s < mirrored_seg->area_count; s++) {
all_pvs_removable = 1;
sub_lv = seg_lv(mirrored_seg, s);
list_iterate_items(seg, &sub_lv->segments) {
for (s1 = 0; s1 < seg->area_count; s1++) {
if (seg_type(seg, s1) != AREA_PV)
/* FIXME Recurse for AREA_LV */
continue;
pv = seg_pv(seg, s1);
pv_found = 0;
list_iterate_items(pvl, removable_pvs) {
if (pv->dev->dev == pvl->pv->dev->dev) {
pv_found = 1;
break;
}
}
if (!pv_found) {
all_pvs_removable = 0;
break;
}
}
if (!all_pvs_removable)
break;
}
if (all_pvs_removable) {
/* Swap segment to end */
new_area_count--;
area = mirrored_seg->areas[new_area_count];
mirrored_seg->areas[new_area_count] = mirrored_seg->areas[s];
mirrored_seg->areas[s] = area;
}
/* Found enough matches? */
if (new_area_count == num_mirrors)
break;
}
if (new_area_count == mirrored_seg->area_count) {
log_error("No mirror images found using specified PVs.");
return 0;
}
}
2005-11-29 21:20:23 +03:00
for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
seg_lv(mirrored_seg, m)->status |= VISIBLE_LV;
}
mirrored_seg->area_count = num_mirrors;
2005-11-29 21:20:23 +03:00
/* If no more mirrors, remove mirror layer */
if (num_mirrors == 1) {
lv1 = seg_lv(mirrored_seg, 0);
_move_lv_segments(mirrored_seg->lv, lv1);
mirrored_seg->lv->status &= ~MIRRORED;
remove_log = 1;
}
2005-11-29 21:20:23 +03:00
if (remove_log) {
log_lv = mirrored_seg->log_lv;
mirrored_seg->log_lv = NULL;
}
2005-11-29 21:20:23 +03:00
/*
* To successfully remove these unwanted LVs we need to
* remove the LVs from the mirror set, commit that metadata
* then deactivate and remove them fully.
*/
2005-11-29 21:20:23 +03:00
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
if (!vg_write(mirrored_seg->lv->vg)) {
log_error("intermediate VG write failed.");
return 0;
}
2005-11-29 21:20:23 +03:00
if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
log_error("Failed to lock %s", mirrored_seg->lv->name);
vg_revert(mirrored_seg->lv->vg);
return 0;
}
2005-11-29 21:20:23 +03:00
if (!vg_commit(mirrored_seg->lv->vg)) {
resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
return 0;
}
2005-11-29 21:20:23 +03:00
log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
2005-11-29 21:20:23 +03:00
if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
log_error("Problem reactivating %s", mirrored_seg->lv->name);
return 0;
}
2005-11-29 21:20:23 +03:00
/* Delete the 'orphan' LVs */
for (m = num_mirrors; m < old_area_count; m++) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
stack;
return 0;
}
2005-11-29 21:20:23 +03:00
if (!lv_remove(seg_lv(mirrored_seg, m))) {
stack;
return 0;
}
}
2005-11-29 21:20:23 +03:00
if (lv1) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
stack;
return 0;
}
if (!lv_remove(lv1)) {
stack;
return 0;
}
}
if (log_lv) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
stack;
return 0;
}
if (!lv_remove(log_lv)) {
stack;
return 0;
}
}
return 1;
}
2005-10-28 16:48:50 +04:00
static int _create_layers_for_mirror(struct alloc_handle *ah,
uint32_t first_area,
uint32_t num_mirrors,
struct logical_volume *lv,
struct segment_type *segtype,
struct logical_volume **img_lvs)
{
uint32_t m;
char *img_name;
size_t len;
len = strlen(lv->name) + 32;
if (!(img_name = alloca(len))) {
log_error("img_name allocation failed. "
"Remove new LV and retry.");
return 0;
}
if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
log_error("img_name allocation failed. "
"Remove new LV and retry.");
return 0;
}
for (m = 0; m < num_mirrors; m++) {
if (!(img_lvs[m] = lv_create_empty(lv->vg->fid, img_name,
NULL, LVM_READ | LVM_WRITE,
ALLOC_INHERIT, 0, lv->vg))) {
log_error("Aborting. Failed to create mirror image LV. "
"Remove new LV and retry.");
return 0;
}
2005-11-29 21:20:23 +03:00
if (m < first_area)
continue;
if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
get_segtype_from_string(lv->vg->cmd,
"striped"),
0, NULL, 0, 0, 0, NULL)) {
log_error("Aborting. Failed to add mirror image segment "
"to %s. Remove new LV and retry.",
img_lvs[m]->name);
return 0;
}
}
2005-10-28 16:48:50 +04:00
return 1;
}
int create_mirror_layers(struct alloc_handle *ah,
uint32_t first_area,
uint32_t num_mirrors,
struct logical_volume *lv,
struct segment_type *segtype,
uint32_t status,
uint32_t region_size,
struct logical_volume *log_lv)
{
struct logical_volume **img_lvs;
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
log_error("img_lvs allocation failed. "
"Remove new LV and retry.");
return 0;
}
if (!_create_layers_for_mirror(ah, first_area, num_mirrors, lv,
segtype, img_lvs)) {
stack;
return 0;
}
/* Already got the parent mirror segment? */
if (lv->status & MIRRORED)
return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors,
MIRROR_IMAGE);
/* Already got a non-mirrored area to be converted? */
if (first_area)
2005-10-28 16:48:50 +04:00
_move_lv_segments(img_lvs[0], lv);
if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
0, region_size, log_lv)) {
log_error("Aborting. Failed to add mirror segment. "
"Remove new LV and retry.");
return 0;
}
lv->status |= MIRRORED;
return 1;
}
2003-05-06 16:22:24 +04:00
2005-11-29 21:20:23 +03:00
int add_mirror_layers(struct alloc_handle *ah,
uint32_t num_mirrors,
uint32_t existing_mirrors,
struct logical_volume *lv,
struct segment_type *segtype)
{
struct logical_volume **img_lvs;
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
log_error("img_lvs allocation failed. "
"Remove new LV and retry.");
return 0;
}
if (!_create_layers_for_mirror(ah, 0, num_mirrors,
lv, segtype,
img_lvs)) {
stack;
return 0;
}
return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors, 0);
}
2003-05-06 16:22:24 +04:00
/*
* 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 list *source_pvl,
2003-05-06 16:22:24 +04:00
struct logical_volume *lv,
struct list *allocatable_pvs,
alloc_policy_t alloc,
2003-05-06 16:22:24 +04:00
struct list *lvs_changed)
{
struct lv_segment *seg;
struct lv_list *lvl;
struct pv_list *pvl;
struct physical_volume *pv;
uint32_t pe;
2003-05-06 16:22:24 +04:00
int lv_used = 0;
uint32_t s, start_le, extent_count = 0u;
2004-05-05 01:25:57 +04:00
struct segment_type *segtype;
struct pe_range *per;
uint32_t pe_start, pe_end, per_end, stripe_multiplier;
/* Only 1 PV may feature in source_pvl */
pvl = list_item(source_pvl->n, struct pv_list);
2004-05-05 01:25:57 +04:00
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "mirror"))) {
stack;
return 0;
}
2003-05-06 16:22:24 +04:00
if (activation() && segtype->ops->target_present &&
!segtype->ops->target_present()) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", segtype->name);
return 0;
}
/* Split LV segments to match PE ranges */
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv->segments) {
2003-05-06 16:22:24 +04:00
for (s = 0; s < seg->area_count; s++) {
2005-06-01 20:51:55 +04:00
if (seg_type(seg, s) != AREA_PV ||
seg_dev(seg, s) != pvl->pv->dev)
2003-05-06 16:22:24 +04:00
continue;
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
2005-06-01 20:51:55 +04:00
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, seg->le +
(per->start - pe_start) *
stripe_multiplier)) {
stack;
2003-05-06 16:22:24 +04:00
return 0;
}
if ((per_end != pe_end &&
per_end < pe_end) &&
!lv_split_segment(lv, seg->le +
(per_end - pe_start + 1) *
stripe_multiplier)) {
stack;
return 0;
}
2003-05-06 16:22:24 +04:00
}
}
}
2003-05-06 16:22:24 +04:00
/* Work through all segments on the supplied PV */
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv->segments) {
for (s = 0; s < seg->area_count; s++) {
2005-06-01 20:51:55 +04:00
if (seg_type(seg, s) != AREA_PV ||
seg_dev(seg, s) != pvl->pv->dev)
continue;
2005-06-01 20:51:55 +04:00
pe_start = seg_pe(seg, s);
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
per_end = per->start + per->count - 1;
2003-05-06 16:22:24 +04:00
if ((pe_start < per->start) ||
(pe_start > per_end))
continue;
log_debug("Matched PE range %u-%u against "
"%s %u len %u", per->start, per_end,
2005-06-01 20:51:55 +04:00
dev_name(seg_dev(seg, s)),
seg_pe(seg, s),
seg->area_len);
/* First time, add LV to list of LVs affected */
if (!lv_used) {
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_used = 1;
}
pv = seg_pv(seg, s);
pe = seg_pe(seg, s);
log_very_verbose("Moving %s:%u-%u of %s/%s",
dev_name(pvl->pv->dev),
pe, pe + seg->area_len - 1,
lv->vg->name, lv->name);
start_le = lv_mirr->le_count;
/* FIXME Clean this up */
release_lv_segment_area(seg, s, seg->area_len);
if (!lv_extend(lv_mirr, segtype, 1,
seg->area_len, 0u, seg->area_len,
pv, pe,
PVMOVE, allocatable_pvs,
alloc)) {
log_error("Unable to allocate "
"temporary LV for pvmove.");
return 0;
}
set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
extent_count += seg->area_len;
lv->status |= LOCKED;
break;
}
2003-05-06 16:22:24 +04:00
}
}
log_verbose("Moving %u extents of logical volume %s/%s", extent_count,
lv->vg->name, lv->name);
return 1;
}
2004-05-05 22:35:04 +04:00
/* Remove a temporary mirror */
2003-05-06 16:22:24 +04:00
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr)
{
2005-06-01 20:51:55 +04:00
struct lv_list *lvl;
2003-05-06 16:22:24 +04:00
struct logical_volume *lv1;
struct lv_segment *seg, *mir_seg;
uint32_t s, c;
2004-05-05 22:35:04 +04:00
/* Loop through all LVs except the temporary mirror */
2005-06-01 20:51:55 +04:00
list_iterate_items(lvl, &vg->lvs) {
lv1 = lvl->lv;
2003-05-06 16:22:24 +04:00
if (lv1 == lv_mirr)
continue;
2004-05-05 22:35:04 +04:00
/* Find all segments that point at the temporary mirror */
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv1->segments) {
2003-05-06 16:22:24 +04:00
for (s = 0; s < seg->area_count; s++) {
2005-06-01 20:51:55 +04:00
if (seg_type(seg, s) != AREA_LV ||
seg_lv(seg, s) != lv_mirr)
2003-05-06 16:22:24 +04:00
continue;
2004-05-05 22:35:04 +04:00
/* Find the mirror segment pointed at */
2003-05-06 16:22:24 +04:00
if (!(mir_seg = find_seg_by_le(lv_mirr,
2005-06-01 20:51:55 +04:00
seg_le(seg, s)))) {
2004-05-05 22:35:04 +04:00
/* FIXME Error message */
2003-05-06 16:22:24 +04:00
log_error("No segment found with LE");
return 0;
}
2004-05-05 22:35:04 +04:00
/* Check the segment params are compatible */
/* FIXME Improve error mesg & remove restrcn */
if (!seg_is_mirrored(mir_seg) ||
2003-05-06 16:22:24 +04:00
!(mir_seg->status & PVMOVE) ||
2005-06-01 20:51:55 +04:00
mir_seg->le != seg_le(seg, s) ||
2003-05-06 16:22:24 +04:00
mir_seg->area_count != 2 ||
mir_seg->area_len != seg->area_len) {
log_error("Incompatible segments");
return 0;
}
2004-05-05 22:35:04 +04:00
/* Replace original segment with newly-mirrored
* area (or original if reverting)
*/
if (mir_seg->extents_copied ==
mir_seg->area_len)
2003-05-06 16:22:24 +04:00
c = 1;
else
c = 0;
if (!move_lv_segment_area(seg, s, mir_seg, c)) {
stack;
return 0;
}
2003-05-06 16:22:24 +04:00
release_lv_segment_area(mir_seg, !c, mir_seg->area_len);
/* Replace mirror with error segment */
2004-05-05 01:25:57 +04:00
if (!
(mir_seg->segtype =
get_segtype_from_string(vg->cmd,
"error"))) {
log_error("Missing error segtype");
2004-05-05 01:25:57 +04:00
return 0;
}
mir_seg->area_count = 0;
2003-05-06 16:22:24 +04:00
2004-05-05 22:35:04 +04:00
/* FIXME Assumes only one pvmove at a time! */
2003-05-06 16:22:24 +04:00
lv1->status &= ~LOCKED;
}
}
if (!lv_merge_segments(lv1))
stack;
2003-05-06 16:22:24 +04:00
}
if (!lv_empty(lv_mirr)) {
stack;
return 0;
}
2003-05-06 16:22:24 +04:00
return 1;
}
2004-05-05 21:56:20 +04:00
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
2003-05-06 16:22:24 +04:00
{
struct lv_segment *seg;
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv_mirr->segments) {
if (!seg_is_mirrored(seg))
2003-05-06 16:22:24 +04:00
continue;
if (seg_type(seg, 0) != AREA_PV)
2003-05-06 16:22:24 +04:00
continue;
2005-06-01 20:51:55 +04:00
return dev_name(seg_dev(seg, 0));
2003-05-06 16:22:24 +04:00
}
return NULL;
}
2004-05-05 21:56:20 +04:00
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
2003-05-06 16:22:24 +04:00
{
struct lv_segment *seg;
uint32_t s;
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv->segments) {
2003-05-06 16:22:24 +04:00
for (s = 0; s < seg->area_count; s++) {
2005-06-01 20:51:55 +04:00
if (seg_type(seg, s) != AREA_LV)
2003-05-06 16:22:24 +04:00
continue;
2005-06-01 20:51:55 +04:00
return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
2003-05-06 16:22:24 +04:00
}
}
return NULL;
}
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
2004-05-05 21:56:20 +04:00
struct device *dev,
uint32_t lv_type)
2003-05-06 16:22:24 +04:00
{
2005-06-01 20:51:55 +04:00
struct lv_list *lvl;
2003-05-06 16:22:24 +04:00
struct logical_volume *lv;
struct lv_segment *seg;
/* Loop through all LVs */
2005-06-01 20:51:55 +04:00
list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
2003-05-06 16:22:24 +04:00
2004-05-05 21:56:20 +04:00
if (!(lv->status & lv_type))
2003-05-06 16:22:24 +04:00
continue;
2004-05-05 22:35:04 +04:00
/* Check segment origins point to pvname */
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv->segments) {
if (seg_type(seg, 0) != AREA_PV)
2003-05-06 16:22:24 +04:00
continue;
2005-06-01 20:51:55 +04:00
if (seg_dev(seg, 0) != dev)
2003-05-06 16:22:24 +04:00
continue;
return lv;
}
}
return NULL;
}
2004-05-05 21:56:20 +04:00
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
uint32_t lv_type)
{
struct physical_volume *pv;
if (!(pv = find_pv_by_name(cmd, name))) {
stack;
return NULL;
}
return find_pvmove_lv(vg, pv->dev, lv_type);
}
2003-05-06 16:22:24 +04:00
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv)
{
2005-06-01 20:51:55 +04:00
struct list *lvs;
2003-05-06 16:22:24 +04:00
struct logical_volume *lv1;
2005-06-01 20:51:55 +04:00
struct lv_list *lvl, *lvl1;
2003-05-06 16:22:24 +04:00
struct lv_segment *seg;
uint32_t s;
if (!(lvs = dm_pool_alloc(cmd->mem, sizeof(*lvs)))) {
2003-05-06 16:22:24 +04:00
log_error("lvs list alloc failed");
return NULL;
}
list_init(lvs);
/* Loop through all LVs except the one supplied */
2005-06-01 20:51:55 +04:00
list_iterate_items(lvl1, &vg->lvs) {
lv1 = lvl1->lv;
2003-05-06 16:22:24 +04:00
if (lv1 == lv)
continue;
2004-05-05 22:35:04 +04:00
/* Find whether any segment points at the supplied LV */
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv1->segments) {
2003-05-06 16:22:24 +04:00
for (s = 0; s < seg->area_count; s++) {
2005-06-01 20:51:55 +04:00
if (seg_type(seg, s) != AREA_LV ||
seg_lv(seg, s) != lv)
2003-05-06 16:22:24 +04:00
continue;
if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
2003-05-06 16:22:24 +04:00
log_error("lv_list alloc failed");
return NULL;
}
lvl->lv = lv1;
list_add(lvs, &lvl->list);
goto next_lv;
}
}
next_lv:
;
2003-05-06 16:22:24 +04:00
}
return lvs;
}
2004-05-05 21:56:20 +04:00
float copy_percent(struct logical_volume *lv_mirr)
2003-05-06 16:22:24 +04:00
{
uint32_t numerator = 0u, denominator = 0u;
struct lv_segment *seg;
2005-06-01 20:51:55 +04:00
list_iterate_items(seg, &lv_mirr->segments) {
2003-05-06 16:22:24 +04:00
denominator += seg->area_len;
2004-05-05 21:56:20 +04:00
if (seg_is_mirrored(seg))
2004-05-05 21:56:20 +04:00
numerator += seg->extents_copied;
else
numerator += seg->area_len;
2003-05-06 16:22:24 +04:00
}
return denominator ? (float) numerator *100 / denominator : 100.0;
}
2005-10-28 01:51:28 +04:00
/*
* Fixup mirror pointers after single-pass segment import
*/
int fixup_imported_mirrors(struct volume_group *vg)
{
struct lv_list *lvl;
struct lv_segment *seg;
uint32_t s;
list_iterate_items(lvl, &vg->lvs) {
list_iterate_items(seg, &lvl->lv->segments) {
if (seg->segtype !=
get_segtype_from_string(vg->cmd, "mirror"))
continue;
if (seg->log_lv)
2005-10-28 16:48:50 +04:00
first_seg(seg->log_lv)->mirror_seg = seg;
2005-10-28 01:51:28 +04:00
for (s = 0; s < seg->area_count; s++)
if (seg_type(seg, s) == AREA_LV)
2005-10-28 16:48:50 +04:00
first_seg(seg_lv(seg, s))->mirror_seg
= seg;
2005-10-28 01:51:28 +04:00
}
}
2005-10-28 16:48:50 +04:00
return 1;
2005-10-28 01:51:28 +04:00
}