1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/format1/import-extents.c

380 lines
8.6 KiB
C
Raw Normal View History

/*
2008-01-30 17:00:02 +03:00
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
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 Lesser General Public License v.2.1.
2004-03-30 23:35:44 +04:00
*
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2002-11-18 17:01:16 +03:00
#include "lib.h"
#include "metadata.h"
2001-11-27 20:29:56 +03:00
#include "disk-rep.h"
2003-09-18 00:35:57 +04:00
#include "lv_alloc.h"
2004-05-05 01:25:57 +04:00
#include "display.h"
2004-09-16 22:40:56 +04:00
#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;
2001-11-27 20:29:56 +03:00
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) {
2005-04-07 16:39:44 +04:00
if (ll->lv->status & SNAPSHOT)
continue;
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm))))
goto_bad;
2002-01-21 19:49:32 +03:00
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)
{
2005-06-01 20:51:55 +04:00
struct lvd_list *ll;
struct lv_map *lvm;
2001-11-27 23:03:45 +03:00
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;
}
2001-11-27 20:29:56 +03:00
lvm->stripes = ll->lvd.lv_stripes;
lvm->stripe_size = ll->lvd.lv_stripesize;
2001-11-27 23:03:45 +03:00
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)
{
2001-11-27 20:29:56 +03:00
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 */
2008-01-30 16:19:47 +03:00
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--;
2001-11-27 20:29:56 +03:00
lvm = lvms[lv_num];
2001-11-27 23:03:45 +03:00
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);
2001-11-27 23:03:45 +03:00
return 0;
}
le = e[i].le_num;
if (le >= lvm->lv->le_count) {
log_error("logical extent number "
"out of bounds");
return 0;
}
2001-11-27 23:03:45 +03:00
if (lvm->map[le].pv) {
log_error("logical extent (%u) "
"already mapped.", le);
2001-11-27 23:03:45 +03:00
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;
2001-11-27 20:29:56 +03:00
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);
2008-01-30 16:19:47 +03:00
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;
}
2004-05-05 01:25:57 +04:00
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
{
2005-04-22 19:44:00 +04:00
uint32_t le = 0, len;
2002-11-18 17:01:16 +03:00
struct lv_segment *seg;
2005-04-22 19:44:00 +04:00
struct segment_type *segtype;
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
2008-01-30 16:19:47 +03:00
return_0;
2001-11-27 23:03:45 +03:00
while (le < lvm->lv->le_count) {
len = _area_length(lvm, le);
2005-04-22 19:44:00 +04:00
if (!(seg = alloc_lv_segment(segtype, lvm->lv, le, len, 0, 0,
NULL, 1, len, 0, 0, 0, NULL))) {
2005-04-22 19:44:00 +04:00
log_error("Failed to allocate linear segment.");
2004-05-05 01:25:57 +04:00
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;
}
2005-04-22 19:44:00 +04:00
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)
{
2005-04-22 19:44:00 +04:00
uint32_t st;
/*
* Is the next physical extent in every stripe adjacent to the last?
*/
2005-04-22 19:44:00 +04:00
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))
2005-04-22 19:44:00 +04:00
return 0;
return 1;
}
2004-05-05 01:25:57 +04:00
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t st, first_area_le = 0, total_area_len;
2005-04-22 19:44:00 +04:00
uint32_t area_len;
2002-11-18 17:01:16 +03:00
struct lv_segment *seg;
2005-04-22 19:44:00 +04:00
struct segment_type *segtype;
2002-01-25 16:41:13 +03:00
/*
* Work out overall striped length
2002-01-25 16:41:13 +03:00
*/
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;
2005-04-22 19:44:00 +04:00
while (first_area_le < total_area_len) {
2005-04-22 19:44:00 +04:00
area_len = 1;
2008-01-30 17:00:02 +03:00
/*
* Find how many extents are contiguous in all stripes
2005-04-22 19:44:00 +04:00
* and so can form part of this segment
*/
while (_check_stripe(lvm, lvm->stripes,
area_len, first_area_le, total_area_len))
2005-04-22 19:44:00 +04:00
area_len++;
if (!(seg = alloc_lv_segment(segtype, lvm->lv,
lvm->stripes * first_area_le,
2005-04-22 19:44:00 +04:00
lvm->stripes * area_len,
0, lvm->stripe_size, NULL,
2005-06-01 20:51:55 +04:00
lvm->stripes,
area_len, 0, 0, 0, NULL))) {
2005-04-22 19:44:00 +04:00
log_error("Failed to allocate striped segment.");
2004-05-05 01:25:57 +04:00
return 0;
}
/*
* Set up start positions of each stripe in this segment
*/
2005-04-22 19:44:00 +04:00
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;
2002-01-25 16:41:13 +03:00
dm_list_add(&lvm->lv->segments, &seg->list);
first_area_le += area_len;
}
return 1;
}
2004-05-05 01:25:57 +04:00
static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm)
{
2004-05-05 01:25:57 +04:00
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);
2008-01-30 16:19:47 +03:00
if (!_build_segments(cmd, lvm))
return_0;
}
return 1;
}
2004-05-05 01:25:57 +04:00
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;
2008-01-30 16:19:47 +03:00
if (!scratch)
return_0;
if (!(maps = _create_lv_maps(scratch, vg))) {
log_error("Couldn't allocate logical volume maps.");
goto out;
}
2001-11-27 20:29:56 +03:00
if (!_fill_maps(maps, vg, pvds)) {
log_error("Couldn't fill logical volume maps.");
goto out;
}
2008-01-30 16:19:47 +03:00
if (!_check_maps_are_complete(maps) && !(vg->status & PARTIAL_VG))
goto_out;
2004-05-05 01:25:57 +04:00
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;
}