From 0bab65915db98d6521272a2d772db760f3289264 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 27 Nov 2001 16:37:33 +0000 Subject: [PATCH] o Sync up todays work on converting to the segmented representation of logical volumes. It includes: format1 changes. metadata.h changes. lv_manip.c changed (striped allocation still not done though). activate.c changes. Nothing has been near a compiler as yet. Alasdair can you look at changing display.c to use to output the mappings in a more segment oriented format please ? I haven't put the span list into struct physical_volume to represent allocated extents. I think the burden of maintaining it for things like lv_extend may out weigh it's uses. --- lib/Makefile.in | 1 + lib/activate/activate.c | 57 +++---- lib/format1/import-export.c | 108 ++++---------- lib/format1/import-extents.c | 278 +++++++++++++++++++++++++++++++++++ lib/format_text/sample.vg | 8 +- lib/metadata/lv_manip.c | 178 +++++++++++++--------- lib/metadata/metadata.h | 41 +++--- lib/metadata/pv_map.c | 80 ++++++---- 8 files changed, 513 insertions(+), 238 deletions(-) create mode 100644 lib/format1/import-extents.c diff --git a/lib/Makefile.in b/lib/Makefile.in index 0674dda3f..3b6b9b806 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -26,6 +26,7 @@ SOURCES=\ format1/disk-rep.c \ format1/format1.c \ format1/import-export.c \ + format1/import-extents.c \ format1/layout.c \ format1/vg_number.c \ log/log.c \ diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 7fb81ad27..e323744d9 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -84,40 +84,33 @@ int lv_open_count(struct logical_volume *lv) } /* - * Creates a target for the next contiguous run of - * extents. + * Emit a target for a given segment. */ -static int _emit_target(struct dm_task *dmt, struct logical_volume *lv, - unsigned int *ple) +static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg) { char params[1024]; - unsigned int le = *ple; uint64_t esize = lv->vg->extent_size; - int i, count = 0; - struct pe_specifier *pes, *first = NULL; + uint32_t s, stripes = seg->stripes; + int w, tw; - for (i = le; i < lv->le_count; i++) { - pes = lv->map + i; + for (w = 0, s = 0; s < stripes; s++, w += tw) { + tw = snprintf(params + w, sizeof(params) - w, + "%s %" PRIu64 "%s", + dev_name(seg->area[s].pv->dev), + (seg->area[s].pv->pe_start + + (esize * seg->area[s].pe)), + s == (stripes - 1) ? "" : " "); - if (!first) - first = pes; - - /* - * check that we're still contiguous. - */ - else if ((pes->pv != first->pv) || - (pes->pe != first->pe + count)) - break; - - count++; + if (tw < 0) { + log_err("Insufficient space to write target " + "parameters."); + return 0; + } } - snprintf(params, sizeof(params), "%s %" PRIu64, - dev_name(first->pv->dev), - first->pv->pe_start + (esize * first->pe)); - - if (!dm_task_add_target(dmt, esize * le, esize * count, - "linear", params)) { + if (!dm_task_add_target(dmt, esize * le, esize * seg->len, + stripes == 1 ? "linear" : "striped", + params)) { stack; return 0; } @@ -129,19 +122,18 @@ static int _emit_target(struct dm_task *dmt, struct logical_volume *lv, int _load(struct logical_volume *lv, int task) { int r = 0; - uint32_t le = 0; struct dm_task *dmt; + struct list *segh; + struct stripe_segment *seg; if (!(dmt = _setup_task(lv, task))) { stack; return 0; } - /* - * Merge adjacent extents. - */ - while (le < lv->le_count) { - if (!_emit_target(dmt, lv, &le)) { + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct stripe_segment); + if (!_emit_target(dmt, seg)) { log_error("Unable to activate logical volume '%s'", lv->name); goto out; @@ -285,4 +277,3 @@ int lvs_in_vg_opened(struct volume_group *vg) return count; } - diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 0e7bf57ec..04b12b048 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -36,28 +36,6 @@ static char *_create_lv_name(struct pool *mem, const char *full_name) return pool_strdup(mem, ptr); } -static int _fill_lv_array(struct logical_volume **lvs, - struct volume_group *vg, struct disk_list *dl) -{ - struct list *lvh; - struct logical_volume *lv; - int i = 0; - - list_iterate(lvh, &dl->lvds) { - struct lvd_list *ll = list_item(lvh, struct lvd_list); - - if (!(lv = find_lv(vg, ll->lvd.lv_name))) { - stack; - return 0; - } - - lvs[i] = lv; - i++; - } - - return 1; -} - int import_pv(struct pool *mem, struct device *dev, struct physical_volume *pv, struct pv_disk *pvd) { @@ -81,6 +59,9 @@ int import_pv(struct pool *mem, struct device *dev, pv->pe_start = pvd->pe_start; pv->pe_count = pvd->pe_total; pv->pe_allocated = pvd->pe_allocated; + + init_list(&pv->allocated); + return 1; } @@ -268,12 +249,12 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd) lv->size = lvd->lv_size; lv->le_count = lvd->lv_allocated_le; - len = sizeof(struct pe_specifier) * lv->le_count; - if (!(lv->map = pool_alloc(mem, len))) { + list_init(&lv->segments); + + if (!lv->segments) { stack; return 0; } - memset(lv->map, 0, len); return 1; } @@ -323,71 +304,34 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg, lvd->lv_allocation |= LV_CONTIGUOUS; } -int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds) -{ - struct disk_list *dl; - struct logical_volume *lv, *lvs[MAX_LV]; - struct physical_volume *pv; - struct pe_disk *e; - int i; - uint32_t lv_num, le; - struct list *pvdh; - - 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 */ - if (!_fill_lv_array(lvs, vg, 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 if(lv_num > dl->pvd.lv_cur) { - log_err("invalid lv in extent map\n"); - return 0; - - } else { - lv_num--; - lv = lvs[lv_num]; - le = e[i].le_num; - - if (le >= lv->le_count) { - log_err("logical extent number " - "out of bounds"); - return 0; - } - - lv->map[le].pv = pv; - lv->map[le].pe = i; - } - } - } - - return 1; -} - int export_extents(struct disk_list *dl, int lv_num, struct logical_volume *lv, struct physical_volume *pv) { + struct list *segh; struct pe_disk *ped; - int le; + struct stripe_segment *seg; + uint32_t pe; + struct span *pes; - for (le = 0; le < lv->le_count; le++) { - if (lv->map[le].pv == pv) { - ped = &dl->extents[lv->map[le].pe]; - ped->lv_num = lv_num; - ped->le_num = le; + list_iterate (segh, &lv->segments) { + seg = list_item(segh, struct stripe_segment); + + for (a = 0; a < seg->stripes; a++) { + if (seg->areas[a].pv != pv) + continue; /* not our pv */ + + pes = seg->areas[a].pes; + + for (pe = 0; pe < pe->len; pe++) { + ped = &dl->extents[pe + pes->start]; + ped->lv_num = lv_num; + ped->le_num = seg->le + a + + (seg->stripes * pe); + } } } + return 1; } diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c new file mode 100644 index 000000000..aa03f5eba --- /dev/null +++ b/lib/format1/import-extents.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#include "metadata.h" +#include "hash.h" +#include "dbg_malloc.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; + 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; + } + + lvm->lv = ll->lv; + if (!(lvm->map = pool_zalloc(sizeof(*lvm->map) + * ll->lv->le_count))) { + stack; + goto bad; + } + + 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; + int i = 0; + + list_iterate(lvh, &dl->lvds) { + struct lvd_list *ll = list_item(lvh, struct lvd_list); + + if (!(lvm = hash_lookup(maps, ll->lvd.lv_name))) { + log_err("Physical volume (%s) contains an " + "unknown logical volume (%s).", + dev_name(dl->dev), ll->lvd.lv_name); + return 0; + } + + lvs[i++] = lvm; + } + + return 1; +} + +static int _fill_maps(struct hash_table *maps, struct list *pvds) +{ + struct list *pvdh; + struct lv_map *map; + + 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 */ + if (!_fill_lv_array(lvs, vg, 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 if(lv_num > dl->pvd.lv_cur) { + log_err("invalid lv in extent map"); + return 0; + + } else { + lv_num--; + lvm = lvs[lv_num]; + le = e[i].le_num; + + if (le >= lvm->lv->le_count) { + log_err("logical extent number " + "out of bounds"); + 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; + + 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 int _same_segment(struct stripe_segment *seg, struct lv_map *lvm, + uint32_t count) +{ + uint32_t s; + uint32_t le = seg->le + (count * seg->stripes); + + for (s = 0; s < stripes; s++) { + if ((lvm->map[le + s].pv != seg->area[s].pv) || + (lvm->map[le + s].pe != seg->area[s].pe + count)) + return 0; + } + return 1; +} + +static int _build_segments(struct pool *mem, struct lv_map *lvm) +{ + uint32_t stripes = lvm->lv->stripes; + uint32_t le; + struct stripe_segment *seg; + size_t len; + + len = sizeof(*seg) * (stripes * sizeof(seg->area[0])); + + for (le = 0; le < lvm->lv->le_count;) { + if (!(seg = pool_zalloc(mem, len))) { + stack; + return 0; + } + + seg->lv = lvm->lv; + seg->le = le; + seg->len = 0; + seg->stripe_size = lvm->stripe_size; + seg->stripes = stripes; + + for (s = 0; s < stripes; s++) { + seg->area[s].pv = lvm->map[le + s].pv; + seg->area[s].pe = lvm->map[le + s].pe; + } + + count = 1; + do { + le += stripes; + seg->len += stripes; + + } while (_same_segment(seg, lvm, count++)); + + list_add(&lvm->lv->segments, seg); + } + + return 1; +} + +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; + } + + if (!_fill_maps(maps, 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; +} diff --git a/lib/format_text/sample.vg b/lib/format_text/sample.vg index d44b453c3..bba353cb6 100644 --- a/lib/format_text/sample.vg +++ b/lib/format_text/sample.vg @@ -8,7 +8,6 @@ vg { extent_size = 8192 # 4M extent_count = 1024 - free_count = 430 max_lv = 99 max_pv = 255 @@ -20,15 +19,12 @@ vg { pv1 { id = "lksjdflksdlsk" - major = 123 - minor = 23 + device = "/dev/hda1" status = [???] - size = ?? pe_start = 8192 - pe_count = 300 - pe_allocated = 30 + pe_count = 300 # ???M } lv1 { diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index e352b0cd3..f4f941921 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -8,6 +8,38 @@ #include "pv_map.h" #include "log.h" +#include + +/* + * These functions adjust the pe counts in pv's + * after we've added or removed segments. + */ +static void _get_extents(struct stripe_segment *seg) +{ + int s, count; + struct physical_volume *pv; + + for (s = 0; i < seg->stripes; s++) { + pv = seg->area[i % seg->stripes].pv; + count = seg->len / seg->stripes; + pv->pe_allocated += count; + } +} + +static void _put_extents(struct stripe_segment *seg) +{ + int s, count; + struct physical_volume *pv; + + for (s = 0; i < seg->stripes; s++) { + pv = seg->area[i % seg->stripes].pv; + count = seg->len / seg->stripes; + + assert(pv->pe_allocated >= count); + pv->pe_allocated -= count; + } +} + /* * The heart of the allocation code. This * function takes a pv_area and allocates it to @@ -15,15 +47,16 @@ * area then the area is split, otherwise the area * is unlinked from the pv_map. */ -static int _alloc_area(struct logical_volume *lv, uint32_t index, - struct physical_volume *pv, struct pv_area *pva) +static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index, + struct physical_volume *pv, struct pv_area *pva) { uint32_t count, remaining, i, start; + struct stripe_segment *seg; start = pva->start; count = pva->count; - remaining = lv->le_count - index; + remaining = lv->le_count - *index; if (remaining < count) { /* split the area */ @@ -36,12 +69,27 @@ static int _alloc_area(struct logical_volume *lv, uint32_t index, list_del(&pva->list); } - for (i = 0; i < count; i++) { - lv->map[i + index].pv = pv; - lv->map[i + index].pe = start + i; + /* create the new segment */ + seg = pool_zalloc(lv->vg->cmd->mem, + sizeof(*seg) * sizeof(seg->area[0])); + + if (!seg) { + log_err("Couldn't allocate new stripe segment."); + return 0; } - return count; + seg->lv = lv; + seg->le = *index; + seg->len = count; + seg->stripe_size = 0; + seg->stripes = 1; + seg->area[0].pv = pv; + seg->area[0].pe = start; + + list_add(&lv->segments, &seg->list); + + *index += count; + return 1; } static int _alloc_striped(struct logical_volume *lv, @@ -78,7 +126,11 @@ static int _alloc_contiguous(struct logical_volume *lv, break; } - allocated += _alloc_area(lv, allocated, pvm->pv, pva); + if (!_alloc_linear_area(lv, &allocated, pvm->pv, pva)) { + stack; + return 0; + } + if (allocated == lv->le_count) break; } @@ -109,9 +161,8 @@ static int _alloc_simple(struct logical_volume *lv, list_iterate(tmp2, &pvm->areas) { pva = list_item(tmp2, struct pv_area); - allocated += _alloc_area(lv, allocated, pvm->pv, pva); - - if (allocated == lv->le_count) + if (!_alloc_linear_area(lv,&allocated, pvm->pv, pva) || + (allocated == lv->le_count)) goto done; } } @@ -135,7 +186,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, { int r = 0; struct pool *scratch; - struct list *pvms; + struct list *pvms, *old_tail = lv->segments->p; if (!(scratch = pool_create(1024))) { stack; @@ -167,6 +218,16 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, if (r) { vg->free_count -= lv->le_count - allocated; + + /* Iterate through the new segments, + * updating pe counts in pv's. */ + for (segh = lv->segments.p; segh != old_tail; segh = segh->p) + _get_extents(list_item(segh, struct stripe_segment)); + } else { + /* Put the segment list back how + * we found it. */ + old_tail->n = &lv->segments; + lv->segments.p = old_tail; } out: @@ -258,27 +319,20 @@ struct logical_volume *lv_create(const char *name, lv->stripes = stripes; lv->size = extents * vg->extent_size; lv->le_count = extents; - - if (!(lv->map = pool_zalloc(cmd->mem, sizeof(*lv->map) * extents))) { - stack; - goto bad; - } + list_init(&lv->segments); if (!_allocate(vg, lv, acceptable_pvs, 0u)) { stack; goto bad; } - for (i = 0; i < lv->le_count; i++) - lv->map[i].pv->pe_allocated++; - vg->lv_count++; list_add(&vg->lvs, &ll->list); lv->vg = vg; return lv; - bad: + bad: if (ll) pool_free(cmd->mem, ll); @@ -287,16 +341,31 @@ struct logical_volume *lv_create(const char *name, int lv_reduce(struct logical_volume *lv, uint32_t extents) { - int i; + struct list *segh; + struct stripe_segment *seg; + uint32_t count = extents; - extents = lv->le_count - extents; + for (segh = lv->segments.p; + (segh != &lv->segments) && count; + segh = segh->p) { + seg = list_item(segh, struct stripe_segment); - for (i = extents; i < lv->le_count; i++) { - lv->map[i].pv->pe_allocated--; + if (seg->len <= count) { + /* remove this segment completely */ + count -= seg->len; + _put_extents(seg); + list_del(segh); + } else { + /* reduce this segment */ + _put_extents(seg); + seg->len -= count; + _get_extents(seg); + count = 0; + } } - lv->le_count = extents; - lv->size = extents * lv->vg->extent_size; + lv->le_count -= extents; + lv->size = lv->le_count * lv->vg->extent_size; return 1; } @@ -304,59 +373,30 @@ int lv_reduce(struct logical_volume *lv, uint32_t extents) int lv_extend(struct logical_volume *lv, uint32_t extents, struct list *acceptable_pvs) { - struct cmd_context *cmd = lv->vg->cmd; - struct pe_specifier *new_map; - struct logical_volume *new_lv; - int i; + uint32_t old_le_count = lv->le_count; + uint64_t old_size = lv->size; - if (!(new_map = pool_zalloc(cmd->mem, sizeof(*new_map) * - (extents + lv->le_count)))) { - stack; + lv->le_count += extents; + lv->size += extents * lv->vg->extent_size; + + if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count)) { + lv->le_count = old_le_count; + lv->size = old_lv_size; return 0; } - memcpy(new_map, lv->map, sizeof(*new_map) * lv->le_count); - - if (!(new_lv = pool_alloc(cmd->mem, sizeof(*new_lv)))) { - pool_free(cmd->mem, new_map); - stack; - return 0; - } - - memcpy(new_lv, lv, sizeof(*lv)); - new_lv->map = new_map; - new_lv->le_count += extents; - new_lv->size += extents * lv->vg->extent_size; - - if (!_allocate(new_lv->vg, new_lv, acceptable_pvs, lv->le_count)) { - stack; - goto bad; - } - - for (i = lv->le_count; i < new_lv->le_count; i++) - new_lv->map[i].pv->pe_allocated++; - - memcpy(lv, new_lv, sizeof(*lv)); - - /* - * new_lv had to be allocated last so we - * could free it without touching the new - * map - */ - pool_free(cmd->mem, new_lv); return 1; - - bad: - pool_free(cmd->mem, new_map); - return 0; } int lv_remove(struct volume_group *vg, struct logical_volume *lv) { int i; + struct list *segh; + struct stripe_segment *seg; - for (i = 0; i < lv->le_count; i++) - lv->map[i].pv->pe_allocated--; + /* iterate through the lv's segments freeing off the pe's */ + list_iterate (segh, &lv->segments) + _put_extents(list_item(segh, struct stripe_segment)); vg->lv_count--; vg->free_count += lv->le_count; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 8d70c6c68..bf9682340 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2001 Sistina Software (UK) Limited. * - * This file is released under the GPL. + * This file is released under the LGPL. * * This is the in core representation of a volume group and its * associated physical and logical volumes. @@ -46,7 +46,6 @@ #define EXPORTED_TAG "PV_EXP" /* Identifier of exported PV */ #define IMPORTED_TAG "PV_IMP" /* Identifier of imported PV */ - struct physical_volume { struct id id; struct device *dev; @@ -60,23 +59,7 @@ struct physical_volume { uint64_t pe_size; uint64_t pe_start; uint32_t pe_count; - uint32_t pe_allocated; -}; - -struct pv_area { - struct physical_volume *pv; - uint32_t start; /* in extents */ - uint32_t len; /* in extents */ -}; - -struct stripe_segment { - struct list list; - - uint32_t stripe_size; - uint32_t stripes; - - /* There will be one pv_area for each stripe */ - struct pv_area areas[0]; + uint32_t pe_allocated; /* FIXME: change the name to alloc_count ? */ }; struct cmd_context; @@ -105,8 +88,23 @@ struct volume_group { struct list lvs; }; +struct stripe_segment { + struct list list; + + struct logical_volume *lv; + uint32_t le; + uint32_t len; + uint32_t stripe_size; + uint32_t stripes; + + /* There will be one area for each stripe */ + struct { + struct physical_volume *pv; + uint32_t pe; + } area[0]; +}; + struct logical_volume { - /* disk */ struct id id; char *name; @@ -118,7 +116,6 @@ struct logical_volume { uint64_t size; uint32_t le_count; - /* the segment array */ struct list segments; }; @@ -287,7 +284,7 @@ struct volume_group *find_vg_with_lv(const char *lv_name); /* FIXME Merge these functions with ones above */ -struct physical_volume *_find_pv(struct volume_group *vg, struct device *dev); +struct physical_volume *find_pv(struct volume_group *vg, struct device *dev); struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name); /* diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index 9666e1b87..64cd4ba3d 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -7,6 +7,8 @@ #include "pv_map.h" #include "log.h" +#include + static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) { struct list *tmp; @@ -35,42 +37,68 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) return 1; } +static int _set_allocated(struct hash_table *hash, + struct physical_volume *pv, int pe) +{ + struct pv_map *pvm; + + if (!(pvm = (struct pv_map *) hash_lookup(hash, dev_name(pv->dev)))) { + log_err("pv_map not present in hash table."); + return 0; + } + + /* sanity check */ + assert(!bit(pvm->allocated_extents, pe)); + + bit_set(pvm->allocated_extents, pe); + return 1; +} + static int _fill_bitsets(struct volume_group *vg, struct list *maps) { - /* - * FIXME: should put pvm's in a table for - * O(1) access, and remove the nasty inner - * loop in this code. - */ struct list *lvh, *pvmh; struct logical_volume *lv; - struct pe_specifier *pes; struct pv_map *pvm; - uint32_t le; + uint32_t i, r = 0; + struct hash_table *hash; - list_iterate(lvh, &vg->lvs) { - lv = &(list_item(lvh, struct lv_list)->lv); + if (!(hash = hash_table_create(128))) { + log_err("Couldn't create hash table for pv maps."); + return 0; + } - for (le = 0; le < lv->le_count; le++) { - pes = lv->map + le; - - /* this is the nasty that will kill performance */ - list_iterate(pvmh, maps) { - pvm = list_item(pvmh, struct pv_map); - - if (pvm->pv == pes->pv) - break; - } - - /* not all pvs are necc. in the list */ - if (pvmh == maps) - continue; - - bit_set(pvm->allocated_extents, pes->pe); + /* populate the hash table */ + list_iterate (pvmh, maps) { + pvm = list_item(pvmh, struct pv_map); + if (!hash_insert(hash, dev_name(pvm->pv->dev), pvm)) { + stack; + goto out; } } - return 1; + /* iterate through all the lv's setting bit's for used pe's */ + list_iterate (lvh, &vg->lvs) { + lv = &(list_item(lvh, struct lv_list)->lv); + + list_iterate (segh, &lv->segments) { + seg = list_item(segh, struct stripe_segment); + + for (i = 0; i < seg->len; i++) { + if (!_set_allocated(hash, + seg->area[i % seg->stripes].pv, + seg->area[i % seg->stripes].pe + + (i / stripes))) { + stack; + goto out; + } + } + } + } + r = 1; + + out: + hash_table_destroy(hash); + return r; } static int _create_single_area(struct pool *mem, struct pv_map *pvm,