/* $NetBSD: import-extents.c,v 1.1.1.2 2009/12/02 00:26:49 haad Exp $ */ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. * * 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 Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser 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 */ #include "lib.h" #include "metadata.h" #include "disk-rep.h" #include "lv_alloc.h" #include "display.h" #include "segtype.h" /* * After much thought I have decided it is easier, * and probably no less efficient, to convert the * pe->le map to a full le->pe map, and then * process this to get the segments form that * we're after. Any code which goes directly from * the pe->le map to segments would be gladly * accepted, if it is less complicated than this * file. */ struct pe_specifier { struct physical_volume *pv; uint32_t pe; }; struct lv_map { struct logical_volume *lv; uint32_t stripes; uint32_t stripe_size; struct pe_specifier *map; }; static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem, struct volume_group *vg) { struct dm_hash_table *maps = dm_hash_create(32); struct lv_list *ll; struct lv_map *lvm; if (!maps) { log_error("Unable to create hash table for holding " "extent maps."); return NULL; } dm_list_iterate_items(ll, &vg->lvs) { if (ll->lv->status & SNAPSHOT) continue; if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) goto_bad; lvm->lv = ll->lv; if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map) * ll->lv->le_count))) goto_bad; if (!dm_hash_insert(maps, ll->lv->name, lvm)) goto_bad; } return maps; bad: dm_hash_destroy(maps); return NULL; } static int _fill_lv_array(struct lv_map **lvs, struct dm_hash_table *maps, struct disk_list *dl) { struct lvd_list *ll; struct lv_map *lvm; memset(lvs, 0, sizeof(*lvs) * MAX_LV); dm_list_iterate_items(ll, &dl->lvds) { if (!(lvm = dm_hash_lookup(maps, strrchr((char *)ll->lvd.lv_name, '/') + 1))) { log_error("Physical volume (%s) contains an " "unknown logical volume (%s).", dev_name(dl->dev), ll->lvd.lv_name); return 0; } lvm->stripes = ll->lvd.lv_stripes; lvm->stripe_size = ll->lvd.lv_stripesize; lvs[ll->lvd.lv_number] = lvm; } return 1; } static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg, struct dm_list *pvds) { struct disk_list *dl; struct physical_volume *pv; struct lv_map *lvms[MAX_LV], *lvm; struct pe_disk *e; uint32_t i, lv_num, le; dm_list_iterate_items(dl, pvds) { pv = find_pv(vg, dl->dev); e = dl->extents; /* build an array of lv's for this pv */ if (!_fill_lv_array(lvms, maps, dl)) return_0; for (i = 0; i < dl->pvd.pe_total; i++) { lv_num = e[i].lv_num; if (lv_num == UNMAPPED_EXTENT) continue; else { lv_num--; lvm = lvms[lv_num]; if (!lvm) { log_error("Invalid LV in extent map " "(PV %s, PE %" PRIu32 ", LV %" PRIu32 ", LE %" PRIu32 ")", dev_name(pv->dev), i, lv_num, e[i].le_num); return 0; } le = e[i].le_num; if (le >= lvm->lv->le_count) { log_error("logical extent number " "out of bounds"); return 0; } if (lvm->map[le].pv) { log_error("logical extent (%u) " "already mapped.", le); return 0; } lvm->map[le].pv = pv; lvm->map[le].pe = i; } } } return 1; } static int _check_single_map(struct lv_map *lvm) { uint32_t i; for (i = 0; i < lvm->lv->le_count; i++) { if (!lvm->map[i].pv) { log_error("Logical volume (%s) contains an incomplete " "mapping table.", lvm->lv->name); return 0; } } return 1; } static int _check_maps_are_complete(struct dm_hash_table *maps) { struct dm_hash_node *n; struct lv_map *lvm; for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { lvm = (struct lv_map *) dm_hash_get_data(maps, n); if (!_check_single_map(lvm)) return_0; } return 1; } static uint32_t _area_length(struct lv_map *lvm, uint32_t le) { uint32_t len = 0; do len++; while ((lvm->map[le + len].pv == lvm->map[le].pv) && (lvm->map[le].pv && lvm->map[le + len].pe == lvm->map[le].pe + len)); return len; } static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t le = 0, len; struct lv_segment *seg; struct segment_type *segtype; if (!(segtype = get_segtype_from_string(cmd, "striped"))) return_0; while (le < lvm->lv->le_count) { len = _area_length(lvm, le); if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le, len, 0, 0, NULL, 1, len, 0, 0, 0))) { log_error("Failed to allocate linear segment."); return 0; } if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe)) return_0; dm_list_add(&lvm->lv->segments, &seg->list); le += seg->len; } return 1; } static int _check_stripe(struct lv_map *lvm, uint32_t area_count, uint32_t area_len, uint32_t base_le, uint32_t total_area_len) { uint32_t st; /* * Is the next physical extent in every stripe adjacent to the last? */ for (st = 0; st < area_count; st++) if ((lvm->map[base_le + st * total_area_len + area_len].pv != lvm->map[base_le + st * total_area_len].pv) || (lvm->map[base_le + st * total_area_len].pv && lvm->map[base_le + st * total_area_len + area_len].pe != lvm->map[base_le + st * total_area_len].pe + area_len)) return 0; return 1; } static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm) { uint32_t st, first_area_le = 0, total_area_len; uint32_t area_len; struct lv_segment *seg; struct segment_type *segtype; /* * Work out overall striped length */ if (lvm->lv->le_count % lvm->stripes) { log_error("Number of stripes (%u) incompatible " "with logical extent count (%u) for %s", lvm->stripes, lvm->lv->le_count, lvm->lv->name); } total_area_len = lvm->lv->le_count / lvm->stripes; if (!(segtype = get_segtype_from_string(cmd, "striped"))) return_0; while (first_area_le < total_area_len) { area_len = 1; /* * Find how many extents are contiguous in all stripes * and so can form part of this segment */ while (_check_stripe(lvm, lvm->stripes, area_len, first_area_le, total_area_len)) area_len++; if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, lvm->stripes * first_area_le, lvm->stripes * area_len, 0, lvm->stripe_size, NULL, lvm->stripes, area_len, 0, 0, 0))) { log_error("Failed to allocate striped segment."); return 0; } /* * Set up start positions of each stripe in this segment */ for (st = 0; st < seg->area_count; st++) if (!set_lv_segment_area_pv(seg, st, lvm->map[first_area_le + st * total_area_len].pv, lvm->map[first_area_le + st * total_area_len].pe)) return_0; dm_list_add(&lvm->lv->segments, &seg->list); first_area_le += area_len; } return 1; } static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm) { return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) : _read_linear(cmd, lvm)); } static int _build_all_segments(struct cmd_context *cmd, struct dm_hash_table *maps) { struct dm_hash_node *n; struct lv_map *lvm; for (n = dm_hash_get_first(maps); n; n = dm_hash_get_next(maps, n)) { lvm = (struct lv_map *) dm_hash_get_data(maps, n); if (!_build_segments(cmd, lvm)) return_0; } return 1; } int import_extents(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *pvds) { int r = 0; struct dm_pool *scratch = dm_pool_create("lvm1 import_extents", 10 * 1024); struct dm_hash_table *maps; if (!scratch) return_0; if (!(maps = _create_lv_maps(scratch, vg))) { log_error("Couldn't allocate logical volume maps."); goto out; } if (!_fill_maps(maps, vg, pvds)) { log_error("Couldn't fill logical volume maps."); goto out; } if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG)) goto_out; if (!_build_all_segments(cmd, maps)) { log_error("Couldn't build extent segments."); goto out; } r = 1; out: if (maps) dm_hash_destroy(maps); dm_pool_destroy(scratch); return r; }