mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
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.
This commit is contained in:
parent
74af29faae
commit
488a58a998
@ -7,6 +7,7 @@
|
|||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "pv_map.h"
|
#include "pv_map.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "dbg_malloc.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@ -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
|
* The heart of the allocation code. This
|
||||||
* function takes a pv_area and allocates it to
|
* 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.
|
* is unlinked from the pv_map.
|
||||||
*/
|
*/
|
||||||
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
|
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;
|
struct stripe_segment *seg;
|
||||||
|
|
||||||
start = pva->start;
|
|
||||||
|
|
||||||
count = pva->count;
|
count = pva->count;
|
||||||
remaining = lv->le_count - *index;
|
remaining = lv->le_count - *index;
|
||||||
|
if (count < remaining)
|
||||||
if (remaining < count) {
|
|
||||||
/* split the area */
|
|
||||||
count = remaining;
|
count = remaining;
|
||||||
pva->start += count;
|
|
||||||
pva->count -= count;
|
|
||||||
|
|
||||||
} else {
|
if (!(seg = _alloc_segment(lv->vg->cmd->mem, 1))) {
|
||||||
/* 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) {
|
|
||||||
log_err("Couldn't allocate new stripe segment.");
|
log_err("Couldn't allocate new stripe segment.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -83,51 +186,42 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
|
|||||||
seg->len = count;
|
seg->len = count;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->stripes = 1;
|
seg->stripes = 1;
|
||||||
seg->area[0].pv = pv;
|
seg->area[0].pv = map->pv;
|
||||||
seg->area[0].pe = start;
|
seg->area[0].pe = pva->start;
|
||||||
|
|
||||||
list_add(&lv->segments, &seg->list);
|
list_add(&lv->segments, &seg->list);
|
||||||
|
|
||||||
|
consume_pv_area(pva, count);
|
||||||
*index += count;
|
*index += count;
|
||||||
return 1;
|
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
|
* Only one area per pv is allowed, so we search
|
||||||
* for the biggest area, or the first area that
|
* for the biggest area, or the first area that
|
||||||
* can complete the allocation.
|
* can complete the allocation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: subsequent lvextends may not be contiguous.
|
||||||
|
*/
|
||||||
static int _alloc_contiguous(struct logical_volume *lv,
|
static int _alloc_contiguous(struct logical_volume *lv,
|
||||||
struct list *pvms, uint32_t allocated)
|
struct list *pvms, uint32_t allocated)
|
||||||
{
|
{
|
||||||
struct list *tmp1, *tmp2;
|
struct list *tmp1;
|
||||||
struct pv_map *pvm;
|
struct pv_map *pvm;
|
||||||
struct pv_area *pva, *biggest;
|
struct pv_area *pva;
|
||||||
|
|
||||||
list_iterate(tmp1, pvms) {
|
list_iterate(tmp1, pvms) {
|
||||||
pvm = list_item(tmp1, struct pv_map);
|
pvm = list_item(tmp1, struct pv_map);
|
||||||
biggest = NULL;
|
|
||||||
|
|
||||||
list_iterate(tmp2, &pvm->areas) {
|
if (list_empty(&pvm->areas))
|
||||||
pva = list_item(tmp2, struct pv_area);
|
continue;
|
||||||
|
|
||||||
if (!biggest || (pva->count > biggest->count))
|
/* first item in the list is the biggest */
|
||||||
biggest = pva;
|
pva = list_item(pvm->areas.n, struct pv_area);
|
||||||
|
|
||||||
if (biggest->count >= (lv->le_count - allocated))
|
if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_alloc_linear_area(lv, &allocated, pvm->pv, pva)) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -162,7 +256,7 @@ static int _alloc_simple(struct logical_volume *lv,
|
|||||||
|
|
||||||
list_iterate(tmp2, &pvm->areas) {
|
list_iterate(tmp2, &pvm->areas) {
|
||||||
pva = list_item(tmp2, struct pv_area);
|
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))
|
(allocated == lv->le_count))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -176,7 +270,7 @@ static int _alloc_simple(struct logical_volume *lv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -103,6 +103,27 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
|||||||
return r;
|
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,
|
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
|
||||||
uint32_t *extent)
|
uint32_t *extent)
|
||||||
{
|
{
|
||||||
@ -127,9 +148,10 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pva->map = pvm;
|
||||||
pva->start = b;
|
pva->start = b;
|
||||||
pva->count = e - b;
|
pva->count = e - b;
|
||||||
list_add(&pvm->areas, &pva->list);
|
_insert_area(&pvm->areas, pva);
|
||||||
*extent = e;
|
*extent = e;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -200,3 +222,17 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
|
|||||||
pool_free(mem, maps);
|
pool_free(mem, maps);
|
||||||
return NULL;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct pv_area {
|
struct pv_area {
|
||||||
|
struct pv_map *map;
|
||||||
uint32_t start;
|
uint32_t start;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
|
||||||
@ -37,4 +38,6 @@ struct pv_map {
|
|||||||
struct list *create_pv_maps(struct pool *mem,
|
struct list *create_pv_maps(struct pool *mem,
|
||||||
struct volume_group *vg, struct list *pvs);
|
struct volume_group *vg, struct list *pvs);
|
||||||
|
|
||||||
|
void consume_pv_area(struct pv_area *area, uint32_t to_go);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user