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

354 lines
6.7 KiB
C
Raw Normal View History

/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "metadata.h"
#include "hash.h"
#include "dbg_malloc.h"
2001-11-27 20:29:56 +03:00
#include "log.h"
#include "pool.h"
#include "disk-rep.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 hash_table *
_create_lv_maps(struct pool *mem, struct volume_group *vg)
{
struct hash_table *maps = hash_create(32);
struct list *llh;
struct lv_list *ll;
struct lv_map *lvm;
if (!maps) {
log_err("Unable to create hash table for holding "
"extent maps.");
return NULL;
}
list_iterate (llh, &vg->lvs) {
ll = list_item(llh, struct lv_list);
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
stack;
goto bad;
}
2001-11-27 20:29:56 +03:00
lvm->lv = &ll->lv;
if (!(lvm->map = pool_zalloc(mem, sizeof(*lvm->map)
* ll->lv.le_count))) {
stack;
goto bad;
}
2001-11-27 20:29:56 +03:00
if (!hash_insert(maps, ll->lv.name, lvm)) {
stack;
goto bad;
}
}
return maps;
bad:
hash_destroy(maps);
return NULL;
}
static int _fill_lv_array(struct lv_map **lvs,
struct hash_table *maps, struct disk_list *dl)
{
struct list *lvh;
struct lv_map *lvm;
2001-11-27 23:03:45 +03:00
memset(lvs, 0, sizeof(*lvs) * MAX_LV);
list_iterate(lvh, &dl->lvds) {
struct lvd_list *ll = list_item(lvh, struct lvd_list);
if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
+ 1 ))) {
log_err("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;
}
2001-11-27 20:29:56 +03:00
static int _fill_maps(struct hash_table *maps, struct volume_group *vg,
struct list *pvds)
{
struct list *pvdh;
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;
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
pv = find_pv(vg, dl->dev);
e = dl->extents;
/* build an array of lv's for this pv */
2001-11-27 20:29:56 +03:00
if (!_fill_lv_array(lvms, maps, dl)) {
stack;
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_err("invalid lv in extent map");
return 0;
}
le = e[i].le_num;
if (le >= lvm->lv->le_count) {
log_err("logical extent number "
"out of bounds");
return 0;
}
2001-11-27 23:03:45 +03:00
if (lvm->map[le].pv) {
log_err("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_err("Logical volume (%s) contains an incomplete "
"mapping table.", lvm->lv->name);
return 0;
}
}
return 1;
}
static int _check_maps_are_complete(struct hash_table *maps)
{
struct hash_node *n;
2001-11-27 20:29:56 +03:00
struct lv_map *lvm;
for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) {
lvm = (struct lv_map *) hash_get_data(maps, n);
if (!_check_single_map(lvm)) {
stack;
return 0;
}
}
return 1;
}
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
{
struct stripe_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) {
stack;
return NULL;
}
return seg;
}
static int _read_linear(struct pool *mem, struct lv_map *lvm)
{
uint32_t le = 0;
struct stripe_segment *seg;
2001-11-27 23:03:45 +03:00
while (le < lvm->lv->le_count) {
seg = _alloc_seg(mem, 1);
seg->lv = lvm->lv;
seg->le = le;
seg->len = 0;
seg->stripe_size = 0;
seg->stripes = 1;
seg->area[0].pv = lvm->map[le].pv;
seg->area[0].pe = lvm->map[le].pe;
do
seg->len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe +
seg->len));
le += seg->len;
2001-11-27 20:29:56 +03:00
list_add(&lvm->lv->segments, &seg->list);
}
return 1;
}
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
{
uint32_t stripes = lvm->stripes, s, le = 0, pe;
struct stripe_segment *seg;
struct pe_specifier *pes;
while (le < lvm->lv->le_count) {
if (!(seg = _alloc_seg(mem, stripes))) {
stack;
return 0;
}
seg->lv = lvm->lv;
seg->le = le;
seg->len = 0;
seg->stripe_size = lvm->stripe_size;
seg->stripes = stripes;
seg->area[0].pv = lvm->map[le].pv;
seg->area[0].pe = lvm->map[le].pe;
do
seg->len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe +
seg->len));
for (s = 1; s < stripes; s++) {
pes = &lvm->map[le + s * seg->len];
seg->area[s].pv = pes->pv;
seg->area[s].pe = pes->pe;
for (pe = 0; pe < seg->len; pe++) {
if (lvm->map[le + s * seg->len + pe].pe !=
pes->pe + pe) {
log_error("Incompatible striping at LE"
" %d on %s",
le + s * seg->len + pe,
seg->lv->name);
return 0;
}
}
}
seg->len *= stripes;
le += seg->len;
list_add(&lvm->lv->segments, &seg->list);
}
return 1;
}
static int _build_segments(struct pool *mem, struct lv_map *lvm)
{
return (lvm->stripes > 1 ? _read_stripes(mem, lvm) :
_read_linear(mem, lvm));
}
static int _build_all_segments(struct pool *mem, struct hash_table *maps)
{
struct hash_node *n;
struct lv_map *lvm;
for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) {
lvm = (struct lv_map *) hash_get_data(maps, n);
if (!_build_segments(mem, lvm)) {
stack;
return 0;
}
}
return 1;
}
int import_extents(struct pool *mem, struct volume_group *vg,
struct list *pvds)
{
int r = 0;
struct pool *scratch = pool_create(10 * 1024);
struct hash_table *maps;
if (!scratch) {
stack;
return 0;
}
if (!(maps = _create_lv_maps(scratch, vg))) {
log_err("Couldn't allocate logical volume maps.");
goto out;
}
2001-11-27 20:29:56 +03:00
if (!_fill_maps(maps, vg, pvds)) {
log_err("Couldn't fill logical volume maps.");
goto out;
}
if (!_check_maps_are_complete(maps)) {
stack;
goto out;
}
if (!_build_all_segments(mem, maps)) {
log_err("Couldn't build extent segments.");
goto out;
}
r = 1;
out:
if (maps)
hash_destroy(maps);
pool_destroy(scratch);
return r;
}