diff --git a/lib/Makefile.in b/lib/Makefile.in index b71579d46..60f06318f 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -28,6 +28,7 @@ SOURCES=\ format1/layout.c \ format1/vg_number.c \ log/log.c \ + metadata/lv_manip.c \ metadata/metadata.c \ metadata/pv_map.c \ mm/dbg_malloc.c \ diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c new file mode 100644 index 000000000..3af0d5cfe --- /dev/null +++ b/lib/metadata/lv_manip.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the LGPL. + */ + +#include "metadata.h" +#include "pv_map.h" +#include "log.h" + +/* + * The heart of the allocation code. This + * function takes a pv_area and allocates it to + * the lv. If the lv doesn't need the complete + * 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) +{ + uint32_t count, remaining, i, start; + + start = pva->start; + + count = pva->count; + remaining = lv->le_count - index; + + if (remaining < count) { + /* split the area */ + count = remaining; + pva->start += count; + pva->count -= count; + + } else { + /* unlink the area */ + list_del(&pva->list); + } + + for (i = 0; i < count; i++) { + lv->map[i + index].pv = pv; + lv->map[i + index].pe = start + i; + } + + return count; +} + +static int _alloc_striped(struct logical_volume *lv, struct list *pvms) +{ + log_err("striped allocation not implemented yet."); + return 0; +} + +static int _alloc_contiguous(struct logical_volume *lv, struct list *pvms) +{ + log_err("contiguous allocation not implemented yet."); + return 0; +} + +static int _alloc_simple(struct logical_volume *lv, struct list *pvms) +{ + struct list *tmp1, *tmp2; + struct pv_map *pvm; + struct pv_area *pva; + uint32_t allocated = 0; + + list_iterate (tmp1, pvms) { + pvm = list_item(tmp1, struct pv_map); + + 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) + break; + } + + if (allocated == lv->le_count) /* FIXME: yuck, repeated test */ + break; + } + + if (allocated != lv->le_count) { + log_err("insufficient free extents to " + "allocate logical volume"); + return 0; + } + + return 1; +} + +struct logical_volume *lv_create(struct io_space *ios, + const char *name, + uint32_t status, + uint32_t stripes, + uint32_t stripe_size, + uint32_t extents, + struct volume_group *vg, + struct pv_list *acceptable_pvs) +{ + struct lv_list *ll = NULL; + struct logical_volume *lv; + struct list *pvms; + struct pool *scratch; + int r; + + if (!(scratch = pool_create(1024))) { + stack; + return NULL; + } + + if (!extents) { + log_err("Attempt to create an lv with zero extents"); + return NULL; + } + + if (vg->free_count < extents) { + log_err("Insufficient free extents in volume group"); + goto bad; + } + + if (vg->max_lv == vg->lv_count) { + log_err("Maximum logical volumes already reached " + "for this volume group."); + goto bad; + } + + if (!(ll = pool_zalloc(ios->mem, sizeof(*ll)))) { + stack; + return NULL; + } + + lv = &ll->lv; + + strcpy(lv->id.uuid, ""); + + if (!(lv->name = pool_strdup(ios->mem, name))) { + stack; + goto bad; + } + + lv->vg = vg; + lv->status = status; + lv->read_ahead = 0; + lv->stripes = stripes; + lv->size = extents * vg->extent_size; + lv->le_count = extents; + + if (!(lv->map = pool_zalloc(ios->mem, sizeof(*lv->map) * extents))) { + stack; + goto bad; + } + + /* + * Build the sets of available areas on + * the pv's. + */ + if (!(pvms = create_pv_maps(scratch, vg))) { + log_err("couldn't create extent mappings"); + goto bad; + } + + if (stripes > 1) + r = _alloc_striped(lv, pvms); + + else if (status & ALLOC_CONTIGUOUS) + r = _alloc_contiguous(lv, pvms); + + else + r = _alloc_simple(lv, pvms); + + if (!r) { + log_err("Extent allocation failed."); + goto bad; + } + + list_add(&ll->list, &vg->lvs); + vg->lv_count++; + vg->free_count -= extents; + + pool_destroy(scratch); + return lv; + + bad: + if (ll) + pool_free(ios->mem, ll); + + pool_destroy(scratch); + return NULL; +} diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 6e741f4e1..7eb557997 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -217,7 +217,7 @@ struct logical_volume *lv_create(struct io_space *ios, uint32_t status, uint32_t stripes, uint32_t stripe_size, - uint64_t extents, + uint32_t extents, struct volume_group *vg, struct pv_list *acceptable_pvs); diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index 0e4244d28..0ff7a81d0 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -103,6 +103,7 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, pva->start = b; pva->count = e - b; list_add(&pvm->areas, &pva->list); + *extent = e; return 1; }