| /* |
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; |
| /* |
| * Alloc 1 extra element, so the loop in _area_length() and |
| * _check_stripe() finds the last map member as noncontinuous. |
| */ |
| if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map) |
| * (ll->lv->le_count + 1)))) |
| 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) { |
| if (!(pv = find_pv(vg, dl->dev))) { |
| log_error("PV %s not found.", dl->dev->pvid); |
| return 0; |
| } |
| 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, SEG_TYPE_NAME_STRIPED))) |
| return_0; |
| |
| while (le < lvm->lv->le_count) { |
| len = _area_length(lvm, le); |
| |
| if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0, |
| NULL, 1, len, 0, 0, 0, NULL))) { |
| 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, SEG_TYPE_NAME_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(segtype, lvm->lv, |
| lvm->stripes * first_area_le, |
| lvm->stripes * area_len, |
| 0, lvm->stripe_size, NULL, |
| lvm->stripes, |
| area_len, 0, 0, 0, NULL))) { |
| 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; |
| } |