From 488a58a9987fa578817f2d2144b45e00ac35d1e8 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 29 Nov 2001 18:45:35 +0000 Subject: [PATCH] o Striped allocator o Changed pv_map.c to maintain the list of free areas in size order, which is more helpful to the allocators. If you want to allocate a bit of an area call consume_area(area, size), this will adjust the area if there's some space left and shuffle it to the correct place in the list. Not tested. --- lib/metadata/lv_manip.c | 184 ++++++++++++++++++++++++++++++---------- lib/metadata/pv_map.c | 38 ++++++++- lib/metadata/pv_map.h | 3 + 3 files changed, 179 insertions(+), 46 deletions(-) diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 6b3d1a357..336d4be4b 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -7,6 +7,7 @@ #include "metadata.h" #include "pv_map.h" #include "log.h" +#include "dbg_malloc.h" #include @@ -40,6 +41,123 @@ static void _put_extents(struct stripe_segment *seg) } } +static struct stripe_segment *_alloc_segment(struct pool *mem, int 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 _alloc_stripe_area(struct logical_volume *lv, int stripes, + struct pv_area **areas, uint32_t *index) +{ + uint32_t count = lv->le_count - *index; + uint32_t per_area = count / stripes; + uint32_t smallest = areas[stripes - 1]->count; + uint32_t s; + struct stripe_segment *seg; + + if (smallest < per_area) + per_area = smallest; + + if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) { + log_err("Couldn't allocate new stripe segment."); + return 0; + } + + seg->lv = lv; + seg->le = *index; + seg->len = per_area * stripes; + seg->stripes = stripes; + + for (s = 0; s < stripes; s++) { + struct pv_area *pva = areas[s]; + seg->area[s].pv = pva->map->pv; + seg->area[s].pe = pva->start; + consume_pv_area(pva, per_area); + } + + list_add(&lv->segments, &seg->list); + *index += seg->len; + return 1; +} + +static int _comp_area(const void *l, const void *r) +{ + struct pv_area *lhs = *((struct pv_area **) l); + struct pv_area *rhs = *((struct pv_area **) r); + + if (lhs->count < rhs->count) + return -1; + + else if (lhs->count > rhs->count) + return 1; + + return 0; +} + +static int _alloc_striped(struct logical_volume *lv, + struct list *pvms, uint32_t allocated, + uint32_t stripes, uint32_t stripe_size) +{ + struct list *pvmh; + struct pv_area **areas; + int pv_count = 0, index; + struct pv_map *pvm; + size_t len; + + list_iterate (pvmh, pvms) + pv_count++; + + /* allocate an array of pv_areas, one candidate per pv */ + len = sizeof(*areas) * pv_count; + if (!(areas = dbg_malloc(sizeof(*areas) * pv_count))) { + log_err("Couldn't allocate areas array."); + return 0; + } + + while (allocated != lv->le_count) { + + index = 0; + list_iterate (pvmh, pvms) { + pvm = list_item(pvmh, struct pv_map); + + if (list_empty(&pvm->areas)) + continue; + + areas[index++] = list_item(pvm->areas.n, + struct pv_area); + } + + if (index < stripes) + goto no_space; + + /* sort the areas so we allocate from the biggest */ + qsort(areas, index, sizeof(*areas), _comp_area); + + if (!_alloc_stripe_area(lv, stripes, areas, &allocated)) { + stack; + return 0; + } + } + + return 1; + + no_space: + + log_error("Insufficient free extents (suitable for striping) to " + "allocate logical volume %s: %u required", + lv->name, lv->le_count); + return 0; +} + + /* * The heart of the allocation code. This * function takes a pv_area and allocates it to @@ -48,32 +166,17 @@ static void _put_extents(struct stripe_segment *seg) * is unlinked from the pv_map. */ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index, - struct physical_volume *pv, struct pv_area *pva) + struct pv_map *map, struct pv_area *pva) { - uint32_t count, remaining, start; + uint32_t count, remaining; struct stripe_segment *seg; - start = pva->start; - count = pva->count; remaining = lv->le_count - *index; - - if (remaining < count) { - /* split the area */ + if (count < remaining) count = remaining; - pva->start += count; - pva->count -= count; - } else { - /* unlink the area */ - list_del(&pva->list); - } - - /* create the new segment */ - seg = pool_zalloc(lv->vg->cmd->mem, - sizeof(*seg) * sizeof(seg->area[0])); - - if (!seg) { + if (!(seg = _alloc_segment(lv->vg->cmd->mem, 1))) { log_err("Couldn't allocate new stripe segment."); return 0; } @@ -83,51 +186,42 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index, seg->len = count; seg->stripe_size = 0; seg->stripes = 1; - seg->area[0].pv = pv; - seg->area[0].pe = start; + seg->area[0].pv = map->pv; + seg->area[0].pe = pva->start; list_add(&lv->segments, &seg->list); + consume_pv_area(pva, count); *index += count; return 1; } -static int _alloc_striped(struct logical_volume *lv, - struct list *pvms, uint32_t allocated, - uint32_t stripes, uint32_t stripe_size) -{ - /* FIXME: finish */ - log_error("Striped allocation not implemented yet in LVM2."); - return 0; -} - /* * Only one area per pv is allowed, so we search * for the biggest area, or the first area that * can complete the allocation. */ + +/* + * FIXME: subsequent lvextends may not be contiguous. + */ static int _alloc_contiguous(struct logical_volume *lv, struct list *pvms, uint32_t allocated) { - struct list *tmp1, *tmp2; + struct list *tmp1; struct pv_map *pvm; - struct pv_area *pva, *biggest; + struct pv_area *pva; list_iterate(tmp1, pvms) { pvm = list_item(tmp1, struct pv_map); - biggest = NULL; - list_iterate(tmp2, &pvm->areas) { - pva = list_item(tmp2, struct pv_area); + if (list_empty(&pvm->areas)) + continue; - if (!biggest || (pva->count > biggest->count)) - biggest = pva; + /* first item in the list is the biggest */ + pva = list_item(pvm->areas.n, struct pv_area); - if (biggest->count >= (lv->le_count - allocated)) - break; - } - - if (!_alloc_linear_area(lv, &allocated, pvm->pv, pva)) { + if (!_alloc_linear_area(lv, &allocated, pvm, pva)) { stack; return 0; } @@ -162,13 +256,13 @@ static int _alloc_simple(struct logical_volume *lv, list_iterate(tmp2, &pvm->areas) { pva = list_item(tmp2, struct pv_area); - if (!_alloc_linear_area(lv,&allocated, pvm->pv, pva) || + if (!_alloc_linear_area(lv, &allocated, pvm, pva) || (allocated == lv->le_count)) goto done; } } - done: + done: if (allocated != lv->le_count) { log_error("Insufficient free logical extents to " "allocate logical volume %s: %u required", @@ -176,7 +270,7 @@ static int _alloc_simple(struct logical_volume *lv, return 0; } - return 1; + return 0; } /* diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index 200a7d715..2075fdfed 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -103,6 +103,27 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) return r; } +/* + * Areas are maintained in size order. + */ +static void _insert_area(struct list *head, struct pv_area *a) +{ + struct list *pvah; + struct pv_area *pva; + + list_iterate (pvah, head) { + pva = list_item(pvah, struct pv_area); + + if (pva->count < a->count) + break; + } + + a->list.n = &pva->list; + a->list.p = pva->list.p; + pva->list.p->n = &a->list; + pva->list.p = &a->list; +} + static int _create_single_area(struct pool *mem, struct pv_map *pvm, uint32_t *extent) { @@ -127,9 +148,10 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 0; } + pva->map = pvm; pva->start = b; pva->count = e - b; - list_add(&pvm->areas, &pva->list); + _insert_area(&pvm->areas, pva); *extent = e; return 1; @@ -200,3 +222,17 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, pool_free(mem, maps); return NULL; } + +void consume_pv_area(struct pv_area *pva, uint32_t to_go) +{ + list_del(&pva->list); + + assert(to_go <= pva->count); + + if (to_go < pva->count) { + /* split the area */ + pva->start += to_go; + pva->count -= to_go; + _insert_area(&pva->map->areas, pva); + } +} diff --git a/lib/metadata/pv_map.h b/lib/metadata/pv_map.h index 5cfe2685d..86e0d7624 100644 --- a/lib/metadata/pv_map.h +++ b/lib/metadata/pv_map.h @@ -20,6 +20,7 @@ */ struct pv_area { + struct pv_map *map; uint32_t start; uint32_t count; @@ -37,4 +38,6 @@ struct pv_map { struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, struct list *pvs); +void consume_pv_area(struct pv_area *area, uint32_t to_go); + #endif