mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
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.
This commit is contained in:
parent
52dc213926
commit
0bab65915d
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
278
lib/format1/import-extents.c
Normal file
278
lib/format1/import-extents.c
Normal file
@ -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;
|
||||
}
|
@ -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 {
|
||||
|
@ -8,6 +8,38 @@
|
||||
#include "pv_map.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "pv_map.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user