diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index f1f5f780f..2ad7ddf29 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -281,6 +281,8 @@ 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 stripe_segment)->stripes; + lvd->lv_stripesize = list_item(lv->segments.n, + struct stripe_segment)->stripe_size; lvd->lv_size = lv->size; lvd->lv_allocated_le = lv->le_count; @@ -314,8 +316,8 @@ int export_extents(struct disk_list *dl, int lv_num, for (pe = 0; pe < (seg->len / seg->stripes); pe++) { ped = &dl->extents[pe + seg->area[s].pe]; ped->lv_num = lv_num; - ped->le_num = seg->le + s + - (seg->stripes * pe); + ped->le_num = seg->le + pe + + s * (seg->len / seg->stripes); } } } diff --git a/lib/format1/import-extents.c b/lib/format1/import-extents.c index bb03e3176..469bc5d57 100644 --- a/lib/format1/import-extents.c +++ b/lib/format1/import-extents.c @@ -238,30 +238,55 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm) static int _read_stripes(struct pool *mem, struct lv_map *lvm) { - uint32_t stripes = lvm->stripes, s; - uint32_t stripe_len = lvm->lv->le_count / stripes; + uint32_t stripes = lvm->stripes, s, le = 0, pe; struct stripe_segment *seg; struct pe_specifier *pes; - if (!(seg = _alloc_seg(mem, stripes))) { - stack; - return 0; + while (le < lvm->lv->le_count) { + if (!(seg = _alloc_seg(mem, stripes))) { + stack; + return 0; + } + + seg->lv = lvm->lv; + seg->le = le; + seg->len = 0; + seg->stripe_size = lvm->stripe_size; + seg->stripes = stripes; + + seg->area[0].pv = lvm->map[le].pv; + seg->area[0].pe = lvm->map[le].pe; + + do + seg->len++; + while ((lvm->map[le + seg->len].pv == seg->area[0].pv) && + (lvm->map[le + seg->len].pe == seg->area[0].pe + + seg->len)); + + for (s = 1; s < stripes; s++) { + pes = &lvm->map[le + s * seg->len]; + + seg->area[s].pv = pes->pv; + seg->area[s].pe = pes->pe; + + for (pe = 0; pe < seg->len; pe++) { + if (lvm->map[le + s * seg->len + pe].pe != + pes->pe + pe) { + log_error("Incompatible striping at LE" + " %d on %s", + le + s * seg->len + pe, + seg->lv->name); + return 0; + } + } + } + + seg->len *= stripes; + le += seg->len; + + list_add(&lvm->lv->segments, &seg->list); } - seg->lv = lvm->lv; - seg->le = 0; - seg->len = lvm->lv->le_count; - seg->stripe_size = lvm->stripe_size; - seg->stripes = stripes; - - for (s = 0; s < stripes; s++) { - pes = &lvm->map[s * stripe_len]; - - seg->area[s].pv = pes->pv; - seg->area[s].pe = pes->pe; - } - - list_add(&lvm->lv->segments, &seg->list); return 1; } diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index fe6cd72a4..675a02dad 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -21,7 +21,7 @@ static void _get_extents(struct stripe_segment *seg) struct physical_volume *pv; for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s % seg->stripes].pv; + pv = seg->area[s].pv; count = seg->len / seg->stripes; pv->pe_allocated += count; } @@ -33,7 +33,7 @@ static void _put_extents(struct stripe_segment *seg) struct physical_volume *pv; for (s = 0; s < seg->stripes; s++) { - pv = seg->area[s % seg->stripes].pv; + pv = seg->area[s].pv; count = seg->len / seg->stripes; assert(pv->pe_allocated >= count); @@ -54,7 +54,8 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes) return seg; } -static int _alloc_stripe_area(struct logical_volume *lv, int stripes, +static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes, + uint32_t stripe_size, struct pv_area **areas, uint32_t *index) { uint32_t count = lv->le_count - *index; @@ -75,6 +76,7 @@ static int _alloc_stripe_area(struct logical_volume *lv, int stripes, seg->le = *index; seg->len = per_area * stripes; seg->stripes = stripes; + seg->stripe_size = stripe_size; for (s = 0; s < stripes; s++) { struct pv_area *pva = areas[s]; @@ -147,7 +149,8 @@ static int _alloc_striped(struct logical_volume *lv, /* sort the areas so we allocate from the biggest */ qsort(areas, index, sizeof(*areas), _comp_area); - if (!_alloc_stripe_area(lv, stripes, areas, &allocated)) { + if (!_alloc_stripe_area(lv, stripes, stripe_size, areas, + &allocated)) { stack; goto out; } @@ -175,7 +178,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index, count = pva->count; remaining = lv->le_count - *index; - if (count < remaining) + if (count > remaining) count = remaining; if (!(seg = _alloc_segment(lv->vg->cmd->mem, 1))) { @@ -272,7 +275,7 @@ static int _alloc_simple(struct logical_volume *lv, return 0; } - return 0; + return 1; } /* @@ -387,6 +390,13 @@ struct logical_volume *lv_create(const char *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"); diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index efb8b31c8..14ecfe783 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -49,7 +49,11 @@ static int _set_allocated(struct hash_table *hash, } /* sanity check */ - assert(!bit(pvm->allocated_extents, pe)); + if (bit(pvm->allocated_extents, pe)) { + log_error("Physical extent %d of %s referenced by more than " + "one logical volume", pe, dev_name(pv->dev)); + return 0; + } bit_set(pvm->allocated_extents, pe); return 1; @@ -60,9 +64,10 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) struct list *lvh, *pvmh, *segh; struct logical_volume *lv; struct pv_map *pvm; - uint32_t i, r = 0; + uint32_t s, pe; struct hash_table *hash; struct stripe_segment *seg; + int r = 0; if (!(hash = hash_create(128))) { log_err("Couldn't create hash table for pv maps."); @@ -85,13 +90,16 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps) list_iterate (segh, &lv->segments) { seg = list_item(segh, struct stripe_segment); - for (i = 0; i < seg->len; i++) { - if (!_set_allocated(hash, - seg->area[i % seg->stripes].pv, - seg->area[i % seg->stripes].pe + - (i / seg->stripes))) { - stack; - goto out; + 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)) { + stack; + goto out; + } } } } diff --git a/tools/lvcreate.c b/tools/lvcreate.c index fc5e48ca7..049ff029c 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -212,7 +212,8 @@ int lvcreate(int argc, char **argv) } if (!(lv = lv_create(lv_name, status, stripes, stripesize, extents, - vg, pvh))) return ECMD_FAILED; + vg, pvh))) + return ECMD_FAILED; if (arg_count(readahead_ARG)) { log_verbose("Setting read ahead sectors"); diff --git a/tools/lvresize.c b/tools/lvresize.c index f14694e80..8f6857344 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -296,7 +296,8 @@ int lvresize(int argc, char **argv) } } - lv_reduce(lv, lv->le_count - extents); + if (!lv_reduce(lv, lv->le_count - extents)) + return ECMD_FAILED; } if (resize == LV_EXTEND && argc) { @@ -333,7 +334,9 @@ int lvresize(int argc, char **argv) log_print("Extending logical volume %s to %s", lv_name, dummy); dbg_free(dummy); - lv_extend(lv, stripes, stripesize, extents - lv->le_count, pvh); + if (!lv_extend(lv, stripes, stripesize, extents - lv->le_count, + pvh)) + return ECMD_FAILED; } /********* FIXME Suspend lv ***********/