From b8c919b402cf781c87d2978fe920ae179f4a3a2b Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 24 Apr 2003 22:23:24 +0000 Subject: [PATCH] o Metadata area struct change. o Support physical extent restrictions on PV lists for allocations e.g. lvcreate -l 200 vg1 /dev/sda1:100-199:300-399 --- lib/display/display.c | 41 ++++--- lib/format1/import-export.c | 31 ++++-- lib/format1/import-extents.c | 46 ++++---- lib/format_text/export.c | 71 +++++++----- lib/format_text/import_vsn1.c | 172 ++++++++++++++++++----------- lib/metadata/lv_manip.c | 196 +++++++++++++++++++++++----------- lib/metadata/merge.c | 15 ++- lib/metadata/metadata.c | 19 +++- lib/metadata/metadata.h | 48 +++++++-- lib/metadata/pv_map.c | 92 +++++++++++----- lib/metadata/pv_map.h | 2 +- lib/report/columns.h | 2 +- lib/report/report.c | 2 +- tools/lvcreate.c | 30 +++--- tools/lvresize.c | 13 ++- tools/toollib.c | 168 ++++++++++++++++++++++++++++- tools/toollib.h | 2 + tools/vgreduce.c | 9 +- tools/vgsplit.c | 10 +- 19 files changed, 700 insertions(+), 269 deletions(-) diff --git a/lib/display/display.c b/lib/display/display.c index 7853faef7..ac8961337 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -42,7 +42,7 @@ static struct { } _segtypes[] = { { SEG_STRIPED, "striped"}, { - SEG_MIRROR, "mirror"}, { + SEG_MIRRORED, "mirror"}, { SEG_SNAPSHOT, "snapshot"} }; @@ -478,14 +478,28 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv, static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre) { - uint32_t len = seg->len / seg->stripes; + switch (seg->area[s].type) { + case AREA_PV: + log_print("%sPhysical volume\t%s", pre, + seg->area[s].u.pv.pv ? + dev_name(seg->area[s].u.pv.pv->dev) : "Missing"); - log_print("%sPhysical volume\t%s", pre, - seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing"); + if (seg->area[s].u.pv.pv) + log_print("%sPhysical extents\t%d to %d", pre, + seg->area[s].u.pv.pe, + seg->area[s].u.pv.pe + seg->area_len - 1); + break; + case AREA_LV: + log_print("%sLogical volume\t%s", pre, + seg->area[s].u.lv.lv ? + seg->area[s].u.lv.lv->name : "Missing"); - if (seg->area[s].pv) - log_print("%sPhysical extents\t%d to %d", pre, - seg->area[s].pe, seg->area[s].pe + len - 1); + if (seg->area[s].u.lv.lv) + log_print("%sLogical extents\t%d to %d", pre, + seg->area[s].u.lv.le, + seg->area[s].u.lv.le + seg->area_len - 1); + + } } int lvdisplay_segments(struct logical_volume *lv) @@ -502,7 +516,7 @@ int lvdisplay_segments(struct logical_volume *lv) log_print("Logical extent %u to %u:", seg->le, seg->le + seg->len - 1); - if (seg->type == SEG_STRIPED && seg->stripes == 1) + if (seg->type == SEG_STRIPED && seg->area_count == 1) log_print(" Type\t\tlinear"); else log_print(" Type\t\t%s", @@ -510,14 +524,14 @@ int lvdisplay_segments(struct logical_volume *lv) switch (seg->type) { case SEG_STRIPED: - if (seg->stripes == 1) + if (seg->area_count == 1) _display_stripe(seg, 0, " "); else { - log_print(" Stripes\t\t%u", seg->stripes); + log_print(" Stripes\t\t%u", seg->area_count); log_print(" Stripe size\t\t%u KB", seg->stripe_size / 2); - for (s = 0; s < seg->stripes; s++) { + for (s = 0; s < seg->area_count; s++) { log_print(" Stripe %d:", s); _display_stripe(seg, s, " "); } @@ -525,8 +539,9 @@ int lvdisplay_segments(struct logical_volume *lv) log_print(" "); break; case SEG_SNAPSHOT: - case SEG_MIRROR: - ; + break; + case SEG_MIRRORED: + break; } } diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 3d0bc77dd..7c0b73ef0 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -342,9 +342,10 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg, } lvd->lv_read_ahead = lv->read_ahead; - lvd->lv_stripes = list_item(lv->segments.n, struct lv_segment)->stripes; - lvd->lv_stripesize = list_item(lv->segments.n, - struct lv_segment)->stripe_size; + lvd->lv_stripes = + list_item(lv->segments.n, struct lv_segment)->area_count; + lvd->lv_stripesize = + list_item(lv->segments.n, struct lv_segment)->stripe_size; lvd->lv_size = lv->size; lvd->lv_allocated_le = lv->le_count; @@ -367,15 +368,25 @@ int export_extents(struct disk_list *dl, uint32_t lv_num, list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - for (s = 0; s < seg->stripes; s++) { - if (seg->area[s].pv != pv) + for (s = 0; s < seg->area_count; s++) { + if (seg->type != SEG_STRIPED) { + log_error("Non-striped segment type in LV %s: " + "unsupported by format1", lv->name); + return 0; + } + if (seg->area[s].type != AREA_PV) { + log_error("LV stripe found in LV %s: " + "unsupported by format1", lv->name); + return 0; + } + if (seg->area[s].u.pv.pv != pv) continue; /* not our pv */ - for (pe = 0; pe < (seg->len / seg->stripes); pe++) { - ped = &dl->extents[pe + seg->area[s].pe]; + for (pe = 0; pe < (seg->len / seg->area_count); pe++) { + ped = &dl->extents[pe + seg->area[s].u.pv.pe]; ped->lv_num = lv_num; - ped->le_num = (seg->le / seg->stripes) + pe + - s * (lv->le_count / seg->stripes); + ped->le_num = (seg->le / seg->area_count) + pe + + s * (lv->le_count / seg->area_count); } } } @@ -396,7 +407,7 @@ int import_pvs(const struct format_type *fmt, struct pool *mem, dl = list_item(pvdh, struct disk_list); - if (!(pvl = pool_alloc(mem, sizeof(*pvl))) || + if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) || !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) { stack; return 0; diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c index c63ea434a..ccbf0e2e6 100644 --- a/lib/format1/import-extents.c +++ b/lib/format1/import-extents.c @@ -216,19 +216,21 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm) seg->type = SEG_STRIPED; seg->le = le; seg->len = 0; + seg->area_len = 0; seg->stripe_size = 0; - seg->stripes = 1; + seg->area_count = 1; - seg->area[0].pv = lvm->map[le].pv; - seg->area[0].pe = lvm->map[le].pe; + seg->area[0].type = AREA_PV; + seg->area[0].u.pv.pv = lvm->map[le].pv; + seg->area[0].u.pv.pe = lvm->map[le].pe; - do + do { seg->len++; - - while ((lvm->map[le + seg->len].pv == seg->area[0].pv) && - (seg->area[0].pv && - lvm->map[le + seg->len].pe == seg->area[0].pe + - seg->len)); + seg->area_len++; + } while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) && + (seg->area[0].u.pv.pv && + lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe + + seg->len)); le += seg->len; @@ -248,10 +250,11 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg, /* * Is the next physical extent in every stripe adjacent to the last? */ - for (st = 0; st < seg->stripes; st++) - if ((lvm->map[le + st * len].pv != seg->area[st].pv) || - (seg->area[st].pv && - lvm->map[le + st * len].pe != seg->area[st].pe + seg->len)) + for (st = 0; st < seg->area_count; st++) + if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) || + (seg->area[st].u.pv.pv && + lvm->map[le + st * len].pe != + seg->area[st].u.pv.pe + seg->len)) return 0; return 1; @@ -281,27 +284,30 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm) seg->lv = lvm->lv; seg->type = SEG_STRIPED; seg->stripe_size = lvm->stripe_size; - seg->stripes = lvm->stripes; - seg->le = seg->stripes * le; + seg->area_count = lvm->stripes; + seg->le = seg->area_count * le; seg->len = 1; + seg->area_len = 1; /* * Set up start positions of each stripe in this segment */ - for (st = 0; st < seg->stripes; st++) { - seg->area[st].pv = lvm->map[le + st * len].pv; - seg->area[st].pe = lvm->map[le + st * len].pe; + for (st = 0; st < seg->area_count; st++) { + seg->area[st].u.pv.pv = lvm->map[le + st * len].pv; + seg->area[st].u.pv.pe = lvm->map[le + st * len].pe; } /* * Find how many blocks are contiguous in all stripes * and so can form part of this segment */ - while (_check_stripe(lvm, seg, le, len)) + while (_check_stripe(lvm, seg, le, len)) { seg->len++; + seg->area_len++; + } le += seg->len; - seg->len *= seg->stripes; + seg->len *= seg->area_count; list_add(&lvm->lv->segments, &seg->list); } diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 66609d397..d88ed2886 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -372,6 +372,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg, { unsigned int s; const char *name; + const char *type; _outf(f, "segment%u {", count); _inc_indent(f); @@ -387,40 +388,51 @@ static int _print_segment(struct formatter *f, struct volume_group *vg, _outf(f, "type = \"%s\"", get_segtype_string(seg->type)); switch (seg->type) { - case SEG_STRIPED: - _outf(f, "stripe_count = %u%s", seg->stripes, - (seg->stripes == 1) ? "\t# linear" : ""); - - if (seg->stripes > 1) - _out_size(f, (uint64_t) seg->stripe_size, - "stripe_size = %u", seg->stripe_size); - - f->nl(f); - _outf(f, "stripes = ["); - _inc_indent(f); - - for (s = 0; s < seg->stripes; s++) { - if (!(name = _get_pv_name(f, seg->area[s].pv))) { - stack; - return 0; - } - - _outf(f, "\"%s\", %u%s", name, seg->area[s].pe, - (s == seg->stripes - 1) ? "" : ","); - } - - _dec_indent(f); - _outf(f, "]"); - break; - case SEG_SNAPSHOT: _outf(f, "chunk_size = %u", seg->chunk_size); _outf(f, "origin = \"%s\"", seg->origin->name); _outf(f, "cow_store = \"%s\"", seg->cow->name); break; - case SEG_MIRROR: - /* mirrors = [ "lvol1", 10, ... ] */ - ; + + case SEG_MIRRORED: + case SEG_STRIPED: + type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe"; + _outf(f, "%s_count = %u%s", type, seg->area_count, + (seg->area_count == 1) ? "\t# linear" : ""); + + if ((seg->type == SEG_STRIPED) && (seg->area_count > 1)) + _out_size(f, (uint64_t) seg->stripe_size, + "stripe_size = %u", seg->stripe_size); + + f->nl(f); + + _outf(f, "%ss = [", type); + _inc_indent(f); + + for (s = 0; s < seg->area_count; s++) { + switch (seg->area[s].type) { + case AREA_PV: + if (!(name = _get_pv_name(f, seg-> + area[s].u.pv.pv))) { + stack; + return 0; + } + + _outf(f, "\"%s\", %u%s", name, + seg->area[s].u.pv.pe, + (s == seg->area_count - 1) ? "" : ","); + break; + case AREA_LV: + _outf(f, "\"%s\", %u%s", + seg->area[s].u.lv.lv->name, + seg->area[s].u.lv.le, + (s == seg->area_count - 1) ? "" : ","); + } + } + + _dec_indent(f); + _outf(f, "]"); + break; } _dec_indent(f); @@ -604,6 +616,7 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg) list_iterate(pvh, &vg->pvs) { pv = list_item(pvh, struct pv_list)->pv; + /* FIXME But skip if there's already an LV called pv%d ! */ if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) { stack; goto bad; diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index c10d765fb..fb004ec12 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -215,7 +215,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, struct hash_table *pv_hash) { unsigned int s; - uint32_t stripes = 0; + uint32_t area_count = 0; struct lv_segment *seg; struct config_node *cn; struct config_value *cv; @@ -223,7 +223,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, uint32_t start_extent, extent_count; uint32_t chunk_size; const char *org_name, *cow_name; - struct logical_volume *org, *cow; + struct logical_volume *org, *cow, *lv1; segment_type_t segtype; if (!(sn = sn->child)) { @@ -254,7 +254,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, } if (segtype == SEG_STRIPED) { - if (!_read_int32(sn, "stripe_count", &stripes)) { + if (!_read_int32(sn, "stripe_count", &area_count)) { log_error("Couldn't read 'stripe_count' for " "segment '%s'.", sn->key); return 0; @@ -262,7 +262,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, } if (!(seg = pool_zalloc(mem, sizeof(*seg) + - (sizeof(seg->area[0]) * stripes)))) { + (sizeof(seg->area[0]) * area_count)))) { stack; return 0; } @@ -270,9 +270,10 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, seg->lv = lv; seg->le = start_extent; seg->len = extent_count; + seg->area_len = extent_count; + seg->type = segtype; switch (segtype) { - case SEG_MIRROR: case SEG_SNAPSHOT: lv->status |= SNAPSHOT; @@ -316,15 +317,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, break; case SEG_STRIPED: - seg->stripes = stripes; - - if (!seg->stripes) { - log_error("Zero stripes *not* allowed for segment '%s'", - sn->key); - return 0; - } - - if ((seg->stripes != 1) && + if ((area_count != 1) && !_read_int32(sn, "stripe_size", &seg->stripe_size)) { log_error("Couldn't read stripe_size for segment '%s'.", sn->key); @@ -337,55 +330,71 @@ static int _read_segment(struct pool *mem, struct volume_group *vg, return 0; } - for (cv = cn->v, s = 0; cv && s < seg->stripes; + seg->area_len /= area_count; + + case SEG_MIRRORED: + seg->area_count = area_count; + + if (!seg->area_count) { + log_error("Zero areas not allowed for segment '%s'", + sn->key); + return 0; + } + + for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) { /* first we read the pv */ const char *bad = "Badly formed areas array for " "segment '%s'."; struct physical_volume *pv; - uint32_t allocated; if (cv->type != CFG_STRING) { log_error(bad, sn->key); return 0; } - if (!(pv = hash_lookup(pv_hash, cv->v.str))) { - log_error("Couldn't find physical volume '%s' " + if (!cv->next) { + log_error(bad, sn->key); + return 0; + } + + if (cv->next->type != CFG_INT) { + log_error(bad, sn->key); + return 0; + } + + /* FIXME Cope if LV not yet read in */ + if ((pv = hash_lookup(pv_hash, cv->v.str))) { + seg->area[s].type = AREA_PV; + seg->area[s].u.pv.pv = pv; + seg->area[s].u.pv.pe = cv->next->v.i; + /* + * Adjust extent counts in the pv and vg. + */ + pv->pe_alloc_count += seg->area_len; + vg->free_count -= seg->area_len; + + } else if ((lv1 = find_lv(vg, cv->v.str))) { + seg->area[s].type = AREA_LV; + seg->area[s].u.lv.lv = lv1; + seg->area[s].u.lv.le = cv->next->v.i; + } else { + log_error("Couldn't find volume '%s' " "for segment '%s'.", cv->v.str ? cv->v.str : "NULL", seg_name); return 0; } - seg->area[s].pv = pv; - - if (!(cv = cv->next)) { - log_error(bad, sn->key); - return 0; - } - - if (cv->type != CFG_INT) { - log_error(bad, sn->key); - return 0; - } - - seg->area[s].pe = cv->v.i; - - /* - * Adjust the extent counts in the pv and vg. - */ - allocated = seg->len / seg->stripes; - pv->pe_alloc_count += allocated; - vg->free_count -= allocated; + cv = cv->next; } /* * Check we read the correct number of stripes. */ - if (cv || (s < seg->stripes)) { - log_error("Incorrect number of stripes in 'area' array " + if (cv || (s < seg->area_count)) { + log_error("Incorrect number of areas in area array " "for segment '%s'.", seg_name); return 0; } @@ -456,9 +465,9 @@ static int _read_segments(struct pool *mem, struct volume_group *vg, return 1; } -static int _read_lv(struct format_instance *fid, struct pool *mem, - struct volume_group *vg, struct config_node *lvn, - struct config_node *vgn, struct hash_table *pv_hash) +static int _read_lvnames(struct format_instance *fid, struct pool *mem, + struct volume_group *vg, struct config_node *lvn, + struct config_node *vgn, struct hash_table *pv_hash) { struct logical_volume *lv; struct lv_list *lvl; @@ -482,17 +491,6 @@ static int _read_lv(struct format_instance *fid, struct pool *mem, return 0; } - lv->vg = vg; - - /* FIXME: read full lvid */ - if (!_read_id(&lv->lvid.id[1], lvn, "id")) { - log_error("Couldn't read uuid for logical volume %s.", - lv->name); - return 0; - } - - memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0])); - if (!(cn = find_config_node(lvn, "status", '/'))) { log_error("Couldn't find status flags for logical volume."); return 0; @@ -503,12 +501,6 @@ static int _read_lv(struct format_instance *fid, struct pool *mem, return 0; } - list_init(&lv->segments); - if (!_read_segments(mem, vg, lv, lvn, pv_hash)) { - stack; - return 0; - } - lv->alloc = ALLOC_DEFAULT; if ((cn = find_config_node(lvn, "allocation_policy", '/'))) { struct config_value *cv = cn->v; @@ -524,6 +516,48 @@ static int _read_lv(struct format_instance *fid, struct pool *mem, if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) lv->read_ahead = 0; + list_init(&lv->segments); + + lv->vg = vg; + vg->lv_count++; + list_add(&vg->lvs, &lvl->list); + + return 1; +} + +static int _read_lvsegs(struct format_instance *fid, struct pool *mem, + struct volume_group *vg, struct config_node *lvn, + struct config_node *vgn, struct hash_table *pv_hash) +{ + struct logical_volume *lv; + struct lv_list *lvl; + + if (!(lvl = find_lv_in_vg(vg, lvn->key))) { + log_error("Lost logical volume reference %s", lvn->key); + return 0; + } + + lv = lvl->lv; + + if (!(lvn = lvn->child)) { + log_error("Empty logical volume section."); + return 0; + } + + /* FIXME: read full lvid */ + if (!_read_id(&lv->lvid.id[1], lvn, "id")) { + log_error("Couldn't read uuid for logical volume %s.", + lv->name); + return 0; + } + + memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0])); + + if (!_read_segments(mem, vg, lv, lvn, pv_hash)) { + stack; + return 0; + } + lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size; /* Skip this for now for snapshots */ @@ -541,9 +575,9 @@ static int _read_lv(struct format_instance *fid, struct pool *mem, log_error("Couldn't read major number for logical " "volume %s.", lv->name); } - - vg->lv_count++; - list_add(&vg->lvs, &lvl->list); + } else { + vg->lv_count--; + list_del(&lvl->list); } return 1; @@ -687,13 +721,21 @@ static struct volume_group *_read_vg(struct format_instance *fid, list_init(&vg->lvs); list_init(&vg->snapshots); - if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg, + + if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg, vgn, pv_hash, 1)) { - log_error("Couldn't read all logical volumes for volume " + log_error("Couldn't read all logical volume names for volume " "group %s.", vg->name); goto bad; } + if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg, + vgn, pv_hash, 1)) { + log_error("Couldn't read all logical volumes for " + "volume group %s.", vg->name); + goto bad; + } + hash_destroy(pv_hash); if (vg->status & PARTIAL_VG) { diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 120ea4aee..9dfb48692 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -6,6 +6,7 @@ #include "lib.h" #include "metadata.h" +#include "locking.h" #include "pv_map.h" #include "lvm-string.h" #include "toolcontext.h" @@ -19,9 +20,12 @@ static void _get_extents(struct lv_segment *seg) unsigned int s, count; struct physical_volume *pv; - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; - count = seg->len / seg->stripes; + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV) + continue; + + pv = seg->area[s].u.pv.pv; + count = seg->area_len; pv->pe_alloc_count += count; } } @@ -31,11 +35,14 @@ static void _put_extents(struct lv_segment *seg) unsigned int s, count; struct physical_volume *pv; - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV) + continue; + + pv = seg->area[s].u.pv.pv; if (pv) { - count = seg->len / seg->stripes; + count = seg->area_len; assert(pv->pe_alloc_count >= count); pv->pe_alloc_count -= count; } @@ -60,13 +67,13 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, struct pv_area **areas, uint32_t *ix) { uint32_t count = lv->le_count - *ix; - uint32_t per_area = count / stripes; + uint32_t area_len = count / stripes; uint32_t smallest = areas[stripes - 1]->count; uint32_t s; struct lv_segment *seg; - if (smallest < per_area) - per_area = smallest; + if (smallest < area_len) + area_len = smallest; if (!(seg = _alloc_segment(lv->vg->cmd->mem, stripes))) { log_err("Couldn't allocate new stripe segment."); @@ -76,15 +83,17 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, seg->lv = lv; seg->type = SEG_STRIPED; seg->le = *ix; - seg->len = per_area * stripes; - seg->stripes = stripes; + seg->len = area_len * stripes; + seg->area_len = area_len; + seg->area_count = stripes; seg->stripe_size = stripe_size; 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); + seg->area[s].type = AREA_PV; + seg->area[s].u.pv.pv = pva->map->pvl->pv; + seg->area[s].u.pv.pe = pva->start; + consume_pv_area(pva, area_len); } list_add(&lv->segments, &seg->list); @@ -188,10 +197,12 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix, seg->type = SEG_STRIPED; seg->le = *ix; seg->len = count; + seg->area_len = count; seg->stripe_size = 0; - seg->stripes = 1; - seg->area[0].pv = map->pv; - seg->area[0].pe = pva->start; + seg->area_count = 1; + seg->area[0].type = AREA_PV; + seg->area[0].u.pv.pv = map->pvl->pv; + seg->area[0].u.pv.pe = pva->start; list_add(&lv->segments, &seg->list); @@ -281,7 +292,7 @@ static int _alloc_next_free(struct logical_volume *lv, * Chooses a correct allocation policy. */ static int _allocate(struct volume_group *vg, struct logical_volume *lv, - struct list *acceptable_pvs, uint32_t allocated, + struct list *allocatable_pvs, uint32_t allocated, uint32_t stripes, uint32_t stripe_size) { int r = 0; @@ -296,7 +307,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, /* * Build the sets of available areas on the pv's. */ - if (!(pvms = create_pv_maps(scratch, vg, acceptable_pvs))) + if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs))) goto out; if (stripes > 1) @@ -359,46 +370,23 @@ static char *_generate_lv_name(struct volume_group *vg, return buffer; } -struct logical_volume *lv_create(struct format_instance *fi, - const char *name, - uint32_t status, - alloc_policy_t alloc, - uint32_t stripes, - uint32_t stripe_size, - uint32_t extents, - struct volume_group *vg, - struct list *acceptable_pvs) +struct logical_volume *lv_create_empty(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + struct volume_group *vg) { struct cmd_context *cmd = vg->cmd; struct lv_list *ll = NULL; struct logical_volume *lv; char dname[32]; - if (!extents) { - log_error("Unable to create logical volume %s with no extents", - name); - return NULL; - } - - if (vg->free_count < extents) { - log_error("Insufficient free extents (%u) in volume group %s: " - "%u required", vg->free_count, vg->name, extents); - return NULL; - } - if (vg->max_lv == vg->lv_count) { log_error("Maximum number of logical volumes (%u) reached " "in volume group %s", vg->max_lv, vg->name); return NULL; } - if (stripes > list_size(acceptable_pvs)) { - log_error("Number of stripes (%u) must not exceed " - "number of physical volumes (%d)", stripes, - list_size(acceptable_pvs)); - return NULL; - } - if (!name && !(name = _generate_lv_name(vg, dname, sizeof(dname)))) { log_error("Failed to generate unique name for the new " "logical volume"); @@ -409,17 +397,20 @@ struct logical_volume *lv_create(struct format_instance *fi, if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) || !(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) { - stack; + log_error("lv_list allocation failed"); + if (ll) + pool_free(cmd->mem, ll); return NULL; } lv = ll->lv; - lv->vg = vg; if (!(lv->name = pool_strdup(cmd->mem, name))) { - stack; - goto bad; + log_error("lv name strdup failed"); + if (ll) + pool_free(cmd->mem, ll); + return NULL; } lv->status = status; @@ -427,30 +418,73 @@ struct logical_volume *lv_create(struct format_instance *fi, lv->read_ahead = 0; lv->major = -1; lv->minor = -1; - lv->size = (uint64_t) extents *vg->extent_size; - lv->le_count = extents; + lv->size = UINT64_C(0); + lv->le_count = 0; list_init(&lv->segments); - if (!_allocate(vg, lv, acceptable_pvs, 0u, stripes, stripe_size)) { - stack; - goto bad; - } - if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { stack; - goto bad; + if (ll) + pool_free(cmd->mem, ll); + return NULL; } vg->lv_count++; list_add(&vg->lvs, &ll->list); return lv; +} - bad: - if (ll) - pool_free(cmd->mem, ll); +struct logical_volume *lv_create(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + uint32_t stripes, + uint32_t stripe_size, + uint32_t extents, + struct volume_group *vg, + struct list *allocatable_pvs) +{ + struct logical_volume *lv; - return NULL; + if (!extents) { + log_error("Unable to create logical volume %s with no extents", + name); + return NULL; + } + + if (vg->free_count < extents) { + log_error("Insufficient free extents (%u) in volume group %s: " + "%u required", vg->free_count, vg->name, extents); + return NULL; + } + + if (stripes > list_size(allocatable_pvs)) { + log_error("Number of stripes (%u) must not exceed " + "number of physical volumes (%d)", stripes, + list_size(allocatable_pvs)); + return NULL; + } + + if (!(lv = lv_create_empty(fi, name, status, alloc, vg))) { + stack; + return NULL; + } + + lv->size = (uint64_t) extents *vg->extent_size; + lv->le_count = extents; + + if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size)) { + stack; + return NULL; + } + + if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) { + stack; + return NULL; + } + + return lv; } int lv_reduce(struct format_instance *fi, @@ -493,7 +527,7 @@ int lv_reduce(struct format_instance *fi, int lv_extend(struct format_instance *fi, struct logical_volume *lv, uint32_t stripes, uint32_t stripe_size, - uint32_t extents, struct list *acceptable_pvs) + uint32_t extents, struct list *allocatable_pvs) { uint32_t old_le_count = lv->le_count; uint64_t old_size = lv->size; @@ -501,10 +535,11 @@ int lv_extend(struct format_instance *fi, lv->le_count += extents; lv->size += (uint64_t) extents *lv->vg->extent_size; - if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count, + if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, stripes, stripe_size)) { lv->le_count = old_le_count; lv->size = old_size; + stack; return 0; } @@ -544,3 +579,34 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv) return 1; } + +/* Lock a list of LVs */ +int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags) +{ + struct list *lvh; + struct logical_volume *lv; + + list_iterate(lvh, lvs) { + lv = list_item(lvh, struct lv_list)->lv; + if (!lock_vol(cmd, lv->lvid.s, flags)) { + log_error("Failed to lock %s", lv->name); + return 0; + } + } + + return 1; +} + +/* Unlock list of LVs */ +int unlock_lvs(struct cmd_context *cmd, struct list *lvs) +{ + struct list *lvh; + struct logical_volume *lv; + + list_iterate(lvh, lvs) { + lv = list_item(lvh, struct lv_list)->lv; + unlock_lv(cmd, lv->lvid.s); + } + + return 1; +} diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index 17db74c83..ba4afe549 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -20,15 +20,20 @@ static int _merge(struct lv_segment *first, struct lv_segment *second) if (!first || (first->type != SEG_STRIPED) || (first->type != second->type) || - (first->stripes != second->stripes) || + (first->area_count != second->area_count) || (first->stripe_size != second->stripe_size)) return 0; - for (s = 0; s < first->stripes; s++) { - width = first->len / first->stripes; + for (s = 0; s < first->area_count; s++) { + width = first->area_len; - if ((first->area[s].pv != second->area[s].pv) || - (first->area[s].pe + width != second->area[s].pe)) + /* FIXME Relax this to first type != second type ? */ + if (first->area[s].type != AREA_PV || + second->area[s].type != AREA_PV) + return 0; + + if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) || + (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe)) return 0; } diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 592dedb4b..d3de78245 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -23,7 +23,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg, log_verbose("Adding physical volume '%s' to volume group '%s'", pv_name, vg->name); - if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) { + if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) { log_error("pv_list allocation for '%s' failed", pv_name); return 0; } @@ -401,6 +401,21 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev) return NULL; } +/* Find segment at a given logical extent in an LV */ +struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le) +{ + struct list *segh; + struct lv_segment *seg; + + list_iterate(segh, &lv->segments) { + seg = list_item(segh, struct lv_segment); + if (le >= seg->le && le < seg->le + seg->len) + return seg; + } + + return NULL; +} + int vg_remove(struct volume_group *vg) { struct list *mdah; @@ -707,7 +722,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name, *label_sector = label->sector; if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) { - log_error("pv_list allocation for '%s' failed", pv_name); + log_error("pv allocation for '%s' failed", pv_name); return 0; } diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 7c0c836d9..a872b097f 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -58,9 +58,14 @@ typedef enum { typedef enum { SEG_STRIPED, SEG_SNAPSHOT, - SEG_MIRROR + SEG_MIRRORED } segment_type_t; +typedef enum { + AREA_PV, + AREA_LV +} area_type_t; + struct cmd_context; struct format_handler; struct labeller; @@ -175,15 +180,25 @@ struct lv_segment { /* FIXME Fields depend on segment type */ uint32_t stripe_size; - uint32_t stripes; + uint32_t area_count; + uint32_t area_len; struct logical_volume *origin; struct logical_volume *cow; uint32_t chunk_size; /* There will be one area for each stripe */ struct { - struct physical_volume *pv; - uint32_t pe; + area_type_t type; + union { + struct { + struct physical_volume *pv; + uint32_t pe; + } pv; + struct { + struct logical_volume *lv; + uint32_t le; + } lv; + } u; } area[0]; }; @@ -220,10 +235,17 @@ struct name_list { char *name; }; +struct alloc_area { + struct list list; + uint32_t start; /* PEs */ + uint32_t count; /* PEs */ +}; + struct pv_list { struct list list; struct physical_volume *pv; - struct list *mdas; + struct list *mdas; /* Metadata areas */ + struct list *alloc_areas; /* Areas we may allocate from */ }; struct lv_list { @@ -357,8 +379,15 @@ struct logical_volume *lv_create(struct format_instance *fi, uint32_t stripe_size, uint32_t extents, struct volume_group *vg, - struct list *acceptable_pvs); + struct list *allocatable_pvs); +struct logical_volume *lv_create_empty(struct format_instance *fi, + const char *name, + uint32_t status, + alloc_policy_t alloc, + struct volume_group *vg); + +/* Manipulate LVs */ int lv_reduce(struct format_instance *fi, struct logical_volume *lv, uint32_t extents); @@ -368,6 +397,10 @@ int lv_extend(struct format_instance *fi, uint32_t stripe_size, uint32_t extents, struct list *allocatable_pvs); +/* Lock list of LVs */ +int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags); +int unlock_lvs(struct cmd_context *cmd, struct list *lvs); + /* lv must be part of vg->lvs */ int lv_remove(struct volume_group *vg, struct logical_volume *lv); @@ -398,6 +431,9 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, 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); +/* Find LV segment containing given LE */ +struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le); + /* * Remove a dev_dir if present. */ diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index eb6bae000..cee992e26 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -11,13 +11,13 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) { struct list *tmp; - struct physical_volume *pv; struct pv_map *pvm; + struct pv_list *pvl; list_iterate(tmp, pvs) { - pv = list_item(tmp, struct pv_list)->pv; + pvl = list_item(tmp, struct pv_list); - if (!(pv->status & ALLOCATABLE_PV)) + if (!(pvl->pv->status & ALLOCATABLE_PV)) continue; if (!(pvm = pool_zalloc(mem, sizeof(*pvm)))) { @@ -25,9 +25,9 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps) return 0; } - pvm->pv = pv; + pvm->pvl = pvl; if (!(pvm->allocated_extents = - bitset_create(mem, pv->pe_count))) { + bitset_create(mem, pvl->pv->pe_count))) { stack; return 0; } @@ -39,8 +39,8 @@ 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, uint32_t pe) +static int _set_allocd(struct hash_table *hash, + struct physical_volume *pv, uint32_t pe) { struct pv_map *pvm; @@ -82,7 +82,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) /* 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)) { + if (!hash_insert(hash, dev_name(pvm->pvl->pv->dev), pvm)) { stack; goto out; } @@ -95,13 +95,14 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - for (s = 0; s < seg->stripes; s++) { - for (pe = 0; pe < (seg->len / seg->stripes); - pe++) { - if (!_set_allocated(hash, - seg->area[s].pv, - seg->area[s].pe - + pe)) { + for (s = 0u; s < seg->area_count; s++) { + for (pe = 0u; pe < seg->area_len; pe++) { + if (seg->area[s].type != AREA_PV) + continue; + if (!_set_allocd(hash, + seg->area[s].u.pv.pv, + seg->area[s].u.pv.pe + + pe)) { stack; goto out; } @@ -140,22 +141,22 @@ static void _insert_area(struct list *head, struct pv_area *a) } static int _create_single_area(struct pool *mem, struct pv_map *pvm, - uint32_t *extent) + uint32_t end, uint32_t *extent) { - uint32_t e = *extent, b, count = pvm->pv->pe_count; + uint32_t e = *extent, b; struct pv_area *pva; - while (e < count && bit(pvm->allocated_extents, e)) + while (e <= end && bit(pvm->allocated_extents, e)) e++; - if (e == count) { + if (e > end) { *extent = e; return 1; } b = e++; - while (e < count && !bit(pvm->allocated_extents, e)) + while (e <= end && !bit(pvm->allocated_extents, e)) e++; if (!(pva = pool_zalloc(mem, sizeof(*pva)))) { @@ -163,6 +164,8 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 0; } + log_debug("Allowing allocation on %s start PE %" PRIu32 " length %" + PRIu32, dev_name(pvm->pvl->pv->dev), b, e - b); pva->map = pvm; pva->start = b; pva->count = e - b; @@ -172,12 +175,18 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 1; } -static int _create_areas(struct pool *mem, struct pv_map *pvm) +static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start, + uint32_t count) { - uint32_t pe = 0; + uint32_t pe, end; - while (pe < pvm->pv->pe_count) - if (!_create_single_area(mem, pvm, &pe)) { + end = start + count - 1; + if (end > pvm->pvl->pv->pe_count - 1) + end = pvm->pvl->pv->pe_count - 1; + + pe = start; + while (pe <= end) + if (!_create_single_area(mem, pvm, end, &pe)) { stack; return 0; } @@ -185,7 +194,36 @@ static int _create_areas(struct pool *mem, struct pv_map *pvm) return 1; } -static int _create_all_areas(struct pool *mem, struct list *maps) +static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm) +{ + struct list *alloc_areas, *aah; + struct alloc_area *aa; + + alloc_areas = pvm->pvl->alloc_areas; + + if (alloc_areas) { + list_iterate(aah, alloc_areas) { + aa = list_item(aah, struct alloc_area); + if (!_create_areas(mem, pvm, aa->start, aa->count)) { + stack; + return 0; + } + + } + } else { + /* Use whole PV */ + if (!_create_areas(mem, pvm, UINT32_C(0), + pvm->pvl->pv->pe_count)) { + stack; + return 0; + } + } + + return 1; +} + +static int _create_all_areas(struct pool *mem, struct list *maps, + struct list *pvs) { struct list *tmp; struct pv_map *pvm; @@ -193,7 +231,7 @@ static int _create_all_areas(struct pool *mem, struct list *maps) list_iterate(tmp, maps) { pvm = list_item(tmp, struct pv_map); - if (!_create_areas(mem, pvm)) { + if (!_create_allocatable_areas(mem, pvm)) { stack; return 0; } @@ -226,7 +264,7 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, goto bad; } - if (!_create_all_areas(mem, maps)) { + if (!_create_all_areas(mem, maps, pvs)) { log_error("Couldn't create area maps in %s", vg->name); goto bad; } diff --git a/lib/metadata/pv_map.h b/lib/metadata/pv_map.h index 86e0d7624..7a00bb3d6 100644 --- a/lib/metadata/pv_map.h +++ b/lib/metadata/pv_map.h @@ -28,7 +28,7 @@ struct pv_area { }; struct pv_map { - struct physical_volume *pv; + struct pv_list *pvl; bitset_t allocated_extents; struct list areas; diff --git a/lib/report/columns.h b/lib/report/columns.h index 3aa89670a..7c877de4e 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -47,7 +47,7 @@ FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count") FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno") FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype") -FIELD(SEGS, seg, NUM, "#Str", stripes, 4, uint32, "stripes") +FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes") FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize") FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize") FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start") diff --git a/lib/report/report.c b/lib/report/report.c index 65ea8e13a..f114bb1d9 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -289,7 +289,7 @@ static int _segtype_disp(struct report_handle *rh, struct field *field, { const struct lv_segment *seg = (const struct lv_segment *) data; - if (seg->stripes == 1) + if (seg->area_count == 1) field->report_string = "linear"; else field->report_string = get_segtype_string(seg->type); diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 83fea1f5f..e8523b3fe 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -107,20 +107,22 @@ static int _read_name_params(struct lvcreate_params *lp, } } - if (lp->lv_name && (ptr = strrchr(lp->lv_name, '/'))) - lp->lv_name = ptr + 1; + if (lp->lv_name) { + if ((ptr = strrchr(lp->lv_name, '/'))) + lp->lv_name = ptr + 1; - /* FIXME Remove this restriction eventually */ - if (lp->lv_name && !strncmp(lp->lv_name, "snapshot", 8)) { - log_error("Names starting \"snapshot\" are reserved. " - "Please choose a different LV name."); - return 0; - } + /* FIXME Remove this restriction eventually */ + if (!strncmp(lp->lv_name, "snapshot", 8)) { + log_error("Names starting \"snapshot\" are reserved. " + "Please choose a different LV name."); + return 0; + } - if (!validate_name(lp->lv_name)) { - log_error("Logical volume name \"%s\" has invalid characters", - lp->lv_name); - return 0; + if (!validate_name(lp->lv_name)) { + log_error("Logical volume name \"%s\" has invalid " + "characters", lp->lv_name); + return 0; + } } return 1; @@ -276,8 +278,8 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd, } } else { if ((lp->minor != -1) || (lp->major != -1)) { - log_error - ("--major and --minor incompatible with -Mn"); + log_error("--major and --minor incompatible " + "with -Mn"); return 0; } } diff --git a/tools/lvresize.c b/tools/lvresize.c index b92fed39c..8c26544d9 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -192,8 +192,12 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) uint32_t sz, str; seg = list_item(segh, struct lv_segment); + + if (seg->type != SEG_STRIPED) + continue; + sz = seg->stripe_size; - str = seg->stripes; + str = seg->area_count; if ((seg_stripesize && seg_stripesize != sz && !ssize) || @@ -239,10 +243,13 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) uint32_t seg_extents; seg = list_item(segh, struct lv_segment); + seg_extents = seg->len; - seg_stripesize = seg->stripe_size; - seg_stripes = seg->stripes; + if (seg->type == SEG_STRIPED) { + seg_stripesize = seg->stripe_size; + seg_stripes = seg->area_count; + } if (extents <= extents_used + seg_extents) break; diff --git a/tools/toollib.c b/tools/toollib.c index 54fbb1acc..f8ff27a06 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -437,11 +437,120 @@ char *default_vgname(struct cmd_context *cmd) return pool_strdup(cmd->mem, vg_path); } +static int _add_alloc_area(struct pool *mem, struct list *alloc_areas, + uint32_t start, uint32_t count) +{ + struct alloc_area *aa; + struct list *aah; + + log_debug("Adding alloc area: start PE %" PRIu32 " length %" PRIu32, + start, count); + + /* Ensure no overlap with existing areas */ + list_iterate(aah, alloc_areas) { + aa = list_item(aah, struct alloc_area); + if (((start < aa->start) && (start + count - 1 >= aa->start)) || + ((start >= aa->start) && + (aa->start + aa->count - 1) >= start)) { + log_error("Overlapping PE ranges detected (%" PRIu32 + "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")", + start, start + count - 1, aa->start, + aa->start + aa->count - 1); + return 0; + } + } + + if (!(aa = pool_alloc(mem, sizeof(*aa)))) { + log_error("Allocation of list failed"); + return 0; + } + + aa->start = start; + aa->count = count; + list_add(alloc_areas, &aa->list); + + return 1; +} + +static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas, + uint32_t size) +{ + char *endptr; + uint32_t start, end; + + /* Default to whole PV */ + if (!c) { + if (!_add_alloc_area(mem, alloc_areas, UINT32_C(0), size)) { + stack; + return 0; + } + return 1; + } + + while (*c) { + if (*c != ':') + goto error; + + c++; + + /* Disallow :: and :\0 */ + if (*c == ':' || !*c) + goto error; + + /* Default to whole range */ + start = UINT32_C(0); + end = size - 1; + + /* Start extent given? */ + if (isdigit(*c)) { + start = (uint32_t) strtoul(c, &endptr, 10); + if (endptr == c) + goto error; + c = endptr; + /* Just one number given? */ + if (!*c || *c == ':') + end = start; + } + /* Range? */ + if (*c == '-') { + c++; + if (isdigit(*c)) { + end = (uint32_t) strtoul(c, &endptr, 10); + if (endptr == c) + goto error; + c = endptr; + } + } + if (*c && *c != ':') + goto error; + + if ((start > end) || (end > size - 1)) { + log_error("PE range error: start extent %" PRIu32 " to " + "end extent %" PRIu32, start, end); + return 0; + } + + if (!_add_alloc_area(mem, alloc_areas, start, end - start + 1)) { + stack; + return 0; + } + + } + + return 1; + + error: + log_error("Physical extent parsing error at %s", c); + return 0; +} + struct list *create_pv_list(struct pool *mem, struct volume_group *vg, int argc, char **argv) { struct list *r; + struct list *alloc_areas; struct pv_list *pvl, *new_pvl; + char *pvname = NULL, *colon; int i; /* Build up list of PVs */ @@ -452,16 +561,29 @@ struct list *create_pv_list(struct pool *mem, list_init(r); for (i = 0; i < argc; i++) { + if ((colon = strchr(argv[i], ':'))) { + if (!(pvname = pool_strndup(mem, argv[i], + colon - argv[i]))) { + log_error("Failed to clone PV name"); + return NULL; + } + } else + pvname = argv[i]; - if (!(pvl = find_pv_in_vg(vg, argv[i]))) { + if (!(pvl = find_pv_in_vg(vg, pvname))) { log_err("Physical Volume \"%s\" not found in " - "Volume Group \"%s\"", argv[i], vg->name); + "Volume Group \"%s\"", pvname, vg->name); return NULL; } + if (!(pvl->pv->status & ALLOCATABLE_PV)) { + log_error("Physical volume %s not allocatable", pvname); + continue; + } + if (pvl->pv->pe_count == pvl->pv->pe_alloc_count) { log_err("No free extents on physical volume \"%s\"", - argv[i]); + pvname); continue; } @@ -472,7 +594,47 @@ struct list *create_pv_list(struct pool *mem, memcpy(new_pvl, pvl, sizeof(*new_pvl)); list_add(r, &new_pvl->list); + + if (!(alloc_areas = pool_alloc(mem, sizeof(*alloc_areas)))) { + log_error("Allocation of alloc_areas list failed"); + return NULL; + } + list_init(alloc_areas); + + /* Specify which physical extents may be used for allocation */ + if (!_parse_pes(mem, colon, alloc_areas, pvl->pv->pe_count)) { + stack; + return NULL; + } + new_pvl->alloc_areas = alloc_areas; } return list_empty(r) ? NULL : r; } + +struct list *clone_pv_list(struct pool *mem, struct list *pvsl) +{ + struct list *r, *pvh; + struct pv_list *pvl, *new_pvl; + + /* Build up list of PVs */ + if (!(r = pool_alloc(mem, sizeof(*r)))) { + log_error("Allocation of list failed"); + return NULL; + } + list_init(r); + + list_iterate(pvh, pvsl) { + pvl = list_item(pvh, struct pv_list); + + if (!(new_pvl = pool_zalloc(mem, sizeof(*new_pvl)))) { + log_error("Unable to allocate physical volume list."); + return NULL; + } + + memcpy(new_pvl, pvl, sizeof(*new_pvl)); + list_add(r, &new_pvl->list); + } + + return r; +} diff --git a/tools/toollib.h b/tools/toollib.h index 45cb8573f..1a7e7d11a 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -81,4 +81,6 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name); struct list *create_pv_list(struct pool *mem, struct volume_group *vg, int argc, char **argv); +struct list *clone_pv_list(struct pool *mem, struct list *pvs); + #endif diff --git a/tools/vgreduce.c b/tools/vgreduce.c index d9ad696fc..6ec664657 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -138,8 +138,13 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) /* Are any segments of this LV on missing PVs? */ list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; + for (s = 0; s < seg->area_count; s++) { + if (seg->area[s].type != AREA_PV) + continue; + + /* FIXME Also check for segs on deleted LVs */ + + pv = seg->area[s].u.pv.pv; if (!pv || !pv->dev) { if (!_remove_lv(cmd, lv, &list_unsafe)) { stack; diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 301e2e56f..4d598d716 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -66,8 +66,12 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) vg_with = NULL; list_iterate(segh, &lv->segments) { seg = list_item(segh, struct lv_segment); - for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s].pv; + for (s = 0; s < seg->area_count; s++) { + /* FIXME Check AREA_LV too */ + if (seg->area[s].type != AREA_PV) + continue; + + pv = seg->area[s].u.pv.pv; if (vg_with) { if (!pv_is_in_vg(vg_with, pv)) { log_error("Logical Volume %s " @@ -104,6 +108,8 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) vg_to->lv_count++; } + /* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */ + return 1; }