mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
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
This commit is contained in:
parent
098102afc0
commit
b8c919b402
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
168
tools/toollib.c
168
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user